diff --git a/.project/objectives/p1-52-api-wasm-build-fix.md b/.project/objectives/p1-52-api-wasm-build-fix.md new file mode 100644 index 00000000..ac7c0b54 --- /dev/null +++ b/.project/objectives/p1-52-api-wasm-build-fix.md @@ -0,0 +1,128 @@ +--- +id: p1-52 +title: api-wasm build fix — unblock WASM bundle for design-lab WASM consumption +priority: p1 +status: missing +scope: game1 +owner: terraformer +updated_at: 2026-05-01 +wave: A.5 +coordinates_with: + - p1-46 + - p1-47 + - p1-48 + - p1-49 + - p1-50 + - p2-49 + - p2-50 +canonical_doc: public/games/age-of-dwarves/docs/terrain/WORLDGEN_RNG.md +--- + +## Summary + +`bash src/simulator/build-wasm.sh` currently fails with an upstream +compilation error in the `getrandom 0.3.x` line on `wasm32-unknown-unknown` +(both `0.3.3` and `0.3.4` reference `backends::inner_u32` / +`backends::inner_u64` symbols that don't exist in the wasm32 backend, +even with `--cfg getrandom_backend="wasm_js"`). + +Root of the dep chain (from `cargo tree -p magic-civ-physics --target +wasm32-unknown-unknown -i getrandom@0.3.4`): + +``` +getrandom v0.3.4 +└── rand_core v0.9.5 + ├── rand v0.9.2 + │ └── mc-trade v0.1.0 + │ ├── mc-ai v0.1.0 → mc-turn → mc-mapgen → magic-civ-physics + │ └── mc-turn ─────────────^ + └── rand_chacha v0.9.0 → rand v0.9.2 +``` + +Wave A pinned the workspace to `rand = "0.9"` (in `mc-trade`) which +forces `rand_core 0.9.x` which forces `getrandom 0.3.x`. The native +build (cargo test on the workspace) compiles fine because native +`getrandom` doesn't take the broken backends path; only the +`wasm32-unknown-unknown` target hits it. + +This blocks the **rolling Wave E** plan: every Wave A–D objective +ships Rust + GDExt + WASM bridges, but the WASM bundle can't be built, +so the design lab can't consume WASM-built selectors and is stuck on +the TS twins. By extension, p1-46 (Wave E lab integration) cannot +land until WASM builds are green. + +This objective is **Wave A.5** — sits between Wave A (foundation +crates) and Waves B–E (consumers). Lands as a small, focused workspace +fix. + +## Acceptance + +- ◻ **Root cause documented** — short writeup in + `src/simulator/api-wasm/BUILD.md` (new) explaining why `getrandom + 0.3.x` fails on `wasm32-unknown-unknown` with our workspace deps, + and the chosen fix path. Future contributors who hit the same wall + read this first. +- ◻ **WASM build green** — `bash src/simulator/build-wasm.sh` exits 0, + produces `.local/build/wasm/magic_civ_physics_bg.wasm` and + `magic_civ_physics.d.ts` containing — at minimum — these exports: + - `tileTectonicsJson(col, row): string | undefined` + - `tileClimateJson(col, row): string | undefined` + - `tileHydrologyJson(col, row): string | undefined` + Verify by `grep -E 'tile(Tectonics|Climate|Hydrology)Json' + .local/build/wasm/magic_civ_physics.d.ts | wc -l` returns 3. +- ◻ **Native build still green** — `cargo check --workspace` clean + after the fix; `cargo test -p mc-mapgen -p mc-climate -p mc-trade + -p mc-turn -p mc-ai` all pass. The fix must not regress native + builds. +- ◻ **Determinism preserved** — the parity tests Wave A established + (`mc-mapgen/tests/cross_build_determinism.rs`) still pass byte-for- + byte after the fix. If the fix involves swapping a randomness source + (e.g. downgrading `rand`), the seed-derive output must be unchanged. +- ◻ **Doc updated** — `WORLDGEN_RNG.md` §11 "Open questions" gets a + new closed bullet recording the fix decision (e.g. "rand pinned to + 0.8 in mc-trade due to getrandom 0.3.x wasm32 breakage"). The + doc-↔-code mirror reflects the actual dep state. +- ◻ **Smoke import test** — add a stub TypeScript file at + `.project/designs/app/src/utils/wasm/smoke.ts` (or similar) that + imports each of the three new `tile*Json` functions and exports a + no-op caller. `npx tsc --noEmit` clean from the design app proves + the WASM bundle is reachable from the lab. This is the gate that + unblocks Wave E rolling. + +## Why this is its own objective rather than a hidden fix in p1-46 + +p1-46 (Wave E) consumes the WASM bundle but doesn't own it. If WASM +build is broken, every downstream Wave is blocked from showing +visual proof — that's a cross-cutting infra concern, not a +lab-specific one. Splitting it out lets `simulator-infra` own the fix +without coupling it to lab-rendering work. + +## Non-goals + +- Wiring the lab to actually consume the WASM bundle — that's p1-46 + Wave E (or rolling-Wave-E increments). +- Adding new WASM exports beyond what Wave A/B already authored — + this objective unblocks the existing surface, doesn't extend it. +- GDExt build pipeline — Godot's bridge is a different cargo target + and doesn't hit this issue. Out of scope. + +## Suggested fix paths (specialist picks one) + +In rough order of cleanliness: + +1. **`[patch.crates-io]` workspace entry** pinning `getrandom 0.3` to + the latest 0.3.x that actually compiles on `wasm32-unknown-unknown` + — if such a version exists. Fast, surgical. +2. **Downgrade `mc-trade`'s `rand` to 0.8** (which uses + `getrandom 0.2.x`, known-good on wasm32). Requires updating + `rand_chacha` and any 0.9-only API usage. Medium scope. +3. **Patch `getrandom 0.3.x` via a fork** with the missing + `backends::inner_*` exports. Highest scope, last resort. + +Specialist verifies determinism vector after the fix — Wave A's +`cross_build_determinism.rs` is the canary. + +## Dependencies + +- Wave A landed (p1-50, p2-49, p2-50) — gives the WASM bridge + functions to verify exist in the built bundle. diff --git a/src/simulator/Cargo.lock b/src/simulator/Cargo.lock index bf42b6b3..fc53a351 100644 --- a/src/simulator/Cargo.lock +++ b/src/simulator/Cargo.lock @@ -881,7 +881,7 @@ dependencies = [ "mc-tech", "mc-trade", "mc-turn", - "rand", + "rand 0.8.6", "serde", "serde_json", "tokio", @@ -1142,7 +1142,7 @@ dependencies = [ name = "mc-trade" version = "0.1.0" dependencies = [ - "rand", + "rand 0.8.6", "serde", "serde_json", ] @@ -1163,7 +1163,7 @@ dependencies = [ "mc-trade", "pollster", "proptest", - "rand", + "rand 0.8.6", "serde", "serde_json", "wgpu", @@ -1420,8 +1420,8 @@ dependencies = [ "bit-vec", "bitflags 2.11.0", "num-traits", - "rand", - "rand_chacha", + "rand 0.9.2", + "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -1456,14 +1456,35 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1473,7 +1494,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", ] [[package]] @@ -1491,7 +1521,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core", + "rand_core 0.9.5", ] [[package]] diff --git a/src/simulator/Cargo.toml b/src/simulator/Cargo.toml index de396264..d3116513 100644 --- a/src/simulator/Cargo.toml +++ b/src/simulator/Cargo.toml @@ -35,7 +35,7 @@ members = [ serde = { version = "1", features = ["derive"] } serde_json = "1" getrandom = "0.2" -rand = "0.9" +rand = "0.8" siphasher = "0.3" # pinned — worldgen seed derivation; see mc-mapgen/RNG.md # Workspace-wide lint configuration — Python-styled Rust.