The wasm bundles in solitaire_server/web/pkg/ are no longer tracked. The
web-wasm-rebuild workflow (which rebuilt them in CI and committed them
back to master) is gone; instead:
- solitaire_server/Dockerfile gains a wasm-builder stage that runs
build_wasm.sh with the same pinned toolchain (wasm-bindgen 0.2.120,
wasm-pack 0.14.0, binaryen 130) and the runtime image copies pkg/
from it — the image build is now the artifacts' single source of truth.
- web-e2e builds the wasm before Playwright runs, and its trigger paths
now include the wasm-feeding crates it actually tests.
- docker-build triggers on solitaire_data/** and build_wasm.sh too, so
every wasm-affecting change redeploys.
- Self-hosters serving /web or /play from a source checkout run
./build_wasm.sh once (script header and ARCHITECTURE.md updated).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
canvas_bg.wasm shipped at 36.2 MB — plain release (opt-level 3, thin
LTO) piped through wasm-opt -O2. Download size, not throughput, is the
binding constraint for the browser canvas, so solitaire_web now builds
with a dedicated wasm-release profile: opt-level "s", fat LTO, one
codegen unit. Local result: 23.2 MB after the unchanged wasm-opt -O2
pass — 35.9% smaller.
The binaryen pass stays at -O2 (the -Oz grey-screen miscompile note in
build_wasm.sh still applies). profile.strip is deliberately NOT set: on
wasm it also removes the target_features custom section, which makes
wasm-opt reject the module ('all used features should be allowed' on
trunc_sat).
Verified with the new artifact: all 5 play_canvas e2e specs pass (debug
bridge, draw3 param, apply/undo, replay diagnostics, 40-seed autoplay
invariants). Headless pixel verification is inconclusive in this
environment — wgpu cannot create a usable adapter locally and panics
identically on the OLD artifact too — so visual parity should be
confirmed against production after the next deploy.
pkg/ artifacts are intentionally not committed: the web-wasm-rebuild
workflow is the single source of truth and will regenerate them with
this profile on merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The web-wasm-freshness gate (#93) false-failed because the Bevy wasm build
baked in machine-specific absolute source paths — the cargo registry
(/home/<user>/.cargo/registry/...), the rustup std sources (~/.rustup/...),
and this checkout — so CI's rebuild (under /workspace, /root) never matched the
committed bytes even with identical pinned tool versions.
build_wasm.sh now exports CARGO_ENCODED_RUSTFLAGS with three --remap-path-prefix
rules (cargo home -> /cargo, rustup home -> /rustup, repo -> /build) so the
embedded paths are identical on any machine. It re-states the
getrandom_backend cfg because a *_RUSTFLAGS env var replaces (not merges with)
.cargo/config.toml's target rustflags.
Regenerated all four artifacts with the remap applied — verified zero
machine-specific paths remain (only canonical /cargo + /rustup prefixes), which
is the precondition for the gate's byte-for-byte rebuild-and-diff to match
across machines.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Grey screen fix (canvas_bg.wasm):
- Rebuilt Bevy WASM from refactored solitaire_core that removes the
per-game KlondikeAdapter field from GameState. The old binary was
built with wasm-opt -Oz; the large adapter allocation pattern appears
to trigger an over-aggressive wasm-opt optimisation that corrupts
Bevy's render pipeline, causing a permanent grey screen on /play.
- build_wasm.sh: change wasm-opt -Oz → -O2. Speed-optimised level avoids
the size-focused transforms that miscompile Bevy's deep render stacks.
solitaire_core refactoring:
- game_state.rs: remove adapter: KlondikeAdapter field; use static
KlondikeAdapter::config_for() instead of a per-instance allocation.
Gate test_pile_state behind #[cfg(feature = "test-support")] so
production builds carry no test-only heap state.
Add instruction_history() public accessor (delegates to saved_moves()).
- card.rs: add Card::new(), face_up(), face_down() const constructors
for more ergonomic test and wasm code.
- pile.rs, solver.rs: cargo fmt.
solitaire_wasm interactive API:
- lib.rs: add SolitaireGame wasm-bindgen struct with draw(), move_cards(),
undo(), auto_complete_step(), serialize(), from_saved() — the full
player-action surface used by game.js.
Add DebugSnapshot, DebugMove, DebugInvariantReport structs and
debug_snapshot(), debug_legal_moves(), debug_apply_move_json()
methods for e2e test automation (window.__FERROUS_DEBUG__ bridge).
Add replay_moves() to export the current game as a Replay v2 payload.
- solitaire_wasm.js + solitaire_wasm_bg.wasm: rebuilt with new API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Captures the exact wasm-pack build command needed to regenerate
solitaire_server/web/pkg/. Removes wasm-pack's package.json and
.gitignore artifacts from the output dir since we manage it directly.
Includes a dependency guard and install instructions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>