Rust minimum-version audit (#53) #
Status: audit/probe complete; the bounded MSRV repair plan is accepted after independent review/closure. Implementation integration is accepted under that current-stable scope after complete stable target partitions, optimized build/replay checks and final independent review. The operator subsequently deprioritized earlier-toolchain compatibility while asking to preserve completed work: remaining local acceptance follows normal stable-toolchain gates. Existing1.75 metadata/check/non-CLI evidence is retained, without claiming unexecuted full CLI/release certification. See the plan's current-scope override. Baseline: e4cfd4c (accepted tactical orientation).
Constraint and observed mismatch #
The workspace and README advertise Rust 1.75. Existing development and the latest accepted all-target gates used Rust 1.98.1. Actual Cargo 1.75 checks stop before compilation because Cargo.lock is version 4. This is not evidence that changing only the lockfile would make the game build.
Parent ran cargo metadata --locked --offline --format-version 1 --filter-platform x86_64-unknown-linux-gnu, traversed resolved dependencies from all workspace members, and inspected declared package minimums. The reachable graph includes the following packages declaring a minimum above 1.75:
| Packages | Resolved version | Declared Rust minimum |
|---|---|---|
| bincode, bincode_derive | 2.0.1 | 1.85 |
| clap, clap_builder | 4.6.6 | 1.85 |
| clap_lex | 1.1.0 | 1.85 |
| derive_more, derive_more-impl | 2.1.1 | 1.81 |
| half | 2.7.1 | 1.81 |
| hashbrown | 0.17.1 | 1.85 |
| indexmap | 2.14.1 | 1.85 |
| jobserver | 0.1.35 | 1.85 |
| rayon | 1.12.0 | 1.80 |
| rayon-core | 1.13.0 | 1.80 |
| serde_spanned | 1.1.1 | 1.85 |
| toml | 1.1.5+spec-1.1.0 | 1.85 |
| toml_datetime | 1.1.1+spec-1.1.0 | 1.85 |
| toml_parser | 1.1.3+spec-1.1.0 | 1.85 |
| toml_writer | 1.1.2+spec-1.1.0 | 1.85 |
| unicode-segmentation | 1.13.3 | 1.85 |
This includes dev dependencies used by the all-target gate; it is not a claim that every package enters the shipped runtime or every target triple. Metadata is not actual minimum-compiler certification. Parent metadata output: session shell call_Mr6Hgcl3TjAKAzGZwr0DXK4y.stdout.
Only hexwork-core and hexwork-render inherit workspace.package.rust-version. Audio, CLI, content, save, term, UI and worldgen report no package minimum. The dependency investigator found current-stable CI/toolchain configuration, not a minimum-version compiler gate.
Source compatibility candidates #
Parent targeted source inspection found four actual post-1.75 API uses:
crates/hexwork-cli/tests/routes.rs:212:std::iter::repeat_nin the ordinary death-route helper.crates/hexwork-ui/src/transfer.rs:376:repeat_nin a bounded presentation test fixture.crates/hexwork-save/src/artifact/mod.rs:461:Result::inspect_err. Any replacement must preserve closing the terminal barrier after directory-creation failure and return the original error after durable allocation.crates/hexwork-worldgen/src/runtime.rs:504:Option::is_none_or. Any replacement must reject both absent and occupied connector endpoints.
This targeted scan is not exhaustive compiler proof. Existing relevant tests include allocation durability/fault tests, malformed_blocked_connector_column_is_rejected, connector landing tests, bounded transfer formatting and actual death-route/replay gates.
Dependency investigation and compatibility boundary #
The read-only dependency investigator used member manifests, the lockfile, exact locally cached registry manifests and official crate metadata. Its context lacked shell execution; parent supplied the actual locked metadata verification above rather than claiming the investigator compiled anything.
The compatible-version candidates it identified include TOML 0.8.23, derive_more 2.0.1, jobserver 0.1.34, clap 4.5.61, half 2.4.1, rayon 1.10.0 with a compatible rayon-core, and older compatible indexmap/unicode-segmentation resolutions. These are investigation candidates, not a frozen graph or verified build. Transitive dependencies and TOML parsing/content behavior still require exact resolution and tests.
Bincode is not an unused dependency: hexwork-save/src/protocol.rs uses its Encode/Decode traits and contextual bounded decoding throughout the current wire protocol. demo.rs and other save paths also use bincode. Stable bincode 2 releases declare Rust 1.85. A bincode 1 downgrade is not a routine version pin and is not authorized. Whether a narrowly maintained bincode 2 source backport can preserve the exact existing bytes and decode-budget semantics is under adversarial review; declared MSRV metadata alone does not prove such a backport impossible.
No immutable fixture regeneration, wire/schema migration, canonical-hash change, dependency-wide update or minimum-version increase is authorized by this audit.
Operator decision status #
Parent recommended considering an explicit Rust 1.85 minimum to preserve the current dependency graph and save formats, versus retaining 1.75 through a larger compatibility effort. The structured question returned operator unavailable, not a selection. This is not approval to change the existing 1.75 constraint. The read-only adversarial second opinion rejected the claim that 1.75 necessarily requires a serialization migration: exact bincode 2.0.1 sources are edition 2021, and its incomplete direct-rustc probe reported unresolved dependency wiring rather than a concrete newer API. That is a feasibility hypothesis, not a build pass. Its unty/virtue output attempts failed on /dev permissions and were not accepted as passes.
Parent therefore retains the existing 1.75 constraint and authorized only an isolated experiment under target/msrv-probe-53/: compile/link exact unchanged bincode 2.0.1, its derive crate and actual feature dependencies using installed 1.75; exercise representative contextual decoding APIs; compare probe bytes with stable. --ignore-rust-version is permitted only to test whether the declarations are the sole blocker, never as project acceptance. Registry and game sources, root lockfile and immutable fixtures stay untouched. No permanent backport/vendor dependency is authorized; any such change requires a separate exact plan, provenance/licensing/maintenance review and genuine full fixture/compiler gates. Other RPG work remains separable.
Accepted probe evidence (not project acceptance) #
The isolated probe compiled and linked exact unchanged cached bincode 2.0.1, bincode_derive 2.0.1, unty 0.0.4 and virtue 0.0.18 under installed Rust 1.75.0 with --ignore-rust-version. Its actual features are bincode default/std/alloc/derive, matching the save dependency; serde is not enabled. Offline registry resolution initially failed, so the disposable manifest uses exact cached path overrides, including resolution-only optional serde metadata. Those absolute cache paths are not an acceptable permanent dependency strategy.
Five synthetic API tests passed on both 1.75 and stable: contextual derive/borrow round trip, trailing rejection, per-field and aggregate limits before payload reads, and codec claim limits. Both probe executions produced the same 23-byte hex 50524f4245303533fb2c010568656c6c6f05776f726c64. The negative control without --ignore-rust-version failed on bincode's declared 1.85 requirement. No codec implementation edits were needed. Parent reviewed the source/logs and reran both five-test suites successfully, compared the captured output bytes and verified unchanged root lockfile, root/save manifests and protocol.rs hashes. The worker additionally checked 122 cached codec-tree files before/after: none changed. Stable emitted existing upstream lifetime-syntax warnings; no warnings or errors appeared on 1.75. No permanent dependency was added.
Evidence lives under ignored target/msrv-probe-53/ (manifest, main.rs, feature tree, toolchain logs, negative control, encoded bytes and integrity report). These tiny PROBE053 records are not genuine v4 fixtures. The result supports planning a metadata-only local codec backport; it does not establish full-game minimum-version support, full persistence coverage, optional-feature/platform support or license/maintenance acceptance.
Before any repair: freeze exact ownership, dependency/source changes, preservation requirements and tests. Successful minimum-version closure requires an actual locked minimum-compiler build/test gate, consistent member/documentation/CI declarations, current-toolchain quality gates and unchanged genuine save/replay fixture contracts. Platform claims must remain limited to tested targets. Other gameplay integration remains independently actionable; this audit alone does not justify blocking the entire 1.0 goal.