feat(dev-base): pin wasm-pack and binaryen into the Rust payload #986

Merged
coilysiren merged 1 commit from aos/claude/dev-base-wasm-toolchain into main 2026-08-09 21:59:02 +00:00
Owner

What

Adds pinned wasm-pack (0.15.0) and binaryen (version_119, bin/wasm-opt only) to the dev-base-lang-rust payload, with BINARYEN_ARCH / WASM_PACK_ARCH entries in write-arch-env.sh and both binaries added to the full image smoke line.

Why

The Rust payload already runs rustup target add wasm32-unknown-unknown, but shipped nothing to drive that target. Every repo building Rust to WASM therefore installs its own toolchain per environment.

galaxy-gen is the worked example. Its bundle is produced in four places with three different toolchains:

  • Local host - ward exec build-js-prod - cargo install wasm-pack (floating), and no binaryen at all
  • GitHub PR CI - ubuntu-latest - floating wasm-pack, binaryen version_119 on PATH
  • Publish Dockerfile - deploy runner - floating wasm-pack, binaryen version_119, and node 20 rather than the image's 22
  • Forgejo main CI - builds no bundle at all, Rust lint plus cargo test only

The artifact serving galaxy-gen.coilysiren.me comes from the third row. Playwright only ever runs against the second. The bundle that ships is not the bundle anything tested.

Why binaryen is the pin that matters

wasm-pack takes wasm-opt from PATH when it finds one and otherwise downloads its own floating latest build. An image without a pinned binaryen therefore reoptimizes every bundle by build date rather than by source, silently. Pinning to the same 119 galaxy-gen already proved against chromium makes this an availability change rather than a behavior change.

Blast radius

Additive. wasm-pack 0.15.0 is what cargo install wasm-pack resolves to today, so a repo moving onto the image keeps its current toolchain and gains only the determinism. No existing tool, path, or version changes.

Only bin/wasm-opt is extracted from the binaryen tarball. lib/libbinaryen.a is a static archive the binary has already absorbed (verified: the extracted wasm-opt is a statically linked ELF), and include/ serves C API consumers this image does not have.

Verification

  • pre-commit run --files ... green on all three files, including code-comment discipline and shellcheck
  • write-arch-env.sh amd64 branch, arm64 branch, and emitted list all agree at 17 vars
  • Both tar extraction commands exercised against the real release tarballs, each landing exactly one binary
  • aarch64 asset names confirmed present in both upstream release listings
  • Not built locally: no Docker daemon on this host. dev-base-pr / build is the authoritative gate here.

Follow-up

Unblocks CI-in-dev-base adoption (agentic-os#328) for WASM repos. galaxy-gen adoption is the first mover and is tracked separately. Note that Playwright e2e still cannot move into dev-base, which carries no browser.

## What Adds pinned `wasm-pack` (0.15.0) and `binaryen` (`version_119`, `bin/wasm-opt` only) to the `dev-base-lang-rust` payload, with `BINARYEN_ARCH` / `WASM_PACK_ARCH` entries in `write-arch-env.sh` and both binaries added to the full image smoke line. ## Why The Rust payload already runs `rustup target add wasm32-unknown-unknown`, but shipped nothing to drive that target. Every repo building Rust to WASM therefore installs its own toolchain per environment. galaxy-gen is the worked example. Its bundle is produced in four places with three different toolchains: * Local host - `ward exec build-js-prod` - `cargo install wasm-pack` (floating), and **no binaryen at all** * GitHub PR CI - `ubuntu-latest` - floating wasm-pack, binaryen `version_119` on PATH * Publish Dockerfile - `deploy` runner - floating wasm-pack, binaryen `version_119`, and node 20 rather than the image's 22 * Forgejo main CI - builds no bundle at all, Rust lint plus `cargo test` only The artifact serving galaxy-gen.coilysiren.me comes from the third row. Playwright only ever runs against the second. The bundle that ships is not the bundle anything tested. ## Why binaryen is the pin that matters `wasm-pack` takes `wasm-opt` from PATH when it finds one and otherwise downloads its own floating `latest` build. An image without a pinned binaryen therefore reoptimizes every bundle by build date rather than by source, silently. Pinning to the same 119 galaxy-gen already proved against chromium makes this an availability change rather than a behavior change. ## Blast radius Additive. `wasm-pack 0.15.0` is what `cargo install wasm-pack` resolves to today, so a repo moving onto the image keeps its current toolchain and gains only the determinism. No existing tool, path, or version changes. Only `bin/wasm-opt` is extracted from the binaryen tarball. `lib/libbinaryen.a` is a static archive the binary has already absorbed (verified: the extracted `wasm-opt` is a statically linked ELF), and `include/` serves C API consumers this image does not have. ## Verification * `pre-commit run --files ...` green on all three files, including code-comment discipline and shellcheck * `write-arch-env.sh` amd64 branch, arm64 branch, and emitted list all agree at 17 vars * Both `tar` extraction commands exercised against the real release tarballs, each landing exactly one binary * aarch64 asset names confirmed present in both upstream release listings * **Not** built locally: no Docker daemon on this host. `dev-base-pr / build` is the authoritative gate here. ## Follow-up Unblocks CI-in-dev-base adoption (agentic-os#328) for WASM repos. galaxy-gen adoption is the first mover and is tracked separately. Note that Playwright e2e still cannot move into dev-base, which carries no browser.
feat(dev-base): pin wasm-pack and binaryen into the Rust payload
All checks were successful
ci / ward-doctor (pull_request) Successful in 15s
ci / aos-cli-tests (pull_request) Successful in 31s
ci / gate (pull_request) Successful in 58s
dev-base-pr / build (pull_request) Successful in 10m59s
2a81de7af3
The Rust payload already adds the wasm32-unknown-unknown target, but shipped
no wasm-pack to drive it and no wasm-opt to post-process the output. Any repo
building Rust to WASM therefore installed its own toolchain per environment,
and galaxy-gen shows what that costs: local dev, GitHub PR CI, and the publish
Dockerfile each resolve a different wasm-pack and a different wasm-opt, so the
bundle that ships is not the bundle anything tested.

binaryen is the pin that matters most. wasm-pack takes wasm-opt from PATH when
it finds one and otherwise downloads its own floating "latest" build, so an
image without it silently reoptimizes every bundle by build date rather than by
source. Pinning it to the same 119 galaxy-gen already proved against chromium
keeps this an availability change, not a behavior change.

wasm-pack 0.15.0 is what `cargo install wasm-pack` resolves to today, so
consumers moving onto the image keep their current toolchain and gain only the
determinism.

Only bin/wasm-opt is kept from the binaryen tarball. lib/libbinaryen.a is a
static archive the binary has already absorbed, and include/ serves C API
consumers this image does not have.

Unblocks app CI-in-dev-base adoption (agentic-os#328) for WASM repos.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
coilysiren deleted branch aos/claude/dev-base-wasm-toolchain 2026-08-09 21:59:02 +00:00
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!986
No description provided.