# The spy program's remaining draws — `P`'s branch split, the counter-mission roll, and the deploy's own `NextFloat` - **Type:** subsystem (static decode + live measurement) - **Owner / date:** lane AP · 2026-09-09 · guest **VM144** (`sots-re-win10-144`, `re@192.168.10.144`) - **Instrument:** lane Z's `draw_sites` return-address ledger at **`probes=8`** (the byte-neutral set; never `probes=11` — lane H bisected 11 as not byte-neutral) - **Continues:** lane AS's `findings/subsystems/spy-detection-roll.md`, whose §6 named this workload from its own failed conjunct; lane AG's `findings/control-flow/gate-indexed-rng-audit.md` §3.2 - **Inputs:** `verify/results/saves/as-turn15-spydeployed.sav` (target 1), `verify/results/saves/as-turn14-predeploy.sav` (target 2) *(Sections 0–3 were written and committed **before** the build and before any measurement, in their own commit. Sections 4 onward are the measurement. Rule 2.)* --- ## 0. Headline of the predictions > **The brief that created this lane asks for "`P`'s three draws". There are three sites but they are > two mutually exclusive branches, and the branch selector is the spy owner's *species*.** From > `as-turn15-spydeployed.sav` **exactly one** of the three can ever fire — `0x00840a3c` — because the > spy's owner is player 0 (`re`), `Species = 0` (Human). `0x00840929` and `0x008409c7` are gated on > `spyOwner->Species == 6`, i.e. **Morrigi**, and are unreachable from this save, from every save in > the 22-save corpus, and from any workload that does not start a *Morrigi* empire. > > Predicted, before the run: `0x00840a3c` fires once, for one word, on the End Turn that produces > `Frame == sdet + 3`; and two sites nobody expected fire on the way — the spy **counter-mission** > roll `0x0088dc43` (lane AG §3.2, corpus 0 of 22, never fired) starting at **Frame 19**, and the > deploy's own `NextFloat` `0x0078c97f` on a separate one-turn run. --- ## 1. `P` decoded — `SpyManager::Slot13RngCallee` `0x008408e0`, complete Program `sots` / "Sword of the Stars.exe", ImageBase `0x00400000`, all addresses VAs. Body disassembled from its start **to the next function start** (rule 17): `0x008408e0 .. 0x00840a5a`, followed by `int3` padding. The ReVa MCP server is down (`CONNECTION_CLOSED`) for this lane too, so this is instruction stream only. ### 1.1 How `P` is reached, and that there is no further gate The chain in `ServerSpyManager::vslot13` `0x008877b0` from lane AS's §1, extended past the point AS stopped at. **Between the last gate and the call to `P` there is no branch at all** — the whole span `0x00887897 .. 0x00887af2` is two `EVENT_SPY_DESTROYED_OWNER`-shaped string builds, a `push_back`, and an event post: ``` 0088781d je 0x887e92 G1 spy.deat (+0x10) == 0 -> next spy 00887856 je 0x887c5b G2 spy.sdet (+0x40) == -1 -> BRANCH D (the detection roll) 00887867 jl 0x887e92 G3 (server.Frame - sdet) < 3 -> next spy 0088787a je 0x887c4f G4 ServerSystem_GetOwner(sysA) == NULL -> sdet := -1, next spy 00887891 je 0x887c4f G5 ServerSystem_GetOwner(sysA) == ownerO -> sdet := -1, next spy 008878a1 call 0x59f1a0 push_back spy.sid into a LOCAL vector at [ebp-0xdc] 008879dd call 0x8862b0 PostEvent "EVENT_SPY_DESTROYED_OWNER" 00887ae3 call 0x7437e0 eax = ServerSystem_GetOwner(sysA) 00887aee push eax ; arg2 = the TARGET system's owner 00887aef push edx ; arg1 = ownerO, the SPY's owner ([ebp-0xc0]) 00887af0 mov ecx,edi ; this = the spy manager 00887af2 call 0x8408e0 P <-- the false-flag draw 00887af7 ... 00887b07 cmp eax,ebx 00887b09 je 0x887b5b ; P returned NULL -> the "unknown empire" event string ``` so **once `sdet` is stamped and three turns have passed, `P` is called unconditionally** (given a target system that is owned and not owned by the spy's own empire). `P`'s arguments are two `Game::ServerPlayer*`, not ids — `P` compares them by pointer against entries of the player vector. ### 1.2 The species branch — and why "three draws" is one draw ``` 00840909 mov esi,[ebp+8] ; esi = arg1 = the SPY'S OWNER (a ServerPlayer*) 0084090c cmp dword ptr [esi+0x5c], 0x6 ; +0x5c = ServerPlayer::Species 00840910 jne 0x840a29 ; NOT species 6 -> BRANCH B ; ---- BRANCH A, species == 6 only -------------------------------------------------------------- 00840919 fld dword ptr ds:0x9e5ac4 ; 0.75f (bytes 00 00 40 3f) 0084091f mov ecx,[eax+0x16c] ; THE STRATEGIC GENERATOR (the object, not +4) 00840929 call 0x8e6dd0 A1 ; Mars::RNG::Chance(strategic, 0.75f) ret 0x0084092e 00840930 je 0x840a45 ; roll failed -> return NULL ; build a candidate list over StrategyServer +0x54..+0x58 (the player vector): ; skip p if p->+0xfb != 0, p->+0xf8 != 0, p == arg1, or p == arg2 008409ac je 0x840a07 ; list EMPTY -> free it, return NULL (no NextInt) 008409ae eax = count - 1 008409b0 mov ecx,[...+0x16c]; add ecx,4 ; the +4 SUB-OBJECT (the NextInt convention) 008409c7 call 0x4271c0 A2 ; Mars::RNG::NextInt(&(count-1)) ret 0x008409cc 008409cf esi = list[eax] ; the blamed empire return esi ; ---- BRANCH B, every other species ------------------------------------------------------------ 00840a2c fld dword ptr ds:0x9e5ac0 ; 0.25f (bytes 00 00 80 3e) 00840a32 mov ecx,[edx+0x16c] ; the strategic generator 00840a3c call 0x8e6dd0 B1 ; Mars::RNG::Chance(strategic, 0.25f) ret 0x00840a41 00840a43 jne 0x8409f2 ; roll SUCCEEDED -> return esi == arg1 (the true owner) 00840a45 xor eax,eax ; else return NULL ``` Both float constants were read as the **four bytes in the image** (rule 23): `0x009e5ac0` is `00 00 80 3e` = `0.25f` and `0x009e5ac4` is `00 00 40 3f` = `0.75f`. `0x009e5ac4` is the *same* word lane AS read as the species-5 multiplier in `SpyCraft_AccumulateDetectionOdds` — one constant, two uses. **So `P` is the attribution roll for a destroyed spy, and it has two completely different shapes:** | spy owner | draw sites reached | semantics | |---|---|---| | `Species == 6` | `0x00840929` (`Chance` 0.75f), then `0x008409c7` (`NextInt`) **only if the roll succeeds and the candidate list is non-empty** | 75 % of the time a **random third empire** is blamed — a false flag. The true owner is *never* returned. | | every other species | `0x00840a3c` (`Chance` 0.25f) | 25 % of the time the **true owner** is returned; otherwise nobody is blamed. | ### 1.3 The species table, decoded from the corpus `Game::ServerPlayer +0x5c` is the field `objects/layouts.md` names **`Species`** (Write `0x008563e0`). The `sim/species` node lists seven `ISsp` names in index order, identical in every save read: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |---|---|---|---|---|---|---| | Human | Hiver | Tarkas | Liir | **_NPC** | Zuul | **Morrigi** | Cross-checked against lane V's `zuul-turn5-species5.sav`, whose three real players all carry `Species = 5` — and lane V's hook independently reported `species=5` on the Zuul double-roll. The four NPC empires (`Alien Menace`, `Peacekeeper Enforcer`, `Von Neumann`, `Independent Colony`) carry `Species = 4` in every save. That also **names lane AS's two unexplained multipliers**: `SpyCraft_AccumulateDetectionOdds` multiplies the per-turn detection odds by `0.75f` for **Zuul** and `0.5f` for **Morrigi**, and by `1.0f` for everyone else. Morrigi are the stealth species on both sites — half the detection odds, and a false flag when they are caught. ### 1.4 What happens to the spy on that turn The local `vector` filled at `0x008878a1` is drained after the spy loop: ``` 00887eb0..00887ee8 for each collected sid, back to front: [[manager]+0x28](sid) ; vtable slot 10 = 0x00838480 ``` and `0x00838480` looks the `SpyCraft` up by `sid`, calls **`ServerSystem::RemoveSpy 0x0074f550`** on the `deat` system (which clears `spy.deat` and erases `sid` from `spies2`), clears the tender's `atto` back-pointer (`spy+0xc`, `ship+0xa8`), erases the craft from the manager's vector at `+0x10`, and invokes the scalar deleting destructor. **The spy is gone at the end of `vslot13`**, which is phase 23 — *before* `vslot14` runs at phase 33. ### 1.5 The deploy's `NextFloat` — `0x0078c97f`, re-read `SHIPACTION_DEPLOYSPY` handler `0x0078c930`, body to the next function start `0x0078c9e0`. One gate, then the draw, with no branch between them: ``` 0078c93d..0078c964 build a 12-byte stack query object (vtable 0x00a09648) and ask it about the ship 0078c969 test al,al 0078c96b jne 0x78c975 ; FALSE -> return 0 with NO DRAW 0078c975 mov ecx,[esi+0x16c]; add ecx,4 ; the strategic generator's +4 sub-object 0078c97f call 0x47d830 ; Mars::RNG::NextFloat ret 0x0078c984 <-- THE DRAW 0078c984 fld qword [0x009e21b0] ; 6.2831854820251465 == 2*pi 0078c98a fldz ; LO = 0.0 angle = LO + (HI - LO) * r ; the float-range idiom, stored through a float32 temp 0078c9ac call 0x0080c860 ; (ship, angle) -> eax 0078c9bb call edx ; [[esi+0x15c]+0x1c] = ServerSpyManager::DeploySpy slot 7 ``` Lane AS read this as `cbh = NextFloat() * 2pi`; that is right in value (`LO` is literally `fldz`) and the expanded form is worth recording because it is the campaign's standard `lerp(LO, HI, r)` shape, not a bare multiply. **The draw is unconditional once the validator passes, so it is exactly one strategic word per applied Deploy Spy order**, in the `ProcessTurn` bracket (`ApplyAllTurnCommands`), not the tail's. **Its predicate is on the command stream**, not on save fields: *"a `SHIPACTION_DEPLOYSPY` command in this turn's command stream"*. Lane AG's gate-indexed audit has two kinds of cell — a measured firing, or a predicate over the save — and this is neither. ### 1.6 A complete RNG scan of all four bodies Every `call`/`jmp` in each body decoded to a real instruction boundary and matched against the seven RNG entry points (`NextFloat 0x0047d830`, `NextInt 0x004271c0`, `Chance 0x008e6dd0`, `Twist 0x00426e00`, `Seed 0x0049fdf0`, `0x005876c0`, `0x0057da00`): | body | range | RNG sites | |---|---|---| | `ServerSpyManager::vslot13` | `0x008877b0 .. 0x00887f30` | `0x00887c8a` only | | `SpyManager::Slot13RngCallee` (`P`) | `0x008408e0 .. 0x00840a5a` | `0x00840929`, `0x008409c7`, `0x00840a3c` | | `SHIPACTION_DEPLOYSPY` handler | `0x0078c930 .. 0x0078c9e0` | `0x0078c97f` only | | `ServerSpyManager::vslot14` | `0x0088db80 .. 0x0088dd2c` | `0x0088dc43` only | No inlined draw is present in any of them (rule 16's tempering immediates do not appear). --- ## 2. The corpus and the state, counted before building (rule 28 practice 5) `as-turn15-spydeployed.sav`, read with `verify/save-reader/save_reader.py`: | field | value | consequence | |---|---|---| | `sim/Frame` | 15 | | | spy `sid` | 1 | | | spy `sown` | 16 | player 0, `re` | | **`re`'s `Species`** | **0 (Human)** | **`P` takes branch B; `0x00840929` and `0x008409c7` are unreachable** | | spy `deat` | 400 (Kepler) | G1 satisfied — lane AS's contribution | | spy `sdet` | **−1** | **the failed conjunct; G2 sends us to branch D every turn** | | spy `sdo` | 0.00839999970048666 | | | spy `tdep` | **15** | `vslot14`'s `Frame − tdep ≥ 3` first holds at **Frame 18** | | spy `cm`, `cmo`, `spyon`, `ncp` | all 0 | `vslot14` G4 fails today; it bootstraps itself at Frame 18 | | spy `cbh` | 5.033599376678467 | `= 2π × 0.8011207…`, i.e. `0x0078c97f` already fired once, unmeasured | | players | 7 — `re`(0), `Revenge Fleet`(0), `Spengler`(0), 4 × `_NPC`(4) | branch A's candidate list would be non-empty, if it were reachable | **Corpus count for `P`, on the predicate `∃ spy with deat != 0 && sdet != -1 && Frame − sdet ≥ 3`: 0 of 22 before this lane, and 0 of 23 including `as-turn15-spydeployed.sav`.** The failed conjunct is `sdet == -1`, exactly as lane AS handed it over — and it is not a conjunct any amount of clicking can satisfy directly. It is satisfied by *waiting*, at a probability the code fixes. **Corpus count for `0x0078c97f`:** not expressible over save fields at all (§1.5). The nearest save-side witness is `cbh != 0`, which holds in **1 of 23** saves — `as-turn15-spydeployed.sav`, because the site fired on the turn that produced it. **No save needs to be manufactured for either target.** Lane AS built both states. This lane generates no map and plays no new game. --- ## 3. Predictions Committed before the build, before the deploy of any binary to VM144, and before any End Turn. ### 3.1 The static claims | | prediction | how it is wrong | |---|---|---| | **PA1** | `P` reaches **at most one** draw site per call, selected by `spyOwner->Species (+0x5c) == 6`. From this save, only `0x00840a3c`. | a `draw_sites` row at `ret_rva 0x0044092e` or `0x004409cc` on any turn of this workload falsifies it outright | | **PA2** | Species indices are `0 Human, 1 Hiver, 2 Tarkas, 3 Liir, 4 _NPC, 5 Zuul, 6 Morrigi`; therefore `AccumulateDetectionOdds`'s `0.75f` is **Zuul** and its `0.5f` is **Morrigi** | a save whose `sim/species` list is ordered differently, or a Zuul save with `Species != 5` | | **PA3** | `0x00840a3c` is `Chance(0.25f)` — a widened `float`, not the decimal 0.25 read from a decompiler | the four bytes at `0x009e5ac0` are not `00 00 80 3e` | | **PA4** | the spy is **destroyed** at the end of `vslot13` on the turn `P` runs: `nspy` 1 → 0, `spies2` at Kepler 1 → 0, and no spy record survives in the autosave | the post-`P` autosave still carries a `spy` record | ### 3.2 Target 1 — the wait, and the per-turn word trajectory Let `T` be the `Frame` on which `sdet` is stamped. `sdo` grows by **0.0084 per turn** and the roll on the End Turn producing `Frame f` uses `sdo = 0.0084 × (f − 14)`, because `AccumulateDetectionOdds` runs *before* the gate. `Chance` costs one word for `0 < p < 1` (board row 367). | | prediction | |---|---| | **PB1** | `sdo` in the autosave after the End Turn producing `Frame f` is exactly `0.0084 × (f − 14)` as a float32, for every `f` until detection: 0.0168, 0.0252, 0.0336, 0.0420, 0.0504, … | | **PB2** | `OnAllCombatDone_Tail` costs **1** word on Frames 16, 17, 18 (`vslot13`'s detection roll alone) | | **PB3** | **`0x0088dc43` fires for the first time in this campaign on Frame 19**, one call, one word, `ret_rva 0x0048dc48`, `strategic = true` — because `vslot14` bootstraps its counter-mission at Frame 18 (`Frame − tdep = 3`, `ncp` empty), setting `spyon`, `cm := 1`, `cmo := 0.2f`, **without drawing on Frame 18 itself** | | **PB4** | from Frame 19 the tail costs **2** words per turn (`vslot13` 1 + `vslot14` 1), and drops to 1 on any turn where `cmo` has accumulated to ≥ 1.0 or where `cm` has just cycled back to 0 | | **PB5** | save-side: `cm` moves off its corpus-constant 0 on **Frame 18**, `spyon` moves to the Kepler owner's id on Frame 18, and `cmo` starts stepping by `0.2f` per failed counter-mission roll from Frame 19 | | **PB6** | on the detection turn `T`: `vslot13` still costs 1 word (the roll that *succeeds*), `sdet := T` | | **PB7** | on `T+1` and `T+2`: **`vslot13` costs ZERO words** — `sdet != -1` skips branch D, and `Frame − sdet < 3` skips the destruction path. A zero at `0x00487c8f` on those two turns is a *positive* result about a third arm and must not be read as "the roll did not fire" (rule 28 practice 6) | | **PB8** | on `T+3`: one row at `ret_rva 0x00440a41`, `entry = Chance`, `calls = 1`, `words = 1`, `no_draw_calls = 0`, `strategic = true`; `vslot13`'s own `0x00487c8f` row **absent**; `vslot14` contributes **0** because the spy was destroyed at the end of phase 23 | | **PB9** | the entry probe on **`Game::SpyManager::Slot13RngCallee 0x008408e0` reads 1** on Frame `T+3` — its first non-zero in the campaign, and the complement of lane AS's demonstration that its zero said nothing about the subtree | | **PB10** | cumulative detection probability: **11 % by +4 turns, 43 % by +10, 70 % by +15, 87 % by +20** — computed from `p_k = 0.0084(k+1)`. *(Lane AS's brief quoted 38/65/85; that is the same model evaluated one turn late, using `p_k = 0.0084k`. Minor, and stated so the difference is on the record before the run.)* | | **PB11** | the tail bracket total over the whole run equals the per-site sum: **residual 0** on every turn | **PB12 — the tail case, stated in advance.** At +20 turns there is a 13 % chance `sdet` is still −1. If that happens, the result reported is the **`sdo` trajectory against PB1** plus the `0x0088dc43` series, and `P` stays a decoded-not-measured site. That is a real measurement of the accumulator and it will be reported as such rather than ground out. ### 3.3 Target 2 — the deploy order From `as-turn14-predeploy.sav`, one Deploy Spy order, one End Turn, `probes=8`: | | prediction | |---|---| | **PC1** | one `draw_sites` row at `ret_rva 0x0038c984`, `entry = NextFloat`, `calls = 1`, `words = 1`, `no_draw_calls = 0`, `strategic = true` | | **PC2** | it lands in the **`ProcessTurn`** bracket, not `OnAllCombatDone_Tail`'s, because `ApplyAllTurnCommands` runs first | | **PC3** | the same turn's `OnAllCombatDone_Tail` costs **exactly 1** — the first detection roll at `sdo = 0.0084` | | **PC4** | the resulting `spy.cbh` reproduces lane AS's value **exactly**: `5.033599376678467`, i.e. `2π × 0.80112…`. The strategic generator is seeded from the save and the per-process AI client seed does not feed it, so the same input plus the same order must draw the same word. **This is the sharpest single prediction in the document**: it says the deploy draw is reproducible across processes, sessions and lanes | | **PC5** | `spies2` at Kepler goes 0 → `[1]`, `deat` 0 → 400, `tdep := 15`, `sdo := 0` then `0.0084` — reproducing lane AS's §4.2 from a different process | ### 3.4 The control | | prediction | |---|---| | **PD1** | two fresh `hooks=off` processes on the **same** input will produce a byte-identical *pre*-turn `(Autosave EndTurn).sav` and **differing** post-turn autosaves | | **PD2** | the differences localise to **one AI player's research pick plus `Summary/Checksum` and the `turnstats` `tch` cell** — the per-process `StrategyClient` seed of `2026-09-08-ai-seed-per-process.md`. Nothing of my empire, the spy, `deat`, `sdet`, `sdo`, `cm`, `cmo` or `spies2` moves | | **PD3** | therefore **this is not a calibration pair and must not enter `determinism-hashes.txt`** — stated in advance so it cannot be a post-hoc excuse (rule 26) | | **PD4** | the leaves this lane's numbers depend on — the `spymgr` sub-tree and the `systems` sub-tree — **do** reproduce across the control pair, and that is the claim that will be checked by sub-tree rather than by whole-file hash | ### 3.5 How the whole model could be wrong * **`countC` is not stable.** `sdo`'s per-turn increment is `0.7 × (0.01 + 0.001 × countC)` with `countC = 2` inferred, not observed. If a fleet moves in or out of Kepler the increment changes and PB1 breaks — **and that would be the most interesting failure available**, because it would identify `countC` from the delta. Symptom: an `sdo` step that is not 0.0084. * **`vslot14` might not bootstrap.** AG's `ncp` check is on a container this lane has only seen as the integer 0. If `ncp` is a count and non-empty means something else, PB3 fires late or not at all. Symptom: Frame 19 tail costs 1, not 2, and `cm` stays 0. * **The stage machine consults `owner->+0xff` (`CnTrd`, FTL Economics) at 1 → 2/3.** This game has no FTL Economics, so the 1 → 3 arm is the one that runs; that changes which stage sequence is exercised but not any word count. * **PB7's two zero turns are the polarity trap in a new place.** `vslot13` will be *entered* on `T+1`/`T+2` (the probe reads 1) and cost 0. If this lane reported that as "the roll stopped working", it would repeat exactly the mistake rule 28 exists for. * **PC4 can fail benignly.** If AI orders applied before mine consume strategic words, `cbh` differs and the deploy draw is still 1 word. That falsifies *reproducibility*, not the site. --- *(End of the pre-registered section. Everything below is measurement.)* --- ## 4. What was run Shim build **`ap-989c692-20260909T0425Z`**, cross-built on CT111 in this lane's own directory `/srv/re-lab/build/sots-engine-ap` after `rm -rf` of the whole tree, from a lane-private `git worktree` at `~/sots-engine-ap` with no local `build*` shipped (rules 21 and 24). `binkw32.dll` sha256 `ae084ed4774caf24ea7927fcb012d1999633f10556c7c99f0209f66067416a17`. Staged to `/srv/re-lab/shim/dist-ap`, deployed to `C:\SOTS\shimdist-ap` on VM144. **This lane wrote no engine code**; `shim.cfg.hp8` and `shim.cfg.hoff` were used unmodified. | run | config | input | End Turns | purpose | |---|---|---|---|---| | **W** | `shim.cfg.hp8` (`probes=8`) | `MyGameas1spydep.sav` (Frame 15) | **11** (15 → 26) | target 1 | | **D** | `shim.cfg.hp8` | `MyGameas1predeploy.sav` (Frame 14) + one `Deploy Spy` order | 1 | target 2 | | **OA / OB** | `shim.cfg.hoff` | `MyGameas1spydep.sav` | 1 each, two fresh processes | control (§7) | **Instrument armed and verified from `shim.log`, not assumed** (rule 1). Both instrumented runs: seven `drawsite:` detours `create=MH_OK enable=MH_OK`; `config: probes=8 -> 8 lane-H entry probes` and all eight `create=MH_OK enable=MH_OK`; **zero** `COVERAGE:` lines; **zero** `config: ignoring unknown key` lines; `draw_site_overflow = 0` on every turn. Probe indices 8–11 report **NOT INSTALLED**, never 0. The one `MH_ERROR_ALREADY_CREATED` line is the `fpu` module losing the race for `BeginProcessTurn` to the ledger; it is present verbatim in lanes AC, AD, AR and AS's logs, so this is the same instrument those lanes ran. **`probes=11` was not used anywhere in this lane.** No number here is comparable to lane AC's turn totals. ### 4.1 The wait cost eleven minutes, not an evening The brief budgeted "~20 End Turns, expensive in wall-clock". On this state an End Turn under `probes=8` completes in **6 seconds**; the eleven turns took **11 minutes** including the load. The expensive part is the launch (~2 min through the intro movies) and the load (~3 min). Turn 27 hit a Von Neumann encounter dialog at Rigel and the driver stopped on it exactly as designed; by then the question was answered and the run was ended there rather than clicked through. The driver is worth carrying forward: a scheduled task (`SOTSAP`) running an in-guest loop that clicks End Turn, then **polls the autosave's mtime** — never a button colour, which is lane AS's lesson — snapshots `(Autosave).sav` per turn, and stops on the first stall with a screenshot. It is left at `C:\SOTS\ui\ap\ap_loop.ps1`. --- ## 5. Target 1 — the wait, measured turn by turn Detection landed on **Frame 22**, seven turns in. `P` therefore ran on **Frame 25**. ### 5.1 The per-turn ledger Every row is `draw_sites` at the post-turn autosave marker, which the shim resets at the pre-turn marker — so these are **per-turn** figures, not cumulative. | Frame | `0x00887c8a` spy 13 | `0x0088dc43` spy 14 | `0x00840a3c` `P` B1 | `0x00820e1d` trade raid | tail bracket | probe `vslot13` | probe `Slot13RngCallee` | |---|---|---|---|---|---|---|---| | 16 | **1** | — | — | — | **1** | 1 | 0 | | 17 | **1** | — | — | — | **1** | 1 | 0 | | 18 | **1** | — | — | — | **1** | 1 | 0 | | 19 | **1** | **1** ← first ever | — | — | **2** | 1 | 0 | | 20 | **1** | **1** | — | 2 | **4** | 1 | 0 | | 21 | **1** | **1** | — | 4 | **6** | 1 | 0 | | **22** | **1** ← succeeds, `sdet := 22` | **1** | — | 7 | **9** | 1 | 0 | | 23 | **—** | **1** | — | 7 | **8** | **1** | 0 | | 24 | **—** | **1** | — | 8 | **9** | **1** | 0 | | **25** | **—** | **—** | **1** ← first ever | 7 | **8** | **1** | **1** ← first ever | | 26 | — | — | — | 8 | **8** | 1 | 0 | Every cell is `calls = words`, `no_draw_calls = 0`, `strategic = true`. **The tail bracket equals the sum of its rows on all eleven turns: residual 0 every turn**, and `draw_site_overflow = 0`. Three lines of that table are the lane: > **Frame 25:** `entry = Chance`, `ret_rva = 0x0044_0a41` (VA `0x00840a41`, the instruction after > `call 0x8e6dd0` at `0x00840a3c`), `calls = 1`, `words = 1`, `no_draw_calls = 0`, > `strategic = true`. **`0x00840a3c` had never fired in this campaign.** > > **Frames 23 and 24:** no row at `0x0048_7c8f` at all, while the entry probe on > `ServerSpyManager::vslot13` reads **1** on both. That is "entered and gated", not "did not run" — > rule 28 practice 1, in a third distinct arm of the same function. > > **Frame 25, the probe column:** `Game::SpyManager::Slot13RngCallee 0x008408e0` reads **1**. Lane AS > demonstrated that this probe's **zero** said nothing about the subtree. This is the other half: > the same probe, on the one turn the callee is actually entered, reads one. ### 5.2 `0x00840929` and `0x008409c7` did not fire, and could not have Neither site appears in any of the eleven turns, including Frame 25 — the one turn `P` ran. **PA1 held.** The reason is not a state we failed to build: `P`'s first instruction pair is `cmp [spyOwner+0x5c], 6` / `jne`, the spy's owner is player 16 `re` with `Species = 0` (Human), and the launch card confirms it in the UI. Branch A is a **Morrigi-only** path. > The brief that created this lane, lane AS's §6, board row 207 and lane AG's §6 all list > `0x00840929` / `0x008409c7` / `0x00840a3c` as three sites behind one gate. They are **two > mutually exclusive branches selected by species**, and no workload can fire more than one of them > per call. To reach the other two, a lane must play a **Morrigi** empire, deploy a spy, and lose it. ### 5.3 `sdo` — the accumulator, exact to the float32 Read from the eleven autosaves. Prediction PB1 was `sdo(f) = 0.0084 × (f − 14)` as a float32. | Frame | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | |---|---|---|---|---|---|---|---|---|---| | `sdo` | 0.016800 | 0.025200 | 0.033600 | 0.042000 | 0.050400 | 0.058800 | 0.067200 | 0.067200 | 0.067200 | | bits | `3c89a027` | `3cce703a` | `3d09a027` | `3d2c0831` | `3d4e703b` | `3d70d845` | `3d89a027` | frozen | frozen | Seven consecutive exact steps of 0.0084, then **frozen** the moment `sdet` stamps — because branch D is the only writer of `sdo` and `sdet != -1` skips it. The freeze is a second, save-side proof that the branch stopped running on Frames 23 and 24, independent of the ledger's zero. Lane AS measured two points of this line (0 → 0.0084 → 0.0168) and derived the rest. **Nine points now lie on it**, and `countC` stayed at 2 for the whole window, so `sdo`'s per-turn increment is a constant on this state rather than a fitted one. ### 5.4 The counter-mission machine, measured for the first time `0x0088dc43` (lane AG §3.2) had **corpus count 0 of 22** and had never fired. It fires here from Frame 19, one call and one word per turn, and the save-side state machine is fully visible: | Frame | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | |---|---|---|---|---|---|---|---|---| | `spyon` | **32** | 32 | 32 | 32 | 32 | 32 | 32 | — | | `cm` | **1** | 1 | **2** | 2 | **3** | 3 | **4** | — | | `cmo` | 0.2 | 0.4 | 0.2 | 0.4 | 0.2 | 0.4 | 0.2 | — | | `ncp` | 0 | 0 | **1** | 1 | **2** | 2 | **3** | — | | words at `0x0088dc43` | **0** | 1 | 1 | 1 | 1 | 1 | 1 | **0** | Everything AG decoded statically is confirmed, and four things are added: 1. **The bootstrap turn costs nothing.** Frame 18 is `Frame − tdep == 3`; `vslot14` sets `spyon`, runs the stage machine `cm: 0 → 1` and `cmo := 0.2f`, and **does not draw**. The first draw is Frame 19. PB3 predicted exactly this and it held. 2. **`cmo` steps by `0.2f` on failure and resets to `0.2f` on success**, as decoded. The stage advanced on Frames 20, 22 and 24 — always on the second try, at `p = 0.4`. Six rolls, three successes; expectation at (0.2, 0.4) alternating is 2.4. Consistent, not validated. 3. **`ncp` is a scalar counter of completed stages, not a container.** It is a plain `int` item in the stream and it increments by exactly 1 on each stage completion (0,0,1,1,2,2,3), in lock-step with `cm`. AG's decode reads the `cm == 0` branch as gated on "`ncp` non-empty"; that gate was **never reached** here, because `cm` never returned to 0 before the spy was destroyed. It stays a rule-6 hypothesis — and a sharper one now that `ncp`'s values are known. 4. **The `CnTrd` the stage machine consults is the TARGET's, not the spy owner's.** AG's caution to lane AS was that a spy program run without FTL Economics takes the `1 → 3` arm. This run took `1 → 2`, and in the save **my player (16) has `CnTrd = False` while Kepler's owner (32) has `CnTrd = True`**. So `owner->+0xff` at that branch is the **victim** empire's FTL Economics. The caution as written would have mispredicted this run. `cm`, `cmo`, `spyon` and `ncp` are four of the 234 fields the value-domain census lists as having only ever held one value. **All four are now off zero**, with a measured trajectory each. ### 5.5 The spy is destroyed at `sdet + 3`, and `vslot13` does it `nspy` goes **1 → 0** between the Frame-24 and Frame-25 autosaves, `spies2` at Kepler returns to `count = 0`, and the `spymgr` record loses its only `spy` child. That is `vslot13`'s drain loop at `0x00887eb0` calling manager vtable slot 10 `0x00838480`, which calls `ServerSystem::RemoveSpy 0x0074f550`. **PA4 held.** It also settles the ordering question in §1.4 behaviourally: `0x0088dc43` costs **0** on Frame 25 although `vslot14`'s entry probe still reads 1. Phase 23 destroys the spy before phase 33 walks the list. --- ## 6. Target 2 — `0x0078c97f`, the site in no inventory, measured Run D: `MyGameas1predeploy.sav` (Frame 14) in a fresh process under `probes=8`; Kepler selected on the map; `Special → Deploy Spy → OK`; one End Turn. ``` draw_sites, post-turn autosave marker, the row verbatim: entry = NextFloat ret_rva = 0x0038_c984 (VA 0x0078c984 -- after `call 0x47d830` at 0x0078c97f) calls = 1 words = 1 no_draw_calls = 0 strategic = true boundary ledger, same turn: BeginProcessTurn 326 -> 326 0 ProcessTurn 326 -> 344 18 <-- the deploy draw is in here OnAllCombatDone_Tail 344 -> 345 1 <-- the first detection roll, sdo = 0.0084 Autosave 345 -> 345 0 ``` **PC1, PC2 and PC3 all held exactly.** The site fires once per applied `SHIPACTION_DEPLOYSPY` command, for one word, on the strategic generator, inside the `ProcessTurn` bracket — and the same turn's tail costs exactly 1, because `ApplyAllTurnCommands` runs before `OnAllCombatDone_Tail` and the freshly deployed spy is immediately eligible for its first detection roll. It appears in **no other turn of this lane**: eleven turns of run W carry no row at `0x0038c984`. That is the stream predicate showing its shape — the site's cost is not a function of the save at all, it is a function of what the player ordered. ### 6.1 The sharpest prediction held: the deploy draw is reproducible across processes **PC4.** Lane AS's `as-turn15-spydeployed.sav` was written by a different process, on a different day, from a different build. This lane's Frame-15 autosave was written by run D. ``` lane AS spy.cbh = 5.033599376678467 (float32 0x40A11333) lane AP spy.cbh = 5.033599376678467 identical cbh / 2pi = 0.8011222000 ``` The same input state plus the same order drew the same word, in two processes separated by hours and by a rebuild. Together with `deat = 400`, `tdep = 15`, `sdo = 0.0084`, `sdet = -1` and `spies2 = [1]` at Kepler reproducing exactly (**PC5**), this says the **strategic** generator's consumption up to `ApplyAllTurnCommands` is deterministic given the save — the per-process AI client seed does not reach it. It is a much stronger statement than a whole-file hash comparison, because it isolates one word to one site. ### 6.2 A correction to lane AS's reading of the same bytes AS gives the site as `cbh = NextFloat() * 2*pi`. The value is right; the expression is the campaign's standard range idiom with `LO` supplied by an `fldz`: ``` 0078c984 fld qword [0x009e21b0] ; HI = 6.2831854820251465 0078c98a fldz ; LO = 0.0 0078c994 fsub st(1),st ; HI - LO 0078c99b fmulp st(1),st ; (HI - LO) * r 0078c99d fstp [ebp+8] ; through a FLOAT32 temp 0078c9a0 fadd [ebp+8] ; LO + that ``` so it is `lerp(0.0, 2*pi, r)` **rounded to float32 mid-expression**, not a `double` multiply. A reimplementation that computes `r * 6.2831854820251465` in double and stores at the end can differ in the last bit. The other half of the sequence is worth writing down because it reads wrong at first glance: ``` 0078c998 push ecx ; reserve DeploySpy's SECOND argument slot 0078c9a9 fstp [esp] ; slot := the angle 0078c9ac call 0x0080c860 ; __thiscall getter, `mov eax,[ecx+0xa8]; ret` -- NO stack args, ; so it leaves the angle slot untouched. eax = the spy's id. 0078c9ba push eax ; the FIRST argument 0078c9bb call edx ; ServerSpyManager::DeploySpy(spyId, angle) ``` `0x0080c860` looks like it consumes the float and does not; the compiler built the argument list out of order and called a zero-argument getter across the half-built frame. **`DeploySpy` takes two arguments**, and `0x008874b0 fld [ebp+0xc]` / `0x008874c0 fstp [esi+0x18]` is where `cbh` is written. Lane AS's *"`spy->cbh (+0x18) := `"* is exactly right; this only names which argument and shows why an eye following `eax` misses it. --- ## 7. The control — a truthful non-pair, and the exposure predicate checked against it Two fresh `hooks=off` processes (**OA**, **OB**) on the same input, one End Turn each, plus this lane's instrumented run **W** and lane AS's three runs from the day before. Six processes, one input, one End Turn. ### 7.1 The hashes ``` input MyGameas1spydep.sav 854a10fa1ea602f0f7909f9bf9154942e56ea5fa1db4cce47d6d32bf53952e08 ``` | run | lane | config | pre-turn `(Autosave EndTurn).sav` | post-turn `(Autosave).sav` | size | |---|---|---|---|---|---| | A | AS | `hoff` | `98e45d3745b91450…` | `262f8bda97c9511d…` | 77,685 | | B | AS | `hoff` | `98e45d3745b91450…` | `e34775a757e6fb3d…` | 77,649 | | M | AS | `probes=8` | `98e45d3745b91450…` | `262f8bda97c9511d…` | 77,685 | | **W** | **AP** | `probes=8` | — | **`262f8bda97c9511d…`** | 77,685 | | **OA** | **AP** | `hoff` | **`98e45d3745b91450…`** | **`e296394f578b3a56…`** | 77,677 | | **OB** | **AP** | `hoff` | *(§7.4)* | *(§7.4)* | | **The pre-turn save is byte-identical across four processes, two lanes and two builds** — including this lane's own, which is not lane AS's binary. That is the strongest statement available about the input, and it is what makes the post-turn comparison meaningful. **The post-turn saves are not.** Five processes have produced **three** distinct outcomes: `262f8bda` (three times: AS's A, AS's M, this lane's W), `e34775a7` (once: AS's B), `e296394f` (once: this lane's OA). > **This is not a calibration pair and must not enter `determinism-hashes.txt`.** Said in advance as > PD3, and it is the honest verdict rather than a post-hoc excuse. ### 7.2 What varies, localised by sub-tree `state_checksum --no-audit --floats bits --mask none`, OA against W: ``` DIVERGED: 15 leaf difference(s) /Summary/Checksum 985948923 -> 985948837 /Sim/turnstats/history/hist[1]/stats[15]/tch 45 -> 46 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/St[60] 3 -> 2 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/TResDone[60] 22469 -> 0 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/Tbd[60] 2 -> 1 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/St[64] 2 -> 4 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/TResDone[64] 0 -> 22469 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/TAcq[64] -1 -> 16 /Sim/players/Player[32 "Revenge Fleet"]/TechTree/TiAcq[64] -1 -> 45 /Sim/players/Player[32]/Events/…/EvDsc 'Research Over Budget' -> 'Research Complete' /Sim/players/Player[32]/Events/…/EvMsg 'Research for Micro-Fusion Drives has gone overbudget.' -> 'Tech Overthrusting has been acquired' /Sim/players/Player[32]/Events/…/EvImg 'EVENT_RESEARCH_OVERBUDGET' -> 'EVENT_RESEARCH_COMPLETE' /Sim/players/Player[32 "Revenge Fleet"]/ResTNm 'DRV_McroFus' -> '' /Sim/players/Player[32 "Revenge Fleet"]/otch/.[34] only-in-B /Sim/players/Player[32 "Revenge Fleet"]/otch/.[0] 33 -> 34 ``` **And the sub-tree digests say which halves of the save are affected**, which is the form the claim should take (PD4): | sub-tree | OA | W | | |---|---|---|---| | `Sim/spymgr` | `9c3f224cf954aa54` | `9c3f224cf954aa54` | **identical** | | `Sim/systems` | `3227b08124339fe2` | `3227b08124339fe2` | **identical** | | `Sim/fleets` | `26a640cdfc597869` | `26a640cdfc597869` | **identical** | | `Sim/trdmgr` | `ed99071bdc121694` | `ed99071bdc121694` | **identical** | | `Sim/players` | `2d1c0cad92679606` | `46ddf6778ef36e0b` | differs | | `Summary` | `66db5e1055c9fe37` | `cb8a4c8e22480af0` | differs (the derived checksum) | > **Every leaf this lane's numbers depend on reproduces across the pair. `spymgr` — the spy's > `deat`, `sdet`, `sdo`, `cm`, `cmo`, `ncp`, `cbh` — is byte-identical between an instrumented run > and an un-instrumented one, as is every system's `spies2`.** What does not reproduce is one AI > empire's research pick and the two derived values downstream of it. **Three distinct picks across five processes** is worth stating plainly, because it is the first time this outcome set has been sampled more than twice: A/M/W completed `Overthrusting` (tech 64), B was part-way through `DRV_NodFoc`, OA went over budget on `DRV_McroFus`. AS observed A and M agreeing and correctly flagged it as a `1/k` coincidence rather than evidence about the instrument. With five samples the set has at least three members and the modal outcome took 3 of 5 — so the coincidence AS refused to lean on was about a 1-in-3 event, not a 1-in-2 one, and refusing to lean on it was right. ### 7.3 The seed-exposure predicate, checked (rule 26 corollary (c)) The coordinator's instruction is to record the exposure fields next to every control hash. Here they are for the **pre-turn** save of the control pair, and for every turn this lane played, so the predicate can be checked rather than asserted. `Species = 4` (NPC) players are omitted; they never decide. Net ids: player 16 is `re` (human), 32 is `Revenge Fleet` (the AI), 48 is `Spengler`. | pre-turn save | Frame | Player[32] `ResTNm` | `NDes` | `NOwn` | ships | exposure | |---|---|---|---|---|---|---| | `as-turn14-predeploy` | 14 | **`''`** | 15 | 10 | 146 | **pick** | | **`as-turn15-spydeployed`** (the control input) | **15** | **`''`** | **15** | **10** | **146→148** | **pick + colonise + 2 ships** | | `w-16` | 16 | `''` | 15 | 11 | 157 | pick + 9 ships | | `w-17` | 17 | `''` | 16 | 12 | 161 | pick + design + colonise + 4 ships | | `w-18` | 18 | `''` | 20 | 12 | 169 | pick + 4 designs + 8 ships | | `w-19` | 19 | `''` | 20 | 12 | 181 | pick + 12 ships | | `w-20` | 20 | `'WEP_AmWhd'` | 20 | 12 | 185 | 4 ships | | `w-21` | 21 | `'WEP_AmWhd'` | 23 | 12 | 201 | 3 designs + 16 ships | | `w-22` | 22 | `'WEP_AmWhd'` | 27 | 12 | 218 | 4 designs + 17 ships | | `w-23` | 23 | `'WEP_AmWhd'` | 27 | 12 | 236 | 18 ships | | `w-24` | 24 | `'WEP_AmWhd'` | 27 | 14 | 235 | colonise ×2 | | `w-25` | 25 | `''` | 28 | 15 | 244 | pick + design + colonise + 9 ships | | `w-26` | 26 | `''` | 28 | 15 | 251 | pick + 7 ships | **The predicate held, and it held in its strong direction.** The control input carries `Player[32].ResTNm == ''` — a pick turn — and the control varied, in exactly the research-pick leaves the predicate names and nothing else. Two independent lanes have now produced that signature on this input. **And the state says something the predicate did not anticipate: on this map exposure is *saturated*.** Every one of the thirteen pre-turn states above carries at least one exposure signature; nine of thirteen carry a research pick, and every single turn adds ships. There is **no quiet turn anywhere in this lineage** to attempt an agreeing control on — so no rung-A oracle pair is obtainable from `as-turn15-spydeployed.sav` at any horizon by waiting, and a lane that wants one on this map must pin the client seeds instead. That is a fact about a 2-empire game where the AI runs a 146 → 251-ship war economy, and it is the opposite end of the same axis from lane AR's quiet turns 38–39. **One nuance that cuts against a naive reading of the predicate.** Exposure is necessary for variation, not sufficient *per process pair*: W (`probes=8`) and AS's A and M (two different configurations, two different builds, three different processes) landed on the **same** post-turn bytes on this exposed pick turn. A single agreeing pair on an exposed turn therefore proves nothing — which is rule 26's original point, now with a measured outcome-set size behind it. ### 7.4 OB, and the verdict ``` OB (Autosave EndTurn).sav 98e45d3745b914506fc4c409ad5a5ad0938a2003ab4c845421a99a8065149c3a 76,706 OB (Autosave).sav 262f8bda97c9511d8d2b41e6a8a0582d6f5364c2b01b1caf99e639d0e4f53ebe 77,685 ``` * **OA ≠ OB.** The two `hooks=off` processes of *this* lane's own control disagree, in **15 leaves, all of them** `Player[32]`'s research pick plus `/Summary/Checksum` and the `turnstats` `tch` cell. Nothing of my empire, the spy, `deat`, `sdet`, `sdo`, `cm`, `cmo`, `ncp`, `spies2`, the systems, the fleets or `trdmgr` moved between them. * **OB is byte-identical to W**, the instrumented run: `state_checksum` prints **IDENTICAL** over **44,438 leaves**. Both are `fc85c4228b9973fa159c1ed6aa851ae0`. So the honest three-part statement, which is all the evidence supports: 1. **Not a calibration pair.** Two fresh un-instrumented processes on this input do not agree, so nothing here may enter `determinism-hashes.txt` as a rung-A pair. **PD1 and PD3 held.** 2. **The instrument is neutral on everything this lane measured.** `probes=8` reproduced an un-instrumented run leaf for leaf, and the sub-trees carrying the spy state are identical across all three of this lane's processes. **PD4 held.** That is a stronger neutrality statement than lane AS could make, because AS's instrumented run agreed with only one of two controls; here it agrees with one control *exactly and completely* while the two controls differ from each other in a leaf class the instrument provably does not touch. 3. **The divergence is the known one, and it was predicted.** **PD2 held**, and it held with the pre-turn exposure fields recorded in advance (§7.3) rather than diagnosed afterwards. **A note for whoever certifies pairs.** Lane AS reported A ≠ B and called the class "one AI player's research pick plus the derived checksum". Two more processes, taken independently, land in the same class and add a third member to the outcome set. That is a second lane reproducing the *class* while failing to reproduce the *value* — which is exactly what a per-process seed feeding a small discrete choice should look like, and it is now measured rather than asserted. --- ## 8. Predictions scored — including the one that was wrong | | prediction | verdict | |---|---|---| | **PA1** | `P` reaches at most one draw site per call, selected by `Species == 6`; only `0x00840a3c` from this save | **HELD.** No row at `0x0044092e` or `0x004409cc` on any of the twelve measured turns, including the turn `P` ran | | **PA2** | species table `0 Human … 4 _NPC, 5 Zuul, 6 Morrigi`; `0.75f` is Zuul, `0.5f` is Morrigi | **HELD** (corpus-wide; the launch card independently shows `re` = Human) | | **PA3** | `0x00840a3c` is `Chance` on a widened `0.25f` | **HELD** — `0x009e5ac0` is `00 00 80 3e` | | **PA4** | the spy is destroyed at the end of `vslot13` on the `P` turn | **HELD** — `nspy` 1 → 0, `spies2` emptied, no `spy` record at Frame 25 | | **PB1** | `sdo(f) = 0.0084 × (f − 14)` exactly, until detection | **HELD** — seven exact float32 steps, then frozen | | **PB2** | tail costs 1 on Frames 16, 17, 18 | **HELD** | | **PB3** | `0x0088dc43` first fires on Frame 19; Frame 18 bootstraps without drawing | **HELD exactly** | | **PB4** | **the tail costs 2 words/turn from Frame 19** | **WRONG.** It costs 2 on Frame 19 and then 4, 6, 9, 8, 9, 8, 8 | | **PB5** | `cm`, `spyon` move on Frame 18; `cmo` steps by `0.2f` | **HELD** | | **PB6** | on the detection turn `vslot13` still costs 1 and `sdet := T` | **HELD** — Frame 22 | | **PB7** | `vslot13` costs **zero** on `T+1`, `T+2` while still being entered | **HELD** — Frames 23, 24: no row, probe reads 1 | | **PB8** | `T+3`: one row at `0x0044_0a41`, 1/1/0/strategic; no `0x0048_7c8f`; `vslot14` contributes 0 | **HELD in all three parts** | | **PB9** | the `Slot13RngCallee` probe reads 1 on `T+3` | **HELD** — its first non-zero in the campaign | | **PB10** | 11 % by +4, 43 % by +10, 70 % by +15, 87 % by +20 | **not tested.** Detection landed at +7, where the model says 26 %. One sample is consistent with the model and does not test it | | **PB11** | residual 0 on every turn | **HELD** on all eleven turns of W and on run D | | **PB12** | the +20 tail case | **not reached** | | **PC1** | `0x0038c984`, `NextFloat`, 1/1/0, strategic | **HELD exactly** | | **PC2** | in the `ProcessTurn` bracket | **HELD** | | **PC3** | the same turn's tail costs exactly 1 | **HELD** | | **PC4** | `cbh` reproduces `5.033599376678467` exactly | **HELD** | | **PC5** | `spies2` 0 → `[1]`, `deat` → 400, `tdep := 15`, `sdo := 0.0084` | **HELD** | | **PD1** | the control pair's pre-turn saves agree, post-turn saves differ | **HELD** | | **PD2** | the divergence is one AI's research pick + checksum + `tch`, and nothing of mine | **HELD** — 15 leaves, localised | | **PD3** | not a calibration pair; must not enter `determinism-hashes.txt` | **HELD**, and stated in advance | | **PD4** | the sub-trees this lane's numbers depend on reproduce | **HELD** — `spymgr`, `systems`, `fleets`, `trdmgr` digests identical; and W is byte-identical to OB over 44,438 leaves | ### 8.1 PB4, the one that was wrong, and why it was wrong I predicted the **tail bracket** would cost 2 words per turn from Frame 19, on the reasoning that `vslot13` contributes 1 and `vslot14` contributes 1. Both halves of that were right on every single turn. The prediction was still wrong, because **the tail has a third contributor and I treated it as a constant zero.** ``` Frame 16 17 18 19 20 21 22 23 24 25 26 vslot13 1 1 1 1 1 1 1 0 0 0 0 <- predicted exactly vslot14 0 0 0 1 1 1 1 1 1 0 0 <- predicted exactly 0x00820e1d 0 0 0 0 2 4 7 7 8 7 8 <- NOT PREDICTED tail bracket 1 1 1 2 4 6 9 8 9 8 8 ``` `0x00820e1d` is the **trade-raid roll** in `TradeManager::Slot13RngCalleeA` — lane AC's site, priced per fleet by lane AD. It was at zero on Frames 16–19 and entered the tail on Frame 20, growing to 8. That is the AI's raider fleets arriving on trade-sector nodes as its navy went from 157 to 251 ships: **`calls == words == the number of qualifying fleets`, exactly lane AD's per-fleet model**, now reproduced on a different map, a different lineage and an AI-owned fleet rather than a player-owned one. AD measured 2; this run measured 2, 4, 7, 7, 8, 7, 8 on seven consecutive turns. The lesson is rule 20's, in the direction nobody watches: I checked that my *sites* were priced, and then quoted a *bracket* total as if the bracket contained only my sites. A bracket is a sum over subsystems, and predicting one requires predicting all of them. The correct form of PB4 was "the **spy** contribution to the tail is 2 words per turn from Frame 19", which is what was measured and what should have been written. **It is also the most useful failure available**, because a wrong bracket prediction that decomposes cleanly into "my model was right, an unmodelled neighbour moved" is a free confirmation of the neighbour's model. The residual was 0 on every turn, so nothing is unaccounted for. --- ## 9. Coverage — what this did not touch, said as loudly as what it did * **`0x00840929` and `0x008409c7` remain unfired, and are now known to need a Morrigi empire.** That is a *stronger* negative than "not reached in the states measured": the gate is decoded, the branch was taken twelve times in the other direction, and the predicate is a single field on the spy's owner. **The workload that closes them, named from the failed conjunct:** a Morrigi single-player game, four spy techs, a spy deployed at a foreign colony with a belt, and ~7 turns of waiting. `0x008409c7` needs one more thing on top — the roll at `0x00840929` must *succeed* (75 %) **and** the candidate list must be non-empty, which needs a **third** non-eliminated empire that is neither the spy's owner nor the target's. This map has one (`Spengler`), so a 3-empire Morrigi game reaches both. * **`P` ran exactly once.** Everything about its cost is a single observation. The loop is over the spy vector, so two spies detected three turns apart should give two calls on different turns and two spies detected on the *same* turn should give two calls on one turn — **that is a reading, not a measurement** (rule 20: do not fit a constant to one observation). * **The `sdo` arithmetic is still validated only in its first and third terms.** `countA`, `countB` and the species multiplier were 0 / 0 / 1.0 for all eleven turns. `countC` held at 2 throughout, which is why the line is straight; nothing here identifies *what* `countC` counts, only that it did not change while one fleet of one ship sat at Kepler. * **The auto-detect arm `(TerrFl & 1) == 0` was never taken.** Lane AS flagged it as the most load-bearing unmeasured branch in the chain and it still is. Nothing in this lane touched it. * **The `ncp`-blocks-rebootstrap gate was never reached** (§5.4 item 3). `cm` never wrapped 4 → 0 because the spy was destroyed at Frame 25 with `cm = 4`. Two more turns of survival would have tested it; a second spy deployed later than the first would too. * **`P`'s return value was not traced.** The Frame-25 roll's outcome (whether `re` was named in Kepler's `EVENT_SPY_DESTROYED` event, a 25 % chance) was not read out of the event text. The ledger prices the site; the semantics in §1.2 are from the instruction stream. * **One turn, one process for the eleven-turn series.** W is a single process. The control pair covers only its **first** turn. Frames 17–26 have no two-process control at all, and by §7.3 every one of them is an exposed turn, so they should not be assumed reproducible. * **Turn 27 was not played.** The driver stopped on a Von Neumann encounter dialog at Rigel, which is where the series ends. Nothing after Frame 26 is measured. * **`probes=11` was not used anywhere in this lane**, and no number here is comparable to lane AC's turn totals. * **No `Guard` region is declared by any hook in this family** — the same gap lanes Z, H, AS and AR reported. `undeclared = 0` in these traces is vacuous. * **The species table is read from the save's own `ISsp` list**, cross-checked on one Zuul save and one hook report. No Morrigi, Hiver, Liir or Tarka save exists in the corpus, so indices 1, 2, 3 and 6 are named but not exercised. --- ## 10. Corrections to earlier findings (rule 11) * **Lane AS §6, board row 207, lane AG §6 and this lane's own brief: "`P`'s three draws".** `0x00840929`, `0x008409c7` and `0x00840a3c` are **not three sites behind one gate**. They are two mutually exclusive branches selected by `spyOwner->Species == 6`, and no call can reach more than one of them. Every inventory that lists them as a group of three should say so. §1.2. * **Lane AG §3.2's caution to lane AS: "a spy program run without FTL Economics takes a different branch of the machine".** The `CnTrd` the stage machine consults at `cm 1 → 2/3` is the **target system owner's**, not the spy owner's. My empire has `CnTrd = False` and the machine still took the `1 → 2` arm, because Kepler's owner has `CnTrd = True`. §5.4 item 4. * **Lane AG §3.2's `ncp` reading.** `ncp` is a scalar `int` in the stream, and it behaves as a **counter of completed counter-mission stages** (0,0,1,1,2,2,3 in lock-step with `cm`). "Non-empty" is therefore `!= 0`, and the branch that consults it was never reached here. §5.4 item 3. * **Lane AS §1.4 / §6.1: "`cbh = NextFloat() * 2*pi`".** Correct in value; the code is `lerp(0.0, 2*pi, r)` with a float32 round in the middle, and the angle is `DeploySpy`'s **second** argument, set up before `0x0080c860` (a zero-argument getter) is called across the half-built frame. AS's "`spy->cbh := `" is right; §6.2 only names which argument. * **Lane AS §6's detection-probability table** (38 % / 65 % / 85 % at +10 / +15 / +20) is the right model evaluated one turn late. `AccumulateDetectionOdds` runs *before* the gate, so the roll on the End Turn producing Frame `f` uses `sdo = 0.0084 × (f − 14)`, not `0.0084 × (f − 15)`. The corrected figures are 43 % / 70 % / 87 %. Measured `sdo` (§5.3) settles it: the Frame-16 autosave already holds 0.0168, so the Frame-16 roll was at 0.0168. * **Lane AG's audit and lane V2's inventory have a column they need.** `0x0078c97f`'s predicate is *"a `SHIPACTION_DEPLOYSPY` command in this turn's command stream"*. It is now **measured**, so the gate-indexed audit's two cell kinds (a firing, or a save predicate) become three: a firing, a save predicate, or a **stream** predicate. This is the first entry in that column. --- ## 11. Artifacts | what | where | |---|---| | the instrumented eleven-turn trace (per-turn `draw_sites` + `probe_entries` + brackets) | `verify/traces/ap-probes8-turn16-turn26.jsonl.gz` | | the deploy-turn trace | `verify/traces/ap-probes8-deploy-turn15.jsonl.gz` | | shim log for the eleven-turn run | `verify/results/shim/ap/ap-probes8-w.shim.log` | | shim log for the deploy run | `verify/results/shim/ap/ap-probes8-d.shim.log` | | **the detected-spy save** — first `sdet != -1`, first non-zero `cm`/`cmo`/`ncp`/`spyon` in the corpus | `verify/results/saves/ap-turn22-spydetected.sav` (83,188 B, `--strict` 0 errors / 0 warnings) | | **the post-`P` save** — the spy destroyed, `nspy` back to 0, `spies2` emptied | `verify/results/saves/ap-turn25-spydestroyed.sav` (84,487 B, `--strict` clean) | | the deploy run's Frame-15 autosave (`cbh` reproduced) | `verify/results/saves/ap-deploy-turn15.sav` | | the two control post-turn saves | `verify/results/saves/ap-oa-turn16.sav`, `ap-ob-turn16.sav` | | addresses this lane mints | `ghidra/addresses.d/ap.json` | | predictions, committed before the build | this file §0–§3, commit `f8ff1b6` | | instrument | `sots-engine` `src/shim/shim.cfg.hp8` and `shim.cfg.hoff`, **both unchanged** — this lane wrote no engine code | ### 11.1 The hashes, for the record ``` input MyGameas1spydep.sav 854a10fa1ea602f0f7909f9bf9154942e56ea5fa1db4cce47d6d32bf53952e08 A/B/M/OA/OB (Autosave EndTurn).sav 98e45d3745b914506fc4c409ad5a5ad0938a2003ab4c845421a99a8065149c3a W (probes=8) turn 16 262f8bda97c9511d8d2b41e6a8a0582d6f5364c2b01b1caf99e639d0e4f53ebe OB (hooks=off) turn 16 262f8bda97c9511d8d2b41e6a8a0582d6f5364c2b01b1caf99e639d0e4f53ebe OA (hooks=off) turn 16 e296394f578b3a5668e5934b9eec8d6c4638ca7411200078f97de1abd346f4c5 turn 22 (detection) 91381bd7e722ac3847795a402d78ebb31d74dbb5d2909f33d243aec3ef8abaf8 turn 25 (P ran; spy destroyed) 46380fcf4498d67507e4471eb9ee3762647c53ee5473be142fe5c34e37344bc3 deploy run, turn 15 844f2b746060dc2c4e2099cdc6ceffd5f55ef858c9e347df28c8aca3041f7165 shim binkw32.dll ap-989c692-… ae084ed4774caf24ea7927fcb012d1999633f10556c7c99f0209f66067416a17 ``` **None of these is a calibration pair.** §7. --- ## 12. VM144 as left **Restored and verified by screenshot at the main menu**, profile `re`, 2026-09-09. * `C:\SOTS\binkw32.dll` restored to lane L3's build from `C:\SOTS\shimdist-l3\binkw32.dll` (sha256 `479B8614D2417603…`, byte-identical to what this lane found in place). * `C:\SOTS\shim.cfg` restored from `C:\SOTS\ui\preAS-shim.cfg` (L3's `shim.cfg.l3probe`, `probes=11`). * The three autosaves restored **byte-identical** from `C:\SOTS\ui\preAS-SavedGames` (`1985E6F4…` / `24B2E072…` / `5EC80C1E…`). This lane's eleven turns had overwritten their contents; lane AS's snapshot is what made the restore possible and it is worth keeping. * `C:\SOTS\shim.trace.jsonl` and `shim.log` removed before the relaunch. **`SavedGames` is still 15 files** — this lane added none and removed none, so **lane AS's row positions still hold**: `MyGameas1predeploy` at **(400, 347)**, `MyGameas1spydep` at **(400, 376)**, `OK` at (682, 624). Verified by screenshot twice this session. All fifteen files hash as AS left them. Left in place, all harmless: `C:\SOTS\shimdist-ap\` (build `ap-989c692-20260909T0425Z`, 63 files), `C:\SOTS\ui\apgo.ps1`, `C:\SOTS\ui\aphash.ps1`, `C:\SOTS\ui\ap\` (the End-Turn driver, its per-turn saves and screenshots), and the scheduled task **`SOTSAP`**. `click_helper.ps1` was **not touched** — this lane needed no new verbs either. ### 12.1 Guest notes worth carrying forward * **The End-Turn driver is the reusable part.** `C:\SOTS\ui\ap\ap_loop.ps1`, run through the `SOTSAP` scheduled task (an `InteractiveToken` clone of `SOTSUI`), reads `C:\SOTS\ui\ap\job.txt` (`turns=`, `tag=`, `first=`, `maxwait=`), clicks End Turn, **polls the autosave's mtime** until it moves, snapshots `(Autosave).sav` to `ap\saves\-.sav`, and **stops on the first stall with a screenshot**. Eleven turns cost 11 minutes unattended. Set `job.txt`, `schtasks /Run /TN SOTSAP`, then watch `ap\loop.log` from outside. * **Nine minutes of this lane went into a screenshot-lag artefact, and the lesson is general.** Four consecutive clicks appeared to select the wrong Load-dialog rows, which read exactly like a coordinate offset and nearly produced a "the click helper is 87 px out on this guest" note. It was not: the click task takes ~3 s to start and ~3 s to run, and a screenshot taken 4 s after `schtasks /Run` shows the state **before** the click. **Wait ≥ 9 s between triggering the click task and screenshotting.** Every documented coordinate on this guest is correct. * **The first click after `fg` is swallowed** by the focus activation. Send `fg`, then `move`, then `sleep`, then `click` — or spend a throwaway click. * **A `wheel` zoom on the star map separates systems that overlap at the default zoom.** Lane AS lost a run to Kepler and Midway sharing a hit test; six notches at the cluster centre and then eight more at the target spread them to ~120 px apart, and the labels render. No affine fit was needed. * **Selecting the system, not the fleet, is what enables `Special`.** With Kepler selected the left panel grows a `Fleets at Kepler` list and `Manage Fleets` / `Move` / `Special` light up; `Special → Deploy Spy` then opens a ship picker whose ship is already selected, so `OK` is the only further click. The whole deploy is four clicks once the right star is under the cursor. * **The pixel test for "is the main menu up" must sample the button, not its label.** (511, 536) is inside the white text of `Load Game` and reads ~(195,191,191) on a bright frame; (470, 530) is the button itself and reads (184, 0, 0). A test on the first point passes only by luck on a dark frame. * **An End Turn on this state costs 6 seconds** under `probes=8` with ~150–250 AI ships. The campaign's "30–45 s per End Turn" figure is from a different guest and a different config. * Turn 27 raised a **Von Neumann encounter at Rigel** ("No ships available", `Done` at (233, 673)). A driver that polls the autosave rather than the screen stalls on it cleanly instead of clicking through something it cannot see. --- ## Proposed board rows New row: ``` | THE SPY ATTRIBUTION ROLL FIRES - and P's "three draws" are TWO SPECIES BRANCHES, only one reachable per game | verify | verified | high | 100% | 2026-09-09 | **Lane AP, VM144, build `ap-989c692-20260909T0425Z`, `probes=8` (never 11), own build dir /srv/re-lab/build/sots-engine-ap rm -rf'd first.** Continues lane AS from `as-turn15-spydeployed.sav`: **11 End Turns, 6 SECONDS EACH** (the brief budgeted an evening; the cost is the launch and the load, not the turns). **DETECTION AT FRAME 22, `P` RAN AT FRAME 25.** `Mars::RNG::Chance` at **0x00840a3c** fired **1 call / 1 word / no_draw_calls=0 / strategic=true** at `ret_rva 0x00840a41` - a site that had never fired. **CORRECTION TO EVERY INVENTORY (row 207, lane AG 6, lane AS 6, and this lane's own brief): 0x00840929 / 0x008409c7 / 0x00840a3c ARE NOT THREE SITES BEHIND ONE GATE.** `SpyManager::Slot13RngCallee 0x008408e0` opens `cmp [spyOwner+0x5c], 6; jne` - `Species == 6` (MORRIGI) takes `Chance(0.75f)` at 0x00840929 and then `NextInt` at 0x008409c7 to blame a RANDOM THIRD EMPIRE (a false flag; the true owner is never named); every other species takes `Chance(0.25f)` at 0x00840a3c and on success returns the TRUE owner. **No call can reach more than one.** Species table decoded from the save's own ISsp list and cross-checked on lane V's Zuul save: **0 Human, 1 Hiver, 2 Tarkas, 3 Liir, 4 _NPC, 5 Zuul, 6 Morrigi** - which also NAMES lane AS's two unexplained multipliers in `AccumulateDetectionOdds` (0.75f = ZUUL, 0.5f = MORRIGI). Constants read as the four bytes (rule 23): 0x009e5ac0 = 0.25f, 0x009e5ac4 = 0.75f (the same word AS read as the Zuul multiplier). **0x008409c7 needs BOTH the 0.75f roll to succeed AND a third non-eliminated empire** that is neither the spy's owner nor the target's. **SECOND SITE CLOSED: 0x0088dc43** (the counter-mission roll, lane AG 3.2, corpus 0 of 22, never fired) fires 1 word/turn from **Frame 19**; the bootstrap turn (Frame == tdep+3) sets spyon/cm:=1/cmo:=0.2f and DRAWS NOTHING. `cm`, `cmo`, `spyon`, `ncp` - four of the value-domain census's 234 single-valued fields - are all OFF ZERO with a measured trajectory. **TWO CORRECTIONS TO AG 3.2:** the `CnTrd` the stage machine consults at cm 1->2/3 is the TARGET OWNER's not the spy owner's (my player has CnTrd=False and it still took 1->2, because Kepler's owner has CnTrd=True), and `ncp` is a SCALAR COUNTER of completed stages (0,0,1,1,2,2,3 in lock-step with cm), not a container. **THIRD SITE CLOSED: 0x0078c97f**, the deploy `NextFloat` in the SHIPACTION_DEPLOYSPY handler that is in NO inventory - 1 call / 1 word / strategic, in the **ProcessTurn** bracket, and **spy.cbh came out 5.033599376678467 BIT-IDENTICAL to lane AS's** from a different process, build and session. **Its predicate is on the COMMAND STREAM, and this is the first measured entry in a column the gate-indexed audit does not have.** THE POLARITY CASE, MEASURED: on Frames 23 and 24 (sdet+1, sdet+2) `vslot13` is ENTERED (probe = 1) and costs **ZERO** - a third arm of the same function, and `sdo` FREEZES at 0.0672 in the save, proving branch D stopped independently of the ledger. On Frame 25 the entry probe on `SpyManager::Slot13RngCallee 0x008408e0` reads **1** - ITS FIRST NON-ZERO EVER, the complement of lane AS's demonstration that its zero said nothing about the subtree. The spy is DESTROYED at the end of phase 23 on sdet+3 by manager vtable slot 10 `0x00838480` -> `ServerSystem::RemoveSpy`, so vslot14 costs 0 that turn: nspy 1->0, spies2 emptied. `sdo` measured on NINE points, exactly `0.0084*(f-14)` as float32 (`3c89a027 3cce703a 3d09a027 3d2c0831 3d4e703b 3d70d845 3d89a027`), which also corrects AS's detection-probability table by one turn: **43%/70%/87%** at +10/+15/+20, not 38/65/85. Residual **0 on all 12 measured turns**, overflow 0. **ONE PREDICTION WRONG AND NAMED: PB4** said the tail costs 2 words/turn from Frame 19; it costs 2,4,6,9,8,9,8,8 because the TRADE-RAID roll 0x00820e1d entered the tail at Frame 20 and grew 2,4,7,7,8,7,8 as the AI's navy went 157->251 ships - an independent live re-confirmation of lane AD's per-fleet model on a different map and an AI-owned fleet. The spy halves were predicted exactly; quoting a BRACKET total requires modelling every subsystem in it. Saves `ap-turn22-spydetected.sav`, `ap-turn25-spydestroyed.sav`, `ap-deploy-turn15.sav`; findings `findings/subsystems/spy-program-draws.md` | ``` ``` | CONTROL ON as-turn15: THREE OUTCOMES IN SIX PROCESSES, and exposure is SATURATED on this map | verify | verified | high | 100% | 2026-09-09 | Lane AP, VM144. Two fresh `hooks=off` processes (OA, OB) on `MyGameas1spydep.sav` + 1 End Turn, added to lane AS's A/B/M and this lane's `probes=8` run W. **Pre-turn `(Autosave EndTurn).sav` is byte-identical across four processes, two lanes and TWO DIFFERENT BUILDS** (`98e45d3745b91450...`). Post-turn: **three distinct outcomes in six processes** - `262f8bda` x4 (AS's A and M, AP's W and OB), `e34775a7` x1 (AS's B), `e296394f` x1 (AP's OA). **OA != OB, so this is NOT a calibration pair and must not enter `determinism-hashes.txt`** - stated in advance as PD3. OA vs OB diverge in **15 leaves, ALL of them Player[32]'s research pick plus /Summary/Checksum and one turnstats `tch` cell**; three distinct picks were sampled (Overthrusting completed / DRV_NodFoc in progress / DRV_McroFus over budget). **`probes=8` IS BYTE-NEUTRAL, PROVEN PROPERLY THIS TIME: W is IDENTICAL to OB over 44,438 leaves** (`state_checksum --floats bits --mask none`), while the two un-instrumented controls differ from each other - so the instrument agrees exactly with a control in a leaf class it provably does not touch. Sub-tree digests: `Sim/spymgr`, `Sim/systems`, `Sim/fleets`, `Sim/trdmgr` all IDENTICAL across the pair; only `Sim/players` and the derived `Summary` move. **RULE 26(c) EXPOSURE FIELDS RECORDED NEXT TO THE HASHES** (coordinator's request): the control input carries `Player[32].ResTNm == ''` - a pick turn - and it varied in exactly the leaves the predicate names. **AND THE PREDICATE IS SATURATED ON THIS MAP: all 13 pre-turn states from Frame 14 to Frame 26 carry at least one exposure signature** (9 of 13 a research pick, every single one a batch of ship completions, four a design, four a colonisation; Player[32]'s navy goes 146 -> 251 ships in twelve turns). **There is NO quiet turn anywhere in this lineage**, so no rung-A pair is obtainable from `as-turn15-spydeployed.sav` by waiting - the opposite end of the axis from lane AR's turns 38-39, and a lane that wants a pair on this map must pin the client seeds. Counter-nuance: exposure is necessary for variation, not sufficient per pair - W, A and M (three processes, two configurations, two builds) landed on the SAME bytes on this exposed turn, so a single agreeing pair on an exposed turn proves nothing. Saves `ap-oa-turn16.sav`, `ap-ob-turn16.sav` | ``` Edits to existing rows: - **Row 62** (guest holders) — `VM144 = FREE (lane AP released 2026-09-09; restored to L3's build 479B8614… + L3's shim.cfg (probes=11) + the three pre-AS autosaves BYTE-IDENTICAL from ui\preAS-SavedGames, main menu verified by screenshot). SavedGames is STILL 15 FILES and lane AS's row positions STILL HOLD - MyGameas1predeploy (400,347), MyGameas1spydep (400,376), OK (682,624), verified by screenshot twice. AP added C:\SOTS\shimdist-ap, ui\ap{go,hash}.ps1, ui\ap\ (an END-TURN DRIVER worth reusing: ap_loop.ps1 + the SOTSAP scheduled task clicks End Turn, POLLS THE AUTOSAVE MTIME, snapshots (Autosave).sav per turn and stops on the first stall with a screenshot - 11 turns unattended in 11 minutes). click_helper.ps1 untouched. GOTCHA THAT COST THIS LANE NINE MINUTES: the click task takes ~6 s end to end, so a screenshot taken 4 s after `schtasks /Run /TN SOTSUI` shows the state BEFORE the click - four such shots read exactly like an 87 px coordinate offset and nearly became a false gotcha. WAIT >= 9 s. GOTCHA: the first click after `fg` is swallowed by the focus activation. GOTCHA: the main-menu pixel test must sample the BUTTON (470,530) = (184,0,0), not the white label at (511,536). TIP: `wheel` zoom separates stars that share a hit test at the default zoom (Kepler vs Midway, which cost lane AS a run) - no affine fit needed. An End Turn on this state costs 6 SECONDS under probes=8.` - **Row 207** (V2's eight sites) — append: `CORRECTED AND ADVANCED 2026-09-09 by lane AP. 0x00840a3c FIRED (1 word, Frame sdet+3 from as-turn15-spydeployed.sav). 0x00840929 and 0x008409c7 are NOT two more sites behind the same gate - they are the MORRIGI branch of SpyManager::Slot13RngCallee (`cmp [spyOwner+0x5c],6`), mutually exclusive with 0x00840a3c, and unreachable in any Human/Hiver/Tarka/Liir/Zuul game. Closing them needs a MORRIGI empire (and, for 0x008409c7, a third surviving empire). Of V2's eight, only 0x0082cdb8 (trade 15) is now both reachable and unfired.` - **Row 418** (lane AS's detection-roll row) — append: `EXTENDED 2026-09-09 by lane AP: the roll fired on seven consecutive turns and SUCCEEDED on Frame 22; `sdo` is exactly 0.0084*(f-14) as float32 over NINE points and FREEZES the moment sdet stamps. AS's probability table is one turn late - the corrected figures are 43%/70%/87% at +10/+15/+20. AS's 0x0078c97f is now MEASURED (1 word, ProcessTurn bracket) and `cbh` reproduced bit-identically across processes and builds.` - **The `0x0088dc43` row of lane AG's audit (§3.2)** — `FIRED 2026-09-09 by lane AP, 1 word/turn from Frame 19 (= tdep + 4). The bootstrap turn draws nothing. TWO CORRECTIONS: the CnTrd consulted at cm 1->2/3 is the TARGET OWNER's, and `ncp` is a scalar counter of completed stages, not a container.` - **The gate-indexed audit's cell taxonomy** — `A THIRD CELL KIND EXISTS AND NOW HAS ITS FIRST MEASURED ENTRY: a STREAM predicate. 0x0078c97f fires once per SHIPACTION_DEPLOYSPY command applied; no predicate over the save can express it, and no call-graph sweep can find it (stack-built ship-action table, lane B6's class).`