Problem
The Rust compiler is an undeclared dependency, and developers and CI use
different ones.
- The devcontainer never pins:
.devcontainer/Dockerfile:89
runs rustup ... -y with no version, so the image freezes on whatever was
stable when it was built (currently 1.91.1) and shifts silently on every
rebuild.
- Every workflow uses
dtolnay/rust-toolchain@stable, which always tracks
current stable (1.97.1 at time of writing).
- No crate declares
rust-version, so there is no MSRV either.
Nobody chose this ~6-version gap, and nothing surfaces it until it breaks.
Why now
It already cost us. On #201 the new wasm-browser-tests job failed five
consecutive runs on a bug that was impossible to reproduce locally:
wasm-bindgen 0.2.105 generated a duplicate JS identifier
SyntaxError: Identifier 'wasm_bindgen_..._convert__closures_____invoke______'
has already been declared
Symbol mangling depends on the compiler, so it appeared only under CI's newer
rustc. The generated glue was a parse error, so no test ever started — the
page sat at "Loading scripts...", the harness's console divs stayed empty, and
four plausible fixes (harness timeout, module size, session ordering, Chrome
sandbox) each did nothing, because none of them touch code that never parses.
Diagnosing it took a verbose chromedriver log capture in CI.
Fixed by upgrading the wasm-bindgen family, but the toolchain gap is what made
it invisible, and every other job carries the same exposure.
Proposed change
Pin forward, to current stable — not back to the devcontainer's 1.91.1.
Pinning backwards would make CI agree with the devcontainer by freezing CI on
an old compiler, which would have hidden this bug rather than caught it:
consumers build with current stable and would still have hit it.
# rust-toolchain.toml
[toolchain]
channel = "1.97.1"
components = ["rustfmt", "clippy"]
targets = ["wasm32-unknown-unknown", "thumbv7em-none-eabihf"]
The catch — this is not a one-file change
rust-toolchain.toml overrides rustup's default, but dtolnay/rust-toolchain
installs targets:/components: onto its own toolchain. Add the file
naively and CI downloads two toolchains, then builds against the pinned one
without wasm32-unknown-unknown, thumbv7em-none-eabihf, rustfmt or
clippy — failing with missing-target errors that look nothing like the cause.
So targets/components move into the file, and all 9 install sites stop
declaring their own:
| workflow |
sites |
ci.yml |
5 stable + 1 nightly (miri) |
docs.yml |
1 |
release.yml |
1 |
security.yml |
2 |
- The Miri job is unaffected —
cargo +nightly overrides the file explicitly.
.devcontainer/Dockerfile should stop installing targets by hand and let
rustup materialize them from the file.
Also in scope
Declare a workspace rust-version. Pinning the toolchain and declaring an MSRV
are different promises: the pin says what we build with, the MSRV says what
consumers need. The repo currently makes neither, while publishing to
crates.io.
Out of scope
Bumping the pin on a schedule / via Dependabot. Worth doing, but let's land the
pin first and see how it feels.
Acceptance
Follow-up from #201 (design 049-pr201-review-closeout.md, work item A).
Problem
The Rust compiler is an undeclared dependency, and developers and CI use
different ones.
.devcontainer/Dockerfile:89runs
rustup ... -ywith no version, so the image freezes on whatever wasstable when it was built (currently 1.91.1) and shifts silently on every
rebuild.
dtolnay/rust-toolchain@stable, which always trackscurrent stable (1.97.1 at time of writing).
rust-version, so there is no MSRV either.Nobody chose this ~6-version gap, and nothing surfaces it until it breaks.
Why now
It already cost us. On #201 the new
wasm-browser-testsjob failed fiveconsecutive runs on a bug that was impossible to reproduce locally:
wasm-bindgen0.2.105 generated a duplicate JS identifierSymbol mangling depends on the compiler, so it appeared only under CI's newer
rustc. The generated glue was a parse error, so no test ever started — the
page sat at "Loading scripts...", the harness's console divs stayed empty, and
four plausible fixes (harness timeout, module size, session ordering, Chrome
sandbox) each did nothing, because none of them touch code that never parses.
Diagnosing it took a verbose chromedriver log capture in CI.
Fixed by upgrading the wasm-bindgen family, but the toolchain gap is what made
it invisible, and every other job carries the same exposure.
Proposed change
Pin forward, to current stable — not back to the devcontainer's 1.91.1.
Pinning backwards would make CI agree with the devcontainer by freezing CI on
an old compiler, which would have hidden this bug rather than caught it:
consumers build with current stable and would still have hit it.
The catch — this is not a one-file change
rust-toolchain.tomloverrides rustup's default, butdtolnay/rust-toolchaininstalls
targets:/components:onto its own toolchain. Add the filenaively and CI downloads two toolchains, then builds against the pinned one
without
wasm32-unknown-unknown,thumbv7em-none-eabihf,rustfmtorclippy— failing with missing-target errors that look nothing like the cause.So targets/components move into the file, and all 9 install sites stop
declaring their own:
ci.ymldocs.ymlrelease.ymlsecurity.ymlcargo +nightlyoverrides the file explicitly..devcontainer/Dockerfileshould stop installing targets by hand and letrustup materialize them from the file.
Also in scope
Declare a workspace
rust-version. Pinning the toolchain and declaring an MSRVare different promises: the pin says what we build with, the MSRV says what
consumers need. The repo currently makes neither, while publishing to
crates.io.
Out of scope
Bumping the pin on a schedule / via Dependabot. Worth doing, but let's land the
pin first and see how it feels.
Acceptance
rust-toolchain.tomlcommitted, targets + components declared theremake checkpasses on the pinned toolchainrustc --versionidentical in the devcontainer and in CIrust-versiondeclaredFollow-up from #201 (design
049-pr201-review-closeout.md, work item A).