# The per-history residue — the same save, two routes to turn 39, both reproducible - **Type:** control-flow / determinism (two instrumented runs; one build, no static reading) - **Owner / date:** lane **BS** · 2026-09-09 · guest **VM144** (`sots-re-win10-144`, 192.168.10.144) - **Spec:** `findings/resolutions/2026-09-09-fleet-id-order-residue.md` §8 (VM144 paragraph) and §9 - **Tests:** §9.2's ranked candidates for the per-history input; §9.3's committed predictions (a)–(d) - **Depends on:** `findings/control-flow/seed-exposure-forward-test.md` (lane BQ — the residue, the click path, the `Done`-pixel test); `findings/control-flow/pinned-seed-rich-turn.md` (lane BP — the *per-process* residue, which this is not) - **Rules exercised:** 2 (predict first), 15, 19, 20, 21, 24, 25, 26 and its corollary (c), 28 --- ## 1. Predictions, committed before the build was deployed and before the game was launched (rule 2) *Everything in §1–§3 was written and committed before `binkw32.dll` was copied onto VM144 and before any hash was read. It is not edited afterwards, only annotated with verdicts in §5.* ### 1.1 What is at stake Lane BQ measured something the campaign had no model for: **`ar-oracle-A-pre.sav` runs turn 39 one way when the state is reached by continuation and another way when it is reached by a load, and both routes are reproducible.** | route | processes | `(Autosave EndTurn)` | `(Autosave)` | |---|---|---|---| | continuation — load `ar-turn37-816raiders.sav`, End Turn, Auto Resolve Peacefully, End Turn | 3 (lane AR) | — | `15b99255…` (F38) then **`7a8b3d5e…`** (F39) | | load — load `ar-oracle-A-pre.sav`, End Turn | 2 (lane BQ) | **`33e30092…`** | **`4c356f59…`** | 23 leaves apart, **17 of them one AI fleet**: `Flt[1570 "Zeta Fleet V"]` (PID 32). Both routes' turn-39 input has it parked at Alpha Centauri (`LocID 432`, `HFPlan False`, `FtFlg 12`, both ships at `Range 9.0`) — and so does turn 37's save, so it had already sat still for a turn. The continuation issued it a move order on turn 39; **both** loads issued nothing. So the pre-turn save does not fully determine the next turn's AI fleet-task decisions. §9.2 ranks the candidates and this lane's job is to say which survives: 1. **AI agent state the save does not carry** — `AISystem::Write` emits nothing; the three `AIAgent` save blocks are cache. A task created on turn 38 exists on turn 39 only in the process that ran turn 38. Same class as the `0x0069dbb0` fuse and the client id counter. **Leading.** 2. **Client generator stream position** — *rejected by the resolver*: 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). 3. **Server-side state not in the save** — nothing in the record points here. Last. ### 1.2 P0 — the neutrality gate, and it is checkable at k = 1 here Rule 19 asks for the measurement with the instrument removed. Unusually, **both** routes already have `hooks=off` controls that agree with themselves, so rule 26 is satisfied on both sides and an instrumented run agreeing with one is *not* a 1/k coincidence — k is 1 on each route. > **P0 — committed.** With `shim.cfg.bsrun` installed: > > * **continuation:** the `(Autosave).sav` after End Turn #1 is `15b99255e1f03dab…` and the > `(Autosave).sav` after End Turn #2 is `7a8b3d5eb3a60eba…`; > * **load:** the `(Autosave EndTurn).sav` is `33e3009254f5acd1…` and the `(Autosave).sav` is > `4c356f5916f0e6e4…`. > > **If either route misses either hash, that route is VOID.** The instrument is not neutral on it and > nothing — not one probe count, not one `airng` row — may be read from it. This is stated as a stop > condition, not as a caveat. ### 1.3 The measurements — §9.3's (a)–(d), committed as mine, plus one of my own > **P1 (= §9.3 a) — the block.** In the **continuation's turn-39** `aiorders` batch, the block for > `pid=32` carries a **list-8 element whose first word is 1570** and at least one **list-14 element > whose first word is 1570**. In the **load's turn-39** block for `pid=32`, **neither is present.** > > Basis: in lane BP's dump the first word of a list-8, list-10 and list-14 element is the fleet id > (list 8 idx0 `ints=[ 2002 … ]`, list 14 idx0 `ints=[ 1970 0 … ]`), and the save-side difference BQ > measured is exactly a `FPlan` with one waypoint (`Wpt 320`) appearing only in the continuation. > **P2 (= §9.3 b) — the task.** The two routes' `aiprobe` counts for the turn-39 window differ in at > least one row, and the difference is on a **task `Execute` entry** (probe idx 2–9) — either a task > that fires in the continuation and not in the load, or the same task firing with a different > `AcquireFleetsForTask` (13) / `IsClaimedByAnotherTask` (14) count. Probe 11 > (`AssignFleetsAndIssueOrders`) is entered in **both** routes, and probe 0 (`RunTaskList`) is > non-zero in both — without which every other row is meaningless (rule 20 is built into the report). > **P3 (= §9.3 c) — the draws.** In every `OnResumePlaying` bracket on **both** routes: > `foreign_words=0`, `foreign_calls=0`, `residual=0`, and no `airngcensus` row whose `rng` is > anything but that client's `+0x134`. The two routes' per-client word counts differ by at most the > cost of the task P2 names. **RNG is not the mechanism**, and this is the measurement that says so > rather than the inference. > **P4 (= §9.3 d) — the pre-turn states.** The continuation's own frame-38 autosave and the load > run's `(Autosave EndTurn).sav` differ in **exactly one leaf**, `/CD[1]/NPrvVa` (+5.00), under > `--floats bits --mask resave`. Restated: the two routes enter turn 39 from *the same state*, so > whatever differs is not in the file. (BQ measured this without an instrument; if it moves under > mine, the instrument moved it and P0 will have said so first.) > **P5 — mine, the exposure fact the standing instruction asks for.** `airng` emits one bracket row > per `StrategyClient::OnResumePlaying` entry carrying `agent=`, so it reports **which clients > actually run an AI turn**. I predict **three** clients run on both routes — `pid` 32, 496 and 512 — > and that players 528/544/560/576 produce **no bracket row with a non-null agent**, matching lane > BP's count of three clients from seven non-human players on the same lineage. `NumOwn == 0` gates > nothing: 496 and 512 have `NumOwn == 0` and are predicted to run. **How each can be wrong, and the symptom** (rule 2): | way it could be wrong | symptom | what it would mean | |---|---|---| | the residue is not in the AI's emission at all | **P1 fails in the null direction**: both routes' pid-32 blocks are element-for-element identical | the divergence is downstream of `BuildTurnCommands` — in the server's application of the block, or in `ProcessFleetMovement`. **This relocates the question and is the more valuable outcome**, because it would exonerate the whole AI-agent-state candidate in one run | | the block differs but no probe does | P1 holds, **P2 fails** | the task set is the same and the *gathering* differs — the fleet set `AcquireFleetsForTask` returns. That is BR's stage-2 territory (`AssignFleetsAndIssueOrders 0x006c16c0` and its 992-byte hub), and the two lanes converge on one function from two directions | | a draw is involved after all | **P3 fails**: a non-zero `foreign_words`, or a census row on `0x00af6e58` | the resolver's rejection of candidate 2 was wrong; the return address names the consumer and the follow-up is a global pin | | the routes do not enter turn 39 from the same state | **P4 fails on a leaf other than `NPrvVa`** | there is a *save-visible* difference and the whole "not in the file" framing is wrong. This is the one failure that would overturn BQ's headline rather than extend it | | the instrument perturbs | **P0 fails** | the run is void; report the miss and stop | | more or fewer than three clients run | **P5 fails** | the client count is a property of the state, not of the lineage, and rule 26 (c)'s "read the predicate against who actually runs" needs a per-save count | **A null result is a real result.** If both routes produce identical AI fleet-task probe sequences *and* identical blocks, I will report that as the finding, not hunt for a difference elsewhere. ### 1.4 What this lane will not settle (rule 15) * **One process per route.** Each route's reproducibility is already established by two or three `hooks=off` processes (AR, BQ); this lane adds the *instrument*, not a third control. So it can say what the AI emitted on each route; it cannot add evidence about whether a route is reproducible. * **No static reading, no build of `game/ai`.** If the answer is "the fleet set differs", naming the container is BR's stage 2, not this lane's. * **The `0x0069dbb0` fuse cannot fire** in a load→one-turn run by construction, so the load arm says nothing about it. The continuation arm runs two turns from a load, which is still inside the 3–40-turn fuse window, so neither arm bears on it in either direction. * **The research probes (16–19) are not installed.** BQ measured `candidatesTried=1` and an agreeing pick on this lineage; four fewer detours is four fewer ways to fail P0. So this lane says nothing about the research half. * **Turn 38's encounter is auto-resolved peacefully on the continuation arm, and that is only safe here because the other side has nothing to fight with** (lane BQ: `Auto Resolve Peacefully` means "I commit no ships", not "no combat occurs"; on a later turn a *planet* fired and killed a different number of raiders in each process). AR's turn-38 encounter reproduced across three processes, which is the only reason this procedure is admissible at all. **It does not generalise.** * **`aiorders.deep=off`**, so list 8's route vector and list 10's counted vector are behind pointers and are *absent* from the dump. The fleet id is in the element window; the waypoint list is not. --- ## 2. Exposure facts, read off the inputs before the runs (rule 26 (c), with the route) Read with `verify/state-checksum/state_checksum.py`'s leaf walk over the typed tree. The standing instruction: record **which players have an AI client**, and record **the route** as part of the procedure. The client list is a *run-time* fact, so it is predicted in P5 and reported in §4; what the saves carry is below. ### 2.1 `ar-turn37-816raiders.sav` — Frame 37, the continuation arm's input | PID | name | NPC | `ResTNm` | `NumOwn` | |---|---|---|---|---| | 16 | `re` (human) | no | `''` | 3 | | **32** | **The Eternal Empire** | no | **`BIO_EnvTail`** | **18** | | 496 | Spengler | yes | `DRV_PlsFiss` | 0 | | 512 | Spengler | yes | `XNC_TrnsMorr2` | 0 | | 528 / 544 / 560 / 576 | Alien Menace / Peacekeeper Enforcer / Von Neumann / Independent Colony | yes | `''` | 0 | `Flt[1570 "Zeta Fleet V"]` (PID 32) on **turn 37**: `LocID 432`, `HFPlan False`, `FtFlg 12`, `NShips 2`, both ships `Range 9.0`. **Identical to its turn-38 state** — so the AI left it parked on turn 38 in the continuation too, and the order it issued on turn 39 is not a continuation of an order in flight. ### 2.2 `ar-oracle-A-pre.sav` — Frame 38, the load arm's input and the continuation arm's midpoint Per-player table as lane BQ published it (§2.1 there): the only player that can research holds a target, `NumDes` 47 constant, `NumOwn` 18 constant, two completions a turn into *existing* `Freighters` fleets — **no new fleet is formed on this turn**, which is why BP's per-process visit order has nothing to vary and why this turn shows no per-process residue. `Flt[1570 "Zeta Fleet V"]`: `LocID 432`, `HFPlan False`, `FtFlg 12`, `NShips 2`, ships 5840 and 6144 both at `Range 9.0`. **This is the leaf set the two routes disagree about.** **Predicate reading, both routes:** no research pick (target held), no design turn, no fleet-assignment batch, no AI fleet at an enemy colony. Rule 26 (c) screens this turn as *not exposed* — and it is exposed anyway, through a term the predicate does not have. That is the point of the lane. --- ## 3. Procedure and configuration ### 3.1 The two runs | | route | procedure | |---|---|---| | **run C** | **continuation** | `SavedGames` reset to exactly `ar-turn37-816raiders.sav`; fresh process; Load → Single Player → row 1 → OK; **End Turn**; the turn-38 encounter resolved with **Auto Resolve Peacefully** then **Done**; **End Turn** | | **run L** | **load** | `SavedGames` reset to exactly `ar-oracle-A-pre.sav`; fresh process; Load → Single Player → row 1 → OK; **End Turn** | Both saves are copied in from `verify/results/saves/`, which moves the Load-dialog rows; with exactly one file the dialog is one row and it is screenshotted and re-derived anyway (lane BQ's tip). The `Done` pixel at (233,673) is sampled to detect the encounter query rather than assumed (≈(183,18,0) query up, near-black on the map). One click per helper call with a screenshot between (lane M, confirmed by BQ on a second guest); ≥ 9 s after `schtasks /Run` before believing a shot (lane AP's nine-minute gotcha). ### 3.2 Configuration — `shim.cfg.bsrun`, one file, both runs | item | value | |---|---| | guest | VM144, **held by lane BS** | | build | `C:\SOTS\shimdist-bs\binkw32.dll`, built fresh in `/srv/re-lab/build/sots-engine-bs` (`rm -rf`'d first, rule 24) from worktree `wip/bs` (rule 21) | | config | `shim.cfg.bsrun` — `hooks=trace` with **all 27 registered hooks named `off`** (the `# exhaustive` marker; `tools/check_shim_configs.py` passes) | | instrument | `aiorders=on` `aiorders.words=32` `aiorders.deep=off`; `aiprobes=16` (probes 0–15: the control+pass recorder, **every task `Execute` entry the table carries**, the three emission exits, the hub, the claim test, `BuildTurnCommands`); `airng=on` `airng.pin_seed=off` | | off | `probes=off`, `watch=off`, `airesearch=off`, `aidesign=off`, `aiseed=off`, no pin of any kind | `aiseed=off` means the **`RunAI` net-id list is not logged** — the brief's config says every template hook off by name, and `aiseed=log` would have been one more detour on `RunAI` than the brief asked for, on a run whose whole value is a k = 1 neutrality check. The exposure fact is taken instead from `airng`'s per-bracket rows, which carry `pid` and `agent` for every `OnResumePlaying` entry — the clients that actually run, measured at the bracket rather than at the seed. §4 reports it as such. ### 3.3 VM144 as found, recorded so it can be put back ``` binkw32.dll 22,972,439 B sha256 479b8614d2417603b64e66482e429ecd3cdfe4033a2c99969ca91553642e517d (= shimdist-l3, BUILD_ID l3cont2-0117495-20260908T2124Z) shim.cfg sha256 692dabb6f00343bfcc2f86d62ade827c295acc4630a18a1f2ddcebd53640978d SavedGames 15 files (hashes in §8) game RUNNING at the main menu (pid 8408), screenshot-verified ``` --- ## 4. Results *(added after the runs; nothing above this line is edited)* ### 4.0 What was run, and both routes passed their own hash check Two fresh processes on VM144, `C:\SOTS\shimdist-bs\binkw32.dll` (`BUILD_ID bs-1654785-20260909T0629Z`), `shim.cfg.bsrun` unmodified in both, `SavedGames` reset to exactly one file before each launch. The Load dialog was screenshotted every time: with one file the row sits at **(400, 261)** and it sat there in both runs. The main menu, the Load dialog, the lobby's `Launch` button, the loaded map, the turn-38 encounter query and the selected dove were each verified from a screendump before the next click. No run was driven by sleeping. **Instrument armed and verified from `shim.log`, not assumed** (rule 1), identically in both runs: ``` config: 45 lines, 0 "ignoring unknown key" 27 of 27 registered template hooks mode=off (not installed) 7 draw sites create=MH_OK enable=MH_OK aiorders batch hook create=MH_OK enable=MH_OK aicfg words=32 deep=0 research=0 seed=off pins=0 detours=17 aiprobe 0..15 create=MH_OK enable=MH_OK (16 of 20; 16..19 not installed by config) airng bracket OnResumePlaying create=MH_OK enable=MH_OK pin_seed=off 0 COVERAGE lines in either log ``` | run | route | input | End Turns | encounter | `(Autosave EndTurn).sav` | `(Autosave).sav` | |---|---|---|---|---|---|---| | **C** | continuation | `ar-turn37-816raiders` (F37) | 2 | turn 38, Deep Space, 1 human DE vs 1 AI CR, **peaceful** | after #1: 107,097 `21447568…`
after #2: 107,478 **`15b99255…`** | after #1: 107,485 `0fe8f374…`
after #2: 107,667 **`7a8b3d5e…`** | | **L** | load | `ar-oracle-A-pre` (F38) | 1 | none | 107,477 **`33e30092…`** | 107,732 **`4c356f59…`** | > **P0 holds on both routes, byte for byte.** `15b99255…` / `7a8b3d5e…` on the continuation and > `33e30092…` / `4c356f59…` on the load, identical to lane AR's three `hooks=off` processes and lane > BQ's two. **The instrument is neutral on both routes at k = 1**, and everything below is read from > runs that passed their own check. **One correction to my own P0, and it is a mis-specification of a snapshot point, not a miss.** §1.2 said "the `(Autosave).sav` after End Turn #1 is `15b99255…`". It is not: that file is `0fe8f374…` (107,485 B), and `15b99255…` is the `(Autosave EndTurn).sav` of **End Turn #2**. So **`ar-oracle-A-pre.sav` is the frame-38 state as End Turn #2 is pressed, not the frame-38 autosave** — which is exactly why it carries `Player.Status == 0` while a post-turn autosave carries 4, and why BQ's load run reproduces it (modulo `NPrvVa`) at *its* `(Autosave EndTurn)` snapshot. The check that belongs at the End-Turn-#1 point is this, and it is the strongest available: ``` state_checksum --floats bits --mask resave ar-oracle-A-pre.sav C-f38.sav [masked: Checksumx1, Statusx8] IDENTICAL ``` **IDENTICAL, and with no `/CD[1]/NPrvVa` residue** — because no load happened between. The continuation reached exactly `ar-oracle-A-pre.sav`'s state before running turn 39. ### 4.1 The block: every save-side divergence has a block-side counterpart `aiorders` list sizes for `pid=32` (the only player that emits anything; 16, 496, 512 and the four NPC blocks are `nonEmpty=0` in every batch of both runs): | batch | list 3 | list 5 | **list 8** | list 10 | **list 12** | list 14 | list 23 | |---|---:|---:|---:|---:|---:|---:|---:| | **C**, turn 38 | 2 | 18 | 3 | 4 | 11 | 6 | 18 | | **C**, turn 39 | 2 | 18 | **1** | 0 | **12** | 0 | 18 | | **L**, turn 39 | 2 | 18 | **0** | 0 | **11** | 0 | 18 | The continuation's turn-39 block differs from the load's in **exactly two elements**: ``` C aielem blk=1 pid=32 list=8 idx=0 ints=[ 1570 ... ] <- Zeta Fleet V, absent from L C aielem blk=1 pid=32 list=12 idx=8 ints=[ 914 ... ] <- Nu Fleet III, absent from L (list 12's other eleven elements are the same fleet ids in the same order in both runs: 274 290 306 322 626 642 786 882 [914] 930 1746 2338) ``` And the save-side divergence — reproduced under the instrument, 23 leaves, `--mask none` — is **exactly those two fleets and nothing else**: ``` DIVERGED: 23 leaf difference(s) (C-post vs L-post) 15 Flt[1570 "Zeta Fleet V"] FPlan only-in-C, LocID 0->432, HFPlan True->False, FtFlg 13->12, Pos/FtOrig/PrvPos x3 each, both ships Range 7.0->9.0 3 Sys[432 "Alpha Centauri"] NumFlts 0->1, Flt only-in-L, FFlags 0->2 2 Flt[914 "Nu Fleet III"] HLay False->True, Lay only-in-L 1 /Sim/ModCount 2147 -> 2145 1 /Summary/Checksum 1 /CD[1]/NPrvVa 501.13 -> 506.13 ``` > **So the divergence is entirely in what the AI emitted.** Nothing diverged in the server's > application of the block, and candidate 3 ("server-side state not in the save") has no work left to > do on this turn. This is the conjunct the null-result branch would have relocated the question to, > and it is closed in the other direction. ### 4.2 The task: a colonise task exists on the continuation's turn 39 and does not exist after a load `aiprobe` counts for the turn-39 window (`turn=`, the per-batch counter; probe 0 is non-zero in both, so no row is unmeasured — rule 20). Run C's turn-38 window is shown for context. | idx | probe | C t38 | **C t39** | **L t39** | Δ | |---:|---|---:|---:|---:|---:| | 0 | `StrategyAIAgent::RunTaskList` [control+pass] | 6 | 6 | 6 | 0 | | 1 | `StrategyClient::OrderList16` | 0 | 0 | 0 | 0 | | 2 | `AITRaid::Execute` | 0 | 0 | 0 | 0 | | **3** | **`AITColonize::Execute` [+Goal]** | **2** | **2** | **0** | **+2** | | 4 | `AITEscortGateInvade::Execute` | 0 | 0 | 0 | 0 | | 5 | `AITInvade::Execute` [+Goal] | 2 | 2 | 2 | 0 | | 6 | `AITNodeBore::Execute` | 0 | 0 | 0 | 0 | | 7 | `AITBuildPoliceShips::Execute` | 2 | 2 | 2 | 0 | | 8 | `AITBuildDeepScanShips::Execute` | 4 | 4 | 4 | 0 | | 9 | `AITAdvanceIdleShips::Execute` | 6 | 6 | 6 | 0 | | 10 | `StrategyAIAgent::RequestBuildForTask` [lists 3,1] | 4 | 4 | 4 | 0 | | **11** | **`StrategyAIAgent::AssignFleetsAndIssueOrders` [14,8,10]** | 6 | **2** | **0** | **+2** | | **12** | **`StrategyAIAgent::IssueRouteForFleets` [list 14]** | 7 | **2** | **0** | **+2** | | 13 | `StrategyAIAgent::AcquireFleetsForTask` | 15 | 12 | 12 | 0 | | 14 | `StrategyAIAgent::IsClaimedByAnotherTask` [entry] | 3055 | 2197 | 2024 | +173 | | 15 | `StrategyClient::BuildTurnCommands` [control] | 5 | 6 | 5 | +1 | `RunTaskList` is **6 in both** — three AI clients × two passes, the same sweep. `AcquireFleetsForTask` is **12 in both**. Six of the eight task `Execute` entries are identical. The whole difference is **`AITColonize::Execute`, entered once per pass in the continuation and never in the load**, and the two emission exits it reaches. The event stream places it exactly (`aievent`, ordered; the ring overflowed at 4096 hits in both runs and says so, so the *counters* above are the evidence and the ordering below is corroboration): ``` C, turn 39, agent=0x3306dbd8 (pid 32): run=7 pass=0 probe=0 RunTaskList run=7 pass=0 probe=3 AITColonize::Execute <- FIRST task in the list ... run=7 pass=0 probe=12 IssueRouteForFleets run=7 pass=0 probe=11 AssignFleetsAndIssueOrders run=7 pass=0 probe=5 AITInvade::Execute run=8 pass=1 probe=0 RunTaskList run=8 pass=1 probe=3 AITColonize::Execute L, turn 39, agent=0x33202398 (pid 32): run=1 pass=0 probe=0 RunTaskList run=1 pass=0 probe=13 AcquireFleetsForTask <- no colonise task to run ... ``` And in run C's **turn-38** window `AITColonize::Execute` is likewise the first task on both passes. So the task was live on turn 38, survived into turn 39 **in the same process**, and after a load of turn 38's own autosave it is simply **not there**. ### 4.3 The draws: no foreign draw in any bracket, on either route `airng`, every `StrategyClient::OnResumePlaying` bracket in both runs — 9 in run C (two turns), 5 in run L (one turn): ``` foreign_words=0 foreign_calls=0 residual=0 in 14 of 14 brackets ``` Turn-39 brackets, per client: | route | pid 32 | pid 496 | pid 512 | pid 16 | |---|---|---|---|---| | **C** (seq 6–9) | left 595→591, **4 words**, 4 calls, 2 sites | 0 words | 0 words | `agent=0x00000000`, 0 words | | **L** (seq 2–5) | left 615→610, **5 words**, 5 calls, 4 sites | 0 words | 0 words | `agent=0x00000000`, 0 words | Sites, turn 39, pid 32: ``` C: 0x002ad878 NextFloat calls=2 words=2 L: 0x002ad878 NextFloat calls=2 words=2 0x00179915 NextInt calls=2 words=2 0x00179915 NextInt calls=2 words=2 0x004e6e09 NextFloat calls=1 words=0 0x00178d15 Chance calls=1 words=1 (facade cl_Chance, ret_rva 0x0029086f) ``` Two things worth stating plainly. * **The per-process global generator `0x00af6e58` took zero words inside any AI bracket in either run.** Its lifetime count is in the census: run L held it at **3 words for the whole process**; run C went **3 → 87 words between the turn-38 and turn-39 brackets** — 84 words drawn on the global during turn 38's processing, entirely *outside* any AI client's turn. That is the combat turn, and it is a free corroboration of the 09-08 warning about `RunCombatRound`; it is not the AI. * **The one extra word is in the *load*, not the continuation, and it is a consequence.** The load's pid-32 bracket spends one more word than the continuation's, at a `Chance` whose return address `0x0029086f` falls inside `AITBuildPoliceShips::Execute` (rva `0x00290380`). Both routes enter that task twice; the roll fires only in the load. So the draw difference sits *downstream* of the task difference, which is the opposite of the direction P3's wording implied. Note also, and against the stream-position candidate rather than for it: the two routes **do** enter turn 39 at different positions in pid 32's own generator (continuation `idx=29`, load `idx=9`, and different seeds besides). That is a real difference, and it is not the mechanism — see §5.2. ### 4.4 The pre-turn states: identical but for the load-boundary counter ``` state_checksum --floats bits --mask resave C-endturn.sav L-endturn.sav [masked: Checksumx1, Statusx8] DIVERGED: 1 leaf difference(s) /CD[1]/NPrvVa: 496.13360595703125 -> 501.13360595703125 ``` One leaf. BQ's correction to `determinism-oracle.md` is re-measured here under an instrument and holds exactly: `--mask resave` does **not** cover `/CD[1]/NPrvVa`, and it advances +5.00 across a load. **The two routes run turn 39 from the same state.** ### 4.5 The exposure fact the standing instruction asks for `aiseed` was off, so **the `RunAI` net-id list is not logged**. What is logged is better for the purpose and is a measurement rather than a save-field reading: `airng` emits one row per `StrategyClient::OnResumePlaying` entry with `pid` and `agent`, and `agent` is non-null only on an AI client. | route | brackets | AI clients (non-null `agent`) | no agent | |---|---|---|---| | **C** | 9 (3 turns' worth of client sweeps) | **32, 496, 512** — `0x3306dbd8`, `0x3306d4c8`, `0x3306cdb8`, stable across both turns | pid 16, `agent=0x00000000`, every time | | **L** | 5 | **32, 496, 512** — `0x33202398`, `0x33202720`, `0x332031b8` | pid 16, `agent=0x00000000` | Players 528 / 544 / 560 / 576 — the four NPC factions — **produce no bracket at all**. Seven non-human players, three AI clients, on this lineage as on `ad-turn27`. And `NumOwn == 0` gates nothing: 496 and 512 have `NumOwn == 0`, run a client, and spend 0 words. ### 4.6 Two by-products, recorded because they bear on other lanes **(a) The image base does not move on VM144 either, and it is a third distinct guest value.** `exe base=0x006b0000` in *both* processes (pids 11992 and 11468), against `0x00f40000` ×5 on VM145 and `0x005e0000` ×3 on VM146. Per boot, not per process, on a third guest. Any "pointer order" reading still means **heap** order (resolution §2.2). **(b) A turn that formed two client-minted fleets did *not* vary — four processes.** Run C's turn 38 is a fleet-assignment turn: `AssignFleetsAndIssueOrders` ×6, list 10 with four `{systemId, fleetId}` elements `(384,2466) (384,2178) (336,2482) (384,2338)`. Decoding (`id = (counter << 4) | node`, Player[32] = node 2): all four are client-minted, and **2466 (counter 154) and 2482 (counter 155) do not exist in `ar-turn37-816raiders.sav`** — they are new fleets minted this turn, in that order. 2178 and 2338 are pre-existing. The output of that turn is `15b99255…`, reproduced by **lane AR's three `hooks=off` processes and by this instrumented run** — four processes, byte for byte. > So the fleet-group visit order **was exercised on this turn, over two new fleets, and its outcome > set was 1.** That does not contradict lane BP — different turn, different groups, and BP's own > outcome set of 2 came from two observations — but it does bound the claim: *a turn that mints new > fleet ids is not thereby a turn whose visit order varies.* One datum, one turn, handed to lane BR. ### 4.7 Lane BR merged while this was being written — one confirmation and one scope correction Lane BR's `ai-visit-order-probe.md` landed on `main` at 02:52 local, after this lane's predictions were committed (15c4471, 02:31) and while its runs were in flight, so neither lane knew the other's answer. Its headline and mine are the same measurement taken from opposite sides — BR held the **route** fixed and varied the process; this lane held the **process shape** fixed and varied the route — and they agree. **Confirmation, on a different save, a different lineage and a third guest.** BR: the per-process global generator at `0x00af6e58` was "touched three times in the entire process, all three at one return address `0x00784f9e` inside `StrategyNetworkClient::OnMessage`, sixteen bytes before the `RunAI` call — one seed per AI client". Run **L**'s census, independently, on `ar-oracle-A-pre`: ``` airngcensus rng=0x00da6e58 ret_rva=0x00384f9e va=0x00784f9e entry=NextUInt calls=3 words=3 ``` Three words, one site, the same Ghidra address, for the whole process. Two lanes, two saves, two guests, same number and same return address. **And a scope correction to BR's row title, measured here.** BR's turn had no encounter. Run **C**'s turn 38 does, and on it the global generator does **not** stop at three: | run | turn | global generator lifetime at the last bracket | |---|---|---| | **L** | 39 only, no encounter | 3 words — `0x00784f9e` NextUInt ×3 | | **C** | 38 (encounter) + 39 | **87 words** — `0x00784f9e` NextUInt ×3, `0x008622aa` NextInt ×2, `0x006f3517` NextInt ×2, `0x006fb6a1` **Chance ×80 = 80 words** (with the inner `0x008e6e09` NextFloat ×80 at 0 words) | The 84 extra words appear **between the turn-38 client sweep and the turn-39 client sweep** — an interval that contains the deep-space encounter and its peaceful auto-resolve. This lane did **not** bracket that interval, so "the encounter spent them" is the obvious reading and not a measurement; what *is* measured is that they are on the global generator, at three named return addresses, and that **none of them is inside any AI client's bracket** (`foreign_words=0`, 14 of 14). > So *"the global generator only mints seeds"* is true **on a turn with no encounter** and false on a > turn with one. That is rule 28's shape exactly: a zero on a gated path is a statement about the > states measured until the gate is a predicate. BR's H2 verdict is untouched — the question there > was whether a foreign draw fires **inside** an AI bracket, and it does not, on either lane's > workload. Only the row's summary sentence needs the scope. --- ## 5. Verdicts on the committed predictions | # | prediction | verdict | |---|---|---| | **P0** | both routes reproduce their published hashes under the instrument | **CONFIRMED**, byte for byte, on both routes. The instrument is neutral at k = 1 on each. *My wording named the wrong snapshot point for one of the four hashes* (§4.0); the continuation's End-Turn-#1 autosave is `ar-oracle-A-pre.sav` **IDENTICAL under `--mask resave`, with no `NPrvVa` residue** | | **P1** | the continuation's turn-39 pid-32 block carries a **list-8** element for fleet 1570 and the load's does not | **CONFIRMED.** `aielem list=8 idx=0 ints=[ 1570 … ]` in C; list 8 is **entirely absent** from L's block | | **P1** | …**and its list-14 pair** | **FALSIFIED.** The continuation's turn-39 block has **no list 14 at all** (list 14 is emitted on turn *38*, six elements, for the fleets formed there). `IssueRouteForFleets` was entered twice on turn 39 and emitted nothing | | **P1**, unpredicted | — | The block also differs by **one list-12 element, fleet 914**, which is the counterpart of the *other* save-side divergence (`Flt[914 "Nu Fleet III"]` `HLay`/`Lay`). **Every save-side leaf that differs has a block-side cause**; I predicted only half of the block difference | | **P2** | a task `Execute` probe fires in one route and not the other | **CONFIRMED, and sharply.** `AITColonize::Execute` — 2 in the continuation, **0** in the load. Six of the eight `Execute` entries are identical, `RunTaskList` is 6 in both, `AcquireFleetsForTask` is 12 in both | | **P2** | …and probe 11 (`AssignFleetsAndIssueOrders`) is entered in **both** | **FALSIFIED.** It is entered **twice in the continuation and zero times in the load**, and so is `IssueRouteForFleets`. The fleet-gathering hub is not reached at all on the load route | | **P3** | `foreign_words=0`, `foreign_calls=0`, `residual=0`, no census row on a foreign generator inside any bracket, both routes | **CONFIRMED**, 14 of 14 brackets. The global generator `0x00af6e58` took **zero** words inside any AI bracket in either run | | **P3** | the two routes' per-client word counts differ by at most the cost of that task | **CONFIRMED numerically, wrong in direction.** 4 (C) vs 5 (L) for pid 32; 0 vs 0 for 496 and 512. The extra word is in the **load**, a `Chance` inside `AITBuildPoliceShips::Execute` — downstream of the task difference, not the cost of the missing task | | **P4** | the two routes' pre-turn states differ only in `/CD[1]/NPrvVa` | **CONFIRMED exactly.** One leaf, +5.00 | | **P5** | three AI clients — 32, 496, 512 — on both routes; the four NPC factions none; `NumOwn == 0` no gate | **CONFIRMED** on both routes, measured at the bracket rather than read off the save | **Which conjunct I satisfied and which I did not.** The conjunction I set out to test was *"the block differs, the task set differs, and no draw is involved."* All three hold. The two clauses that failed are both **over-specifications in the direction of "the load does less than I thought"**: I expected the load to run the same machinery and reach a different answer, and instead it does not run the machinery at all. ### 5.1 The verdict: candidate 1 survives, and it is now measured rather than inferred > **The per-history residue is AI agent state that the save does not carry. Specifically: a > `Colonize` task that is alive in the agent's task list on turn 39 in a process that ran turn 38, > and is absent from a process that loaded turn 38's autosave. It is the first task in the list on > both of the continuation's turns; it is the task that reaches > `AssignFleetsAndIssueOrders`/`IssueRouteForFleets` and issues `Zeta Fleet V`'s move; and after a > load it does not exist, so the two emission exits are never entered and list 8 is never written.** The chain is closed end to end and every link is a measurement on this run: ``` turn 38 runs in-process -> a Colonize task is in the agent's task list on turn 39 (probe 3: 2 hits in C, 0 in L; RunTaskList 6 in both) -> it reaches the pass-1 emission exits (probes 11 and 12: 2 and 2 in C, 0 and 0 in L) -> the block gains a list-8 element for fleet 1570 and a list-12 element for fleet 914 (aielem, both absent from L) -> the save gains Zeta Fleet V's FPlan/LocID/FtFlg/Pos/Range and loses Nu Fleet III's Lay (23 leaves, all of them those two fleets plus Checksum/ModCount/NPrvVa) ``` **Ranking the resolution's §9.2 candidates after the run:** | | candidate | verdict | |---|---|---| | **1** | **AI agent state the save does not carry** | **SURVIVES**, and is the only one that explains a *task that is not there*. It is the same class as the `0x0069dbb0` fuse and the client id counter, and the record's "`AISystem::Write` emits nothing" is no longer needed as an inference to reach it | | 2 | client generator stream position | **does not explain it.** The routes really do differ in stream position (§4.3), so this run does not exclude it on that ground — what excludes it is that (i) both routes are seed-insensitive (AR: three processes, three seed sets, agree; BQ: two loads, two seed sets, agree), and (ii) the difference is a **task that is absent**, at `RunTaskList` pass 0 with an identical sweep count, not a decision resolved differently. A draw changes an outcome; it does not add an element to a task list | | 3 | server-side state not in the save | **positively disfavoured now.** Every diverging save leaf has a block-side counterpart, so nothing diverged in the application of the block | ### 5.2 What would falsify this verdict Stated so the next lane can kill it cheaply, in decreasing order of directness: 1. **Dump the agent's task list at `RunTaskList` entry on both routes** (one hook, the vector at the agent, `{count, per-element vtable}`) and find the two lists **identical**. Then `AITColonize` is present in both and something *inside* it returns early on the load route — which would move the answer from "the task is not there" to "the task's own state is not there", a different claim with the same parent. **This is the probe I would run next and it is one lane-hour.** Prediction under the verdict: the continuation's pid-32 task list holds a colonise task at turn-39 entry and the load's does not, and the counts differ by exactly one. 2. **A load that produces the colonise task.** If any load of `ar-oracle-A-pre.sav` ever emits list 8 for 1570, the residue is not deterministic-per-route and the whole two-residue framing is wrong. BQ has two `hooks=off` loads agreeing and this lane has a third instrumented one; a fourth is cheap. 3. **A continuation that does not produce it** — e.g. run turn 37 → 38 → *save manually* → quit → reload → turn 39. If that reproduces the **continuation's** answer, the missing input is in the save after all and this lane read a load-boundary artefact. 4. **Find `Colonize` task state in the save.** The three `AIAgent` save blocks are recorded as cache (backlog §4.1); if one of them turns out to carry a task list, the input is in the file and the engine has to honour it. ### 5.3 What this means for the rungs, in one sentence each * **Rung C / C-exact.** The scope line the resolver wrote stands and is now measured: *every byte-match claim is a claim about a **load→turn** procedure.* An engine that runs one turn from a save can never reproduce a continuation's turn on this lineage, because the original's AI carried a task across the turn boundary that the file does not hold. This is not a defect to fix — it is the definition of the comparison. * **Rung B / replay.** Untouched and strengthened again from a third direction: the block is where the divergence lives, and replay applies the block off the wire. * **`game/ai`.** If our AI keeps its task list in the engine's own state across turns (it must, to be an AI at all), then our engine has the *same* property — a continuation and a load will differ — and that is faithful, not a bug. What must not happen is for our task list to be reconstructed differently from a save than the original reconstructs it, and this lane says nothing about that. --- ## 6. Coverage, and what was not done (rule 15) * **One instrumented process per route.** Reproducibility of each route is lane AR's (three processes) and lane BQ's (two); this lane adds the instrument and a fourth/third process respectively, both landing on the published hashes. It is not an independent test of reproducibility. * **The task is named by its `Execute` entry, not by reading its object.** `AITColonize::Execute` is the probe table's name for the address `0x0028b400`; this lane did not read the task object, its goal, or which system it was colonising. The `Colonize` reading is the probe table's, inherited from lanes AI2/AI3, not re-derived here. * **Why the colonise task exists on turn 39 in the continuation is not measured.** It was already running on turn 38 (probe 3 = 2 there too). Whether turn 38 *created* it, or it predates turn 37, is untested — `ar-turn37-816raiders.sav` reached by *its own* load would answer it and was not run. * **`aiorders.deep=off`**, so list 8's route vector and list 10's counted vector were not followed. The list-8 element's first word (the fleet id) is in the window; its waypoint payload is not, and the claim "`Wpt 320`" is lane BQ's from the save, not this lane's from the block. * **List 12 is named by its position, not decoded.** Its elements are fleet ids; the continuation's carries 914 and the load's does not; the save-side counterpart is `Flt[914]`'s `HLay`/`Lay`. **The causal direction is not established** — "in list 12 ⇒ lay cleared" and "absent from list 12 ⇒ lay set by something else" both fit one observation (rule 20). One line of watchpoint would settle it. * **The `aievent` ring overflowed** (4096 of 5359 hits in C, of a larger number in L) and says so in the file. Every ordering statement in §4.2 is from the recorded prefix; every *count* is from the complete counters. * **`0x0069dbb0`'s fuse** cannot have fired in either arm and nothing here bears on it. * **The turn-38 encounter was auto-resolved peacefully and reproduced**, which is a datum for AR's procedure and **not** a general licence: lane BQ measured a peaceful auto-resolve against a *colony* varying across three processes. This one reproduced because both sides committed nothing that fought. * **No claim about `game/ai`'s own behaviour.** Nothing was built or compared against the engine. --- ## 7. Artefacts | what | where | |---|---| | this document | `findings/control-flow/per-history-residue.md` | | shim config, both runs, unmodified | `verify/results/shim/bs/shim.cfg.bsrun` (source: `sots-engine` `src/shim/shim.cfg.bsrun`, branch `wip/bs`) | | run **C** — block, draws, log | `verify/results/shim/bs/C-{aiorders.txt,airng.txt,shim.log}` | | run **L** — block, draws, log | `verify/results/shim/bs/L-{aiorders.txt,airng.txt,shim.log}` | | run **C** saves | `verify/results/saves/bs/bs-C-endturn.sav` (`15b99255…`), `bs-C-post.sav` (`7a8b3d5e…`), `bs-C-f38-autosave.sav` (`0fe8f374…`, the End-Turn-#1 autosave, new) | | run **L** saves | `verify/results/saves/bs/bs-L-endturn.sav` (`33e30092…`), `bs-L-post.sav` (`4c356f59…`) | | inputs (unchanged) | `verify/results/saves/ar-turn37-816raiders.sav`, `verify/results/saves/ar-oracle-A-pre.sav` | | build | CT111 `/srv/re-lab/build/sots-engine-bs` (`rm -rf`'d first), staged `/srv/re-lab/shim/dist-bs`, `BUILD_ID bs-1654785-20260909T0629Z`, exports 66/66 identical | `verify/results/saves/bs/` is a subdirectory, so it is invisible to the corpus scan and **the coverage ratchet is not touched** (rule 27), exactly as lane BQ left `bq/`. --- ## 8. VM144 as left **Hold released. Guest restored and verified byte for byte against the as-found snapshot (§3.3):** ``` SavedGames the same 15 files, every sha256 identical to as-found (row positions UNCHANGED: MyGameas1predeploy (400,347), MyGameas1spydep (400,376), OK (682,624)) binkw32.dll 22,972,439 B 479b8614d2417603… (= shimdist-l3, l3cont2-0117495-20260908T2124Z) shim.cfg 692dabb6f00343bf… game RUNNING at the main menu, screenshot-verified, as found ``` Left in place, all additive: `C:\SOTS\shimdist-bs`, `C:\SOTS\ui\preBS\` (the as-found SavedGames + `shim.cfg.asfound` + `binkw32.dll.asfound`), `C:\SOTS\ui\bs\` (the two inputs and this lane's outputs), `C:\SOTS\ui\bs{go,hash}.ps1`. **`click_helper.ps1` is unmodified.** `ap_loop.ps1` and the `SOTSAP` task are untouched. **Six things for the next holder of VM144.** * **The Load path has a step the row-62 notes do not mention: a LOBBY.** After the file-list `OK` the game does **not** go to the map — it shows the player-setup lobby ("Human", the two player cards) with **`Launch` at (511,663)** and `Cancel Game` at (511,692). Loading is **OK → ~2 min → lobby → `Launch` → ~2 min → map**, so the "3–4 min load" is two waits with a click in the middle, and a lane that sleeps 4 minutes and screenshots will find the lobby and think the load hung. * **The game window is at screen (-8,-39)–(1032,749), client 1024×749** — the bottom 19 px of the game's 768-tall client is off-screen. `SetCursorPos` coordinates are screen coordinates and the published ones are all still correct (`End Turn` (100,714), `Done` (233,673), `Auto Resolve Peacefully` (667,641), OK (682,624)). But the **click helper's `shot` captures the *window*, whose origin is (-8,-39)**, so a coordinate read off a helper screenshot must have (8,39) subtracted before it is clicked. A `qm monitor` screendump (`tools/vmshot.py --one 144`) is the *screen* and needs no correction — prefer it. * **With `SavedGames` reset to exactly one file the row is at (400,261)** — one pixel off lane BQ's (400,262) on VM145 and inside the same row. BQ's tip is confirmed on a second guest: reset to one file and there is nothing to re-derive. * **This state's End Turn is FAST** — the autosave appeared **within 5 s** of the click on both turns, with 16 aiprobes + the airng bracket + the aiorders dump installed. Budget the *load*, not the turn. * **Startup is ~2 min** (`fg` + `key {ESC}` ×3 spaced ~2.5 s, then ~90 s), confirming AR's and BQ's correction on a third guest. * **`ar-oracle-A-pre.sav` is a pre-turn snapshot (`Player.Status == 0`), not a post-turn autosave.** In a continuation it is the `(Autosave EndTurn).sav` of the *second* End Turn. Do not expect the `(Autosave).sav` after the first End Turn to equal it — that file is `0fe8f374…` and differs in `Status` ×4 + `Checksum` only. --- ## Proposed board rows New rows: ``` | THE PER-HISTORY RESIDUE IS A TASK THAT THE SAVE DOES NOT CARRY - a Colonize task alive on turn 39 by continuation and ABSENT after a load, measured end to end | control-flow | verified | high | 100% | 2026-09-09 | **Lane BS**, VM144, `findings/control-flow/per-history-residue.md`. Predictions committed before the build was deployed (commit 15c4471). Two instrumented runs of the AR lineage to turn 39, `aiorders=on` + 16 aiprobes + the `airng` OnResumePlaying bracket, no pin, all 27 template hooks off by name. **INSTRUMENT NEUTRALITY CHECKED AT k = 1 ON BOTH ROUTES AND PASSED BYTE FOR BYTE** - continuation `15b99255...`/`7a8b3d5e...` (lane AR's three hooks=off processes), load `33e30092...`/`4c356f59...` (lane BQ's two). **THE ANSWER: `AITColonize::Execute` is entered TWICE (once per pass) in the continuation and ZERO times after a load**, while `RunTaskList` is 6 in both (3 AI clients x 2 passes), `AcquireFleetsForTask` is 12 in both and six of the eight task Execute entries are identical. It is the FIRST task in pid 32's list on both of the continuation's turns, and it is the task that reaches the pass-1 emission exits: `AssignFleetsAndIssueOrders` 2 vs **0** and `IssueRouteForFleets` 2 vs **0** - the fleet-gathering hub is NOT REACHED AT ALL on the load route. Consequence in the block: the continuation's turn-39 pid-32 block carries `list=8 idx=0 ints=[ 1570 ... ]` (Zeta Fleet V) and one extra `list=12` element `[ 914 ... ]` (Nu Fleet III), and the load's block carries NEITHER - list 8 is entirely absent. **EVERY ONE OF THE 23 DIVERGING SAVE LEAVES HAS A BLOCK-SIDE COUNTERPART** (15 on Flt[1570], 3 on Sys[432], 2 on Flt[914], plus ModCount/Checksum/NPrvVa), so nothing diverged in the SERVER's application of the block and candidate 3 (server-side state) is disfavoured. **RNG IS EXCLUDED BY MEASUREMENT: `foreign_words=0 foreign_calls=0 residual=0` in 14 of 14 brackets across both runs, and the per-process global generator 0x00af6e58 took ZERO words inside any AI bracket** (it moved 3 -> 87 words across the continuation's turn 38, entirely OUTSIDE the AI brackets - that is the combat turn). Per-client words turn 39: pid 32 = 4 (continuation) vs 5 (load), 496 and 512 = 0 on both; the ONE extra word is in the LOAD, a Chance at ret_rva 0x0029086f inside AITBuildPoliceShips::Execute - downstream of the task difference, not its cost. Pre-turn states differ in EXACTLY ONE LEAF, `/CD[1]/NPrvVa` +5.00 (BQ's correction re-measured under an instrument). VERDICT: **resolution 09-09 §9.2 candidate 1 SURVIVES and is now measured rather than inferred**; candidate 2 (stream position) does not explain a task that is not there (and the routes DO differ in stream position, so this run does not exclude it on that ground - the seed-insensitivity of both routes does); candidate 3 is disfavoured. FALSIFIER, one lane-hour: hook the task vector at `RunTaskList` entry and log `{count, per-element vtable}` for pid 32 on both routes - under this verdict the continuation's list holds a colonise task at turn-39 entry and the load's does not, and the counts differ by exactly one. **SCOPE CONFIRMED: every byte-match claim in every rung is a claim about a load->turn procedure, and that is the definition of the comparison, not a defect to fix** | ``` ``` | TWO PREDICTIONS FAILED, BOTH BECAUSE THE LOAD ROUTE DOES LESS THAN ANYONE EXPECTED - and one block difference nobody predicted | meta | verified | high | 100% | 2026-09-09 | Lane BS, from the same runs. (1) **P1's list-14 clause FALSIFIED**: the continuation's turn-39 block has NO list 14 AT ALL - list 14 is emitted on turn 38 (six elements, for the two fleets minted there), and on turn 39 `IssueRouteForFleets` is entered twice and emits nothing. So "a list-8 element and its list-14 pair" was wrong about the shape of a move order. (2) **P2's "probe 11 is entered in BOTH routes" FALSIFIED**: `AssignFleetsAndIssueOrders` is entered 2x in the continuation and **0x** in the load. The brief and I both expected the load to run the same machinery to a different answer; it does not run the machinery. (3) **UNPREDICTED AND IT STRENGTHENS THE RESULT**: the block ALSO differs by one `list=12` element, fleet **914**, which is the counterpart of the OTHER save-side divergence (`Flt[914 "Nu Fleet III"]` HLay False->True, Lay only-in-load). I predicted half the block difference and the other half was there waiting - which is what turns "the AI emitted a move order" into "**every** diverging leaf is in the block". List 12's elements are fleet ids (274 290 306 322 626 642 786 882 [914] 930 1746 2338); its meaning is NOT decoded and the causal direction is NOT established (rule 20) - one watchpoint would settle it | ``` ``` | A TURN THAT MINTED TWO NEW FLEET IDS DID NOT VARY - four processes, byte-identical, on a turn whose visit order was exercised | control-flow | verified | med | 100% | 2026-09-09 | Lane BS, VM144, a by-product of the continuation run. Turn 38 of the AR lineage IS a fleet-assignment turn: `AssignFleetsAndIssueOrders` entered **6x**, list 10 carries four `{systemId, fleetId}` elements `(384,2466) (384,2178) (336,2482) (384,2338)`, and decoding by `id = (counter << 4) | node` (Player[32] = node 2) all four are CLIENT-MINTED - with **2466 (counter 154) and 2482 (counter 155) absent from `ar-turn37-816raiders.sav`**, i.e. two fleets minted on this turn, in that order. That turn's output is `15b99255...`, produced by **lane AR's three `hooks=off` processes AND this instrumented run - four processes, byte for byte**. So the fleet-group visit order was exercised over two new fleets and its **outcome set was 1**. This does NOT contradict lane BP (different turn, different groups, and BP's outcome set of 2 rests on two observations) but it BOUNDS the claim: **a turn that mints new fleet ids is not thereby a turn whose visit order varies.** One turn, one datum, handed to lane BR for stage 2 - if the container is address-keyed, this turn is a case where two same-size allocations landed in the same relative order in four processes, which the LFH randomisation model has to accommodate | ``` Edits to existing rows: - **Row 62** — `VM144 = FREE (lane BS released 2026-09-09; guest RESTORED and verified byte-for-byte to as-found: SavedGames = the same 15 files with identical sha256 so AS's row positions STILL HOLD - MyGameas1predeploy (400,347), MyGameas1spydep (400,376), OK (682,624); binkw32.dll = shimdist-l3 22,972,439 B 479b8614..., shim.cfg = 692dabb6..., game RUNNING at the main menu screenshot-verified, as found).` Lane BS left `C:\SOTS\shimdist-bs` + `C:\SOTS\ui\preBS\` + `C:\SOTS\ui\bs\` + `ui\bs{go,hash}.ps1`; `click_helper.ps1` and `ap_loop.ps1` unmodified. **GOTCHA THAT THE ROW-62 CLICK PATH DOES NOT MENTION: THE LOAD PATH HAS A LOBBY.** After the file-list `OK` the game does NOT go to the map - it shows the player-setup lobby ("Human", the two player cards) with **`Launch` at (511,663)** and `Cancel Game` at (511,692). The sequence is **OK -> ~2 min -> LOBBY -> `Launch` -> ~2 min -> map**, so the documented "3-4 min load" is two waits with a click in the middle; a lane that sleeps four minutes and screenshots will find the lobby and read it as a hang. **GOTCHA: the game window sits at screen (-8,-39)-(1032,749) with a 1024x749 client**, so the click helper's `shot` (which captures the WINDOW) is offset by (8,39) from screen coordinates - subtract it before clicking anything read off a helper screenshot. `tools/vmshot.py --one 144` captures the SCREEN and needs no correction; prefer it. All published screen coordinates are still correct (`End Turn` (100,714), `Done` (233,673), `Auto Resolve Peacefully` (667,641), Load `OK` (682,624)). **CONFIRMS BQ ON A SECOND GUEST: reset SavedGames to exactly ONE file and the Load row is at (400,261)** - one pixel off BQ's (400,262) and inside the same row, nothing to re-derive. **CONFIRMS AR/BQ ON A THIRD GUEST: `fg` + `key {ESC}` x3 spaced ~2.5 s then ~90 s puts the main menu up in about TWO minutes.** **TIP: End Turn on this state is FAST - the autosave appeared within 5 s of the click with 16 aiprobes + the airng bracket + the aiorders dump installed. Budget the LOAD, not the turn.** **IMAGE BASE: `exe base=0x006b0000` in BOTH processes on VM144** (vs 0x00f40000 x5 on VM145 and 0x005e0000 x3 on VM146) - per boot, not per process, on a third guest. - **Row 424** (AR's oracle pair) — append: `MECHANISM FOUND 2026-09-09 (lane BS, VM144): the reason this pair does not survive a load is that a **Colonize task** alive in Player[32]'s AI agent on turn 39 by continuation is ABSENT after a load - `AITColonize::Execute` 2 vs 0, `AssignFleetsAndIssueOrders` 2 vs 0, `IssueRouteForFleets` 2 vs 0, while `RunTaskList` is 6 in both. Both routes reproduced their published hashes UNDER INSTRUMENT, so the pair is now certified in both forms with the instrument as well as without it.` - **Row 426** (the 09-09 resolution's row) — append: `LANE BS RAN §8's VM144 PARAGRAPH 2026-09-09. §9.2 candidate 1 (AI agent state the save does not carry) SURVIVES and is measured, not inferred: the missing input is a TASK. Candidate 3 (server-side state) is disfavoured - every diverging save leaf has a block-side counterpart. Candidate 2 (stream position) is not what explains it, though the two routes DO differ in stream position, so this run does not exclude it on that ground; the seed-insensitivity of both routes does. §9.3's (a) and (d) CONFIRMED, (b) CONFIRMED and sharper than written, (c) CONFIRMED with the word difference in the OPPOSITE route from the one implied. Two clauses FALSIFIED, both over-specifications: there is no list-14 pair on turn 39, and probe 11 is NOT entered on the load route at all.` - **Row 360 / the pinned-seed rows** — append: `BOUNDED 2026-09-09 (lane BS): a turn that mints new client fleet ids is not thereby a turn whose visit order varies. AR turn 38 minted TWO (2466 counter 154, 2482 counter 155, both absent from ar-turn37) through six entries to AssignFleetsAndIssueOrders, and four processes (AR's three hooks=off plus BS's instrumented one) produced 15b99255... byte for byte - outcome set 1 on that turn.` - **`determinism-hashes.txt`** — the AR load-form pair (resolution §9.3) enters with the route on the line, and BS adds a second certified procedure for the same lineage: `ar-turn37-816raiders.sav -> (load, End Turn, Auto Resolve Peacefully, End Turn) -> (Autosave EndTurn) 15b99255... / (Autosave) 7a8b3d5e...`, four processes, three of them un-instrumented. **Both lines must carry the `/CD[1]/NPrvVa` mask note**, and the load-form line must say that its `(Autosave EndTurn)` is a RESAVE of `ar-oracle-A-pre.sav` differing on that one leaf. - **Lane BR's new row** (`RNG excluded by measurement, the global generator only mints seeds`) — append a scope clause: `SCOPED 2026-09-09 (lane BS, VM144, independently and on a different lineage): the three-words-one-site measurement REPRODUCES EXACTLY on ar-oracle-A-pre - `rng=0x00af6e58 ret_rva=0x00384f9e va=0x00784f9e NextUInt calls=3 words=3` for a whole process. **But "only mints seeds" holds only on a turn with NO ENCOUNTER.** On the AR continuation's turn 38, which has a deep-space encounter auto-resolved peacefully, the same generator ends the process at **87 words**: the 3 seed words plus `0x006fb6a1` Chance x80 = 80 words and two NextInt pairs at `0x008622aa` / `0x006f3517`. The 84 extra words fall between the turn-38 and turn-39 client sweeps - an interval containing the encounter - and were NOT bracketed, so their attribution to the encounter is a reading, not a measurement. **H2's verdict is untouched** (the question is whether a foreign draw fires INSIDE an AI bracket, and foreign_words=0 in 14 of 14 brackets across BS's two runs as well); only the summary sentence needs the scope. Rule 28's shape.` - **Rule 26 (c) term (5)** — append one clause to the load-history term: `and the difference can be that the load route does not run the machinery at all: on the AR lineage the continuation enters AssignFleetsAndIssueOrders twice on turn 39 and the load zero times, because the TASK that would have called it does not exist after a load (lane BS).`