diff --git a/docs/msrv-audit.md b/docs/msrv-audit.md new file mode 100644 index 0000000..878902f --- /dev/null +++ b/docs/msrv-audit.md @@ -0,0 +1,69 @@ +# Rust minimum-version audit (#53) + +Status: audit/probe complete; the bounded [MSRV repair plan](msrv-repair-plan.md) is accepted after independent review/closure. Implementation and minimum-compiler acceptance remain pending. Rust1.75 is retained. 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_n` in the ordinary death-route helper. +- `crates/hexwork-ui/src/transfer.rs:376`: `repeat_n` in 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. diff --git a/docs/msrv-repair-plan.md b/docs/msrv-repair-plan.md new file mode 100644 index 0000000..595a20b --- /dev/null +++ b/docs/msrv-repair-plan.md @@ -0,0 +1,128 @@ +# Rust 1.75 compatibility repair — reviewed plan (#53) + +Status: scoped implementation plan accepted after independent HOLD/repair/re-review closure. D/S/V may implement only their owned sections. This is not project MSRV or implementation acceptance. + +## Goal + +Keep the existing Rust 1.75 minimum without changing game behavior, canonical content, save/replay bytes or bounded decoding. The operator was unavailable and did not approve a minimum-version increase or serialization migration. `msrv-audit.md` contains the actual metadata audit and parent-repeated scratch experiment: unchanged bincode 2.0.1/derive sources compile and exercise contextual decoding on 1.75 when only their version declarations are bypassed. This is grounds for a reviewed local compatibility backport, not permission to bypass version checks in production. + +No new gameplay, schema tags, fixture regeneration, codec implementation/unsafe changes, minimum-version increase, or broad dependency update. Keep stable as the ordinary developer tooling channel; add real minimum-compiler enforcement. Linux is the locally executable certification target. Configured macOS CI is not a claim that remote CI or Windows has run. + +## Implementation Summary + +Preserve exact codec implementation sources while maintaining local minimum-support metadata, conservatively resolve the remaining compatible dependency graph, replace four newer APIs without behavior changes, and add executable provenance/build/CI verification. Three disjoint owners implement dependency/build metadata (D), mechanical game-source compatibility (S), and verification tooling (V). + +## Implementation Plan + +Parent plan -> independent review/closure -> parallel D, S and V implementation -> parent integration/provenance review and verifier negative controls -> compiler/content/save focused gates -> full stable and 1.75 all-target coverage in bounded local partitions -> final independent implementation/evidence review -> findings closure and scoped documentation/commit. + +### Ownership + +- **D owns only:** root `Cargo.toml`, `Cargo.lock`, all nine `crates/*/Cargo.toml`, `.github/workflows/ci.yml`, new `vendor/bincode-2.0.1/**`, new `vendor/bincode_derive-2.0.1/**`, `vendor/README.md`, `vendor/provenance.json`, `vendor/verify.py`, and the two authenticated original archives at `vendor/upstream/bincode-2.0.1.crate` and `vendor/upstream/bincode_derive-2.0.1.crate`. No game Rust source, existing fixtures, content assets, ordinary README, deny policy, or toolchain-file changes. +- **V owns only:** new `scripts/verify_msrv.py` and `scripts/tests/test_verify_msrv.py`. Consume D's output read-only; no manifest/workflow/vendor edits. The exact CLI contracts below let D wire CI while V implements independently. +- **S owns only:** `crates/hexwork-cli/tests/routes.rs`, `crates/hexwork-ui/src/transfer.rs`, `crates/hexwork-save/src/artifact/mod.rs`, `crates/hexwork-save/src/artifact/tests.rs`, `crates/hexwork-worldgen/src/runtime.rs`, `crates/hexwork-worldgen/tests/runtime_plans.rs`. No manifests/dependencies/codec sources or other game changes. +- Parent owns audit/plan, README minimum-support explanation, checklist, acceptance and commits. Workers do not commit, format peers or run uncoordinated full workspace gates. Compiler-dependent checks wait for both owners to finish their prerequisites. Report newly discovered errors outside ownership rather than silently broadening it. + +### D.1 Exact local codec backport + +Use the exact published bincode 2.0.1 and bincode_derive 2.0.1 package archives (local registry cache if present; otherwise ordinary Cargo/package acquisition). Verify archive checksums against the existing lockfile before extraction. Extraction/copy of existing package contents is package tooling, not shell-authored source; all authored edits use file tools. Never mutate registry caches or reference absolute cache paths in the production graph. + +Retain the original package source, MIT `LICENSE.md`, README, `Cargo.toml.orig`, and archive release metadata including hidden `.cargo_vcs_info.json` when present. Inventory the complete archive file set, excluding only explicitly recorded registry extraction markers such as `.cargo-ok`/`.cargo-checksum.json` if absent from the published archive. Do not silently omit tests, benches or other archived files. Store both original authenticated archives so CI verification does not require an external cache or download. `vendor/provenance.json` records package/version/checksum from baseline `e4cfd4c` lock entries, upstream source/license, complete retained member set and original hashes, and exact allowed manifest deltas. + +D implements `python3 vendor/verify.py --root vendor` (stdlib Python3.11) with named checks `verify_archive_checksums`, `verify_complete_package_trees`, and `verify_manifest_allowlist`. Read archives without extracting them during verification; reject unsafe archive member paths/symlinks rather than following them. Check the exact retained-file set, every source/license byte, original normalized/original manifests, and the precise parsed AND textual allowed Cargo.toml deltas below; reject missing/extra files, source edits and arbitrary manifest differences. `--self-test` creates disposable copies outside production and proves rejection of an altered codec file, removed license, extra `.rs` file, non-allowlisted manifest change, and altered archive/inventory checksum. It must also accept a pristine copied tree. No codec algorithms, derives, allocation/claim logic, unsafe code or decode limits may change. + +Permitted vendored manifest changes ONLY: +1. `rust-version = "1.85.0"` to `"1.75"` in both packages, documenting that this is HEXWORK-maintained support, not an upstream claim. +2. Pin bincode's dependency on bincode_derive exactly to `=2.0.1` so a future resolution cannot silently bypass the matching local backport. + +Root workspace dependency bincode becomes exact `=2.0.1`; root `[patch.crates-io]` points those two names to the relative versioned vendor directories. Exclude both directories explicitly from automatic workspace membership so project-wide formatting/clippy/test commands do not rewrite or treat upstream test suites as project members. Do not vendor unty, virtue, serde or the probe's optional metadata closure: they were needed only as scratch offline path references and do not need a permanent code fork. + +The vendor README must state scope (actual std/alloc/derive feature set), verification/fixture obligations, provenance and license, unsupported untested feature/platform limits, and maintenance policy: monitor upstream issues/releases; no automatic codec upgrade or source patch; any future change requires exact byte/budget tests and independent review. Do not suppress project warnings globally to accommodate upstream warnings. Existing dependency lint treatment remains distinct from project lint gates. If the archive license/provenance is unavailable or source edits beyond these metadata lines appear necessary, stop for parent review. + +### D.2 Compatible graph and format-3 lockfile + +Every member must explicitly inherit `rust-version.workspace = true`; root minimum remains 1.75. Preserve existing compatible direct versions and their features. Change TOML's direct workspace requirement to exact `=0.8.23`; all canonical assets and parser callers remain unchanged. This is a parser-version change requiring content/validation and fixture gates, not an assumed byte-neutral change. + +Use conservative Cargo updates/pins for the identified incompatible transitive packages. Candidate targets, to be verified by actual resolution: +- derive_more 2.0.1 and matching derive_more-impl; +- unicode-segmentation 1.12.0; +- indexmap 2.11.4 with its compatible hashbrown; +- jobserver 0.1.34; +- clap 4.5.61 with matching builder and compatible lex; +- half 2.4.1; +- rayon 1.10.0 and compatible rayon-core 1.12.1. + +TOML's older datetime/edit/serde_spanned/winnow subtree may necessarily replace the current 1.1 family. Record every changed package and the dependency edge requiring it. Keep bincode encode/derive versions, hecs, zstd/zstd-safe/zstd-sys, serde, serde_json, sha2, crossterm, signal-hook, fs2, getrandom direct dependency and unicode-width unchanged unless a concrete incompatibility requires parent approval. Build-only/dev-only changes are still recorded. Do not add unused direct dependencies solely to hide a transitive constraint, disable current features to make a compiler pass, run an unconstrained whole-graph update, or hand-author package/checksum entries. + +The final lockfile must be format 3, parseable by Cargo 1.75, with no untracked dependency resolution during any `--locked` gate. Prefer a Cargo-generated format-3 result. If modern Cargo retains format 4 while conservatively updating the graph, the sole permitted mechanical lock edit is its top-level format field from 4 to 3, AFTER verifying the graph contains no git/registry encoding differences that need format-4 semantics. Before/after TOML parsing must show the same complete package/source/checksum/dependency metadata except that one format integer, and both Cargo 1.75 and stable must consume it with `--locked` without rewriting it. This narrow format conversion is not permission to edit resolution entries. Report its exact method; if either Cargo rejects or rewrites it, stop and resolve the cause rather than forcing acceptance. + +Name and execute separate preflights: both `cargo +stable metadata --locked --format-version 1` and `cargo +1.75.0 metadata --locked --format-version 1` unfiltered; then each with `--filter-platform x86_64-unknown-linux-gnu`, `--filter-platform x86_64-apple-darwin`, and `--filter-platform aarch64-apple-darwin`. Capture JSON and before/after lock hashes for every successful command. Use actual filtered feature/target metadata to distinguish active build dependencies from inactive Windows/wasm entries, but **inactive compilation does not imply that old Cargo can parse the package manifest**. Any inactive package that blocks required metadata parsing/resolution also requires a precise dependency-edge/error report and parent-approved compatible pin, not dismissal or source edits. A package declaring <=1.75 is not enough: actual minimum-compiler workspace all-target checks must pass. Additional active incompatibilities follow the same report/approval rule; no blanket updates. Metadata for macOS does not certify macOS compilation. No `--ignore-rust-version` outside the disposable probe. + +### D.3 CI enforcement + +Keep two explicit Ubuntu/macOS matrix jobs: existing `build` uses stable and new `msrv` installs exactly1.75.0. Give each job `timeout-minutes: 180` and `CARGO_TARGET_DIR: target/ci-${{ matrix.os }}-stable` or `target/ci-${{ matrix.os }}-1.75.0` respectively; any future cache key must include OS/toolchain/lock hash. Set job `RUSTUP_TOOLCHAIN` explicitly to `stable` or `1.75.0`, so the repository's stable toolchain file cannot shadow minimum testing. Both jobs set up Python3.11 via actions/setup-python@v5 and install exact verification-only `PyYAML==6.0.2`; this is not a game dependency. Both run `python3 vendor/verify.py --root vendor`, the V metadata/fixture/CI checks below, and capture metadata via `cargo metadata --locked --format-version 1 > target/msrv-metadata.json` after creating `target/`. + +Freeze stable commands: `cargo fmt --all -- --check`; `cargo clippy --locked --workspace --all-targets -- -D warnings`; retain cargo-deny installation/check without altering deny policy; `cargo test --locked --workspace --all-targets`; `cargo bench --locked --workspace -- --test`; `cargo build --locked --workspace --release`. Freeze minimum commands: `cargo check --locked --workspace --all-targets`; `cargo test --locked --workspace --all-targets`; `cargo build --locked --workspace --release`. Both jobs run `python3 -m unittest discover -s scripts/tests -p 'test_verify_msrv.py'` and `python3 vendor/verify.py --root vendor --self-test`. No minimum clippy/format gate is required; stable is the lint/format policy. + +CI deliberately retains a monolithic exhaustive Cargo test command, with explicit180-minute job budget. The last local equivalent all-target run took about one hour before the tool cap plus the non-CLI remainder, so this is a conservative configured budget, not a claim about remote timings. The local harness3600-second cap is not a GitHub Actions limit. Local parent acceptance MUST use the metadata-audited partitions in V.4 below. `verify_ci_msrv_contract` verifies every command/flag/toolchain/matrix/budget, and `verify_target_partition_coverage` recognizes the explicit CI workspace/all-target command as exhaustive in addition to checking the local partition plan. Do not change `rust-toolchain.toml`, remove bench smoke semantics, or claim remote/macOS/Windows execution. + +### S.1 Behavior-preserving replacements + +- Route helper: replace exactly four repeated `Input::Confirm` values with `[Input::Confirm; 4]` (the input is Copy). Preserve order/count and every ordinary route action; no fixture or lethal-prefix changes. +- UI transfer test fixture: replace `repeat_n` with the 1.75-compatible repeat/take equivalent, preserving the same unread-row count and hidden sentinel. No product formatting change or broad lint allowances. Member minimum inheritance must prevent modern clippy recommending APIs outside the supported floor; coordinate with D before final clippy. +- Artifact allocation: replace `inspect_err` with explicit `if let Err(error) = create_managed_directory(...) { self.close_terminal_barrier(); return Err(error); }`. Preserve ordering after durable counter adoption and before token insertion/observer callback; return the original typed error unchanged. +- Connector validation: replace `is_none_or` with an explicit match (missing => rejection, present occupied => rejection, present empty => continue). Preserve exact error code/message and validation order; no worldgen writes or geometry changes. + +### V. Verification infrastructure and exact CLI contracts + +Prerequisites: Python3.11+ (`tomllib`), stdlib unittest/tarfile/hashlib/json/subprocess, and exact PyYAML6.0.2 only for semantic YAML parsing. Rust production dependencies are unaffected. Verifiers return nonzero on any failed contract; no automatic repairs. Authored files remain within ownership. D's `vendor/verify.py` uses stdlib only; V can invoke it after D lands it but cannot edit it. + +V implements these subcommands in `scripts/verify_msrv.py`, with named internal checks and unit tests in the owned test file: + +1. `metadata --root . --metadata target/msrv-metadata.json`: `verify_msrv_metadata` parses actual Cargo JSON plus repository manifests/lock; checks every workspace member explicitly inherits root1.75 and reports it, both vendor crates are excluded as workspace members, and resolved bincode/derive2.0.1 nodes activate the relative local patches (no registry/cache substitute). Check the root exact bincode requirement and relative patch destinations. Do not misclassify inactive dependencies as active merely because they appear in full metadata. Actual compiler checks remain separate. +2. `lock-conversion --before --after Cargo.lock`: `verify_lock_v3_conversion` uses tomllib and raw bytes to require the exact same complete metadata except top-level4→3, with byte diff limited to that one integer. `lock-stable --before --after Cargo.lock`: `verify_lock_stability` requires identical bytes after locked metadata/build/test operations. D preserves pre-conversion/snapshot files only under ignored `target/msrv-validation/`, never by modifying expected data to match output. If Cargo generates format3 directly, record that method and still perform lock-stability checks; header-conversion verification is conditional only on using that method. +3. `fixtures --root .`: `verify_fixture_integrity` checks all three genuine v4 fixture SHA256 constants already fixed in `crates/hexwork-cli/tests/phase12/v4_compat.rs`/provenance at baseline, never values derived from repaired outputs. It must fail on a tampered temporary copy. No fixture writes in production. +4. `partitions --metadata --output ` constructs a local command plan: non-CLI `cargo test --locked --workspace --exclude hexwork-cli --all-targets`, CLI library and all binary targets, and each declared CLI integration, benchmark and example target using explicit Cargo selectors. `verify-partitions --metadata --plan ` invokes `verify_target_partition_coverage` to independently compare expected metadata target IDs/kinds with command coverage, rejecting omissions, duplicates or unsupported selectors. Current CLI metadata has nine targets; do not hardcode away future added kinds. Unit negative controls remove a target partition or an all-target selector and must fail. Parent uses this output to audit recorded local gate results. CI's exact `cargo test --locked --workspace --all-targets` is separately verified as exhaustive coverage, not confused with the local partition scheme. +5. `ci --workflow .github/workflows/ci.yml`: `verify_ci_msrv_contract` parses YAML structurally with safe_load and checks both named jobs, OS matrices, explicit toolchain action/env, Python/PyYAML prerequisites, distinct target directories,180-minute budgets, all required locked individual Cargo commands, verifier/unit-test calls and retained stable deny/bench steps. Each required Cargo invocation is its own run step with the exact frozen argv; reject wrappers, ignored failures and added ignore-rust-version flags rather than attempting to validate arbitrary shell. Metadata capture is the separately frozen redirect command in D.3. CI invokes metadata/fixtures/ci subcommands with the arguments in this section after capture. No production compiler bypass or global lint suppression is allowed. + +`python3 -m unittest discover -s scripts/tests -p 'test_verify_msrv.py'` must accept minimal pristine test inputs and reject altered dependency/checksum during format conversion, lock rewrite, missing inheritance in a member manifest/metadata, inactive patch/wrong vendor membership, tampered fixture copies, missing CLI target coverage, missing CI --locked/--all-targets, wrong minimum toolchain/env, and absent verifier calls. Use temporary copies/synthetic metadata/workflows; never mutate root/source/fixtures for negative controls. D's vendor self-tests cover source-set/license/archive/manifest negatives. V may complete its template-based unit tests before D; actual integrated positive runs wait for D/S and parent review. + +## Acceptance Criteria + +M aliases from the candidate correspond one-to-one to AC numbers below. + +| AC | Required evidence | +|---|---| +| AC.1 | D's `verify_archive_checksums`, `verify_complete_package_trees`, `verify_manifest_allowlist` and vendor `--self-test` verify complete authenticated package/license/source sets and only allowed manifest deltas. Parent reviews provenance/maintenance; no cache paths or codec changes. | +| AC.2 | V's `verify_msrv_metadata`, `verify_lock_v3_conversion` when used, `verify_lock_stability`, plus all explicit full/filtered metadata preflights and real1.75 locked all-target check. All members inherit1.75, patches activate and vendor membership stays excluded. Separate old-Cargo manifest parsing from active compilation. | +| AC.3 | Content all-target tests on1.75 and stable, specifically `canonical_pack_loads_validates_and_hashes`, `hash_matches_raw_manifest_order_loader`, `malformed_temp_pack_preserves_file_and_line`, `malformed_toml_reports_line`; unchanged assets and golden hash. | +| AC.4 | New `allocation_directory_failure_closes_barrier_after_durable_counter` as specified below, plus existing `allocation_before_and_after_publish_faults_preserve_or_adopt_counter_exactly`. Original typed failure and post-durability barrier/order retained. | +| AC.5 | New `malformed_missing_connector_column_is_rejected` beside existing `malformed_blocked_connector_column_is_rejected`; assert the specific endpoint-carving diagnostic, not merely is_err. Preserve `connector_endpoints_are_carved_with_supported_landings` and all topology gates. | +| AC.6 | Retain `transfer_prompt_bounds_and_sanitizes_content`, CLI `routes` target and actual `transfers_lifecycle`, `transfers_live`, `tactical_orientation` targets. Exact route order/count and bounded UI sentinel behavior remain unchanged. | +| AC.7 | Both toolchains run full Save all-target tests and CLI `phase11_gate`: Save and CLI's `genuine_pretransfer_v4_fixtures_decode_and_reencode_identically`, CLI `binary_loads_and_replays_pretransfer_v4_fixtures`, Save `genuine_v3_run_replay_fixtures_reject_before_v4_body_parse` and `v4_initial_lineage_and_dual_images_share_all_budgets`. V `verify_fixture_integrity` checks all three baseline hashes. Protocol source/budgets unchanged; no regeneration. | +| AC.8 | Stable format/strict all-target clippy, both toolchains' locked full workspace target tests and release builds. V `verify_target_partition_coverage` audits local metadata-driven partitions and rejects removed targets/selectors. Final results are on frozen source with separate target directories and no ignore flag. | +| AC.9 | V `verify_ci_msrv_contract` and its negative controls enforce each structural workflow/toolchain/locked-command/verifier/budget requirement, plus final independent source/provenance/CI/doc review. Remote/macOS/Windows execution remains distinguished from local Linux proof. | + +## Test Strategy + +For AC.4, add a test-only one-shot IoHooks implementation in the owned artifact tests. Open/recover normally, derive the next RunId/run_dir from the current counter, then install the hook. On `FaultPoint::PublishedSyncFailed` for `VAULT_FILE_NAME` only, create a regular file at that run_dir and return `Ok(())`; other calls return success. This deliberately permits normal parent sync/replacement to finish rather than injecting durability uncertainty. Call `allocate_run_with_observer` with a counting observer. Assert the hook fired, Conflict/`managed-type-conflict` and exact path, persisted and in-memory advanced counter, no allocation token or observer calls, `recovery_is_complete() == false`, and subsequent allocation returns NotReady/`managed-recovery-required`. This is a synthetic post-publication filesystem conflict, not an added production hook or concurrency claim. + +For AC.5, remove only the connector endpoint voxel from an otherwise valid generated plan, leaving access/support unchanged, and assert the specific endpoint-carving diagnostic. Retain the occupied endpoint case. + +Execute vendor and V positive/negative controls before trusting their outputs. Parent then runs explicit metadata preflights, focused tests and complete target partitions from AC.1–9. Unit templates do not replace positive verification of the integrated real repository/workflow. Preserve pre-conversion lock evidence and before/after locked-command snapshots under ignored target/msrv-validation. + +Workers may run prerequisite-focused checks, but parent owns final comprehensive gates. Save/CLI gates can be slow; use TMPDIR=/var/tmp and tool budgets up to7200 while keeping each command under the observed3600-second cap. Do not compare huge full-world Debug strings; use existing canonical hashes, exact histories, decoded identity and genuine fixture byte equality. + +## Review Strategy + +Fix or explicitly rebut every plan finding. High/critical plan findings require another independent plan-reviewer pass after closure and before dispatch. After automatable testing, an independent implementation/evidence reviewer checks vendor source diff/provenance, exact package changes, verifiers/negative controls, both compiler gates and genuine fixture evidence. Fix or explicitly rebut every implementation finding; repeat independent review after critical findings until closed or escalated, and after high findings that alter the frozen contract. Source mutations after a gate require affected rechecks and appropriate final gates. No worker PASS replaces parent acceptance. + +## Documentation Strategy + +Parent records review closure and exact accepted method/results in this plan and audit, clarifies README source-build support and local-backport maintenance obligations, updates only the scoped checklist evidence, and commits after acceptance. D owns vendor-specific provenance/license/maintenance documentation; V documents verifier CLI usage in its script help. Preserve preflight/gate limitations: no production ignore flag, no fixture regeneration, local Linux proof versus configured but unexecuted remote CI/other platforms. + +## Risks, Blockers, and Required Decisions + +The operator's unavailable response is not approval to raise the minimum or migrate serialization. Retain1.75; the candidate backport is limited to authenticated exact-source maintenance with only the allowlisted manifest changes. Initial plan-review HOLD (high verifier gap, medium parsing/structure/CI coverage gaps, low hook precision) was repaired with explicit D/V verifier ownership, negative controls, full/filtered old-Cargo preflights, fixed CI commands/budgets and the named successful post-publication hook. Second independent review ACCEPT closed every finding with no remaining issue; D/S/V handoff is authorized within this contract. Local prerequisite observation: Python3.13 is present but pip/ensurepip and cargo-deny are absent. Parent installed only PyYAML6.0.2's pure-Python package under ignored `target/msrv-python-53/` from its authenticated official PyPI source archive (SHA256 `d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e`). Local V commands can set `PYTHONPATH=$PWD/target/msrv-python-53`; CI uses its separately installed Python3.11/pip. No local cargo-deny pass is claimed. + +Stop for parent review if codec/derive implementation changes, wire drift, budget changes, feature removals, unapproved dependency churn, fixture differences or new minimum-compiler errors outside the four known source sites appear. A future discovery can revise the graph; it is not permission to waive Rust1.75 or persistence contracts. This repair does not complete broader gameplay, accessibility, content/balance, performance or shipping gates.