# `state_checksum --relabel-new-ids`: comparing two post-turn saves modulo this turn's new id labelling Lane BT, 2026-09-09. **Host only — no VM was touched.** VM140 (reference guest) untouched; VM141, VM144 and VM146 were held by lanes AZ, BS and BR throughout and were not approached. Implements `findings/resolutions/2026-09-09-fleet-id-order-residue.md` §3 item 1, verbatim as the specification and with the two engine-side items (§3.2 canonical visit order, §3.3 the `--ai-visit-order` override) deliberately **not** started — they belong in `sots-engine` and the resolver ranked them after this one. Consumes: `findings/control-flow/pinned-seed-rich-turn.md` (lane BP — the acceptance data), `findings/subsystems/id-allocation.md` (the id scheme), `findings/control-flow/raid-gate-multiplicity.md` (lane AD — the negative acceptance data). Touches only `verify/state-checksum/*` and this file. --- ## 0. Result Both halves of the acceptance pass, and the second half passes **because a guard fires**, not because the matcher happened to find nothing. | half | pair | verdict | |---|---|---| | **positive** | `bp-pinA-turn28` vs `bp-pinB-turn28`, pre `bp-turn28-pre` | `IDENTICAL modulo pi = {1970<->1986}` — 35 leaves → **0**, and π is exactly the one transposition | | **negative** | `ad-oracle-A-post` vs `ad-oracle-B-post`, pre `ad-turn27-two-raiders` | `REFUSED` (the two runs minted different id **sets**), then `DIVERGED: 94 leaf difference(s)` — byte-for-byte the same 94 the tool reports without the flag | Existing behaviour is unchanged when the flag is absent: over every save in `verify/results/saves/` under both `--floats bits --mask none` and `--floats canonical --mask resave`, the pre-change and post-change modules produce identical root digests **and identical per-node digests at every node of the tree** (§5.1). --- ## 1. What was built `verify/state-checksum/state_checksum.py` gains one flag: ```sh state_checksum.py POST-A.sav POST-B.sav --relabel-new-ids PRE-TURN.sav ``` The operation, in the order the code does it: 1. Parse all three saves. **Prove coverage on the unmodified parse** (`audit_coverage` runs before any rewrite), so `coverage: PROVED` still means what it has always meant: every byte of the file is a function of the digest's inputs. 2. `new(X) = { fleet ids in X } \ { fleet ids in PRE }`, restricted to **node nibble ≠ 0** — the client-minted space (`id-allocation.md` §1: `id = (counter << 4) | node`, node 0 is the sim that owns the board, node `PlyrIdx + 1` is a player's own client). 3. Key each new fleet by a content key that does not mention its id: **`(LocID if non-zero else FPlan/pnd destination, sorted ship-id set)`**, with the two location kinds tagged apart so a fleet *standing at* system 384 never keys the same as one *bound for* 384. 4. Build **π** from the key correspondence, one node at a time. 5. **Exchange the matched fleets' bodies between their slots** (see §4.2 — this is not what the spec said, and the spec was wrong), keeping each slot's id and its id-attached label `FtName`. 6. Rewrite every *reference* to a permuted id under π: a ship's `FltID` back-reference and a system's `Flt` entry. 7. Compare `ShipIDs[]` / `FleetIDs[]` / `DesignIDs[]` as **sets**. 8. Mask `/Summary/Checksum`, **with the reason printed on its own line**. 9. Print π and the verdict. New public surface: `RelabelRefused`, `Relabelling`, `build_relabelling`, `apply_relabelling`, `format_permutation`, `id_node`, and `checksum_result` (the parse/digest split that lets the mode parse once, audit, then rewrite). The relabelled root is **domain-separated** — `relabel-new-ids` is folded into the root preimage — so a "modulo π" root can never be mistaken for a strict one. The extra preimage word is appended *only* in this mode, so every root recorded before the flag existed is bit-for-bit unchanged. --- ## 2. Acceptance, positive half — verbatim ``` $ uv run python3 verify/state-checksum/state_checksum.py \ verify/results/saves/bp-pinA-turn28.sav verify/results/saves/bp-pinB-turn28.sav \ --floats bits --mask none \ --relabel-new-ids verify/results/saves/bp-turn28-pre.sav A a83c425215b6d7e88bc998f4948081e7 verify/results/saves/bp-pinA-turn28.sav B a83c425215b6d7e88bc998f4948081e7 verify/results/saves/bp-pinB-turn28.sav policy: floats=bits mask=none reader=74fd562c75e2679e relabel: pre-turn save verify/results/saves/bp-turn28-pre.sav relabel: pi = {1970<->1986} relabel: 1970 (counter 123, node 2) -> 1986 at 384, ships [6976] relabel: 1986 (counter 124, node 2) -> 1970 bound-for 80, ships [5264] relabel: 2002 (counter 125, node 2) -> 2002 bound-for 384, ships [6992] relabel: 3 new client-minted fleet id(s) on node(s) [2]; 2 relabelled, 2 fleet body/bodies exchanged, Fltx1, FltIDx2 rewritten relabel: /Summary/Checksum is MASKED: it is derived from the whole state and its inputs are unmodelled (rule 18's open item), so it cannot be recomputed under a relabelling and its move is not independent evidence. Unmask by dropping --relabel-new-ids. relabel: Master id lists (ShipIDs/FleetIDs/DesignIDs) are compared as SETS: their element order is the order the turn's commands were applied in, which is the same visit-order residue. Membership is still exact -- an added or removed id still reports. IDENTICAL modulo pi = {1970<->1986} $ echo $? 0 ``` Read the per-id lines: the counters printed are the decode the resolver did by hand (`123/124/125`, node 2 = Player[32]'s client), and the content keys are what carries the match — the group **at system 384 with ship 6976** is fleet 1970 in A and fleet 1986 in B; the group **bound for system 80 with ship 5264** is 1986 in A and 1970 in B; the group bound for 384 is 2002 in both. Exactly the resolver's §2.1 reading, recovered from the saves alone. Without the flag the same pair is `DIVERGED: 35 leaf difference(s)` (regression-locked by `test_POSITIVE_the_same_pair_still_diverges_without_the_flag`, which asserts the count is 35). So the mode removes **35 leaves and no others**: `IDENTICAL modulo one transposition and nothing else`. --- ## 3. Acceptance, negative half — verbatim, and why it is the right kind of failure ``` $ uv run python3 verify/state-checksum/state_checksum.py \ verify/results/saves/ad-oracle-A-post.sav verify/results/saves/ad-oracle-B-post.sav \ --floats bits --mask none \ --relabel-new-ids verify/results/saves/ad-turn27-two-raiders.sav A 1faf04cad2bbf2d7e5ecf560b8807504 verify/results/saves/ad-oracle-A-post.sav B 53043168ad03cae13355db9f5f381b50 verify/results/saves/ad-oracle-B-post.sav policy: floats=bits mask=none reader=74fd562c75e2679e relabel: pre-turn save verify/results/saves/ad-turn27-two-raiders.sav relabel: REFUSED -- the new client-minted fleet ids differ between the two saves -- A minted [1970, 1986], B minted [1970, 1986, 2002]; only in B [2002]. That is a difference in what was allocated, not in how it was labelled, so no relabelling is defensible relabel: NO relabelling was applied; the comparison below is the ordinary one, and nothing has been absorbed. DIVERGED: 94 leaf difference(s) /Summary/Checksum: -1043321805 -> 1995746704 /Sim/DesignIDs[]: removed [2002], added [2018] (85 -> 85 entries) /Sim/FleetIDs[]: removed [], added [2002] (58 -> 59 entries) /Sim/ShipIDs[]: list-reordered /Sim/ModCount: 1496 -> 1500 ... 89 more ... $ echo $? 1 ``` 94 is the number the tool reports for that pair **without** the flag, unchanged. On a refusal nothing is rewritten, nothing is masked and no list is set-compared: the refusal path *is* the ordinary comparison. That is deliberate — a mask applied on a run whose relabelling was refused would be a mask nobody asked for. **The refusal is by cardinality, not by content.** AD's run A minted **two** client fleets and run B minted **three**. The guard that fires is G3 (π must permute one set), and it fires before the content matcher is ever consulted. That matters, because it means AD's pair does **not** exercise the content key negatively. I exercised that separately, two ways (§4.3, §5.3): a synthetic pair whose new ids agree and whose contents differ, and — the belt-and-braces version — **forcing the transposition onto AD's pair with the guard bypassed**, which still leaves **82 differing leaves**, including `DesignIDs[]`, `ModCount`, four `turnstats` rows, both AI build queues and `Player[32]`'s money. The guard is not the only thing standing between AD's pair and a green verdict; it is the first of several. --- ## 4. Where the specification did not survive contact Four places. The first two changed the implementation; the third and fourth are scope notes the next lane needs. (Lane BU landed mid-lane, confirming H1 — the visit order is an address-keyed container whose key is the fleet's `Location*`. That settles the *cause* of the residue and changes nothing here: the comparison side quotients the residue out regardless of what produces it, and it must go on refusing when the difference is not a relabelling. The forward notes in §4.1 and §4.2 are addressed to the engine-side canonical order and stand as written.) ### 4.1 `FtName` is an **id-attached label**, and "every id-valued leaf" does not reach it In *both* of BP's saves, fleet **1970 is "Sigma Fleet VI"** and **1986 is "Tau Fleet VI"**. The name follows the **id**, not the ship group. It is a Greek-letter ordinal minted from a per-player counter that advances with the same pass that mints the id, so it is exactly as much a function of the visit order as the id is — and exactly as little a decision. Consequence: applying π only to id-valued leaves would move the group at system 384 from slot 1970 to slot 1986 **carrying the name "Sigma Fleet VI"**, and compare it against B's 1986 "Tau Fleet VI". Two spurious leaf differences, and the acceptance "and nothing else" would have failed. Handled by keeping the name with the slot rather than with the body, and **gating it**: the mode refuses unless `FtName` is the same at every matched id in both saves. If the name does not track the id, something real differs and the tool must not paper over it (`test_a_name_that_does_not_track_the_id_is_refused`). Cross-check that this is a naming *counter* and not a coincidence, from AD's pair: A minted two client fleets, so A's node-0 fleet **7120 is "Upsilon Fleet VI"**; B minted three, so B's **7120 is "Phi Fleet VI"**. The Greek sequence is **per player and shared between the client's and the server's fleets** — one more thing an engine-side canonical visit order (§3.2 of the resolution) has to reproduce, and one the resolver's item 2 does not currently mention. ### 4.2 Applying π to the `Flt[]` **keys** introduces a spurious `reordered` The master fleet table's element order, and the `FleetIDs[]` list, are **identical in A and B** (measured: both are `[…, 6960, 1970, 1986, 2002, 7120, …]`) and are a function of the id, not of the visit order. Renumber A's slots under π and A's table reads `…1986, 1970, 2002…` against B's `…1970, 1986, 2002…`, which the differ correctly reports as a reorder — an artefact of the tool, not of the saves. The equivalent operation with no artefact is to **exchange the fleet bodies between the slots**, leaving slot ids, `FleetIDs[]`, and every object label exactly as the file wrote them. That is what the implementation does. It is the same quotient, taken from the other side. Worth carrying into the engine-side item: **the fleet table is id-ordered, not visit-ordered**, so canonicalising the visit order in `game/ai` will reorder lists 8/10 and the apply order, and will *not* reorder the save's fleet table. ### 4.3 "new ids of the same node" is not a fleet-only id space `ad-oracle-A-post` carries **2002 as a `DesignID`**; `ad-oracle-B-post` carries **2002 as a `FltID`**. The per-node counter is shared across object kinds, so a node's new-id set spans fleets, designs and (in principle) ships. This mode matches **fleets only**, as the spec says. What keeps that safe is guard G5 (§5.2): any leaf anywhere holding a permuted id at a site the tool does not model as a fleet reference is a **refusal**. Anyone extending the mode to designs must read this paragraph first — the two spaces interleave. ### 4.4 "list-8/10/14 words when comparing command blocks" is **not** implemented, and does not belong here Lists 8/10/14 live in the `aiorders` **shim dump**, not in a `.sav`. `state_checksum.py` parses saves; it has no reader for the block. Wiring π into a block comparison belongs wherever those dumps are differed (lane BP did it by hand under its proven noise mask, `pinned-seed-rich-turn.md` §2). Recorded as not-done with the reason rather than silently dropped. ### 4.5 Two smaller notes - **Master id lists as sets is unconditional in this mode**, including when π is the identity. `ShipIDs[]`'s element order is the apply order, which is the same residue; membership stays exact, so an added or removed id still reports. It is nonetheless a real weakening and it is printed on every run. A lane that wants that order back should reach for a separate flag, not for this one. - **The `--mask resave` composition the resolver asked for works**: `--mask resave --relabel-new-ids …` on BP's pair reports `[masked: Checksumx1, Statusx8]` and `IDENTICAL modulo pi = {1970<->1986}`. The relabel mask is added to whichever preset is in effect and de-duplicated against it. --- ## 5. The guards, and how each was made to fire Five guards. **Every one refuses; none degrades to a partial relabelling.** A refusal prints its reason, applies nothing, and runs the ordinary comparison — the conservative direction, because a real divergence then still reports. | | guard | how it was made to fire | |---|---|---| | **G1** | only ids **absent from the pre-turn save** may be relabelled | `test_ids_present_in_the_pre_turn_save_are_never_in_pi`; and the strong form, `test_two_pre_turn_fleets_that_swapped_contents_are_NOT_absorbed` — two *pre-existing* fleets exchanging contents is the very shape this mode absorbs, and it must still report | | **G2** | only ids with a **non-zero node nibble** | `test_server_minted_ids_are_never_relabelled` — two node-0 (server) fleets exchanging contents still diverges | | **G3** | π must be a **permutation of one set** — so the two saves must have minted the same ids | `test_different_new_id_sets_are_refused` (synthetic: one run mints a third fleet) and **lane AD's real pair** (§3) | | **G4** | the content keys must **correspond one-to-one**, and be **unique on each side** | `test_new_fleets_whose_contents_differ_are_refused`; `test_an_ambiguous_content_key_is_refused` (two new fleets with the same location and ship set) | | **G5** | **no leaf anywhere** in either save may hold a permuted id at a site the tool does not model | `test_an_unmodelled_reference_site_is_refused` (a `SomeOtherRef` leaf holding 1970); `test_the_completeness_scan_matches_raw_bytes_not_the_typed_value` | | — | `FtName` must track the id in both saves | `test_a_name_that_does_not_track_the_id_is_refused` (§4.1) | | — | a refusal leaves both parse trees **untouched** | `test_a_refusal_leaves_both_trees_untouched` — the digest of A before and after a refused `build_relabelling` is identical | ### 5.1 The default path is unchanged Checked two ways, because "the tool is used by several lanes and by the determinism oracle": - **Digest equivalence, whole corpus.** The pre-change module (`git show HEAD:…`) and the post-change module were run over all **43** `.sav` files in `verify/results/saves/` under `--floats bits --mask none` and under `--floats canonical --mask resave`, comparing the root digest, the coverage record, the mask hits, **and the `(path, digest)` of every node in the tree**. `saves checked: 43 mismatches: 0`. - **CLI stdout equivalence, every mode.** Single-save; `--tree --depth 3`; `--json`; the BP pair; the AD pair at `--limit 500`; `turn2/turn3 --mask resave --ulps 2`; `--record-chain` and `--chain` over turns 1/2/3. **5,602 lines, byte-identical** between the two modules (only the chain file's own path normalised). The one change that *could* have moved a recorded root — folding a policy word into the root preimage — is appended **only** when the new mode is active. An intermediate version of this work appended an empty word unconditionally, which moved the root; that was caught by the equivalence check above, which is the reason it exists. ### 5.2 G5 matches raw bytes, not the reader's typed value — on purpose The digest is a function of *(save bytes, reader schema)*, never of the bytes alone (STATE_CHECKSUM.md §2.4). A leaf the schema happens to type as a float or a raw blob still carries the id, and a value-based completeness scan would not see it — a guard a typing slip can silently empty is the "green verdict over an empty region set" of earned rule 1. This is not hypothetical: while building the synthetic fixture, the reader typed a `Flt` reference as a **float** (`2.76e-42`, the denormal whose bit pattern is 1970) and a value-based scan missed it. Matching on the raw four bytes catches it. The cost is that a genuine 4-byte float in the denormal range around a permuted id would refuse — a refusal is the safe direction, and no such value exists in the corpus. ### 5.3 The strongest negative: bypass the guard and it still diverges `test_NEGATIVE_even_forcing_a_partial_relabelling_cannot_hide_it` hands `apply_relabelling` the transposition `{1970↔1986}` it *would* have built if G3 did not exist, applies it to AD's A save, and compares under the full "modulo π" policy (checksum masked, master lists as sets). **82 leaves still differ.** The guards are the tool's honesty, not its only defence. ### 5.4 Tests 24 new tests (20 synthetic in `RelabelTest`, 4 real-save in `RealSaveTest`), **7 of which assert a refusal**. The whole suite is 38 → **62 tests, all passing**: ``` $ uv run python3 -m unittest test_state_checksum.RelabelTest # 20 tests, OK, 0.07 s $ uv run python3 -m unittest test_state_checksum.RealSaveTest.test_POSITIVE_… \ …test_NEGATIVE_… # 4 tests, OK, 88.7 s $ uv run python3 -m unittest discover -s . -t . # 62 tests, OK ``` ### 5.5 One pre-existing test failure, fixed, that is not about this change The first full-suite run failed one test — `test_known_resave_delta_localises_to_five_named_leaves` — and **the pre-change module fails it identically**, so it is not a regression. The test enumerates candidate pairs over *sorted filenames* and asserted the re-save direction as `4 -> 0`; `cb-turn2to3-endturn.sav`, added to the corpus by an earlier lane, sorts before `turn2-state.sav`, so that pair reads `0 -> 4`. The claim is symmetric and the assertion now is too (all four `Status` leaves must still move the *same* way, with `Checksum` following by ∓16). Recorded rather than quietly patched, per earned rule 11. --- ## 6. What this lane did NOT do 1. **No VM, no game, no build.** Host only. The three held guests were not approached. 2. **Neither engine-side deliverable** (`sots-engine` `game/ai` canonical visit order; the `--ai-visit-order` override). Out of scope by the brief, and ranked after this one by the resolver. 3. **No command-block comparison** (§4.4). 4. **Designs and ships are not relabelled**, only fleets — per the spec. §4.3 says what has to be read before that changes. 5. **`Summary/Checksum` is still unmodelled.** It is masked with its reason, not solved. STATE_CHECKSUM.md §4.6 records the two derivations already ruled out; nobody should re-run them. 6. **π's *existence* is not evidence that the two runs agree on the turn.** It is evidence that they agree *up to the labelling of the ids created on it*. The claim the mode licenses is exactly the resolver's C-set shape and no more. --- ## 7. Reproducing every number here ```sh cd ~/sots-re S=verify/results/saves # positive uv run python3 verify/state-checksum/state_checksum.py \ $S/bp-pinA-turn28.sav $S/bp-pinB-turn28.sav --floats bits --mask none \ --relabel-new-ids $S/bp-turn28-pre.sav # negative uv run python3 verify/state-checksum/state_checksum.py \ $S/ad-oracle-A-post.sav $S/ad-oracle-B-post.sav --floats bits --mask none \ --relabel-new-ids $S/ad-turn27-two-raiders.sav # guards cd verify/state-checksum && uv run python3 -m unittest -v test_state_checksum.RelabelTest ``` --- ## Proposed board rows New row: ``` | STATE_CHECKSUM --relabel-new-ids: BP'S PINNED PAIR IS IDENTICAL MODULO ONE TRANSPOSITION, AD'S UNPINNED PAIR IS REFUSED AND STILL DIVERGES | tooling | verified | high | 100% | 2026-09-09 | Lane BT, HOST ONLY (no VM; 140 untouched, 141/144/146 held by AZ/BS/BR and not approached). Implements the 2026-09-09 fleet-id-order resolution §3 item 1 (`findings/subsystems/relabel-new-ids.md`). `state_checksum.py POST-A POST-B --relabel-new-ids PRE` computes the ids NEW in each post-turn save, restricts to node nibble != 0 (client-minted; `id-allocation.md` id=(counter<<4)|node), matches those fleets by a key that does not mention the id - (LocID if non-zero else FPlan/pnd destination, sorted ship-id set), with "at 384" and "bound-for 384" tagged apart - builds the bijection pi, rewrites every fleet reference, compares ShipIDs/FleetIDs/DesignIDs as SETS, masks /Summary/Checksum WITH ITS REASON ON THE LINE, and prints pi. **POSITIVE: `bp-pinA` vs `bp-pinB` = `IDENTICAL modulo pi = {1970<->1986}`, 35 leaves -> 0, exit 0**, with pi recovered from the saves alone and printed with the counters (123/124/125, node 2) and the content keys - the group AT Sys 384 with ship 6976 is 1970 in A and 1986 in B; the group BOUND FOR Sys 80 with ship 5264 is 1986 in A and 1970 in B; 2002's group is 2002 in both. **NEGATIVE: `ad-oracle-A/B-post` REFUSED and `DIVERGED: 94 leaf difference(s)`, exit 1** - byte-identically the 94 the tool reports without the flag, because on a refusal NOTHING is rewritten, masked or set-compared. The refusal is by CARDINALITY (A minted 2 client fleets, B minted 3), so AD's pair does not exercise the content matcher; that is exercised separately, and FORCING the transposition onto AD's pair with the guard bypassed STILL LEAVES 82 LEAVES. FIVE GUARDS, EVERY ONE REFUSES RATHER THAN DEGRADES: G1 only ids absent from the pre-turn save (tested with two PRE-EXISTING fleets exchanging contents - must still report); G2 only non-zero node nibbles (node-0 swap still reports); G3 pi must permute ONE set; G4 content keys correspond one-to-one and are unique per side; G5 NO leaf anywhere may hold a permuted id at an unmodelled site, matched on RAW BYTES not the reader's typed value (a value scan is empty the moment the schema types a reference as a float - this happened during development). Refusal prints its reason and falls back to the ORDINARY comparison, never to a partial relabelling. THREE SPECIFICATION CORRECTIONS FROM CONTACT WITH THE DATA: (1) **FtName is an ID-ATTACHED LABEL** - 1970 is "Sigma Fleet VI" and 1986 "Tau Fleet VI" in BOTH saves, a Greek ordinal minted by the same pass as the id, so "apply pi to every id-valued leaf" would have produced two spurious name diffs; the name stays with the SLOT, gated by a guard requiring it to track the id in both saves. The counter is PER PLAYER AND SHARED WITH THE SERVER'S FLEETS - AD's A (2 client fleets) names node-0 fleet 7120 "Upsilon", B (3) names it "Phi" - which the engine-side canonical visit order must reproduce and §3.2 does not mention. (2) **Applying pi to the Flt[] KEYS introduces a spurious `reordered`**: the fleet table and FleetIDs[] are ID-ordered and IDENTICAL in A and B, so renumbering slots reorders A against B; the artefact-free equivalent is to EXCHANGE THE FLEET BODIES between slots, leaving slot ids, FleetIDs[] and every label as written. (3) **A node's new-id set is NOT fleet-only**: 2002 is a DesignID in ad-oracle-A-post and a FltID in ad-oracle-B-post - the per-node counter is shared across object kinds, and G5 is what keeps a fleet-only matcher safe. NOT DONE, with reasons: lists 8/10/14 (they are aiorders SHIM DUMP words, not save leaves - this tool has no block reader); designs/ships; the two engine-side items. DEFAULT PATH PROVEN UNCHANGED: pre- and post-change modules compared over the whole save corpus under two policies on root digest, coverage, mask hits AND every (path,digest) in the tree - zero mismatches; plus byte-identical CLI stdout on the single-save, BP, AD and resave invocations. The relabelled root is DOMAIN-SEPARATED so a "modulo pi" root can never be read as a strict one. 24 new tests (20 synthetic + 4 real-save acceptance), 7 of them asserting a refusal; suite 38 -> 62, all passing. ALSO FIXED, PRE-EXISTING AND NOT A REGRESSION (the pre-change module fails it identically): `test_known_resave_delta_localises_to_five_named_leaves` enumerated pairs over SORTED FILENAMES and hard-coded the re-save direction 4->0; `cb-turn2to3-endturn.sav` sorts before `turn2-state.sav`, so that pair reads 0->4 and the test failed on a corpus fact. Assertion is now direction-symmetric (all four Status leaves must still move the SAME way, Checksum following by -/+16). Artefacts: `verify/state-checksum/state_checksum.py`, `test_state_checksum.py`, `STATE_CHECKSUM.md` §2.6 | ``` Edits to existing rows: - **Row 424 / the resolver row of 2026-09-09** — append: `ENGINE ITEM 1 IS DONE (lane BT, host): state_checksum --relabel-new-ids ships with both acceptance halves green - BP's pair IDENTICAL modulo {1970<->1986}, AD's pair refused and still 94-leaf DIVERGED. Three corrections to §3.1 from the data: FtName is an id-attached label and needs the same treatment as the id (and its counter is per-player and shared with the server's fleets, which §3.2's canonical visit order must also reproduce); relabelling the Flt[] keys is the wrong operation - exchange the bodies, because the fleet table is id-ordered and identical in both saves; and a node's new-id set spans object kinds (2002 is a DesignID in ad-oracle-A-post and a FltID in ad-oracle-B-post). Lists 8/10/14 are not in scope for this tool - they are shim-dump words, not save leaves.` - **Row 333 (C-exact)** — append: `Comparison side delivered 2026-09-09 (lane BT): `state_checksum --relabel-new-ids `, guarded so it refuses rather than absorbs; see findings/subsystems/relabel-new-ids.md.` - **`determinism-oracle.md`'s "Qualified" paragraph** — when it is written, "modulo π" now has an executable definition and a printed π; cite `relabel-new-ids.md` §1 for the operation and §5 for the guards. - **`id-allocation.md` §5** — alongside the canonical-visit-order item the resolver asked for, add the two measured facts from §4.1/§4.2 of this document: the **fleet-name ordinal** is per player and shared between client- and server-minted fleets, and the **master fleet table is id-ordered**, not visit-ordered. - **Row 62** — VM140/141/144/146 unchanged by this lane; it took no guest.