# Resolution — the residue under pinned seeds is a visit order, it is written into the block, and it is not yet known to be RNG or heap - **Type:** resolution (course-setting; two new measurements taken here, from BP's logs already on disk) - **Trigger:** lane BP's P1 falsified — `findings/control-flow/pinned-seed-rich-turn.md` §3 (probe 2 of `2026-09-09-seed-exposure-is-a-predicate.md`) - **Date / author:** 2026-09-09 · re-resolver - **Touches:** board rows 326 / 333 / 360 / 415; `backlog.md` §2 Rung B and Rung C; `method-rules.md` rule 26 (c) wording, new corollary (d); `id-allocation.md` §5; `determinism-oracle.md`; `verify/state-checksum/state_checksum.py` (a new mode); `src/shim/shim.cfg.cbpin` --- ## 0. Decision 1. **BP's restatement is accepted and sharpened.** Given (save, per-client seeds) the AI's command block on `ad-turn27` is determined **up to the order in which `AssignFleetsAndIssueOrders` visits the groups that need a new fleet.** The ids are not the variable — the node-2 counter hands out 1970, 1986, 2002 in that order in every process (§2.1). The visit order is. On this turn the visit order changes exactly three things: which client-minted id each group receives, the element order of lists 8/10, and — downstream — the apply order, which is why `ShipIDs[]` comes out reordered. Every decision is invariant under it. 2. **The residual input is not lost; it is written into the block.** List 10 carries `{systemId, fleetId, ships[]}` per group, so any captured original run records its own visit order for free. C-exact therefore survives **literally**, with one more per-run input that costs nothing to capture: (save, seeds, **visit order as read off list 10**) → byte match. C-set's shape covers the uncaptured case: our canonical order is one member of the original's outcome set of orders. §3 says what the engine and the comparison tool must do. 3. **The pointer-order reading is not yet the leading hypothesis — it is one of two, and the other is already named in the record.** AI1's consumer list for the per-process global generator at `0x00af6e58` includes two AI-band sites nobody has named (`0x0079ea90+0x73`, an `RNG_Chance`, and `0x005b9f00+0xc0`); the seed pin does not touch that generator. What *has* moved since 09-08 is that pointer order now has a **measured precondition** (§2.2): in two processes with identical configuration, BP's own dumps show the same run of consecutive same-size heap allocations landing in different relative address orders. So the mechanism the reading needs is present in this process. That is a precondition, not the cause. 4. **One probe, one run, no build, VM146, ~12 minutes** (§4): BP's exact pinned procedure with `airng=on` added (pin_seed off). The `OnResumePlaying` bracket attributes **every draw on every generator** during each AI client's turn to a return address and a generator address, and the inlined-draw inventory has no site in the AI band, so the observer is complete there. It is also run C. **Prediction committed:** zero foreign draws in Player[32]'s bracket — the global does not move — and the autosave is one of the two known files. If a foreign draw appears, its return address names the consumer and the follow-up is a global pin; if none, RNG is excluded by measurement and the follow-up is the container hook, placed by one static read. 5. **Rung C is restated (§6). Rung B is not restated; its value is confirmed and it gains a concrete target.** Replay applies ids off the wire in block order, so it is insulated from this residue by construction. One `aiorders.deep=on` run of BP's pinned procedure that lands on `e913ff41…` is the first fully reproducible rich-turn record — (pre-turn save, seeds, deep block, autosave) — and the engine can be measured against it whenever the sim reaches that turn. 6. **No rule 29.** BP's third run is the right practice and it belongs in rule 26 as corollary (d): when the instrument cannot be removed, pin it to a natural run's observed values and require it to reproduce that run before reading anything from a pinned pair. BP's amendment to (c) is right in substance and overreaches in one clause; corrected wording in §7. The `shim.cfg` trap BP found (an unnamed hook is silently installed) gets a structural fix, not a rule. 7. **Lane BQ's result, which arrived mid-ruling, is folded in (§9) and does not change the probe.** Image base is constant across processes on *both* guests (`0x00f40000` ×5 on VM145, `0x005e0000` ×3 on VM146), so "pointer order" can only mean **heap** order, which §2.2 measures as per-process. BQ's per-*history* input (a fleet moved by continuation, not after a load) is a different input from BP's per-*process* one, and the probe holds history fixed (every run is a load), so it is unconfounded. The leading mechanism for BQ's residue is **AI agent state the save does not carry** (inference; `AISystem::Write` emits nothing), and the consequence for the rungs is a scope, not a loss: **every byte-match claim is a claim about load→turn procedures.** Rung A: BQ's reading is confirmed — the load-form pair enters `determinism-hashes.txt`, AR's continuation hash does not. --- ## 1. The surprise, and the instrument Two fresh processes with the three AI client seeds pinned to identical words, identical build, identical config, identical input, identical pre-turn autosave, produced different turn-28 states — 35 leaves, one transposition. The prediction was IDENTICAL. The evidence is as strong as reported, and stronger than a bare falsification, because the run that *should* have been the weak one — L, unpinned — is byte-identical to A. Instrument: fresh tree (rule 24), lane worktree (rule 21), every registered hook off by name with the count in the log (27), zero unknown keys, three of three `pinned=1` in both pinned runs, identical `config:` lines, no wildcard hit, no fourth client. **The instrument is exonerated for the A/B difference** — the two processes carried the same instrument and one of them reproduced an unpinned run byte for byte, which a perturbing instrument could only do by a 1/k coincidence. Rule 26 applies to the A/B pair exactly as BP says: it does not agree with itself, so it certifies nothing. What carries weight is L = A. What no `hooks=off` control could have said here, stated so nobody looks for one: a pin cannot be applied without hooks, so "the un-instrumented pinned game" does not exist. The L/A agreement is the control this design admits (§7, corollary (d)). ## 2. Two measurements this resolution adds, from BP's files ### 2.1 The ids decode, and they say the counter is deterministic `id = (counter << 4) | node` (`id-allocation.md`, verified on twenty saves and the instruction stream). Player[32] is `PlyrIdx 1`, so its client is node **2**: | id | hex | counter | node | what | |---:|---|---:|---:|---| | 1970 | 0x7b2 | 123 | 2 | client-minted, first new fleet | | 1986 | 0x7c2 | 124 | 2 | second | | 2002 | 0x7d2 | 125 | 2 | third | | 7072 | 0x1ba0 | 442 | 0 | server id, an existing fleet | | 6976 / 5264 | 0x1b40 / 0x1490 | 436 / 329 | 0 | server-minted ships | So the AI minted three fleet ids at emission, counters 123–125 contiguous, in both processes. List 10's elements in A are `(384,1970) (80,1986) (384,2002) (816,7072)`; in B `(80,1970) (384,1986) (384,2002) (816,7072)`. The id follows the visit; the group at system 80 was visited first in B and second in A. **The variable is the visit order of the first two groups**; 2002's group and the existing fleet came third and fourth in every process. (Two of three processes agree, so "third in every process" is two observations, not a law.) ### 2.2 Same-size heap allocations land in different relative orders across processes — measured The `aielem` dump records each command node's heap address (`node=0x…`). Runs A and B have identical configuration and identical decisions, so the allocation sequence through the AI turn is the same (inference: supported by the identical outputs, not proved). Player 32's list 3 — nineteen nodes allocated in one pass — in visit order: - **A:** `f838 f538 f898 f4f8 f518 fa38 fc98 …` (idx1 < idx0, idx3 < idx2) - **B:** `e1c0 e320 e200 e380 e460 e500 e260 …` (idx1 > idx0, idx3 > idx2) Relative order differs between two processes for the same allocation sequence. That is what the Windows 8+ low-fragmentation heap does by design (randomised slot selection within a bucket), and it is the precondition any address-keyed container needs to walk in a per-process order. **Measured: allocation order is per-process here. Inferred: that some container on the fleet-assignment path is address-keyed.** The second half is what the probe chain settles. The image, by contrast, does not move: `exe base=0x005e0000` in all three of BP's processes on VM146 and `0x00f40000` in all five of BQ's on VM145 — per boot, not per process. So any "ASLR" reading that reaches for image-base randomisation is excluded on these guests; the only addresses that vary between processes are heap (and stack). "Pointer order" in this document means heap order. ### 2.3 Time is not a live hypothesis with a mechanism `AIProcessMinTime` is a trailing minimum-duration `Sleep` (`ai-task-system.md`), not a slice; the AI turn runs synchronously inside `StrategyClient::OnResumePlaying` (lane PAR), and stepping order is save order × stable priority (AI2). No wall-clock input to the visit order is in the record. Not excluded — nothing is — but it has no mechanism and is ranked last. ## 3. Ruling on the restatement, and what "canonicalisable" means concretely **Accepted, sharpened as in §0.1.** Two qualifications, both rule 23's shape: - "Every decision is invariant under the visit order" is a statement about *this turn*. A visit order can change a decision wherever an earlier visit consumes something a later one wanted (an escort, a build slot, the one move order). On `ad-turn27` the move in list 8 went to the group at system 80 in both orders. The general claim needs the mechanism named and its scope read. - The outcome set of orders has been observed at size 2 from two distinct observations. Its true size is unknown; run C (the probe run) is the first datum on it. **For `sots-engine`, three deliverables, ranked by what they unblock:** 1. **Comparison side — `state_checksum.py --relabel-new-ids ` (sots-re, host only).** Given the pre-turn save, compute the ids new in each post-turn save; among them, match fleets with node nibble ≠ 0 by a content key that does not depend on the id — `(LocID or FPlan destination, sorted ship-id set)` — and build the bijection π between the two saves. Apply π to every id-valued leaf (`Flt[]` keys, `Sys[*]/Flt[*]`, ship→fleet references, `FleetIDs[]` entries, list-8/10/14 words when comparing blocks), treat the master id lists `ShipIDs[]` / `FleetIDs[]` / `DesignIDs[]` as sets, and report `IDENTICAL modulo π = {1970↔1986}` with π printed. `Summary/Checksum` is derived and its inputs are unmodelled (rule 18's open item), so it is masked *with that reason on the line* until the checksum is modelled. Acceptance: BP's `bp-pinA` vs `bp-pinB` reads IDENTICAL modulo one transposition and nothing else; AD's `ad-oracle-A/B-post` still DIVERGE (their difference is seed-driven and must not be absorbed). 2. **Engine side — `game/ai`, at the point where a task forms a fleet from a ship group** (the original: `AssignFleetsAndIssueOrders 0x006c16c0`, pass 1, minting via `IDMap::AllocateOnLocalNode` on node `PlyrIdx+1`, emitting list 10 then any list 8/14 for that fleet). Visit the groups in a **canonical order that is a function of the save alone** — ascending `systemId`, then ascending minimum ship id in the group — and mint in that order. This is deterministic across our own processes by construction and is one member of the original's outcome set. Nothing else in `id-allocation.md` §5 changes: mint at emission, carry the id in the command, the applier honours non-zero ids. 3. **Engine side, exactness knob — an optional visit-order override** read from a captured block: `--ai-visit-order =/,…` (or simply "take the list-10 order from the `--turn-commands` capture when both are given"). With it, (save, seeds, order) reproduces the original's exact bytes on every captured run — C-exact literal. Three words per new fleet, the same cost class as `--ai-seed`. Build it after (1) and (2); it is what turns "modulo π" into "=". The comparison should never accept a relabelling that is not a bijection between *new* ids of the same node, and it should refuse to relabel anything present in the pre-turn save. That is the guard that keeps (1) from absorbing a real divergence. ## 4. Hypotheses and the one probe | | hypothesis | mechanism in the record | what the probe shows | |---|---|---|---| | **H1** | an address-keyed container (or an unstable sort seeded by one) on the fleet-assignment path walks in heap order | precondition measured (§2.2); container **not** identified | zero foreign draws in the bracket; order then needs the container hook (stage 2) | | **H1b** | an uninitialised word read by a comparator on that path | this codebase leaves uninitialised words in command elements (L4/CB's noise set) | same as H1 at stage 1; stage 2 separates: visit order tracks neither address nor id | | **H2** | a draw on the per-process global generator `0x00af6e58` inside the AI turn — AI1's `0x0079ea90+0x73` (`Chance`) or `0x005b9f00+0xc0`, both unnamed; or on Seed record #2's object | named consumers exist; none has been seen firing on a turn | ≥1 `airngcensus` row with `rng != client+0x134` inside Player[32]'s bracket, with its return address | | H3 | wall clock | none (§2.3) | — | **The probe — lane "BR", VM146, one fresh process, no build.** `C:\SOTS\shimdist-bp` is still deployed with BP's build; take `shim.cfg.bppin` verbatim (seeds `32=156ebbbd,496=fe7b2826, 512=0ed341d1` plus the wildcard, every hook off by name) and change exactly three lines: `airng=on`, `airng.pin_seed=off`, `airng.out=`. `aiorders` stays on with `deep=0` so the block is comparable with A/B. Load `ad-turn27-two-raiders.sav`, one End Turn, collect `(Autosave).sav`, `shim.log`, the `airng` output and the `aiorders` dump. Why this and not run C alone or probe 3's ledger alone: it **is** run C (a third pinned sample), and it **is** probe 3 on AD's state (the per-client ledger with `this`), and the `airng` detour has a measured neutrality — byte-identical to the published oracle in two fresh processes (`roll-parity.md`). The seven draw entry points are the only way to draw in the AI band: lane I's inlined-draw inventory has its eleven functions in the network, encounter, lobby and combat subsystems and **none between `0x680000` and `0x6e0000`**, so a draw the observer does not see during the bracket would have to come through a path the direct-call closure cannot reach — which the `left_delta − observed` residual on the client generator reports for that generator, and the census reports for every other. **Predictions, committed before the run:** - **P1.** `(Autosave).sav` ∈ {`e913ff41…`, `724528ff…`}. A third file means either the order outcome set exceeds 2 or the added detour perturbed the turn; those are separated by one more run with `airng=off` (plain run C), which cannot land on a third file under the first reading with probability better than 1/3. - **P2.** In Player[32]'s `OnResumePlaying` bracket: `foreign_words=0 foreign_calls=0`, no `airngcensus` row whose `rng` is `0x00af6e58` or Seed record #2's object, `residual=0`. The same for clients 496 and 512. - **P3.** Player[32]'s own generator spends single-digit words in the bracket, at return addresses in the AI band; 496 and 512 spend fewer. (Not load-bearing; recorded so the ledger has a number to disagree with.) - **P4.** The `aiorders` dump differs from A and B only inside the proven noise set plus, at most, the three-word transposition. **Course after the probe, either branch:** - *P2 fails* (a foreign draw in the bracket): the return address names the consumer. Follow-up is the global pin — `RNG_Seed(0xaf6e58, K)` from the shim after `Application::Initialize` (09-08 resolution §6 named it for combat; ~20 lines), two fresh processes, prediction byte-identical. If the draw is on record #2's object, pin that object's seed in the `Seed` detour instead. - *P2 holds*: RNG is excluded by measurement for the AI turn. Stage 2, one lane: read `AssignFleetsAndIssueOrders 0x006c16c0` and the fleet-gathering hub it feeds (the 992-byte body AI2 mapped; result vector at `[ebp-0x3c]`) far enough to find the loop that visits the ship groups and the container it walks — that is a bounded static read *to place a hook*, not to derive an answer (rule 18). Hook the loop; log `(element address, systemId, minted fleetId)` in visit order; two fresh processes. Prediction under H1: visit order equals ascending element address in both, and the two processes' address orders differ exactly where their visit orders differ. Under H1b: order tracks neither. Either way the container's identity is what `game/ai` needs to know it is canonicalising the right thing. Do not start stage 2's read before the probe returns; the probe is twelve minutes and a foreign draw would make the read moot. ## 5. Standing claims | claim | verdict | scope / correction | |---|---|---| | Row 326 / 09-08: the AI client seed is per-process and is the cause of `turn1-state`'s variation | **survives unchanged** | L1's per-process seeding reproduced a fourth time (nine distinct words, three processes). | | Row 360: pinned seeds collapse three processes to one | **survives with scope** | True on `turn1-state`. On `ad-turn27` pinning collapses 94 leaves to 35 and every *decision* leaf; it does not collapse the fleet visit order. | | Row 415 / AD: "the variation is the AI's decisions" | **survives with a qualification** | Right for 59 of the 94 leaves and for every substantive choice (build at `Sys[272]`, fleet split, design, money); incomplete — the remaining 35 are a non-seed per-process visit order. | | 09-09 resolution §4 reading 3: "a non-seed per-process cause, not excluded on rich states" | **confirmed, and localised** | It is alive; it is confined to the fleet-assignment visit order on this turn; it is written into list 10. | | 09-09 §3: "AD's varying design is not the composer varying" | **survives, strengthened** | BP extends it from two save bodies to the *commands that created them*: list 1 identical including the name bytes. | | 09-09 §6 probe 2's cost/mechanism brief: "seven non-human players; wildcard or list every id" | **corrected** | Three AI clients (32/496/512); four NPC factions have no client. The wildcard would have pinned three and said nothing. BP's log run is what made the count a measurement. | | 09-08 resolution: "pointer-ordered tie under ASLR — withdrawn" | **survives as withdrawn for the research pick; re-opened as H1 for the fleet visit order** | Different decision, different consumer, and now a measured precondition (§2.2). It was wrong there; it is untested here. | | Backlog §2 C-exact: "nothing else per-process reaches the turn" | **overturned as written; restated (§6)** | One more per-process input reaches rich turns; it is observable in the block. | | Backlog §2 Rung B: replay of a captured block byte-matches | **survives, strengthened** | The residual input is in the block; replay applies ids off the wire in block order. | | `id-allocation.md` §5 (mint at emission; honour ids off the wire; the client counter is a function of allocation order) | **survives; one addition** | Add: the *visit order* that determines which group gets which counter is per-process in the original; `game/ai` visits canonically (§3.2). | | Rule 26 (c) as BP amended it | **survives with a wording fix** | §7. | | `determinism-oracle.md` "Qualified" | **needs the paragraph BP proposed** | Pinned seeds do not make a rich turn reproducible; the residual is the fleet visit order; comparison modulo π is defined in §3.1. | ## 6. Rungs **Rung C bullet in `backlog.md` §2 — replace the C-exact sub-bullet with:** > - **C-exact.** Given the seeds captured from an original run (`sots_turn --ai-seed =`), > our AI's command block equals that run's block element for element and the autosave byte-matches > — **up to one further per-process input, measured on `ad-turn27` (lane BP, 2026-09-09): the order > in which the AI visits the ship groups that need a new fleet.** The seed determines every > decision on that turn (94 unpinned leaves → 35 pinned, all one transposition); the visit order > determines which client-minted id each group gets and the element order of lists 8/10. That > input is **written into the block** (list 10's `{systemId, fleetId, ships[]}`), so on every > captured run it is available for free: `(save, seeds, visit order)` → byte match, with the > engine visiting canonically by default (ascending system id, then minimum ship id) and taking > the captured order as an override for exact replay. Comparison is `state_checksum > --relabel-new-ids`: identical modulo a bijection on that turn's new ids, with the bijection > printed and `Summary/Checksum` masked with its reason. Precondition unchanged: the per-client > draw ledger. **Scope (lane BQ, 2026-09-09): every byte-match claim in this rung is a claim > about a load→one-turn procedure.** The original's AI carries state across turns that no save > holds (a fleet moved by continuation and not after a load, on the same file), so an engine run > from a save can only be compared with an original run from that save; a continuation is not a > target, by construction. **Open:** whether the visit order is heap order or a draw on the > per-process global generator (probe BR), and whether it can change a *decision* on some other > turn — on this one it cannot. and append to the mechanism paragraph: > The residual visit order is not the seed and not the client stream. It is per-process, and the > only mechanisms in the record are an address-keyed container (heap allocation order is measured > per-process in this game — BP's node addresses) or a draw on the global generator at > `0x00af6e58`, which the seed pin does not touch. One run separates them. **Rung B bullet — append, no restatement:** > **2026-09-09.** Lane BP's result makes the case for this rung from the other side: with seeds > pinned, the only thing that still varies between processes is a visit order that the block > itself records (list 10 carries the fleet id each ship group received). Replay applies ids off the > wire in block order and is insulated from it by construction. The first rich-turn record is one > `aiorders.deep=on` run of BP's pinned procedure away: if it lands on `e913ff41…` it is > (`ad-turn27-two-raiders.sav`, seeds `32=156ebbbd,496=fe7b2826,512=0ed341d1`, deep block, > `e913ff41…`) — the workload that completes thirteen ships, creates a design and colonises a > system, which no replay can be measured on until the sim runs `ProcessTurn` on a state that rich. Rung A: untouched. ## 7. Rules **Rule 26 (c) — BP's amendment, corrected.** BP's inserted clause reads "for a player that has an AI client and something to decide with … because they have `NumOwn == 0` and the engine builds three AI clients". The measured fact is the first half only: **the four NPC factions have no client, so their `ResTNm == ''` is inert.** `NumOwn == 0` is not shown to be a gate — players 496 and 512 have `NumOwn == 0` and *do* have clients (they held targets, so the pick was not exercised either way). Replace the parenthetical with: > (lane BP, 2026-09-09: `ad-turn27` has seven non-human players and the engine builds **three** AI > clients — `RunAI` fires for net ids 32/496/512; the four NPC factions 528–576 get no client and > their `ResTNm == ''` is inert. A save-field predicate must be read against **who actually runs**, > which is a property of the player kind, not of the field. Whether a client with `NumOwn == 0` > reaches the pick is untested: 496/512 held targets.) **Rule 26, new corollary (d) — draft:** > **(d) When the instrument cannot be removed, make it reproduce a natural run.** A seed pin needs > hooks, so "the un-instrumented pinned game" does not exist and rule 19's control is unavailable. > Lane BP's answer: run the save once *unpinned* with the seeds logged, pin the next processes to > **those observed values**, and require a pinned run to reproduce the unpinned one **byte for > byte** before anything is read from a pinned pair. That agreement is the pin's own control — a > perturbing pin could match a natural run only by a 1/k coincidence — and it is a **noise mask**: > any word that differs between two runs with identical outputs cannot be a word the applier reads > (lane CB's argument). On `ad-turn27` that mask reduced a 9-block, 81-element comparison to three > words. The wildcard form of a pin (every client to one constant) is a valid intervention and a > worse one: it certifies nothing about a turn that happened, and it would have hidden that the > save's seven non-human players produce three clients. Pin to what was observed; count what ran. Ranked by damage: none — nothing wrong was published; BP stopped where the brief said to stop and the localisation is the best this campaign has produced on an AI turn. That is the brief working, not a rule. Corollary, not rule 29, on the same grounds as last time. **A structural fix instead of a rule, for BP's inherited defect.** Under `hooks=trace`, a registered hook *not named* in the config is silently installed in trace mode; `shim.cfg.cbpin` omitted six. The fix is in the shim, not in discipline: when any pin or capture module is on (`aiseed=pin`, `airng.pin_seed`, `aiorders=on`), an unnamed registered hook is a **configuration error** that aborts before `Application::Initialize`, and `shim.log` prints the installed-hook count next to the registered count on every run (BP read "27 of 28 off" by hand; make the shim print it). Also fix the wrapped header comment on `shim.cfg.cbpin` line 4 and add the six `hook.*=off` lines. Engine item, one lane-hour. ## 8. Course **VM146 — lane BR, the probe, now.** Brief, one paragraph: *BP's dist is still deployed at `C:\SOTS\shimdist-bp`. Copy `shim.cfg.bppin` to `shim.cfg.brprobe` and change exactly three lines: `airng=on`, `airng.pin_seed=off`, `airng.out=`; diff the two configs' non-comment lines and quote the diff in the report (BP's own check). Verify `aiseed pinned=1` ×3 and `airng: bracket … MH_OK` in `shim.log` before reading anything. One fresh process, load `ad-turn27-two-raiders.sav` (Load-dialog row 1 at (400,260) per BP's row-62 note; wait 12–16 s before trusting a wall frame), one End Turn, collect `(Autosave).sav`, `shim.log`, the airng output, the aiorders dump. Report: the autosave hash and which of `e913ff41…` / `724528ff…` it equals; for each of the three brackets the `airng` row (`left_delta`, `observed`, `residual`, `foreign_words`, `foreign_calls`) and every `airngcensus` row whose `rng` is not that client's `+0x134`, with return addresses; the aiorders diff against A and B under BP's noise mask. Predictions are §4's P1–P4. If a foreign draw appears, stop and post its return address; if none, stop and post the row. Do not read the binary. Do not compare any pinned file with AD's unpinned files.* **VM146, same lane, after the probe, if the guest is still warm:** one more run of `shim.cfg.bppin` with `aiorders.deep=on` and `airng=off` — the Rung B record (§6). Report only the hash and whether the deep dump follows list 10's ship vectors and list 8's routes. **VM144 — lane "BS", BQ's per-history residue, now (§9.3).** Two instrumented runs on the AR lineage, both routes to turn 39: *(continuation)* load `ar-turn37-816raiders.sav`, End Turn, Auto Resolve Peacefully, End Turn; *(load)* load `ar-oracle-A-pre.sav`, End Turn. Config: `aiorders=on` (`deep=off`), `airng=on` (pin_seed off), `aiprobes` on every task `Execute` entry the probe table carries, every template hook off by name. Both routes have self-agreeing controls, so instrument neutrality is checkable at k = 1: the continuation must give `15b99255…`/`7a8b3d5e…`, the load `33e30092…`/`4c356f59…`. Predictions in §9.3. If either hash misses, stop: the instrument is not neutral on that route and the run is void. Stage 2 of BR (the container hook) or the global pin goes to whichever of VM144/VM146 frees first. **Lane AZ (VM141) — no redirect.** BQ has released VM145; its next work is BS if it wants it, since it holds the click path and the `Done`-pixel test for that lineage. **All lanes, one line:** *when you record pre-turn exposure facts next to a hash, record which players have an AI client (the `RunAI` net-id list, or "not logged"), not just `ResTNm`/`NumOwn` — and record the route (load or continuation) as part of the procedure.* **Host, no VM — three items, in order:** (1) `state_checksum.py --relabel-new-ids` per §3.1, with BP's pair as the positive acceptance and AD's pair as the negative; (2) the shim config-strictness fix and `shim.cfg.cbpin` repair per §7; (3) `id-allocation.md` §5 gets the canonical-visit-order item and `determinism-oracle.md` gets BP's "Qualified" paragraph with §3.1's definition of "modulo π". **Docs to correct in place (rule 11):** `raid-gate-multiplicity.md` §5 footnote — the 94 leaves are 59 seed + 35 visit-order; `ai-order-emission.md` §4.5 and `turn-command-replay.md` §4 row 5 — list 10 is `StrategyServer::OnCommand_TransferShips` (lane W3 named it; the AI-side notes still call it "unnamed"); `pinned-seed-rich-turn.md` §2.4's "a player with no colonies has no research income and does not reach the pick" — mark as inference; the measured fact is "no client"; `determinism-oracle.md` round-trip rule — BQ's `/CD[1]/NPrvVa` correction (+5.00 per load; not covered by `--mask resave`); `determinism-hashes.txt` — the load-form AR pair (§9.3), route on the line. ## 9. Lane BQ's result, folded in BQ's `seed-exposure-forward-test.md` landed while this was being written. Three of its results bear on this case; each is ruled here rather than in a second document, because they are one picture. ### 9.1 The frame of the probe is not wrong, but there are two residues and they get two names - **BP:** two processes, *same route* (both loads), **disagree** → a **per-process** input. - **BQ:** two processes, same route (both loads), **agree**; the *other route* (continuation from turn 37) disagrees with both → a **per-history** input, and *no* per-process input on that turn. These are different inputs in the same layer, and the second is consistent with the first: BP's residue lives in the visit order over groups that need a *new* fleet, and AR's turn 39 formed none (two ships into existing `Freighters` fleets). The visit-order model therefore predicts, after the fact, exactly what AR and BQ measured — no per-process variation on a turn with nothing to visit. Retrospective, so worth one line and no more. Probe BR holds the route fixed (every run is a load, as BP's were), so it is unconfounded by BQ's input. BQ's proposal — the per-client ledger on `ar-oracle-A-pre → 39` by both routes — is the right probe for the *second* input and is adopted as lane BS (§8), with two additions: `aiorders=on`, and the task-entry probes. The reason is §9.2: the leading mechanism for a per-history input is not a draw, and a ledger alone would report it only indirectly. ### 9.2 What the per-history input can be, ranked — inference throughout 1. **AI agent state the save does not carry.** `AISystem::Write` emits nothing and the three `AIAgent` save blocks are cache (backlog §4.1); tasks, claims and goals created on turn 38 exist on turn 39 only in the process that ran turn 38. A task that took `Zeta Fleet V` on turn 38 and issued its move on 39 is exactly a continuation-only order. This is the same class as two things already in the record — the `0x0069dbb0` fuse (`agent+0x36c` not persisted) and the client id counter (`id-allocation.md` §3.2, restarts on load). Three named siblings; leading. 2. **Client generator stream position** — *rejected as the mechanism.* Both routes are seed-insensitive on this turn (AR's three continuation processes had three seed sets and agreed; BQ's two loads had two and agreed), so no draw-dependent decision is what differs. 3. **Server-side state not in the save** — the sim reproduces by load on the canonical pair and on BQ's own 1b pair; nothing in the record points here. Last. **Predictions for lane BS, committed:** (a) the continuation's turn-39 block for pid 32 carries a list-8 element for fleet 1570 and its list-14 pair, and the load's block does not; (b) a task `Execute` entry probe fires in the continuation and not in the load — or the same task fires in both and gathers a different fleet set; (c) `airng` shows the two routes' per-client word counts differing by at most that task's cost, with zero foreign draws in both; (d) the pre-turn autosaves differ only in `/CD[1]/NPrvVa`. If (a) holds and (b) shows no task difference, the gathering hub's fleet set is the next place to look, and that is BR's stage 2 territory — the two lanes converge on the same 992-byte function from two directions. ### 9.3 Rung A — BQ's reading confirmed `ar-oracle-A-pre.sav → (load, one End Turn) → (Autosave EndTurn) 33e30092… / (Autosave) 4c356f59…` enters `determinism-hashes.txt` as the standalone's first trade-raid pair, with the route, the exposure facts (Player[32] `BIO_EnvTail` held, no design, two completions into existing fleets, four raiders parked, no encounter) and the `NPrvVa` mask on the line. `ar-oracle-A-pre → 7a8b3d5e…` does **not** enter as a load→turn pair; AR's two-turn continuation from `ar-turn37-816raiders.sav` stays certified as *that* procedure (three processes) and is not an engine target, because the engine runs from a save. This is the §6 scope line: every engine comparison is load→turn. The canonical pair `turn2-state → turn3-state` already satisfies it — it was reproduced by load (CB, ID §3.2) and matched the continuation, which is the case where the agent carried nothing that mattered. ### 9.4 Rule 26 (c) — BQ's four amendments, ruled, and the consolidated text (i) **accepted:** `ResTNm == ''` names a pick; exposure is `|candidates| > 1`, not readable from the save but readable from one `airesearch=on` run of it. (ii) **accepted with the §7 wording fix** — the false-positive class is "no AI client", and `NumOwn` is a proxy that has not been shown to gate (496/512). (iii) **accepted:** the combat term, and BQ's sentence for it. (iv) **accepted and generalised:** exposure is a property of (save, route); (c)'s "(save, procedure, hashes)" already carries it, and the route is part of the procedure. Replace the predicate sentence of rule 26 (c) — from "rule 28's shape:" to the semicolon before "one consumer (`0x0069dbb0`)" — with: > rule 28's shape, with the terms measured so far: **(1)** `ResTNm == ''` at turn start, for a > player that actually runs an AI client (a property of the player kind — on `ad-turn27` and the AR > lineage seven non-human players yield three clients, and the four NPC factions' `ResTNm == ''` > is inert), names a turn on which a pick is **made**; it is **exposed** only if the candidate walk > is offered more than one candidate, which one `airesearch=on` run of the save reads > (`candidatesTried`; lane BQ: 1 on `ar-oracle-A-post`, and the pick agreed); **(2)** `NumDes` > moving names a design turn; **(3)** a batch of completions that forms *new* fleets names a > fleet-assignment turn, and on such a turn a per-process visit order survives the seed pin (lane > BP); **(4)** an AI fleet standing at an enemy colony names a combat turn, and `Auto Resolve > Peacefully` means "I commit no ships", not "no combat occurs" — the planet fights and > `RunCombatRound` is per-process (lane BQ); **(5)** the route is part of the procedure: the same > file reached by continuation and by load can run its next turn differently, both reproducibly > (lane BQ), so a continuation's hash is never a load→turn target; --- ## Proposed `campaign/board.md` rows New row: ``` | THE PINNED-SEED RESIDUE IS A VISIT ORDER, IT IS WRITTEN INTO THE BLOCK, AND ONE RUN SEPARATES HEAP ORDER FROM A GLOBAL-RNG DRAW | meta | verified | high | 100% | 2026-09-09 | Resolver, on lane BP's falsified P1 (`findings/resolutions/2026-09-09-fleet-id-order-residue.md`). RULING ON BP'S RESTATEMENT: accepted and sharpened. The ids are NOT the variable - 1970/1986/2002 decode (id-allocation.md) to node 2 = Player[32]'s client, counters 123/124/125, minted in that order in every process. The variable is the ORDER in which AssignFleetsAndIssueOrders (0x006c16c0, pass 1) visits the ship groups needing a new fleet: A visited the group at Sys 384 first, B the group at Sys 80 first; 2002's group third in both. That order changes the id each group gets, the element order of lists 8/10 and the apply order (hence ShipIDs[] reordered) and NO decision on this turn. **AND IT IS WRITTEN INTO THE BLOCK**: list 10 = StrategyServer::OnCommand_TransferShips {systemId, fleetId, ships[]} records the assignment on every captured run, so C-EXACT SURVIVES LITERALLY with one more free input: (save, seeds, visit order) -> byte match; C-set's shape covers the uncaptured case (canonical order = one member of the outcome set). ENGINE: (1) `state_checksum --relabel-new-ids ` - bijection on that turn's new node-k ids matched by (location, ship set), master id lists as sets, Summary/Checksum masked WITH REASON, refuses to relabel anything in the pre-turn save; accept = BP's pair IDENTICAL modulo {1970<->1986}, AD's pair still DIVERGED; (2) game/ai visits groups canonically (ascending systemId, then min ship id) and mints in that order; (3) optional captured-order override for exact replay. RULING ON POINTER ORDER: not yet leading - ONE OF TWO. The record already names two unnamed AI-band consumers of the per-process global generator 0x00af6e58 (0x0079ea90+0x73 Chance, 0x005b9f00+0xc0; AI1's list) which the seed pin does not touch. What moved: pointer order now has a MEASURED PRECONDITION - BP's aielem dumps carry node heap addresses, and runs A and B (identical config, identical decisions) show the same run of consecutive same-size allocations in DIFFERENT relative address orders (list 3: A idx1idx0, idx3>idx2) - Win8+ LFH randomisation, live in this process. Precondition, not cause. Wall clock has no mechanism (AIProcessMinTime is a trailing Sleep; AI turn is synchronous in OnResumePlaying). THE PROBE (lane BR, VM146, one fresh process, no build, ~12 min): BP's shim.cfg.bppin + `airng=on` (pin_seed off) - the OnResumePlaying bracket attributes EVERY draw on EVERY generator in each client's turn by return address and generator (airngcensus rows, foreign_words/foreign_calls); lane I's inlined-draw inventory has NO site in the AI band so the observer is complete there; airng is measured behaviour-neutral (roll-parity.md). It is also run C. PREDICTIONS: P1 autosave in {e913ff41, 724528ff}; P2 foreign_words=0 in all three brackets, no census row on 0xaf6e58 or Seed record #2; P4 aiorders diff = noise set + at most the transposition. Foreign draw -> its retaddr names the consumer, follow-up = global pin (RNG_Seed(0xaf6e58,K) after Initialize) x2, predict identical. None -> RNG excluded by measurement; stage 2 = one static read of 0x006c16c0 + the gathering hub TO PLACE A HOOK on the group walk, log (element addr, systemId, minted id) in visit order x2 processes, predict order = ascending address. RUNG C restated (backlog text in §6); RUNG B not restated - value confirmed, replay is insulated by construction, and a `aiorders.deep=on` run of BP's pinned procedure landing on e913ff41 is the first rich-turn record. RULE 26(c): BP's wording corrected - the measured fact is "no client", NumOwn==0 is NOT shown to gate (496/512 have NumOwn==0 AND clients). NEW COROLLARY 26(d): when the instrument cannot be removed, pin to a natural run's observed values and require byte-identity with it before reading a pinned pair; the agreement is the pin's control AND a noise mask. No rule 29. STRUCTURAL FIX for BP's shim.cfg trap: an unnamed registered hook under a pin/capture config is a config error; print installed/registered counts. VM144 held for stage 2 / the global pin | ``` Edits to existing rows: - **Row 360** — take BP's proposed scope note, then append: `RESOLVER 2026-09-09: the residual is the AI's fleet-group VISIT ORDER, observable in list 10 of the block; C-exact survives with it as a third input. Heap order vs global-RNG draw separated by lane BR (VM146).` - **Row 415** — take BP's proposed append; add: `The 35 are a visit order, not a decision; see the resolver row of 2026-09-09.` - **Row 326** — take BP's proposed append unchanged. - **Row 333** — replace BP's proposed append with: `C-EXACT RESTATED 2026-09-09 (resolver, on lane BP): determined up to the fleet-group visit order in AssignFleetsAndIssueOrders, which the block itself records (list 10); engine visits canonically, comparison relabels new ids (state_checksum --relabel-new-ids). Rung B unchanged and strengthened.` - **Row 424** (AR's oracle pair) — take BQ's proposed append unchanged; add: `Resolver 2026-09-09: confirmed. The load-form pair enters determinism-hashes.txt; the continuation form is not an engine target. Every rung's byte-match claim is load->turn.` - **BQ's three proposed new rows** — accept as written, with one wording change in the third: replace `Read the predicate only for a non-eliminated AI player with NumOwn > 0` with `Read the predicate only for a player that actually runs an AI client (RunAI's net-id list); NumOwn is a proxy not shown to gate - 496/512 have NumOwn == 0 and clients.` - **BQ's `determinism-oracle.md` correction** (`/CD[1]/NPrvVa` +5.00 per load) — accept; `--mask resave` gains the leaf with its reason, and `--relabel-new-ids` (§3.1) must compose with it. - **Row 62** — VM146: lane BR (probe, then the deep Rung-B record); VM144: lane BS (BQ's per-history residue, both routes, `aiorders` + `airng` + task-entry probes); VM145: FREE (BQ released, restored); VM141: AZ unchanged; VM140 untouched.