Skip to content

ci: pin the emscripten toolchain; stop the format gate swallowing rustfmt - #161

Merged
akesling merged 1 commit into
mainfrom
akesling/pin-emsdk-toolchain
Aug 6, 2026
Merged

ci: pin the emscripten toolchain; stop the format gate swallowing rustfmt#161
akesling merged 1 commit into
mainfrom
akesling/pin-emsdk-toolchain

Conversation

@akesling

@akesling akesling commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Two CI reliability bugs, both live on main right now.

1. The wasm toolchain was unpinned

scripts/build-wasm.sh bootstrapped with emsdk install latest and deploy-site.yml cached it under the constant key emsdk-latest. That combination means the compiler is whatever latest resolved to on the day the cache was last populated — and a cache eviction silently changes it.

That eviction has now happened. Emscripten's wasm exception-handling ABI moved, and the fresh latest fails to link:

wasm-ld: error: undefined symbol: __cpp_exception
wasm-ld: error: undefined symbol: _Unwind_DeleteException / _Unwind_RaiseException
error: could not compile `path-cli` (bin "path")

This is not branch-specific — main hits it on its next deploy.

Fix: .emsdk-version is the single source of truth. The build script installs exactly that version; the workflow keys its emsdk cache on the file's hash, so a cache miss reinstalls the same compiler and bumping the pin invalidates the cache automatically. An emscripten already on PATH that differs from the pin warns — naming both versions and the link errors the skew produces — rather than failing, so developer machines with their own SDK still build.

Pinned to 5.0.1, verified rather than assumed: built this workspace on 5.0.1 with both the --dev profile and the default wasm profile CI actually runs (LTO, opt-level=z, strip). Both link clean, no __cpp_exception / _Unwind_* errors. For the record, a fresh emsdk clone currently maps latest → 5.0.1 while the failing CI run reported releases-833aa203…, which is precisely the skew being pinned out.

2. The format gate reported PASS on rustfmt failures

gate_format ran cargo fmt --check and then prettier, so the function's exit status was only ever prettier's. rustfmt failures were swallowed — which is why crates/toolpath-codex/src/{io.rs,paths.rs} have been unformatted on main without anyone hearing about it. They are reformatted here (pure cargo fmt --all output, no other edits).

Both checks now always run — one pass reports every formatting problem — and either failing fails the gate. Verified by appending a deliberately misformatted function and running both versions of the gate: the old one printed PASS: format, the new one prints the rustfmt diff, still runs prettier, then FAIL: format.

While in there: gate_format's bare cd "${_root}/site" leaked the working directory into every gate that ran after it (gates execute in the caller's shell). It and gate_site's cd now run in subshells. The other gates were checked for the same masking pattern — gate_examples already accumulates failures, the rest are single-command — and scripts/{fmt,check}.sh use set -euo pipefail.

Testing

All 8 quality gates green in a clean clone: format, shellcheck, clippy, test, doc, examples, plugin, site.

Known adjacent issue left alone to keep this diff to the two fixes: wasm_is_stale() passes .cargo/config.toml to find under a -name '*.rs' -o -name 'Cargo.toml' predicate that can never match it, so --if-changed misses link-flag changes.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…tfmt

The wasm build installed `latest` and cached it under a constant key, so
an expired cache silently swapped compilers. Emscripten's wasm
exception-handling ABI has since moved, and the fresh `latest` fails to
link with undefined __cpp_exception / _Unwind_* symbols — main is
exposed to this on its next deploy, not just one branch.

.emsdk-version is now the single source of truth: the build script
installs that version and the deploy workflow keys its emsdk cache on
the file's hash, so a cache miss reinstalls the same compiler and a bump
invalidates the cache. A mismatched emscripten already on PATH warns
(naming both versions and the link errors it causes) rather than
failing, so developer machines still build.

The format gate returned only prettier's status, so `cargo fmt --check`
failures reported PASS — two files have been unformatted on main
unnoticed and are reformatted here. Both checks now always run and
either failing fails the gate. The gate's bare `cd` also leaked the
working directory into every later gate; it and the site gate's now run
in subshells.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔍 Preview deployed: https://7c775899.toolpath.pages.dev

@akesling
akesling merged commit b5f7f66 into main Aug 6, 2026
3 checks passed
@akesling
akesling deleted the akesling/pin-emsdk-toolchain branch August 6, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant