feat(dev-base): bake the wasm-bindgen CLI so wasm-pack stops downloading it #1420

Merged
coilyco-ops merged 3 commits from aos/claude/md68 into main 2026-08-29 16:38:52 +00:00
Owner

The image pins wasm-pack, trunk, and wasm-opt. The wasm-opt block states exactly why:

wasm-pack takes wasm-opt from PATH when it finds one and otherwise downloads its own floating "latest" build

wasm-pack treats wasm-bindgen the same way, and that one was never baked. The hole this image closed twice was left open on the third leg, and it is the leg that actually fails.

Evidence

galaxy-gen#89 is the worked example. Seven of its last twelve runs ended cancelled, and every one of the six I pulled logs for (157, 158, 159, 160, 163, 164) died on the identical line:

    Finished `release` profile [optimized] target(s) in 6.76s
[INFO]: ⬇️  Installing wasm-bindgen...
The runner cancelled the job because it exceeds the maximum run time

Run 164 started 06:28:29 and was killed 06:58:30: under seven seconds compiling the crate, then the rest of a 30m runner budget on one download. Run 165 reproduced it after I bounded the job at 10m. Same shape as galaxy-gen#84, which is why the pinned-toolchain section already exists.

The one subtlety

WASM_BINDGEN_VERSION is not free to float. wasm-pack compares the CLI against the wasm-bindgen crate version a consumer locks and fetches the matching CLI when they differ, so a stale pin does not fail loudly, it silently restores the stall this removes. The pin tracks consumers rather than leading them.

0.2.118 is what galaxy-gen locks today, and its wasm-bindgen = "^0.2" can move on any cargo update with nobody choosing it. docs/dev-base-wasm-toolchain.md carries that rule and the --mode no-install escape for a consumer who would rather have drift fail loudly.

Shape

  • Both arches take the upstream musl tarball, so neither depends on host glibc. WASM_BINDGEN_ARCH resolves beside every other tool's arch var.
  • Only the two binaries wasm-pack invokes are kept. wasm2es6js ships in the tarball and wasm-pack never calls it.
  • The full image now verifies wasm-bindgen --version alongside the other three, so an unplumbed arg cannot pass silently.
  • New doc is a separate page because dev-base-image.md sits exactly at its 120-line cap.

What I could not check

I have no Docker daemon on this host, so I never built the image. The build is the validation. Asset names and tarball layout were verified against the upstream release rather than assumed - note the repo has moved to wasm-bindgen/wasm-bindgen, and the URL here uses the canonical org.

pre-commit run --all-files is clean.

Refs galaxy-gen#89

The image pins `wasm-pack`, `trunk`, and `wasm-opt`. The wasm-opt block states exactly why: > wasm-pack takes wasm-opt from PATH when it finds one and otherwise downloads its own floating "latest" build wasm-pack treats `wasm-bindgen` the same way, and that one was never baked. The hole this image closed twice was left open on the third leg, and it is the leg that actually fails. ## Evidence galaxy-gen#89 is the worked example. Seven of its last twelve runs ended `cancelled`, and every one of the six I pulled logs for (157, 158, 159, 160, 163, 164) died on the identical line: Finished `release` profile [optimized] target(s) in 6.76s [INFO]: ⬇️ Installing wasm-bindgen... The runner cancelled the job because it exceeds the maximum run time Run 164 started 06:28:29 and was killed 06:58:30: under seven seconds compiling the crate, then the rest of a 30m runner budget on one download. Run 165 reproduced it after I bounded the job at 10m. Same shape as galaxy-gen#84, which is why the pinned-toolchain section already exists. ## The one subtlety `WASM_BINDGEN_VERSION` is not free to float. wasm-pack compares the CLI against the wasm-bindgen **crate** version a consumer locks and fetches the matching CLI when they differ, so a stale pin does not fail loudly, it silently restores the stall this removes. The pin tracks consumers rather than leading them. 0.2.118 is what galaxy-gen locks today, and its `wasm-bindgen = "^0.2"` can move on any `cargo update` with nobody choosing it. `docs/dev-base-wasm-toolchain.md` carries that rule and the `--mode no-install` escape for a consumer who would rather have drift fail loudly. ## Shape - Both arches take the upstream musl tarball, so neither depends on host glibc. `WASM_BINDGEN_ARCH` resolves beside every other tool's arch var. - Only the two binaries wasm-pack invokes are kept. `wasm2es6js` ships in the tarball and wasm-pack never calls it. - The full image now verifies `wasm-bindgen --version` alongside the other three, so an unplumbed arg cannot pass silently. - New doc is a separate page because `dev-base-image.md` sits exactly at its 120-line cap. ## What I could not check I have no Docker daemon on this host, so I never built the image. The build is the validation. Asset names and tarball layout were verified against the upstream release rather than assumed - note the repo has moved to `wasm-bindgen/wasm-bindgen`, and the URL here uses the canonical org. `pre-commit run --all-files` is clean. Refs galaxy-gen#89
feat(dev-base): bake the wasm-bindgen CLI so wasm-pack stops downloading it
Some checks failed
ci / aos-cli-tests (pull_request) Successful in 42s
ci / gate (pull_request) Successful in 1m2s
dev-base-pr / build (pull_request) Failing after 11m15s
a4150e201d
The image pins wasm-pack, trunk, and wasm-opt, and the wasm-opt block states
exactly why:

    wasm-pack takes wasm-opt from PATH when it finds one and otherwise
    downloads its own floating "latest" build

wasm-pack treats wasm-bindgen the same way, and that one was never baked. So
the hole this image closed twice was left open on the third leg, and it is the
one that actually fails.

galaxy-gen is the worked example (galaxy-gen#89). Seven of its last twelve runs
ended `cancelled`, and every one of the six I pulled logs for died on the same
line:

        Finished `release` profile [optimized] target(s) in 6.76s
    [INFO]: ⬇️  Installing wasm-bindgen...
    The runner cancelled the job because it exceeds the maximum run time

Under seven seconds to compile the crate, then the rest of a 30m runner budget
spent on one download. Same shape as galaxy-gen#84, which is why the pinned
toolchain section already exists.

WASM_BINDGEN_VERSION is not free to float, and that is the one subtlety here.
wasm-pack compares the CLI against the wasm-bindgen CRATE version a consumer
locks and fetches the matching CLI when they differ, so a stale pin does not
fail loudly, it silently restores the stall. The pin tracks consumers rather
than leading them. 0.2.118 is what galaxy-gen locks today, and its
`wasm-bindgen = "^0.2"` can move it on any `cargo update`.
docs/dev-base-wasm-toolchain.md carries that rule and the --mode no-install
escape for a consumer who would rather drift failed loudly.

Both arches take the upstream musl tarball, so neither depends on host glibc.
Only the two binaries wasm-pack invokes are kept. The full image now verifies
`wasm-bindgen --version` alongside the other three.

The new doc is a separate page because dev-base-image.md sits exactly at its
120-line cap.

I could not build the image to check this: no Docker daemon on the host I am
on. The build is the validation.

Refs galaxy-gen#89

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Agent-Role: platform
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
fix(dev-base): emit WASM_BINDGEN_ARCH into arch.env, not just the case block
All checks were successful
ci / aos-cli-tests (pull_request) Successful in 35s
ci / gate (pull_request) Successful in 1m4s
dev-base-pr / build (pull_request) Successful in 6m27s
a16738ee4e
The build failed on my own previous commit:

    /bin/bash: line 1: WASM_BINDGEN_ARCH: unbound variable

prepare-build-stage.sh carries the arch map twice. The `case` block assigns
every var, and a separate `printf` writes an explicit allowlist of them to
/opt/agentic-os/arch.env, which is the only thing the Dockerfile stages
source. I added the two case entries and missed the writer, so the variable
existed while the script ran and never reached the file that consumes it.

Verified this time rather than assumed: ran the script for both TARGETARCH
values against a redirected output path, and arch.env now carries
WASM_BINDGEN_ARCH=x86_64 and =aarch64 respectively. Both release URLs answer
206 to a ranged request.

The failure was at least loud - `set -eux` plus an unset variable stopped the
layer immediately with the variable named - so no guard is added here.

Refs galaxy-gen#89

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Agent-Role: platform
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
Merge branch 'main' into aos/claude/md68
Some checks failed
ci / aos-cli-tests (pull_request) Successful in 39s
ci / gate (pull_request) Successful in 1m3s
dev-base-pr / build (pull_request) Failing after 15m20s
78ca56ad10
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1420
No description provided.