953 lines
70 KiB
Markdown
953 lines
70 KiB
Markdown
# 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<int> 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<int>` 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) := <the float argument>`"* 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 := <the float argument>`" 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\<tag>-<NN>.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).`
|