Repository navigation
Port the last C#-only jobs to Rust, and add Rust to the devcontainer (port stage 13a) - #176
Conversation
Adds rust/contract/tests/planner_defaults.rs, which builds the same payload as the C# PlannerDefaultsTest and writes it in Verify's strict JSON layout (BOM, two-space indent, no final newline), with doubles through blueprint::json_out::format_f64. The bytes match the committed src/vue/src/lib/plannerDefaults.verified.json exactly. The test compares and fails on any difference. UPDATE_PLANNER_DEFAULTS=1 rewrites the file instead. An exhaustive destructure of OilFieldOptions stands in for EmitsEveryOilFieldOptionsProperty: a new field that is not emitted fails to compile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
rust/planner/tests/factorio_oracle.rs checks the planner's hardcoded Factorio facts against test/FactorioTools.Test/OilField/factorio-oracle.json, as FactorioOracleTest.cs does: vanilla entity and module names, the pumpjack terminal offsets, direction values, raw pole and beacon geometry, and MAX_UNDERGROUND against max_underground_distance. It also checks the planner's own footprints (PUMPJACK_WIDTH and the options presets) against the collision boxes. EntityNameToSize lives in the blueprint crate as a private function, so its check is a unit test in rust/blueprint/src/write.rs. Rust has no reflection, so entity_names::vanilla and item_names::vanilla gain ALL arrays, and a data.rs unit test counts the constants in each module's source so a constant missing from ALL fails. MAX_UNDERGROUND is now pub, matching the rest of the planner crate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
…(port stage 13a) FactorioToolsApi.ts was generated from the WebApp's swagger.json, which goes away with the .NET code in 13b. It is now a hand-maintained file: the unused HTTP client plumbing is gone, along with @ts-nocheck and the generated banner, and it is linted and formatted like the rest of src/. FactorioToolsApi.test.ts checks it against the plan and normalize responses in rust/contract/fixtures/contract.jsonl: typed samples the compiler checks with `satisfies Required<...>`, the key shape and value types of every recorded response, every strategy and quality name the contract writes, and the error envelope shape. Also drops the swagger-gen script and the swagger-typescript-api dependency, the CI step that regenerated the client, the client's .gitattributes line, and ApiError.response, which nothing has set since the site moved to the in-browser planner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
The node:fs read needed a `/// <reference types="node" />`, which puts Node's globals into the type-check of the whole app. vite/client already types `*?raw` imports as strings, and vitest resolves the file outside src/vue, so the test now imports the jsonl that way. The production build does not include it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
`cargo run --release -p snapshots --bin normalize-lists` rewrites big-list.txt and small-list.txt the way the C# CLI's `oil-field normalize` does: big less small, then small less the new big, blueprints cleaned to their pumpjacks, repeats dropped, comments kept in the small list only. Two differences on purpose: - A blueprint's identity is its normalized JSON, the text SerializeBlueprint compresses. A line whose own data decodes strictly to exactly that text is kept as written, and lines are compared by that text. Neither flate2 nor .NET 10 reproduces the committed compressed bytes, so a literal port (or the C# itself today) would rewrite all 1,208 blueprint lines with no change. - No console prompt for a line that does not normalize: it fails naming the file and line, and --keep-invalid keeps such lines as the C#'s "y" does. tests/normalize.rs checks the committed lists are already normalized: no blueprint twice (by JSON, so a recompressed copy counts), none in both lists, and the tool's logic changes neither file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
… stage 13a) The snapshot tests compared every *.verified.txt with the Rust output, but only .NET Verify could write them. With UPDATE_SNAPSHOTS=1 the same tests write instead: they create missing files, rewrite changed ones (a UTF-8 byte order mark, then the text with LF line ends, as Verify writes) and delete *.verified.txt files no case produces any more. Without it nothing changes, except that failures now name the command. The pinned count of 2,748 snapshot files is replaced by a count derived from the two blueprint lists, so a new test blueprint needs no edit there, and update mode checks the case set before deleting by it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
The site builds the Rust planner with `npm run build-wasm`, and the devcontainer had no Rust, so the Devcontainer job built the planner on the runner and copied it in. Now the image carries the toolchain and the job builds and tests Rust inside the container. - Dockerfile: rustup-init 1.29.1, pinned and checksummed like Node, with the rust-toolchain.toml pin (1.98.1, rustfmt, clippy, wasm32) pre-installed for the ubuntu user, plus rust-src for rust-analyzer. gcc and libc6-dev for linking. Self-update is off so the rustup pin holds. - devcontainer.json: named volumes for rust/target and the cargo registry and git caches, chowned in postCreate; postCreate ends with build-wasm; rust-analyzer added. - devcontainer.yml: rust/rust-toolchain.toml in the paths filter; the toolchain step checks RUST_VERSION against the toolchain file, rustc and cargo in rust/, and the wasm32 target; the runner-side planner build is gone, replaced by build-wasm in the front-end step; new cargo test step. - CLAUDE.md Devcontainer section: what the container covers now, with measured timings. .NET, Lua and PowerShell stay until stage 13b removes the C#. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
Covers the plannerDefaults generator, the hand-maintained API types and their test, adding a test blueprint with normalize-lists and UPDATE_SNAPSHOTS, changing planner output on purpose, and the Rust port of the Factorio oracle test. The .NET and Lua docs stay until 13b removes those builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: 🔵 Low · up to
|
Stage 13a of #138. The live site has run the Rust planner since #174. Before stage 13b deletes the C#, this PR moves the last jobs only the C# does over to Rust. It does that while the C# still exists, so each port is checked against real C# behavior. No C# is deleted here, and no test data moves.
Merging deploys the site, as every merge to
maindoes. The only site change is thatApiErrorloses its unusedresponsefield, along with the dead branch that displayed it. Nothing has set that field since 12b.What's ported
PlannerDefaultsTestwritessrc/vue/src/lib/plannerDefaults.verified.jsonrust/contract/tests/planner_defaults.rs. It fails when the file is stale;UPDATE_PLANNER_DEFAULTS=1rewrites it. An exhaustive destructure makes a new option that isn't emitted fail to compile.FactorioOracleTestchecks hardcoded game facts againstfactorio-oracle.jsonrust/planner/tests/factorio_oracle.rs: all 7 checks, plus an entity-size check inrust/blueprint. Rust has no reflection, soentity_names::vanilla::ALLanditem_names::vanilla::ALLlist the names, and a test fails if a constant is missing from them. It also adds one check the C# never had: the planner's own pumpjack, pole and beacon sizes against the collision boxes.oil-field normalizecargo run --release -p snapshots --bin normalize-lists(--keep-invalid,--dir), plus a test that the lists are normalized: no repeats and no blueprint in both lists*.verified.txtsnapshots and the scoreboardUPDATE_SNAPSHOTS=1 cargo test --release -p snapshots -- --include-ignoredcreates, rewrites and deletes stale snapshots. The pinned 2,748 count is replaced by one derived from the cases.swagger-genwritesFactorioToolsApi.tsfromWebApp/swagger.json@ts-nocheck.FactorioToolsApi.test.tschecks it against all 358 plan and normalize responses and 27 error envelopes inrust/contract/fixtures/contract.jsonl: key shape, value types and exact enum sets. The fixture loads with a Vite?rawimport and isn't in the production bundle.vue-tscTwo side findings:
normalizeon .NET 10 rewrites all 1,208 committed blueprint lines to identical content, because they were compressed by an older zlib. The Rust tool leaves a line exactly as written when it's already normalized, so its diffs show only real changes.UPDATE_SNAPSHOTS, nobody could add a test blueprint or make a deliberate output change once 13b removes the C#.Devcontainer
RUST_VERSION=1.98.1with rustfmt, clippy, rust-src and wasm32).rust/targetand the cargo registry and git caches each get their own volume.RUST_VERSION,rustc,cargoand the wasm32 target all matchrust/rust-toolchain.toml.cargo test --all-targetsinside the container.@devcontainers/cli@0.89.0: the toolchain check,cargo test(175 passed), the front end,dotnet test(4,302 passed) and the Lua transpile. A full run takes about 8 minutes.Other changes
swagger-genscript, itsswagger-typescript-apidevDependency (1,019 lockfile lines) and the "Check the committed API client is up to date" CI step are removed.Checks
cargo test --all-targetsgives 190 passed and 7 ignored; the release gates (-p snapshots -p contract --include-ignored) give 37 passed; the wasm32 workspace build succeeds; and update mode over the whole tree leavesgit statusclean.npm ci,build-wasm,build,npm test(55 tests) and eslint all pass.pull_requestonly, withcontents: readand no untrusted${{ }}inrun:steps.Cargo.lock, and one npm devDependency is gone.*.verified.txtfiles under the test directory, and only after checking how many snapshots the cases should produce.Next: stage 13b
13b moves the test data out of
test/, then deletes .NET, Lua, the submodules, the C# recorders and their CI jobs. It also strips .NET from the devcontainer and updates the docs.🤖 Generated with Claude Code
https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
Summary by CodeRabbit
New Features
Bug Fixes
Tests