Implements the 2026-09-09 fleet-id-order resolution, section 3 item 1. Given the
pre-turn save, compute the ids new in each post-turn save, match the client-minted
(node nibble != 0) new fleets by a key that does not mention the id -- (LocID or
FPlan destination, sorted ship-id set) -- build the bijection pi, rewrite every
fleet reference, compare the master id lists as sets, mask /Summary/Checksum with
its reason on the line, and print pi.
Acceptance, both halves:
bp-pinA vs bp-pinB IDENTICAL modulo pi = {1970<->1986} (35 leaves -> 0)
ad-oracle-A vs -B REFUSED, then DIVERGED: 94 leaves (unchanged)
Five guards, every one refusing rather than degrading: only ids absent from the
pre-turn save; only non-zero node nibbles; pi must permute one set; content keys
must correspond one-to-one and be unique per side; and no leaf anywhere may hold a
permuted id at an unmodelled site (matched on raw bytes, not the reader's typed
value). A refusal rewrites nothing and falls back to the ordinary comparison.
Three corrections to the specification from contact with the data, in
findings/subsystems/relabel-new-ids.md section 4: FtName is an id-attached label
and needs the same treatment as the id; relabelling the Flt[] keys is the wrong
operation (exchange the bodies -- the fleet table is id-ordered and identical in
both saves); a node's new-id set spans object kinds.
Default path proven unchanged: pre- and post-change modules agree on the root
digest, coverage, mask hits and every (path, digest) in the tree over all 43 saves
under two policies, and on 5,602 lines of CLI stdout across every mode.
Also fixes a pre-existing, unrelated test failure: the re-save localisation test
enumerated pairs over sorted filenames and hard-coded the direction 4 -> 0, which
a later corpus addition reversed. Suite 38 -> 62 tests, all passing.
27 KiB
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:
state_checksum.py POST-A.sav POST-B.sav --relabel-new-ids PRE-TURN.sav
The operation, in the order the code does it:
- Parse all three saves. Prove coverage on the unmodified parse (
audit_coverageruns before any rewrite), socoverage: PROVEDstill means what it has always meant: every byte of the file is a function of the digest's inputs. 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, nodePlyrIdx + 1is a player's own client).- 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. - Build π from the key correspondence, one node at a time.
- 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. - Rewrite every reference to a permuted id under π: a ship's
FltIDback-reference and a system'sFltentry. - Compare
ShipIDs[]/FleetIDs[]/DesignIDs[]as sets. - Mask
/Summary/Checksum, with the reason printed on its own line. - 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 resavecomposition the resolver asked for works:--mask resave --relabel-new-ids …on BP's pair reports[masked: Checksumx1, Statusx8]andIDENTICAL 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.savfiles inverify/results/saves/under--floats bits --mask noneand 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-chainand--chainover 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
- No VM, no game, no build. Host only. The three held guests were not approached.
- Neither engine-side deliverable (
sots-enginegame/aicanonical visit order; the--ai-visit-orderoverride). Out of scope by the brief, and ranked after this one by the resolver. - No command-block comparison (§4.4).
- Designs and ships are not relabelled, only fleets — per the spec. §4.3 says what has to be read before that changes.
Summary/Checksumis 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.- π'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
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 <pre.sav>, 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 π; citerelabel-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.