From 51243ef8b33a83ac831ba7ea242501754f310ec9 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 9 Sep 2026 03:14:28 -0400 Subject: [PATCH] lane BS merged: the per-history residue is an absent Colonize task; BR's generator row scoped to encounter-free turns --- campaign/DASHBOARD.md | 18 +++++++++--------- campaign/board.md | 13 ++++++++----- guides/method-rules.md | 7 ++++++- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/campaign/DASHBOARD.md b/campaign/DASHBOARD.md index e03364b..ba2ee3b 100644 --- a/campaign/DASHBOARD.md +++ b/campaign/DASHBOARD.md @@ -1,16 +1,16 @@ # SotS RE campaign — coverage dashboard -Generated 2026-09-09 07:03 UTC · `sots-re` @ 2ad6652,2026-09-09 · `sots-engine` @ dea127d,2026-09-09 (242 commits) · regenerate with `tools/dashboard.py` +Generated 2026-09-09 07:14 UTC · `sots-re` @ 1bae655,2026-09-09 · `sots-engine` @ dea127d,2026-09-09 (242 commits) · regenerate with `tools/dashboard.py` > **North star:** A functional reimplementation of the engine — behavior-equivalent, NOT byte-for-byte ## 1. Map coverage (campaign/board.md) -438 targets · mapped-or-better **390/438** `[█████████░] 89%` · verified **348/438** `[████████░░] 79%` +441 targets · mapped-or-better **393/441** `[█████████░] 89%` · verified **351/441** `[████████░░] 80%` | Status | Count | % | |---|---:|---:| -| verified | 348 | 79% | +| verified | 351 | 80% | | mapped | 42 | 10% | | in-progress | 5 | 1% | | backlog | 41 | 9% | @@ -19,19 +19,19 @@ Generated 2026-09-09 07:03 UTC · `sots-re` @ 2ad6652,2026-09-09 · `sots-engine | Type | verified | mapped | in-progress | backlog | blocked | total | |---|---:|---:|---:|---:|---:|---:| | objects | 46 | 6 | 0 | 3 | 1 | 56 | -| control-flow | 38 | 2 | 1 | 0 | 0 | 41 | +| control-flow | 40 | 2 | 1 | 0 | 0 | 43 | | subsystems | 4 | 8 | 0 | 2 | 1 | 15 | | engine | 31 | 0 | 0 | 0 | 0 | 31 | | verify | 105 | 15 | 3 | 35 | 0 | 158 | | phase2 | 13 | 3 | 1 | 0 | 0 | 17 | -| meta | 92 | 6 | 0 | 1 | 0 | 99 | +| meta | 93 | 6 | 0 | 1 | 0 | 100 | | other | 19 | 2 | 0 | 0 | 0 | 21 | ## 2. Binary understanding - RTTI type descriptors: **1,924** (`Game::` 1,404, `Mars::` 194; serializable types 179) - Classes with recovered member layouts: **384** / 1,598 named classes `[██░░░░░░░░] 24%` — `objects/layouts.json` (serializer recovery) plus classes recovered by hand in `struct-recovery.md` + `schema-gaps-resolved.md`. Note 179 types are *serializable*; the recovery also reaches non-serializable ones, so this is not a subset of that -- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1291**, verified **1160** `[█████████░] 90%` +- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1294**, verified **1163** `[█████████░] 90%` ## 3. Data layer @@ -133,11 +133,11 @@ Most recent open: ## 9. Delta since previous dashboard -- verified targets: 343 → 348 (+5) · mapped-or-better: 385 → 390 (+5) +- verified targets: 348 → 351 (+3) · mapped-or-better: 390 → 393 (+3) - engine LOC: 58,647 → 58,647 (+0) · test files: 122 → 122 (+0) · checks: 4,257 → 4,257 (+0) -- addresses verified: 1,160 → 1,160 (+0) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0) +- addresses verified: 1,160 → 1,163 (+3) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0) - standalone leaves closed: 45 → 45 (+0) · leaves still diverging: 63 → 63 (+0) --- warnings: board.md: unknown types subsystems; mars-rng.md: no oracle total row parsed; mars-stream.md: no oracle total row parsed; mars-vfs.md: no oracle total row parsed - + diff --git a/campaign/board.md b/campaign/board.md index 0e63151..09bb824 100644 --- a/campaign/board.md +++ b/campaign/board.md @@ -59,7 +59,7 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | P2-B3 ProcessResearch (behavioral, RNG) | phase2 | mapped | high | 85% | 2026-09-08 | LIVE, PARTIAL PASS: 15 calls compared, 13 zero-divergence; RNG post-state matched 14/15 incl. every roll (validates MT19937 + draw mapping + odds together). 2 divergences are the declared SetResearched boundary. ORACLE FAILS by exactly one item across 40,300: an unposted EVENT_RESEARCH_OVERBUDGET - compare was blind because the event list was never a declared region. fpu_cw=0x127f => 53-bit double, x87 question SETTLED. No Zuul in the save: double roll still disassembly-only . RECAPTURED WITH GUARDS 2026-09-08 (lane R): the oracle gap is now a COMPARE DIVERGENCE - `side.events.after.v.next_id orig=4 ours=3` on call 0, its only divergent field, with node[144] progress 2879->5768 and flag 1->2 both reproduced and the single RNG draw identical. 15 calls over 5 turns: 3 diverged, **RNG 15/15** (better than the original 14/15 - no tech-effect draw in this session). Guards on the two completion calls map SetResearched: ConMod[0..2]/OutMod/PopMod, ResTNm, TechTree+0x20 order counter, and the undeclared otch vector | . **LANE V 2026-09-08 (build `eventlive-dd38117-20260908T0916Z`): the events divergence is CLOSED on the reference turn** - 3 calls, 3 compared, **0 diverged, exit 0**. Over 5 turns 15 calls / **2** diverged (was 3), both short by exactly 1 `next_id` = the unmodelled `EVENT_TECHS_UNLOCKED`. **CORRECTION to lane R's 'RNG 15/15': that was WORKLOAD LUCK, not a property.** On lane V's call 9 the completed tech had `research_roll_pending` set, so the original drew one word `ours` did not (`left` 374 vs 375, `next_index` 250 vs 249) - the `OnTechResearched` callback draw, a DECLARED out-of-scope boundary (P-events-wiring §3 says so in as many words). Honest statement: the `rng` region reproduces bit-for-bit on every call that does not complete a roll-triggering tech, and is short by exactly one draw on every call that does. Also live: `sizeof(ObservedTech)` = **44**, measured twice (`observed_techs.bytes` 440->484 and 484->528). Zuul double roll now CLOSED on a species-5 save lane V made - see its own row | RNG signatures (Ghidra) | meta | verified | high | 100% | 2026-09-08 | Seed/Twist/NextFloat/NextInt verified; draw = y/(2^32-1); NextInt [0,n] inclusive; lazy twist; left@+0x9c4. RUNTIME CONFIRMED: fpu_cw=0x127f (53-bit double, round-nearest) - our next_float model is right, float_from_pc24 is an unused contingency | | engine: game/effects | engine | verified | high | 100% | 2026-09-08 | merged: TechId enum (196 slots @10000+i), 44 ids with typed strategic effects, species flag bits, ApplyTechEffect; 254 checks | -| VM140 exclusivity (lab rule) | meta | verified | high | 100% | 2026-09-08 | one agent at a time. Holder: **VM140=FREE, oracle bytes verified intact), VM141=FREE (L2 released, 192.168.10.143, hooks=off), VM144=FREE (L3 released; workload saves left on disk, so Load-dialog row positions have moved on that guest), VM145=FREE, save set restored), VM146=FREE (CB released, stopped, restored)** (five parallel investigations 2026-09-08). VM140 remains the reference/oracle guest. Was: FREE (W3 released 2026-09-08, oracle bytes verified; **AND THE LAB IS NOW FIVE GUESTS** - VM141/144/145/146 are ZFS clones for probes and workloads, VM140 remains the exclusive reference; W2 released 2026-09-08, VM restored + oracle bytes verified; H released 2026-09-08, oracle reproduced + VM restored; N released 2026-09-08; Z released 2026-09-08; O-workloads released 2026-09-08 08:30 local, see the LANE O note at the end of this row; U-unlock released 2026-09-08 06:55 local; V-eventlive before it; F-fpucw before it, M-movefleet before that). QUEUE: empty. VM left at the MAIN MENU, `hooks=trace`, build `recap-7584bad-20260908T0615Z` restored from `C:\SOTS\shimdist-recap` (that dist also carries `shim.cfg.recap{trace,b3,b1,misc}`). Lane M also left `C:\SOTS\shimdist-mf` + `C:\SOTS\ui\mf{deploy,release}.ps1` in place - harmless, and a working template for the next lane. Windows Update DISABLED/paused on the VM. Non-holders build /srv/re-lab/build/sots-engine-, stage dist-, deploy C:\SOTS\shimdist-. GOTCHA (lane R): after `schtasks /Run /TN SOTS` the main menu can take >60 s - SCREENSHOT AND VERIFY before clicking, or the click path lands in Credits. GOTCHA (lane M): drive the load dialog ONE rui.ps1 CALL PER CLICK with a screenshot between - a single chained cmd.txt loses sync and silently ends up somewhere else. And the Load Game dialog does NOT pre-select Single Player on a fresh launch: the documented path really is Load Game (512,536) -> Single Player (512,290) -> OK (551,523) -> row -> OK (682,624) -> Launch (511,663). ref-turn2 row is at (400,436) GOTCHA (lane F, confirms lane R): the >60 s startup is REAL and cost a whole wasted run — do not sleep-and-click, **verify the main menu from a screenshot** (`verify/fpu-cw/` run scripts poll a screenshot until the Load Game / Exit buttons are bright red; 3 probes ≈ 25 s was typical). TIP (lane F): reset `SavedGames\` to a fixed file set before every run — the Load dialog row positions depend on how many files are listed, so a constant set means the click path never has to be re-derived (with the 4-file set ref-turn2 sits at (400,348), not (400,436)). PowerShell over SSH mangles quoting badly: send snippets base64 as `powershell -EncodedCommand`, or use `-ExecutionPolicy Bypass -File`. Lane F left `C:\SOTS\shimdist-fpu` + `C:\SOTS\ui\f{deploy,grab,fpu}.ps1` + `C:\SOTS\ui\preF\` (the pre-lane-F SavedGames snapshot, restored) in place. VM RESTORED: recap build `recap-7584bad-20260908T0615Z`, `hooks=trace`, SavedGames back to the 7-file pre-F set, main menu verified by screenshot. GOTCHA (lane V, third confirmation): the >60 s startup is REAL - the Kerberos intro was still on screen at t+30 s and the main menu appeared at ~t+70 s. GOTCHA (lane V): `type ` via the click helper did **NOT** register in the game's text fields this session (neither the Create Game name nor the Save Game file name took SendKeys); the workaround is to accept the default name and **rename the `.sav` on disk** - the Load dialog lists files by FILENAME. SAVEDGAMES IS NOW **8 FILES**: the pre-existing 7 plus `zuul-turn5.sav` (a species-5 save, see the Zuul row). Row positions are UNCHANGED for existing lanes because `zuul-turn5` sorts last: **ref-turn2 is still (400,436)**, zuul-turn5 is the new row 8 at (400,465), rows 29 px apart from y=262 - verified by screenshot `verify/results/shim/eventlive/load-dialog-8files.png`. The three autosaves now belong to the Zuul game. Lane V left `C:\SOTS\shimdist-v` + `C:\SOTS\ui\v{deploy,release,click}.ps1`. VM RESTORED: recap build `recap-7584bad-20260908T0615Z`, `hooks=trace`, main menu verified by screenshot. LANE U (2026-09-08): left `C:\SOTS\shimdist-u` + `C:\SOTS\ui\u{deploy,release}.ps1` in place. SavedGames is STILL 8 FILES (the three autosaves now belong to the Zuul game at turn 15) - **ref-turn2 is still (400,436)**, zuul-turn5 still (400,465). A QEMU-level screenshot (feed `screendump /tmp/vm140.ppm` to `qm monitor 140` on spicy, then scp the .ppm) is more reliable than the click helper's `shot` action and does not need the game window. FOURTH confirmation of the >60 s startup: the Kerberos intro was still on screen at t+45 s, the main menu at ~t+85 s. VM RESTORED: recap build `recap-7584bad-20260908T0615Z`, `hooks=trace`, main menu verified by screenshot. | **LANE O 2026-09-08.** **VM140 is FREE.** Holder was O-workloads; released 2026-09-08 after ~9 turns of Zuul play (turn 15 -> 23) and a fresh 3-turn Human game. **CORRECTION to lane V's `type` gotcha: the click helper's `type` DOES reach the game's text fields - you must CLICK THE FIELD FIRST.** `click 480 234` (the Save Game File Name box) then `type ` worked every time this session, and `click 500 363` + `type` worked for the Create Game name box; lane V's failure was almost certainly an unfocused field. Saves can therefore be named properly and no longer need renaming on disk (the file written is gameName + typedName). Coordinates confirmed this session at 1024x768: in-game menu = round button (1000,714) -> `Save` (937,679) / `Quit to Main Menu` (937,698) -> confirm OK (537,377); Save dialog `Save` (772,233), `Game Successfully Saved` OK (612,383), `Done` (772,542); map panel `Research` (55,124) `Design` (142,124) `Build` (221,124), `Manage Fleets` (60,464) `Move` (155,464) `Special` (229,464), `End Turn` (100,714); Build screen `Add To Queue` (125,714); **Esc leaves the Build and Research screens** - the bottom-left button on the Research screen is `Cancel research`, NOT back, and clicking it pops `Confirm Cancel`. Move mode: send `move X Y` FIRST to read the target's name / Range / ETA off the map, THEN `click`, because that readout is what tells you whether the route is a node route (2-5 turns) or a sublight crawl (37-86 turns). **Chained clicks in one `cmd.txt` DO work for repeated clicks on the SAME button** (`Add To Queue`) but drop about half at `sleep 250` and about 1 in 6 at `sleep 500` - count the result, never assume. End Turn takes 30-45 s under `hooks=trace` with ~25 ships. A mid-turn AI diplomacy popup can steal a scripted click sequence - screenshot after any batch that seems to have done nothing. **VM RESTORED and verified**: quit to the main menu (screenshot), `SavedGames` back to the ORIGINAL 8-file set with the three autosaves restored BYTE-IDENTICAL (sha256 prefixes 0630daaa / e0bf3485 / 1f0dc162), so `ref-turn2` is still (400,436) and `zuul-turn5` still (400,465); lane O's staging dir `C:\SOTS\o-stage` removed; `shim.cfg` still `hooks=trace`, build `recap-7584bad-20260908T0615Z` untouched. Lane O's 7 saves live in the REPO ONLY - push one back with `scp verify/results/saves/.sav re@192.168.10.139:C:/SOTS/SavedGames/` when a compare needs it, and remember that adding a file shifts the Load dialog rows (`MyGame*` sorts BEFORE `MyGameverify1*` **VM141 = FREE (lane AD released 2026-09-08; guest restored, SavedGames back to AC's 13-file set byte-identical PLUS `ad-turn27-two-raiders.sav`, so Load-dialog rows have MOVED AGAIN - screenshot the dialog).** Lane AD left `C:\SOTS\shimdist-ad` + `C:\SOTS\ui\ad-*.ps1`; `click_helper.ps1` unmodified. **GOTCHA: startup on this guest is ~4.5 min through THREE intro movies** (fg + `key {ESC}` x3 via the click helper, then ~90 s), and loading a turn-27 save is a further 3-4 min - budget **~9 min per run** before the first End Turn. **GOTCHA: the first End Turn click after leaving Move mode is swallowed exiting the mode**; the turn starts on the second click. **VM144 = FREE (lane AS released 2026-09-09**; restored to L3's build + `shim.cfg` + the three pre-AS autosaves byte-identical, main menu verified by screenshot). **SavedGames is now 15 FILES** - AS added `MyGameas1predeploy` (400,347) and `MyGameas1spydep` (400,376), so **ROW POSITIONS HAVE MOVED AGAIN**; screenshot the dialog. AS left `C:\SOTS\shimdist-as` + `ui\as{go,hash}.ps1` + `ui\preAS-*`; `click_helper.ps1` untouched. **VM141 = FREE (lane AR released 2026-09-09**; restored, `shim.cfg.hoff`, this lane's `binkw32.dll`, SavedGames = AD's set PLUS `ar-turn37-816raiders.sav`; with autosaves deleted the list is 12 rows from y=260 at 29 px pitch, `ar-turn37-816raiders` is **row 3 at (400,318)**). Left `C:\SOTS\shimdist-ar` + `ui\ar-*.ps1`; `click_helper.ps1` unmodified. **GOTCHA, CORRECTS THE STARTUP FIGURE: `fg` + `key {ESC}` x3 spaced ~2.5 s then ~90 s puts the main menu up in about TWO minutes, not 4.5** - the 4.5 figure is what you get by waiting the movies out. Loading a turn-37 save is a further 3-4 min and that part is NOT compressible. **GOTCHA: `rdrag x y x y` (a zero-length right-drag) IS A RIGHT-CLICK** - the fleet panel's `Add To New Fleet`/`Split Ships` menu is right-click-only and the helper has no right-click verb. **GOTCHA: a trade-sector node is a legal move target EVEN WHEN ITS CUBE IS NOT DRAWN** - in Move mode the hover readout names it; fit `screen = (A*wx + B*wz + C, D*wx + E*wz + F)` from two known points in the save and you land on any node first try. **GOTCHA: the encounter query BLOCKS End Turn** - sample the `Done` pixel at (233,673): ~(183,18,0) when a query is up, ~(8,8,8) on the map; `Auto Resolve Peacefully` (667,641), `Done` (233,673). **VM144 = FREE (lane AP released 2026-09-09**; restored to L3's build + L3's `shim.cfg` + the three pre-AS autosaves BYTE-IDENTICAL, main menu screenshot-verified). SavedGames **STILL 15 FILES** and AS's row positions **STILL HOLD** - `MyGameas1predeploy` (400,347), `MyGameas1spydep` (400,376), OK (682,624), verified 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` 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**. **GOTCHA THAT COST NINE MINUTES: the click task takes ~6 s end to end, so a screenshot taken 4 s after `schtasks /Run` shows the state BEFORE the click** - four such shots read exactly like an 87 px coordinate offset and **nearly became a false gotcha in this very row**. WAIT >= 9 s. **GOTCHA: the first click after `fg` is swallowed by 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 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`. **VM146 = FREE (lane BP released 2026-09-09 restored** and hash-verified: pre-BP autosaves byte-identical, `shim.cfg` `hooks=off` and `binkw32.dll` restored to the pre-BP files, game process **not running, exactly as found**). `ad-turn27-two-raiders.sav` deliberately left on disk, so **Load-dialog rows have MOVED**: autosaves deleted gives 7 rows from y=260 at 29 px pitch, `ad-turn27-two-raiders` **row 1 at (400,260)**. Left `C:\SOTS\shimdist-bp` + `ui\bp{deploy,shot,hash}.ps1` + `ui\preBP\`. **GOTCHA THAT COST FOUR WASTED CLICKS: the lab wall's `/shot/.png` serves a CACHED frame and can be a whole poll cycle (~5 s) BEHIND your last action.** Clicking a Load row then shooting 5 s later shows it un-selected; a second click shows it selected - which reads exactly like a swallowed click and is not. **Wait ~12-16 s, or take two shots and use the second.** Loading the turn-27 save is **3.5-4 min** and is NOT compressible; End Turn on it ~35 s with the light hook set. **VM145 = FREE (lane BQ released 2026-09-09**, RESTORED and verified byte-for-byte to as-found: SavedGames = the same 9 files with identical sha256, `binkw32.dll` = shimdist-recap, `shim.cfg` `hooks=trace`, game stopped). Left `ui\preBQ\` + `ui\bq\` + `ui\bq{deploy,grab,click}.ps1`; `click_helper.ps1` unmodified. **GOTCHA (confirms AR's startup correction on a SECOND guest): ~2 min to the main menu**; loading a turn-38/39 save is a further 3-4 min and is NOT compressible. **GOTCHA (confirms lane M on a second guest): chained clicks through the Load dialog DROP** - a three-click chain landed only the first, twice. **ONE click per helper call with a screenshot between.** **TIP: reset SavedGames to EXACTLY ONE file (the run's input) and the Load dialog is one row at (400,262) with nothing to re-derive.** **GOTCHA: `cmd.exe` windows from the SOTSUI task appear OVER the game and cover the map** - `fg` raises the game; screenshot before believing a click landed. **CONFIRMED: the `Done` pixel at (233,673) reads (183,18,0) with a query up and (0,0,0) on the map**; `Auto Resolve Peacefully` (667,641) fills the centre panel with the dove, so the selection is confirmable from a screenshot before `Done`. **VM146 = FREE (lane BR released 2026-09-09 02:47 restored** and hash-verified: SavedGames back to the 9-file pre-BR set, both autosaves byte-identical to `ui\preBP\`, `shim.cfg` `hooks=off`, `binkw32.dll` restored, `shim.trace.jsonl` removed, game **not running, exactly as found**). `ad-turn27-two-raiders.sav` still on disk so BP's Load geometry **still holds, re-verified by screenshot**: 7 rows from y=260 at 29 px pitch, row 1 at (400,260). **BETTER INSTRUMENT THAN THE WALL, AND IT RETIRES BP'S FOUR-WASTED-CLICKS GOTCHA: take the screendump yourself** - `echo 'screendump /tmp/x.png -f png' | qm monitor ` on spicy, then scp: that is the **LIVE** framebuffer with no poll cycle in it. Twelve screenshots, zero ambiguous frames. BP's "wait 12-16 s" is needed only for the wall's `/shot/.png`. **`tools/vmshot.py` cannot run from the WSL host - it imports PIL and PIL is not installed.** **GOTCHA: `bpshot.ps1` sleeps 3 s then prints `ui\log.txt`, but the click-helper task writes that file at the END of its batch** - any batch longer than ~3 s prints the PREVIOUS batch's log. **VM141 = FREE (lane AZ released 2026-09-09**; restored, `shim.cfg.hoff`, this lane's `binkw32.dll`). **SavedGames has grown by a WHOLE NEW GAME**: AR's 12-row set PLUS `MyGameazTarka.sav` and `MyGameazTarkat11cr.sav`, and **the three autosaves now belong to the Tarka game** - screenshot the Load dialog and re-derive. Left `C:\SOTS\shimdist-az` + `ui\az-{go,ui}.ps1`. **GOTCHAS: `rdrag` ROTATES the star map** (left-drag does NOT pan, arrow keys do nothing, **the camera does not follow the selection**); the Move-mode hover **snaps to the nearest SYSTEM over >100 px**, so a node within ~3 ly of a member star needs a camera rotation first; `wheel` zooms **both** the star map and the research tree; **a research node under a HUD panel is silently unclickable**; and **a blind auto-resolve-peacefully click sequence DOES NOT resolve a real battle** - peaceful is not offered when both sides have ships, and it cost this lane a 16-ship fleet. | +| VM140 exclusivity (lab rule) | meta | verified | high | 100% | 2026-09-08 | one agent at a time. Holder: **VM140=FREE, oracle bytes verified intact), VM141=FREE (L2 released, 192.168.10.143, hooks=off), VM144=FREE (L3 released; workload saves left on disk, so Load-dialog row positions have moved on that guest), VM145=FREE, save set restored), VM146=FREE (CB released, stopped, restored)** (five parallel investigations 2026-09-08). VM140 remains the reference/oracle guest. Was: FREE (W3 released 2026-09-08, oracle bytes verified; **AND THE LAB IS NOW FIVE GUESTS** - VM141/144/145/146 are ZFS clones for probes and workloads, VM140 remains the exclusive reference; W2 released 2026-09-08, VM restored + oracle bytes verified; H released 2026-09-08, oracle reproduced + VM restored; N released 2026-09-08; Z released 2026-09-08; O-workloads released 2026-09-08 08:30 local, see the LANE O note at the end of this row; U-unlock released 2026-09-08 06:55 local; V-eventlive before it; F-fpucw before it, M-movefleet before that). QUEUE: empty. VM left at the MAIN MENU, `hooks=trace`, build `recap-7584bad-20260908T0615Z` restored from `C:\SOTS\shimdist-recap` (that dist also carries `shim.cfg.recap{trace,b3,b1,misc}`). Lane M also left `C:\SOTS\shimdist-mf` + `C:\SOTS\ui\mf{deploy,release}.ps1` in place - harmless, and a working template for the next lane. Windows Update DISABLED/paused on the VM. Non-holders build /srv/re-lab/build/sots-engine-, stage dist-, deploy C:\SOTS\shimdist-. GOTCHA (lane R): after `schtasks /Run /TN SOTS` the main menu can take >60 s - SCREENSHOT AND VERIFY before clicking, or the click path lands in Credits. GOTCHA (lane M): drive the load dialog ONE rui.ps1 CALL PER CLICK with a screenshot between - a single chained cmd.txt loses sync and silently ends up somewhere else. And the Load Game dialog does NOT pre-select Single Player on a fresh launch: the documented path really is Load Game (512,536) -> Single Player (512,290) -> OK (551,523) -> row -> OK (682,624) -> Launch (511,663). ref-turn2 row is at (400,436) GOTCHA (lane F, confirms lane R): the >60 s startup is REAL and cost a whole wasted run — do not sleep-and-click, **verify the main menu from a screenshot** (`verify/fpu-cw/` run scripts poll a screenshot until the Load Game / Exit buttons are bright red; 3 probes ≈ 25 s was typical). TIP (lane F): reset `SavedGames\` to a fixed file set before every run — the Load dialog row positions depend on how many files are listed, so a constant set means the click path never has to be re-derived (with the 4-file set ref-turn2 sits at (400,348), not (400,436)). PowerShell over SSH mangles quoting badly: send snippets base64 as `powershell -EncodedCommand`, or use `-ExecutionPolicy Bypass -File`. Lane F left `C:\SOTS\shimdist-fpu` + `C:\SOTS\ui\f{deploy,grab,fpu}.ps1` + `C:\SOTS\ui\preF\` (the pre-lane-F SavedGames snapshot, restored) in place. VM RESTORED: recap build `recap-7584bad-20260908T0615Z`, `hooks=trace`, SavedGames back to the 7-file pre-F set, main menu verified by screenshot. GOTCHA (lane V, third confirmation): the >60 s startup is REAL - the Kerberos intro was still on screen at t+30 s and the main menu appeared at ~t+70 s. GOTCHA (lane V): `type ` via the click helper did **NOT** register in the game's text fields this session (neither the Create Game name nor the Save Game file name took SendKeys); the workaround is to accept the default name and **rename the `.sav` on disk** - the Load dialog lists files by FILENAME. SAVEDGAMES IS NOW **8 FILES**: the pre-existing 7 plus `zuul-turn5.sav` (a species-5 save, see the Zuul row). Row positions are UNCHANGED for existing lanes because `zuul-turn5` sorts last: **ref-turn2 is still (400,436)**, zuul-turn5 is the new row 8 at (400,465), rows 29 px apart from y=262 - verified by screenshot `verify/results/shim/eventlive/load-dialog-8files.png`. The three autosaves now belong to the Zuul game. Lane V left `C:\SOTS\shimdist-v` + `C:\SOTS\ui\v{deploy,release,click}.ps1`. VM RESTORED: recap build `recap-7584bad-20260908T0615Z`, `hooks=trace`, main menu verified by screenshot. LANE U (2026-09-08): left `C:\SOTS\shimdist-u` + `C:\SOTS\ui\u{deploy,release}.ps1` in place. SavedGames is STILL 8 FILES (the three autosaves now belong to the Zuul game at turn 15) - **ref-turn2 is still (400,436)**, zuul-turn5 still (400,465). A QEMU-level screenshot (feed `screendump /tmp/vm140.ppm` to `qm monitor 140` on spicy, then scp the .ppm) is more reliable than the click helper's `shot` action and does not need the game window. FOURTH confirmation of the >60 s startup: the Kerberos intro was still on screen at t+45 s, the main menu at ~t+85 s. VM RESTORED: recap build `recap-7584bad-20260908T0615Z`, `hooks=trace`, main menu verified by screenshot. | **LANE O 2026-09-08.** **VM140 is FREE.** Holder was O-workloads; released 2026-09-08 after ~9 turns of Zuul play (turn 15 -> 23) and a fresh 3-turn Human game. **CORRECTION to lane V's `type` gotcha: the click helper's `type` DOES reach the game's text fields - you must CLICK THE FIELD FIRST.** `click 480 234` (the Save Game File Name box) then `type ` worked every time this session, and `click 500 363` + `type` worked for the Create Game name box; lane V's failure was almost certainly an unfocused field. Saves can therefore be named properly and no longer need renaming on disk (the file written is gameName + typedName). Coordinates confirmed this session at 1024x768: in-game menu = round button (1000,714) -> `Save` (937,679) / `Quit to Main Menu` (937,698) -> confirm OK (537,377); Save dialog `Save` (772,233), `Game Successfully Saved` OK (612,383), `Done` (772,542); map panel `Research` (55,124) `Design` (142,124) `Build` (221,124), `Manage Fleets` (60,464) `Move` (155,464) `Special` (229,464), `End Turn` (100,714); Build screen `Add To Queue` (125,714); **Esc leaves the Build and Research screens** - the bottom-left button on the Research screen is `Cancel research`, NOT back, and clicking it pops `Confirm Cancel`. Move mode: send `move X Y` FIRST to read the target's name / Range / ETA off the map, THEN `click`, because that readout is what tells you whether the route is a node route (2-5 turns) or a sublight crawl (37-86 turns). **Chained clicks in one `cmd.txt` DO work for repeated clicks on the SAME button** (`Add To Queue`) but drop about half at `sleep 250` and about 1 in 6 at `sleep 500` - count the result, never assume. End Turn takes 30-45 s under `hooks=trace` with ~25 ships. A mid-turn AI diplomacy popup can steal a scripted click sequence - screenshot after any batch that seems to have done nothing. **VM RESTORED and verified**: quit to the main menu (screenshot), `SavedGames` back to the ORIGINAL 8-file set with the three autosaves restored BYTE-IDENTICAL (sha256 prefixes 0630daaa / e0bf3485 / 1f0dc162), so `ref-turn2` is still (400,436) and `zuul-turn5` still (400,465); lane O's staging dir `C:\SOTS\o-stage` removed; `shim.cfg` still `hooks=trace`, build `recap-7584bad-20260908T0615Z` untouched. Lane O's 7 saves live in the REPO ONLY - push one back with `scp verify/results/saves/.sav re@192.168.10.139:C:/SOTS/SavedGames/` when a compare needs it, and remember that adding a file shifts the Load dialog rows (`MyGame*` sorts BEFORE `MyGameverify1*` **VM141 = FREE (lane AD released 2026-09-08; guest restored, SavedGames back to AC's 13-file set byte-identical PLUS `ad-turn27-two-raiders.sav`, so Load-dialog rows have MOVED AGAIN - screenshot the dialog).** Lane AD left `C:\SOTS\shimdist-ad` + `C:\SOTS\ui\ad-*.ps1`; `click_helper.ps1` unmodified. **GOTCHA: startup on this guest is ~4.5 min through THREE intro movies** (fg + `key {ESC}` x3 via the click helper, then ~90 s), and loading a turn-27 save is a further 3-4 min - budget **~9 min per run** before the first End Turn. **GOTCHA: the first End Turn click after leaving Move mode is swallowed exiting the mode**; the turn starts on the second click. **VM144 = FREE (lane AS released 2026-09-09**; restored to L3's build + `shim.cfg` + the three pre-AS autosaves byte-identical, main menu verified by screenshot). **SavedGames is now 15 FILES** - AS added `MyGameas1predeploy` (400,347) and `MyGameas1spydep` (400,376), so **ROW POSITIONS HAVE MOVED AGAIN**; screenshot the dialog. AS left `C:\SOTS\shimdist-as` + `ui\as{go,hash}.ps1` + `ui\preAS-*`; `click_helper.ps1` untouched. **VM141 = FREE (lane AR released 2026-09-09**; restored, `shim.cfg.hoff`, this lane's `binkw32.dll`, SavedGames = AD's set PLUS `ar-turn37-816raiders.sav`; with autosaves deleted the list is 12 rows from y=260 at 29 px pitch, `ar-turn37-816raiders` is **row 3 at (400,318)**). Left `C:\SOTS\shimdist-ar` + `ui\ar-*.ps1`; `click_helper.ps1` unmodified. **GOTCHA, CORRECTS THE STARTUP FIGURE: `fg` + `key {ESC}` x3 spaced ~2.5 s then ~90 s puts the main menu up in about TWO minutes, not 4.5** - the 4.5 figure is what you get by waiting the movies out. Loading a turn-37 save is a further 3-4 min and that part is NOT compressible. **GOTCHA: `rdrag x y x y` (a zero-length right-drag) IS A RIGHT-CLICK** - the fleet panel's `Add To New Fleet`/`Split Ships` menu is right-click-only and the helper has no right-click verb. **GOTCHA: a trade-sector node is a legal move target EVEN WHEN ITS CUBE IS NOT DRAWN** - in Move mode the hover readout names it; fit `screen = (A*wx + B*wz + C, D*wx + E*wz + F)` from two known points in the save and you land on any node first try. **GOTCHA: the encounter query BLOCKS End Turn** - sample the `Done` pixel at (233,673): ~(183,18,0) when a query is up, ~(8,8,8) on the map; `Auto Resolve Peacefully` (667,641), `Done` (233,673). **VM144 = FREE (lane AP released 2026-09-09**; restored to L3's build + L3's `shim.cfg` + the three pre-AS autosaves BYTE-IDENTICAL, main menu screenshot-verified). SavedGames **STILL 15 FILES** and AS's row positions **STILL HOLD** - `MyGameas1predeploy` (400,347), `MyGameas1spydep` (400,376), OK (682,624), verified 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` 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**. **GOTCHA THAT COST NINE MINUTES: the click task takes ~6 s end to end, so a screenshot taken 4 s after `schtasks /Run` shows the state BEFORE the click** - four such shots read exactly like an 87 px coordinate offset and **nearly became a false gotcha in this very row**. WAIT >= 9 s. **GOTCHA: the first click after `fg` is swallowed by 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 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`. **VM146 = FREE (lane BP released 2026-09-09 restored** and hash-verified: pre-BP autosaves byte-identical, `shim.cfg` `hooks=off` and `binkw32.dll` restored to the pre-BP files, game process **not running, exactly as found**). `ad-turn27-two-raiders.sav` deliberately left on disk, so **Load-dialog rows have MOVED**: autosaves deleted gives 7 rows from y=260 at 29 px pitch, `ad-turn27-two-raiders` **row 1 at (400,260)**. Left `C:\SOTS\shimdist-bp` + `ui\bp{deploy,shot,hash}.ps1` + `ui\preBP\`. **GOTCHA THAT COST FOUR WASTED CLICKS: the lab wall's `/shot/.png` serves a CACHED frame and can be a whole poll cycle (~5 s) BEHIND your last action.** Clicking a Load row then shooting 5 s later shows it un-selected; a second click shows it selected - which reads exactly like a swallowed click and is not. **Wait ~12-16 s, or take two shots and use the second.** Loading the turn-27 save is **3.5-4 min** and is NOT compressible; End Turn on it ~35 s with the light hook set. **VM145 = FREE (lane BQ released 2026-09-09**, RESTORED and verified byte-for-byte to as-found: SavedGames = the same 9 files with identical sha256, `binkw32.dll` = shimdist-recap, `shim.cfg` `hooks=trace`, game stopped). Left `ui\preBQ\` + `ui\bq\` + `ui\bq{deploy,grab,click}.ps1`; `click_helper.ps1` unmodified. **GOTCHA (confirms AR's startup correction on a SECOND guest): ~2 min to the main menu**; loading a turn-38/39 save is a further 3-4 min and is NOT compressible. **GOTCHA (confirms lane M on a second guest): chained clicks through the Load dialog DROP** - a three-click chain landed only the first, twice. **ONE click per helper call with a screenshot between.** **TIP: reset SavedGames to EXACTLY ONE file (the run's input) and the Load dialog is one row at (400,262) with nothing to re-derive.** **GOTCHA: `cmd.exe` windows from the SOTSUI task appear OVER the game and cover the map** - `fg` raises the game; screenshot before believing a click landed. **CONFIRMED: the `Done` pixel at (233,673) reads (183,18,0) with a query up and (0,0,0) on the map**; `Auto Resolve Peacefully` (667,641) fills the centre panel with the dove, so the selection is confirmable from a screenshot before `Done`. **VM146 = FREE (lane BR released 2026-09-09 02:47 restored** and hash-verified: SavedGames back to the 9-file pre-BR set, both autosaves byte-identical to `ui\preBP\`, `shim.cfg` `hooks=off`, `binkw32.dll` restored, `shim.trace.jsonl` removed, game **not running, exactly as found**). `ad-turn27-two-raiders.sav` still on disk so BP's Load geometry **still holds, re-verified by screenshot**: 7 rows from y=260 at 29 px pitch, row 1 at (400,260). **BETTER INSTRUMENT THAN THE WALL, AND IT RETIRES BP'S FOUR-WASTED-CLICKS GOTCHA: take the screendump yourself** - `echo 'screendump /tmp/x.png -f png' | qm monitor ` on spicy, then scp: that is the **LIVE** framebuffer with no poll cycle in it. Twelve screenshots, zero ambiguous frames. BP's "wait 12-16 s" is needed only for the wall's `/shot/.png`. **`tools/vmshot.py` cannot run from the WSL host - it imports PIL and PIL is not installed.** **GOTCHA: `bpshot.ps1` sleeps 3 s then prints `ui\log.txt`, but the click-helper task writes that file at the END of its batch** - any batch longer than ~3 s prints the PREVIOUS batch's log. **VM141 = FREE (lane AZ released 2026-09-09**; restored, `shim.cfg.hoff`, this lane's `binkw32.dll`). **SavedGames has grown by a WHOLE NEW GAME**: AR's 12-row set PLUS `MyGameazTarka.sav` and `MyGameazTarkat11cr.sav`, and **the three autosaves now belong to the Tarka game** - screenshot the Load dialog and re-derive. Left `C:\SOTS\shimdist-az` + `ui\az-{go,ui}.ps1`. **GOTCHAS: `rdrag` ROTATES the star map** (left-drag does NOT pan, arrow keys do nothing, **the camera does not follow the selection**); the Move-mode hover **snaps to the nearest SYSTEM over >100 px**, so a node within ~3 ly of a member star needs a camera rotation first; `wheel` zooms **both** the star map and the research tree; **a research node under a HUD panel is silently unclickable**; and **a blind auto-resolve-peacefully click sequence DOES NOT resolve a real battle** - peaceful is not offered when both sides have ships, and it cost this lane a 16-ship fleet. **VM144 = FREE (lane BS released 2026-09-09**, RESTORED and byte-verified to as-found: SavedGames = the same 15 files with identical sha256 so **AS's row positions STILL HOLD**, `binkw32.dll` = shimdist-l3, game RUNNING at the main menu screenshot-verified, as found). **GOTCHA THE ROW-62 CLICK PATH DOES NOT MENTION: THE LOAD PATH HAS A LOBBY.** After the file-list `OK` the game does **NOT** go to the map - it shows the player-setup lobby with **`Launch` at (511,663)** and `Cancel Game` at (511,692). The sequence is **OK -> ~2 min -> LOBBY -> `Launch` -> ~2 min -> map**, so the documented "3-4 min load" is **two waits with a click in the middle**; a lane that sleeps four minutes and screenshots will find the lobby and read it as a hang. **GOTCHA: the game window sits at screen (-8,-39), so the click helper's `shot` captures the WINDOW and is offset by (8,39) from screen coordinates** - subtract it before clicking anything read off a helper screenshot. `tools/vmshot.py --one 144` captures the SCREEN and needs no correction; **prefer it**. **CONFIRMS BQ ON A SECOND GUEST**: reset SavedGames to exactly ONE file and the Load row is at (400,261). **CONFIRMS AR/BQ ON A THIRD GUEST**: ~2 min to the main menu. **TIP: End Turn on this state is FAST** - the autosave appeared within 5 s with 16 aiprobes + the airng bracket + the aiorders dump installed. **Budget the LOAD, not the turn.** **IMAGE BASE `0x006b0000` in BOTH processes on VM144** (vs `0x00f40000` x5 on VM145, `0x005e0000` x3 on VM146) - **per boot, not per process**, on a third guest. | | Zuul double-roll (behavioural) | verify | verified | high | 100% | 2026-09-08 | **CLOSED by lane V 2026-09-08.** No species-5 save existed, so lane V MADE one on VM140: a custom game with only Zuul left in the Available Species pool (both players Zuul), 4 End Turns under `shim.cfg.recapb3`. **8 calls, 8 compared, 0 diverged, exit 0.** All four researching calls have `species=5` and the generator advances by TWO, not one: `left` 540->538 / 522->520 / 504->502 / 485->483, `next_index` +2 each, `mt` hash unchanged; `ours` reproduced every post-state bit-for-bit. Save `verify/results/saves/zuul-turn5-species5.sav` (48559ab5b719b332, 59,131 B, turn 5, homeworld Gallandro) and on the VM as `C:\SOTS\SavedGames\zuul-turn5.sav`. NOT yet exercised by it: a Zuul tech COMPLETION (node 144 was at ~4,700 of 5,000 after 5 turns - one more End Turn gets there), so `SetResearched` and the Zuul boarding-pod grant are still untouched. Report `findings/subsystems/eventlive-verification.md` §5 **EXTENDED by lane U 2026-09-08: the double roll and the COMPLETION PATH together.** `zuul-turn5` + 10 more End Turns (turn 5 -> 15) under the same config: **20 calls, 20 compared, 0 diverged, exit 0**, with TWO Zuul completions. Call 2 (turn 7, alloc {144,1376}) advances the generator by two (`left` 449->447, `next_index` 175->177) AND runs the unlock cascade in the same call - node 144 -> state 4 / order 21 / turn_researched 7, nodes 132 and 136 -> state 2 with cost_rp 10000 / 16000 and turn_available 7, `next_id` 10->12, `observed_techs` 396->440. Note the ZUUL tree unlocks only 132 and 136 from tech 144 where the HUMAN tree also unlocks 142, so this is an independent instance of the cascade, not a repeat. Trace `verify/traces/unlock-b3-zuul.jsonl.gz` | | budget tail coverage (expenses/aid/debt) | verify | backlog | — | 0% | 2026-09-08 | 8 ComputeBudget slots were always 0 in ref-turn2 (no sliders, no aid, no debt, no handicap). Need a save with expense sliders, a debtor and a research-aid treaty to exercise ExpenseTotal + the aid/bonus tail . CONFIRMED AND WORSE 2026-09-08 (lane R, 4284 calls): **13 of 22 slots are 0 on every call** - tradeIncome, shipCarriedPop, secondaryManager, bonusIncome, systemIncomeNeg, debtInterest, construction, expenses, researchMoneyGiven, savingsGiven, tra, researchPointsGiven, trp | **LANE O 2026-09-08.** **PARTIALLY unblocked, and three of the remaining slots are now shown to be UNREACHABLE through the 1.8 UI.** Delivered: `[11] construction` and a large `[8] maintenance` are live in `zuul-turn17-orders2.sav` (build queue of 20 DEs) and `zuul-turn23-fleet23.sav` (27 DEs in service, `Maint` 14,500 vs 3,000/1,000 in every earlier save); the empire research slider is off default (`ResRate` 0.97 vs 0.25) in all five Zuul saves. NOT delivered, with reasons. **(a) `[12] expenses`**: `Nexp` is `[]` for EVERY player in ALL 11 saves across turns 1-23, human and AI alike, and no screen in the 1.8 UI (map panel, Build, Research, Ranking, Intel Analysis, Empire Population Manager, in-game menu) exposes a per-category expense slider - the only economic sliders are the empire Savings/Research split and the per-system `SRs/SRt/SRsc/SRtf/SRi/SRoh` rates, which land in `Sys`, not `Nexp`. Working hypothesis: slot 12 is dead in 1.8. **(b) `[10] debtInterest` / `[7] systemIncomeNeg`**: a debtor cannot be manufactured quickly - a ship's savings cost is deducted at QUEUE time so the queue cannot be over-committed, and `Maint` counts only ships IN SERVICE, which arrive at construction-budget/ship-cost per turn (~4.5 DE/turn here). With income floored at 78,570 (Planetary Budget pushed fully to Construction; measured 124,055 -> 78,570 on the panel) that is ~157 destroyers, i.e. ~35 more End Turns. Reachable, just not cheap. **(c) `[13]/[14]/[19]` aid**: a treaty offer DOES occur (the AI offered a non-aggression pact on turn 3 of the Human game and it was accepted - `human-turn3-noderoute.sav`), but the accepted pact leaves the player's `aid` count 0, and SotS 1.8 has no player-initiated treaty UI - proposals are AI-driven events. Research aid needs a longer game and luck, not a click path | hook GetDifficultyMods | meta | backlog | — | 0% | 2026-09-08 | B1 derived the two difficulty rows from trace values (AI maintenance divisor 3, research x1.5) instead of snapshotting them; hook it properly so they stop being constants | @@ -237,7 +237,7 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | standalone data root | engine | verified | high | 100% | 2026-09-08 | The standalone grew `--data DIR` / $SOTS_DATA_DIR. NO GAME DATA EMBEDDED; absence costs exactly the six census counters and SAYS SO. Note for integrators: with a data root set, `game_data_realdata` fails - and it FAILS IDENTICALLY ON UNMODIFIED MAIN, because the extracted sots.gob is a different data version than the counts that test pins. Not a regression; worth pinning the data version in that test | | THE STRATEGIC AI IS A StrategyClient, not part of ProcessTurn | control-flow | verified | high | 90% | 2026-09-08 | Lane AI1, instruction-verified. One extra Game::StrategyClient (0x708 B) is built PER AI PLAYER at SNMRunAI (net msg 0x3d) by StrategyApp::RunAI 0x008706f0, carrying a Game::StrategyAIAgent at StrategyClient+0x12c, and it receives the same SE* events the human client does. THE PER-TURN TRIGGER IS SEResumePlaying, client event 0x26, raised by StrategyServer::ResumePlaying 0x007ddc90 to every player with Status==0; it lands in StrategyClient::OnResumePlaying 0x00777480 which does `if (this->+0x12c) agent->vt[1](0x26, ev)` - and THAT CALL RUNS THE AI'S WHOLE TURN SYNCHRONOUSLY ON THE MAIN THREAD. Order: ProcessTurn -> OnAllCombatDone_Tail -> "(Autosave EndTurn)" [the save is written HERE] -> SNMResumePlaying -> each AI client's ~30 phases -> cl_EndTurn -> human End Turn -> SNMUpdate -> ApplyTurnCommands (ModCount++ per command) -> ProcessTurn. EXACTLY THE SHAPE LANE A2 MEASURED. CORRECTION to turn-spine.md 2.3: RaiseAIPrepareTurn/SEAIPrepareTurn (type 9) is CONSTRUCTION, not a turn hook - two callers, RunAI and CreateGame, both one-shot | | how an AI decision becomes a command | control-flow | verified | high | 95% | 2026-09-08 | THERE IS NO SEPARATE AI ORDER CHANNEL - the join to everything we already own. StrategyClient+0x160 is an ACCUMULATING TurnCommands; +0x4d8 is the send buffer. ~21 client order methods in 0x00762ca0..0x00763f60 each do `lea ecx,[this+0x160]` and call a TurnCommands::Add* helper. At End Turn, StrategyClient::BuildTurnCommands 0x00783780 does Clear(+0x4d8); +0x4d8 = +0x160; playerId; SetResearchRate - WHICH INCIDENTALLY EXPLAINS why every save's block has the research-rate gate set and the other five clear. SendEndTurn copies +0x4d8 into SNMEndTurn. **11 of the 21 order methods are called directly from the AI module; 7 of those are also UI-reachable.** So ModCount is downstream of StrategyClient+0x160, and RUNG B REDUCES TO FILLING THAT OBJECT THE WAY THE AI DOES | -| AI determinism: every client seeded with ZERO | verify | mapped | high | 85% | 2026-09-08 | All AI randomness uses a PER-CLIENT Mars::RNG at StrategyClient+0x134 (operator_new(0x9cc) + RNG_Seed(ctorArg) in the client ctor); all six direct NextInt sites in the AI band reach it, as do the two facade helpers cl_Chance and cl_RandRange. **ZERO AI CALLS TO THE STRATEGIC GENERATOR** - which closes lane Z's zero residual FROM THE OTHER SIDE, and neither lane has to weaken anything. The seed comes from NextUInt() on a static g_GlobalRNG at 0x00af6e58 that is **NEVER SEEDED** (its only static init writes the IStreamable vftable; none of the six RNG_Seed call sites targets it), and AN ALL-ZERO MT STATE IS A FIXED POINT OF THE TWIST - so every AI client is seeded with 0. GOOD: constant and reproducible. BAD: **the AI's generator state is in NO SAVE** - the StrategyAIAgent::Streamable block's 35 tags carry none. UNVERIFIED LIVE: P1/P2 routed to the VM holder **SCOPE, MEASURED 2026-09-09 (lane BP)**: on the rich turn `ad-turn27` **pinning does NOT collapse two processes to one.** It collapses **94 leaves to 35**, and the 35 are a single **fleet-id transposition** with every decision leaf identical. **Pinning explains the AI's CHOICES on a rich turn; it does not explain the ORDER in which two new fleets are matched to their ids.** | +| AI determinism: every client seeded with ZERO | verify | mapped | high | 85% | 2026-09-08 | All AI randomness uses a PER-CLIENT Mars::RNG at StrategyClient+0x134 (operator_new(0x9cc) + RNG_Seed(ctorArg) in the client ctor); all six direct NextInt sites in the AI band reach it, as do the two facade helpers cl_Chance and cl_RandRange. **ZERO AI CALLS TO THE STRATEGIC GENERATOR** - which closes lane Z's zero residual FROM THE OTHER SIDE, and neither lane has to weaken anything. The seed comes from NextUInt() on a static g_GlobalRNG at 0x00af6e58 that is **NEVER SEEDED** (its only static init writes the IStreamable vftable; none of the six RNG_Seed call sites targets it), and AN ALL-ZERO MT STATE IS A FIXED POINT OF THE TWIST - so every AI client is seeded with 0. GOOD: constant and reproducible. BAD: **the AI's generator state is in NO SAVE** - the StrategyAIAgent::Streamable block's 35 tags carry none. UNVERIFIED LIVE: P1/P2 routed to the VM holder **SCOPE, MEASURED 2026-09-09 (lane BP)**: on the rich turn `ad-turn27` **pinning does NOT collapse two processes to one.** It collapses **94 leaves to 35**, and the 35 are a single **fleet-id transposition** with every decision leaf identical. **Pinning explains the AI's CHOICES on a rich turn; it does not explain the ORDER in which two new fleets are matched to their ids.** **BOUNDED 2026-09-09 (lane BS)**: **a turn that mints new client fleet ids is not thereby a turn whose visit order varies.** AR turn 38 minted **two** (counters 154 and 155, both absent from `ar-turn37`) through **six** entries to `AssignFleetsAndIssueOrders`, and **four processes** (AR's three `hooks=off` plus BS's instrumented one) produced `15b99255...` **byte for byte** - outcome set **1** on that turn. | | P2: the test that decides whether Rung B is stated correctly | verify | in-progress | — | 0% | 2026-09-08 | ROUTED TO LANE H (holds VM140). Load one save twice IN TWO FRESH PROCESSES, End Turn in each, diff the autosaves. Predicted byte-identical incl. ModCount. IF IT HOLDS, Rung B stays as written (implement the AI, the byte-match is reachable from a save alone). **IF IT FAILS, Rung B is UNREACHABLE FROM A SAVE ALONE** and must be restated as "reproduces a recorded command stream", making --turn-commands injection the primary path instead of writing an AI. A roadmap-level answer for ten minutes of VM time, and it must be TWO SEPARATE PROCESS LAUNCHES to catch per-process seeding - distinct from the oracle restoration, which re-runs the same path | | CORRECTION: fuzzy::IAIRule is the TACTICAL AI | subsystems | verified | high | 100% | 2026-09-08 | A framing error the roadmap and several briefs carried: Game::fuzzy::IAIRule is the tactical/COMBAT AI - its only four implementors are TacAISquadRule_*. The STRATEGIC AI is 34 IAITask goals + 29 IAIRelationScale/Shift diplomacy terms + AIRulesDB (mostly SHIP DESIGN, and AIRulesDB::SelectRules_T is the ship-design selector, NOT the task selection loop). Only the strategic half is on the Rung-B path | | AI module boundary: lane AI1 read ~3% | meta | verified | high | 100% | 2026-09-08 | The module is **1,629 functions / ~360 KB** (dense core 0x680000-0x6d1000) and lane AI1 read the spine, maybe 3%, and says so. NOT DONE: the 34 IAITask bodies - NOT ONE - and IAITask's 8 pure virtuals are unnamed; THE TASK SELECTION LOOP IS UNFOUND; 19 of the 30 AI Process-Turn phases are unclassified addresses; the order-method -> list mapping (mechanical, one pass); and g_CurrentClientIndex 0x00ae4808 is uninstrumented - who sets it and in what ORDER AI clients are stepped matters, BECAUSE ModCount IS A COUNT. ONE HOP IS INFERRED NOT READ: StrategyAIContext::Broadcast 0x006b3840 delivering to the queued callback that reaches OnAIPacket - the identification is safe (one caller, registered by one function, jump table indexed by exactly the codes that function emits) but a next lane should finish it. ALSO UNSETTLED: AIProcessMinTime + Game::AIProcessingDialog hint at a think-time throttle; no deferral seen in OnAIPacket but no per-frame driver was looked for, and if an AI turn CAN span frames the clean "all AI orders in before the human's End Turn" ordering needs revisiting | @@ -421,9 +421,9 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | rule 28 practice 4, demonstrated rather than argued | meta | verified | high | 100% | 2026-09-09 | Lane AS ran both instruments on the same turn: the **entry probe** on `SpyManager::Slot13RngCallee 0x008408e0` read **0**, while the **return-address ledger** recorded `0x00887c8a` firing for **one word** in the caller's body. Four lanes had previously read that zero as a statement about the subtree; it was only ever a statement about which function the call sits in. **Polarity matters too and is now practice 6**: the `je` jumps PAST the roll, so belt-gone means **no draw AND the spy detected anyway** - a zero at that site means two opposite things, and the intuitive reading is backwards | | VERDICT: `TradeManager+0x0c` IS the per-system containing-sector table - the writer is found and the raid target pick FIRES | control-flow | verified | high | 100% | 2026-09-09 | **Lane AR**, VM141, `findings/control-flow/raid-target-pick-verdict.md`. Decides lane AG's §3.3 final paragraph, the one load-bearing inference AG flagged as unproven, and lane AD correctly reported it could not separate on sector 832. **BOTH INSTRUMENTS AGREE (rule 3).** STATIC: the writer AG's §7 lists as NOT FOUND is **`FUN_00841700`** (214 B, 0x00841700-0x008417d5) - it clears the +0x0c vector, RESIZES it to `count(([this+4])+0x40..+0x44)` (the SYSTEMS vector, the very container `FUN_00841cd0` indexes with `rt->trfr` at 0x00841d36), then walks the SECTOR vector x each sector's MEMBER SYSTEM vector executing `mov [this->+0x0c + m->+0x5c * 4], sector` at 0x008417a8. `ServerSystem+0x5c` is the serialised **`Idx`** field (objects/layouts.md, grade verified), so this is literally `containingSector[system.Idx] = sector` and **G_B1a cannot reject a valid trfr, BY CONSTRUCTION**. It is called from the DESERIALISER `FUN_00858a10` at 0x00858f07, so a loaded save has the table populated. LIVE: with 4 raiders parked (2 CR on sector 832, 2 DE on sector **816**, all `Pos` bit-equal), `Slot13RngCalleeA` is entered **4x/turn, 4 words**, every turn - and on turn 42 `Slot13RngCalleeB` reached its target pick: **`NextInt` at call `0x0088b613`, calls=1 words=1**, the FIRST firing of that site in the campaign. `OnAllCombatDone_Tail` cost **5** words that turn against **4** on every other turn; bracket residual **0** on all six turns. **THE SAME RUN CARRIES ITS OWN CONTROL**: on turns 38 and 40 `B` was entered by a cruiser on sector 832 and cost **0 words** - same process, same build, same instrument, same function, only the sector differs. AC's and AD's proof-carrying zero is a fact about the SECTOR, not the code path. Instrument `probes=8` (NOT 11), shim `ar-989c692-20260909T0313Z`, cfg `shim.cfg.hp8` unmodified, lane worktree + own build dir `/srv/re-lab/build/sots-engine-ar` rm -rf'd first (rules 21, 24) | | `B` costs ONE word on a success, not two - and the deciding value is a SPECIES FLAG set by a constructor for exactly two species | control-flow | verified | high | 100% | 2026-09-09 | Lane AR. Lane AG's committed §3.3 prediction was **3 words on a succeeding turn** (`A` 1 + `B`'s NextInt 1 + `FUN_00820af0`'s NextFloat 1) and §5.2 says `B` costs 2 on success. **MEASURED: the tail cost 5 with k=4 raiders and one success, i.e. `B` cost 1, and there is NO `0x00820c1b` row on that turn.** Why: `FUN_00820af0`'s third short-circuit is `SpeciesDef_HasInterceptFlag 0x0053baf0` - twelve bytes, `cmp [ecx+0x144],0; setne al` - and `InitTable 0x005453a0` sets that flag word at 0x0054562f/0x00545638 for **species 0 (HUMAN) bit 0 and species 5 (ZUUL) bit 1 ONLY**. `Get 0x00545cc0` returns `0x00b10a00 + k*0x184`, the same table InitTable fills. So **a Human or Zuul raider intercepts at frac=1.0 and draws nothing; the other five species draw a NextFloat at 0x00820c1b**. The general tail model is **`k + s + z`** words: k = permitted raiders parked with `Pos` bit-equal, s = their successes ON A SECTOR THAT SOURCES A ROUTE, z = s again unless the raider's species sets the flag. Measured at k+s with k = 4,4,4,4,4,3 and s = 0,0,0,0,1,0. THE CHEAPEST UNEXERCISED STATE IN THE TRADE HALF IS NOW A NON-HUMAN, NON-ZUUL RAIDER - z has never been observed through `B` by anyone. Rule 23's lesson pointing a new way: the deciding value was not a float literal but a FLAG WORD SET BY A CONSTRUCTOR, invisible to any amount of reading `FUN_00820af0` alone **SCOPE CORRECTED (lane AZ 2026-09-09)**: "every other species draws a word" is **wrong for HIVER raiders and for HIVER-owned routes**, and Hiver can never research Commerce Raiding anyway (`CCC_ComRaid` pct 0 on both edges), so that conjunct is unreachable through `vslot13` for a player. **The drawing raiders are Tarkas, Liir and Morrigi.** And this row's `frac = 1.0` is **inverted**: the short-circuit sets **0.0**. | -| ORACLE PAIR on the turn-37 raider state - and the probes=8 instrument is BYTE-NEUTRAL, whole-save | meta | verified | high | 100% | 2026-09-09 | Lane AR (rules 19, 26). Two fresh `hooks=off` processes loading `ar-turn37-816raiders.sav` and running the same two End Turns produced **BYTE-IDENTICAL** autosaves at both snapshot points: Frame 38 `15b99255e1f03dab…` and Frame 39 `7a8b3d5eb3a60eba…`; `state_checksum --floats bits --mask none` prints **IDENTICAL**, root `237020deca931f5a180289592cece7ae`, coverage PROVED (1,173,884 B rebuilt, 67,239 leaves), 0 error 0 warn. **THEN** a fourth process with `shim.cfg.hp8` installed produced the SAME TWO HASHES. So the instrument is behaviour-neutral **at whole-save byte granularity**, not merely on the sub-tree the measurement reads - the stronger form of what lane AD could show. Order matters and it was the right order: the control was reproduced FIRST and shown to be a single outcome, so rule 26's `1/k` coincidence caveat does not apply (k=1). **THIS CORRECTS THE SCOPE OF LANE AD'S ROW**: "no oracle pair for this state / the AI varies per process" is true of `ad-turn27-two-raiders.sav` and NOT true of the same lineage ten turns later, so it is a fact about that state, not about the engine. No explanation for the difference is offered and none should be inferred. `ar-turn37-816raiders.sav` + 2 End Turns is the first RUNG-A CALIBRATION PAIR from this lineage and the obvious candidate for the standalone's first trade-raid comparison **SCOPED by the resolver 2026-09-09**: the agreement is **explained** (no exposed AI decision on turns 38-39 - target held then completed, no design created, forced ship placement) and it does **NOT transfer** - Player[32] enters turn 40 with `ResTNm == ''`. Use the **second turn**, `ar-oracle-A-pre.sav -> 7a8b3d5e...`, as the standalone's pair once probe 1b reproduces it **by load**. The peaceful auto-resolve on turn 38 reproduced across three processes but almost certainly bypasses `RunCombatRound`; the combat-turn warning stands. **LOAD-BOUNDARY SCOPE 2026-09-09 (lane BQ)**: this pair is certified **ONLY** as the two-turn continuation from `ar-turn37-816raiders.sav`. **Its second half does NOT survive being reached by load**: `ar-oracle-A-pre.sav` + load + one End Turn gives `4c356f59...`, twice, differing from `7a8b3d5e...` in **17 leaves of ONE AI fleet's movement** (`Zeta Fleet V` moved in the continuation, stayed put after a load). **Use the load->turn hashes for the standalone.** | +| ORACLE PAIR on the turn-37 raider state - and the probes=8 instrument is BYTE-NEUTRAL, whole-save | meta | verified | high | 100% | 2026-09-09 | Lane AR (rules 19, 26). Two fresh `hooks=off` processes loading `ar-turn37-816raiders.sav` and running the same two End Turns produced **BYTE-IDENTICAL** autosaves at both snapshot points: Frame 38 `15b99255e1f03dab…` and Frame 39 `7a8b3d5eb3a60eba…`; `state_checksum --floats bits --mask none` prints **IDENTICAL**, root `237020deca931f5a180289592cece7ae`, coverage PROVED (1,173,884 B rebuilt, 67,239 leaves), 0 error 0 warn. **THEN** a fourth process with `shim.cfg.hp8` installed produced the SAME TWO HASHES. So the instrument is behaviour-neutral **at whole-save byte granularity**, not merely on the sub-tree the measurement reads - the stronger form of what lane AD could show. Order matters and it was the right order: the control was reproduced FIRST and shown to be a single outcome, so rule 26's `1/k` coincidence caveat does not apply (k=1). **THIS CORRECTS THE SCOPE OF LANE AD'S ROW**: "no oracle pair for this state / the AI varies per process" is true of `ad-turn27-two-raiders.sav` and NOT true of the same lineage ten turns later, so it is a fact about that state, not about the engine. No explanation for the difference is offered and none should be inferred. `ar-turn37-816raiders.sav` + 2 End Turns is the first RUNG-A CALIBRATION PAIR from this lineage and the obvious candidate for the standalone's first trade-raid comparison **SCOPED by the resolver 2026-09-09**: the agreement is **explained** (no exposed AI decision on turns 38-39 - target held then completed, no design created, forced ship placement) and it does **NOT transfer** - Player[32] enters turn 40 with `ResTNm == ''`. Use the **second turn**, `ar-oracle-A-pre.sav -> 7a8b3d5e...`, as the standalone's pair once probe 1b reproduces it **by load**. The peaceful auto-resolve on turn 38 reproduced across three processes but almost certainly bypasses `RunCombatRound`; the combat-turn warning stands. **LOAD-BOUNDARY SCOPE 2026-09-09 (lane BQ)**: this pair is certified **ONLY** as the two-turn continuation from `ar-turn37-816raiders.sav`. **Its second half does NOT survive being reached by load**: `ar-oracle-A-pre.sav` + load + one End Turn gives `4c356f59...`, twice, differing from `7a8b3d5e...` in **17 leaves of ONE AI fleet's movement** (`Zeta Fleet V` moved in the continuation, stayed put after a load). **Use the load->turn hashes for the standalone.** **MECHANISM FOUND 2026-09-09 (lane BS, VM144)**: the reason this pair does not survive a load is that a **Colonize task** alive in Player[32]'s AI agent on turn 39 by continuation is **ABSENT after a load** - `AITColonize::Execute` **2 vs 0**, `AssignFleetsAndIssueOrders` **2 vs 0**, `IssueRouteForFleets` **2 vs 0**, while `RunTaskList` is 6 in both. **Both routes reproduced their published hashes UNDER INSTRUMENT**, so the pair is now certified in both forms with the instrument as well as without it. | | `CreateRaidEncounter`'s candidate list is NOT always empty - 0x008939ee fires, and rule 20's case study gets its positive | control-flow | verified | high | 100% | 2026-09-09 | Lane AR, turn 43 of `verify/traces/ar-r1-turn38-turn43.jsonl`. `ServerTradeManager::CreateRaidEncounter` entered **3x** and its subtree drew **two** words: `NextInt 0x008939ee calls=1 words=1` - the site lane H measured at 0 on every turn and that `tail-rng-ledger.md` has carried as a zero ever since, the campaign's own case study for rule 20 - and `NextFloat 0x00820c1b calls=1 words=1` through the OTHER caller `0x0082cf65`, i.e. lane AG §5.1's chain `CreateRaidEncounter -> 0x00892640 -> 0x0082ce00 -> FUN_00820af0`. `Slot13RngCalleeB` was entered **0** times that turn, so neither word is `B`'s. **Two of AG's §5.1/§5.2 unread gates are now read from opposite directions.** The honest form of the cost claim is neither "0 or 1 further word" nor "at least six draws" but **unbounded above and state-dependent**; the first non-zero observation is 2 | -| SEED EXPOSURE IS A PREDICATE ON THE PRE-TURN SAVE - why AR's control agreed where AD's and AS's did not | meta | verified | high | 100% | 2026-09-09 | Resolver, on lane AR's falsified P7 (`findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md`). Three lanes, three controls, one mechanism: the per-process AI client seed (row 326) is present on EVERY turn and reaches the save ONLY through a decision whose outcome set is larger than one given the state. Read off the saves on disk: **AD 27->28** - Player[32] completed BIO_TerBac (no pick: ResTNm held), created a design (NumDes 46->47; the two "Bravestar Mk 3" bodies are BYTE-IDENTICAL apart from DesID 2002/2018), colonised a system (NumOwn 15->16), completed THIRTEEN ships into five new fleets - and A/B differ in the build choice at Sys[272] (978 vs 962), the fleet split (B one fleet more, ModCount 1496 vs 1500), and id allocation ORDER downstream. **AS 15->16** - Player[32] entered with ResTNm == '' and picked (64 vs 62). **AR 37->38, 38->39** - Player[32] held BIO_EnvTail then completed it (pick deferred), NumDes constant at 47, two freighters a turn into EXISTING Freighters fleets, one encounter auto-resolved peacefully: ~100 leaves moved per turn, all forced, three processes agree. READING: not luck, not a pinned AI - no EXPOSED decision reached; explicable from the pre-turn save. ResTNm == '' names a pick turn (rule 28's shape); NumDes/NumOwn/batch completions name the others; 0x0069dbb0 has a 3-40-turn fuse and cannot show within two turns of a load. **Player[32] enters turn 40 with ResTNm == '' - AR's pair MUST NOT be extended by a turn.** RUNG A RULING: AR's pair is certified for its procedure; the single-turn form `ar-oracle-A-pre.sav -> 7a8b3d5e...` is the standalone's first trade-raid pair ONCE one load->End Turn run reproduces the hash (probe 1b, VM145). OPEN: the build/fleet consumer behind AD's variation is UNIDENTIFIED and reading 3 (a non-seed per-process input) is NOT excluded on rich turns - row 360 pinned an early-game turn only. PROBES: (2) VM146, `aiseed=pin` on ad-turn27 x2 fresh processes, predict IDENTICAL - if not, resolver case; (1) VM145, ar-oracle-A-post + 1 End Turn x2, predict DIFFER in Player[32] TechTree/ResTNm only; (3) per-client draw ledger on both states - the C-exact prerequisite, now decisive. No rule 29: rules 23/26 produced the right behaviour (AR refused the inference); rule 26 gets corollary (c) **PROBE 1 RUN 2026-09-09 (lane BQ, VM145). 1b FALSIFIED**: `ar-oracle-A-pre` + **LOAD** + one End Turn gives `4c356f59...`, not `7a8b3d5e...`, **reproducibly in two processes** - the AI moved `Zeta Fleet V` in the continuation and not after a load, so the pair may **NOT** enter `determinism-hashes.txt` in AR's form; the **LOAD form** (`33e30092.../4c356f59...`) is certified instead. The resave canonicalisation is **EXONERATED**. Probe 1 **CONFIRMED** "the files differ" and `/Sim/RNG` + `/Sim/trdmgr` + player-0 fleets identical, but **FALSIFIED the mechanism**: the research pick **AGREED** (both chose `BIO_GrvAdpt`) and the variation is a **COMBAT at Venkman**. Producer run: A and B both returned null, Player[32] reached the **candidate walk**, `candidatesTried=1` - **the outcome set is a singleton by COUNT, not by producer gate**. | +| SEED EXPOSURE IS A PREDICATE ON THE PRE-TURN SAVE - why AR's control agreed where AD's and AS's did not | meta | verified | high | 100% | 2026-09-09 | Resolver, on lane AR's falsified P7 (`findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md`). Three lanes, three controls, one mechanism: the per-process AI client seed (row 326) is present on EVERY turn and reaches the save ONLY through a decision whose outcome set is larger than one given the state. Read off the saves on disk: **AD 27->28** - Player[32] completed BIO_TerBac (no pick: ResTNm held), created a design (NumDes 46->47; the two "Bravestar Mk 3" bodies are BYTE-IDENTICAL apart from DesID 2002/2018), colonised a system (NumOwn 15->16), completed THIRTEEN ships into five new fleets - and A/B differ in the build choice at Sys[272] (978 vs 962), the fleet split (B one fleet more, ModCount 1496 vs 1500), and id allocation ORDER downstream. **AS 15->16** - Player[32] entered with ResTNm == '' and picked (64 vs 62). **AR 37->38, 38->39** - Player[32] held BIO_EnvTail then completed it (pick deferred), NumDes constant at 47, two freighters a turn into EXISTING Freighters fleets, one encounter auto-resolved peacefully: ~100 leaves moved per turn, all forced, three processes agree. READING: not luck, not a pinned AI - no EXPOSED decision reached; explicable from the pre-turn save. ResTNm == '' names a pick turn (rule 28's shape); NumDes/NumOwn/batch completions name the others; 0x0069dbb0 has a 3-40-turn fuse and cannot show within two turns of a load. **Player[32] enters turn 40 with ResTNm == '' - AR's pair MUST NOT be extended by a turn.** RUNG A RULING: AR's pair is certified for its procedure; the single-turn form `ar-oracle-A-pre.sav -> 7a8b3d5e...` is the standalone's first trade-raid pair ONCE one load->End Turn run reproduces the hash (probe 1b, VM145). OPEN: the build/fleet consumer behind AD's variation is UNIDENTIFIED and reading 3 (a non-seed per-process input) is NOT excluded on rich turns - row 360 pinned an early-game turn only. PROBES: (2) VM146, `aiseed=pin` on ad-turn27 x2 fresh processes, predict IDENTICAL - if not, resolver case; (1) VM145, ar-oracle-A-post + 1 End Turn x2, predict DIFFER in Player[32] TechTree/ResTNm only; (3) per-client draw ledger on both states - the C-exact prerequisite, now decisive. No rule 29: rules 23/26 produced the right behaviour (AR refused the inference); rule 26 gets corollary (c) **PROBE 1 RUN 2026-09-09 (lane BQ, VM145). 1b FALSIFIED**: `ar-oracle-A-pre` + **LOAD** + one End Turn gives `4c356f59...`, not `7a8b3d5e...`, **reproducibly in two processes** - the AI moved `Zeta Fleet V` in the continuation and not after a load, so the pair may **NOT** enter `determinism-hashes.txt` in AR's form; the **LOAD form** (`33e30092.../4c356f59...`) is certified instead. The resave canonicalisation is **EXONERATED**. Probe 1 **CONFIRMED** "the files differ" and `/Sim/RNG` + `/Sim/trdmgr` + player-0 fleets identical, but **FALSIFIED the mechanism**: the research pick **AGREED** (both chose `BIO_GrvAdpt`) and the variation is a **COMBAT at Venkman**. Producer run: A and B both returned null, Player[32] reached the **candidate walk**, `candidatesTried=1` - **the outcome set is a singleton by COUNT, not by producer gate**. **LANE BS RAN THE VM144 PARAGRAPH 2026-09-09.** Candidate 1 (**AI agent state the save does not carry**) **SURVIVES and is MEASURED, not inferred: the missing input is a TASK.** Candidate 3 (server-side state) is **disfavoured** - every diverging save leaf has a block-side counterpart. Candidate 2 (stream position) is not what explains it. **Two clauses FALSIFIED, both over-specifications**: there is no list-14 pair on turn 39, and `AssignFleetsAndIssueOrders` is **NOT entered at all** on the load route. | | 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` | | predict at the SITE, not at the bracket | meta | verified | med | 100% | 2026-09-09 | Lane AP's PB4, the one prediction it got wrong, and the lesson generalises. AP forecast every spy-half draw **exactly** and still missed its headline number, because it had predicted the whole `OnAllCombatDone_Tail` total and **an unrelated subsystem entered the bracket**: the trade-raid roll `0x00820e1d` arrived at Frame 20 and grew **2 -> 8 words** as the AI's navy went **157 -> 251 ships**. A bracket total is a sum over every subsystem inside it, so quoting one commits you to modelling all of them. **Predict and report per site, by return address; let the bracket total be the arithmetic check, not the claim.** The consolation: the surprise was itself a result - an independent live re-confirmation of lane AD's per-fleet raid model, on a different map and an AI-owned fleet. Now a corollary to rule 23 | @@ -435,7 +435,7 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | Rule 26 (c) needs four corrections, all measured on one lineage in one session | meta | verified | high | 100% | 2026-09-09 | Lane BQ, from probe 1. (1) **`ResTNm == ''` is NECESSARY, NOT SUFFICIENT** for research exposure: it names a turn on which a pick is MADE; exposure needs `|candidates accepted by TryResearchCandidate| > 1`, and on `ar-oracle-A-post -> 40` it is 1, so the pick agreed across two processes. Lane AS's varying pick (64 vs 62) had a longer list. The sufficient condition is NOT readable from the pre-turn save. (2) **The predicate has a false-positive class, and it was visible BEFORE the run**: four NPC players (528 Alien Menace, 544 Peacekeeper Enforcer, 560 Von Neumann, 576 Independent Colony) carry `ResTNm == ''` on EVERY turn of this lineage INCLUDING the turns whose controls agree; all four have `NumOwn == 0`. Read the predicate only for a non-eliminated AI player with NumOwn > 0. (3) **The predicate has no COMBAT term and needs one** - turn 40 was exposed through `RunCombatRound`, and the pre-turn save names the condition as plainly as it names ResTNm: an AI fleet standing at an enemy colony. (4) **A fourth term is not a predicate on the save at all**: turn 39 ran one way by continuation and another way after a load, BOTH reproducibly, so exposure is a property of (save, procedure, LOAD HISTORY), not of (save, turn). Rule 26 (c)'s instruction "record the pair as (save, procedure, hashes)" was already right and is now load-bearing for a reason it did not anticipate | | THE PINNED-SEED RESIDUE IS A VISIT ORDER, IT IS WRITTEN INTO THE BLOCK, AND ONE RUN SEPARATES HEAP ORDER FROM A GLOBAL-RNG DRAW | meta | verified | high | 100% | 2026-09-09 | Resolver, on lane BP's falsified P1 (`findings/resolutions/2026-09-09-fleet-id-order-residue.md`). RULING ON BP'S RESTATEMENT: accepted and sharpened. The ids are NOT the variable - 1970/1986/2002 decode (id-allocation.md) to node 2 = Player[32]'s client, counters 123/124/125, minted in that order in every process. The variable is the ORDER in which AssignFleetsAndIssueOrders (0x006c16c0, pass 1) visits the ship groups needing a new fleet: A visited the group at Sys 384 first, B the group at Sys 80 first; 2002's group third in both. That order changes the id each group gets, the element order of lists 8/10 and the apply order (hence ShipIDs[] reordered) and NO decision on this turn. **AND IT IS WRITTEN INTO THE BLOCK**: list 10 = StrategyServer::OnCommand_TransferShips {systemId, fleetId, ships[]} records the assignment on every captured run, so C-EXACT SURVIVES LITERALLY with one more free input: (save, seeds, visit order) -> byte match; C-set's shape covers the uncaptured case (canonical order = one member of the outcome set). ENGINE: (1) `state_checksum --relabel-new-ids ` - bijection on that turn's new node-k ids matched by (location, ship set), master id lists as sets, Summary/Checksum masked WITH REASON, refuses to relabel anything in the pre-turn save; accept = BP's pair IDENTICAL modulo {1970<->1986}, AD's pair still DIVERGED; (2) game/ai visits groups canonically (ascending systemId, then min ship id) and mints in that order; (3) optional captured-order override for exact replay. RULING ON POINTER ORDER: not yet leading - ONE OF TWO. The record already names two unnamed AI-band consumers of the per-process global generator 0x00af6e58 (0x0079ea90+0x73 Chance, 0x005b9f00+0xc0; AI1's list) which the seed pin does not touch. What moved: pointer order now has a MEASURED PRECONDITION - BP's aielem dumps carry node heap addresses, and runs A and B (identical config, identical decisions) show the same run of consecutive same-size allocations in DIFFERENT relative address orders (list 3: A idx1idx0, idx3>idx2) - Win8+ LFH randomisation, live in this process. Precondition, not cause. Wall clock has no mechanism (AIProcessMinTime is a trailing Sleep; AI turn is synchronous in OnResumePlaying). THE PROBE (lane BR, VM146, one fresh process, no build, ~12 min): BP's shim.cfg.bppin + `airng=on` (pin_seed off) - the OnResumePlaying bracket attributes EVERY draw on EVERY generator in each client's turn by return address and generator (airngcensus rows, foreign_words/foreign_calls); lane I's inlined-draw inventory has NO site in the AI band so the observer is complete there; airng is measured behaviour-neutral (roll-parity.md). It is also run C. PREDICTIONS: P1 autosave in {e913ff41, 724528ff}; P2 foreign_words=0 in all three brackets, no census row on 0xaf6e58 or Seed record #2; P4 aiorders diff = noise set + at most the transposition. Foreign draw -> its retaddr names the consumer, follow-up = global pin (RNG_Seed(0xaf6e58,K) after Initialize) x2, predict identical. None -> RNG excluded by measurement; stage 2 = one static read of 0x006c16c0 + the gathering hub TO PLACE A HOOK on the group walk, log (element addr, systemId, minted id) in visit order x2 processes, predict order = ascending address. RUNG C restated (backlog text in §6); RUNG B not restated - value confirmed, replay is insulated by construction, and a `aiorders.deep=on` run of BP's pinned procedure landing on e913ff41 is the first rich-turn record. RULE 26(c): BP's wording corrected - the measured fact is "no client", NumOwn==0 is NOT shown to gate (496/512 have NumOwn==0 AND clients). NEW COROLLARY 26(d): when the instrument cannot be removed, pin to a natural run's observed values and require byte-identity with it before reading a pinned pair; the agreement is the pin's control AND a noise mask. No rule 29. STRUCTURAL FIX for BP's shim.cfg trap: an unnamed registered hook under a pin/capture config is a config error; print installed/registered counts. VM144 held for stage 2 / the global pin | | MY OVER-READ of lane BP, corrected by the resolver | meta | verified | med | 100% | 2026-09-09 | I amended rule 26(c) with "a player that has an AI client **and something to decide with** ... because they have `NumOwn == 0`". **The `NumOwn == 0` half is not measured.** The measured fact is only that the four NPC factions get **no client**, so their `ResTNm == ''` is inert. **Players 496 and 512 have `NumOwn == 0` AND have clients** - they held research targets, so the pick was not exercised either way, and whether a client with `NumOwn == 0` reaches the pick is **untested**. I read a gate into a correlation in a rule I was in the middle of correcting for over-claiming. Wording replaced with the resolver's | -| RNG IS EXCLUDED BY MEASUREMENT FOR THE AI VISIT ORDER - the global generator is drawn THREE TIMES IN A PROCESS, all three to mint the AI client seeds | control-flow | verified | high | 100% | 2026-09-09 | Lane BR, VM146, the single probe of `findings/resolutions/2026-09-09-fleet-id-order-residue.md` section 4 (`findings/control-flow/ai-visit-order-probe.md`). No build: lane BP's dist `bp-989c692-20260909T0505Z`, `shim.cfg.brprobe` = `shim.cfg.bppin` with EXACTLY THREE non-comment lines changed (`airng=on`, `airng.pin_seed=off`, `airng.out=`), diffed twice - once file-to-file on the guest, once from the two runs' runtime `config:` lines, both giving the same three lines. 28 of 28 registered hooks off BY NAME, zero unknown keys, zero COVERAGE lines, `aiseed call=1/2/3 pinned=1`, no wildcard hit, `airng: bracket ... MH_OK` + `pin_seed=off`. Route: LOAD. RunAI net-id list: 32/496/512 (three clients; the four NPC factions get none) - confirmed a second way by the bracket firing 5x (pid 16 human agent=0, then 32/496/512 with agents, then 16). **P1 HOLDS: `(Autosave).sav` = `e913ff41...`, BYTE-IDENTICAL to lane BP's runs A and L** (state_checksum IDENTICAL, root 8100b289..., 61147 leaves; vs BP's B, the same 35-leaf transposition, leaf for leaf; pre-turn `16f63adb...` IDENTICAL). Not a third file, so the resolver's ambiguity caution does not fire - AND this is the airng detour's own rule-26(d) control: an instrumented process reproduced an unpinned natural run byte for byte, so `airng`'s behavioural neutrality is now MEASURED on this state, not argued from roll-parity.md. **P2 HOLDS, AND HARDER THAN PREDICTED. `foreign_words=0 foreign_calls=0 residual=0` in ALL THREE AI brackets** (pid 32: left_delta=79 observed=79 calls=75 sites=4; pid 496 and pid 512: left_delta=0, observed=0 - they run a full AI turn and DRAW NOTHING, rule 20's design working). left_delta == observed on pid 32 so there is NO INLINED DRAW on the AI path either, confirming lane I's inventory from the other side. **AND THE LIFETIME CENSUS CLOSES IT: the per-process global generator 0x00af6e58 (runtime 0x00cd6e58) was drawn EXACTLY 3 TIMES, 3 WORDS, FROM ONE RETURN ADDRESS, `va=0x00784f9e`, entry NextUInt - and the count is 3 at every seq from 2 to 5, i.e. it does not move during the turn at all.** `0x00784f9e` is INSIDE `StrategyNetworkClient::OnMessage 0x00784640` and sits 16 BYTES BEFORE the `RunAI` call site that lane AI1 recorded at OnMessage+0x96e = 0x00784fae, and it fires exactly three times for exactly three AI clients at the same log timestamps as the three `aiseed call=` lines: **it is the AI client seed mint - board row 326's mechanism, measured live with its consumer address, generator address and call count, and it is the ONLY thing that generator does in the whole process.** (Inference on the identification, one instruction from a measurement; this lane was instructed not to read the binary.) The two unnamed AI-band consumers the resolution named as H2 candidates (0x0079ea90+0x73, 0x005b9f00+0xc0) DO NOT APPEAR IN THE CENSUS AT ALL. **VERDICT: H2 IS DEAD. H1/H1b (an address-keyed container or an uninitialised-word comparator on the fleet-assignment path) IS THE ONLY HYPOTHESIS LEFT.** **P4 HOLDS in its strong form**: under BP's L/A-proven noise mask (plus unset `aiblk` gate payloads, lane L4's class), BR vs run A = 9 blocks / 81 elements / identical key sets / identical per-list sizes / identical SET gates and **NOT ONE differing word outside the noise set**; BR vs run B = **EXACTLY the three transposition words** (list 8 idx1 w0 1986/1970, list 10 idx0 w0 384/80, list 10 idx1 w0 80/384). The comparator was self-tested against BP's published A/B and L/A results first. **P3 FALSIFIED** (it was labelled not load-bearing): pid 32 spent 79 words, not single digits - rule 23's corollary again, a bracket total is a sum over every subsystem in it. INCIDENTAL, and it is a rule-28 practice-4 case: **the 3-40-turn fuse consumer 0x0069dbb0 DOES draw - on the LOAD path, before the bracket, on each client's own (pinned) generator** (census 0x0069dc02 and 0x0069dc2e: 2+1 words for client 32, 1+1 for 496 and 512, all inside life_in). Its turn-time behaviour is still untested. FREE MEASUREMENT FROM THE DUMPS: section 2.2's LFH precondition now holds on FOUR processes (list-3 node addresses in four different relative orders for an identical allocation sequence - including between L and A, whose autosaves are byte-identical), AND a negative that matters for stage 2 - **the emitted command nodes' relative address order does NOT track the visit order** (BR and A share a visit order and differ in node order; BR and B share a node order and differ in visit order), so the block cannot substitute for the container hook. NEXT (unchanged, now unblocked): one bounded static read of AssignFleetsAndIssueOrders 0x006c16c0 + the gathering hub TO PLACE A HOOK on the group walk, log (element addr, systemId, minted id) in visit order, x2 processes. Artefacts: `verify/results/shim/br/` | +| RNG IS EXCLUDED BY MEASUREMENT FOR THE AI VISIT ORDER - the global generator is drawn THREE TIMES IN A PROCESS, all three to mint the AI client seeds | control-flow | verified | high | 100% | 2026-09-09 | Lane BR, VM146, the single probe of `findings/resolutions/2026-09-09-fleet-id-order-residue.md` section 4 (`findings/control-flow/ai-visit-order-probe.md`). No build: lane BP's dist `bp-989c692-20260909T0505Z`, `shim.cfg.brprobe` = `shim.cfg.bppin` with EXACTLY THREE non-comment lines changed (`airng=on`, `airng.pin_seed=off`, `airng.out=`), diffed twice - once file-to-file on the guest, once from the two runs' runtime `config:` lines, both giving the same three lines. 28 of 28 registered hooks off BY NAME, zero unknown keys, zero COVERAGE lines, `aiseed call=1/2/3 pinned=1`, no wildcard hit, `airng: bracket ... MH_OK` + `pin_seed=off`. Route: LOAD. RunAI net-id list: 32/496/512 (three clients; the four NPC factions get none) - confirmed a second way by the bracket firing 5x (pid 16 human agent=0, then 32/496/512 with agents, then 16). **P1 HOLDS: `(Autosave).sav` = `e913ff41...`, BYTE-IDENTICAL to lane BP's runs A and L** (state_checksum IDENTICAL, root 8100b289..., 61147 leaves; vs BP's B, the same 35-leaf transposition, leaf for leaf; pre-turn `16f63adb...` IDENTICAL). Not a third file, so the resolver's ambiguity caution does not fire - AND this is the airng detour's own rule-26(d) control: an instrumented process reproduced an unpinned natural run byte for byte, so `airng`'s behavioural neutrality is now MEASURED on this state, not argued from roll-parity.md. **P2 HOLDS, AND HARDER THAN PREDICTED. `foreign_words=0 foreign_calls=0 residual=0` in ALL THREE AI brackets** (pid 32: left_delta=79 observed=79 calls=75 sites=4; pid 496 and pid 512: left_delta=0, observed=0 - they run a full AI turn and DRAW NOTHING, rule 20's design working). left_delta == observed on pid 32 so there is NO INLINED DRAW on the AI path either, confirming lane I's inventory from the other side. **AND THE LIFETIME CENSUS CLOSES IT: the per-process global generator 0x00af6e58 (runtime 0x00cd6e58) was drawn EXACTLY 3 TIMES, 3 WORDS, FROM ONE RETURN ADDRESS, `va=0x00784f9e`, entry NextUInt - and the count is 3 at every seq from 2 to 5, i.e. it does not move during the turn at all.** `0x00784f9e` is INSIDE `StrategyNetworkClient::OnMessage 0x00784640` and sits 16 BYTES BEFORE the `RunAI` call site that lane AI1 recorded at OnMessage+0x96e = 0x00784fae, and it fires exactly three times for exactly three AI clients at the same log timestamps as the three `aiseed call=` lines: **it is the AI client seed mint - board row 326's mechanism, measured live with its consumer address, generator address and call count, and it is the ONLY thing that generator does in the whole process.** (Inference on the identification, one instruction from a measurement; this lane was instructed not to read the binary.) The two unnamed AI-band consumers the resolution named as H2 candidates (0x0079ea90+0x73, 0x005b9f00+0xc0) DO NOT APPEAR IN THE CENSUS AT ALL. **VERDICT: H2 IS DEAD. H1/H1b (an address-keyed container or an uninitialised-word comparator on the fleet-assignment path) IS THE ONLY HYPOTHESIS LEFT.** **P4 HOLDS in its strong form**: under BP's L/A-proven noise mask (plus unset `aiblk` gate payloads, lane L4's class), BR vs run A = 9 blocks / 81 elements / identical key sets / identical per-list sizes / identical SET gates and **NOT ONE differing word outside the noise set**; BR vs run B = **EXACTLY the three transposition words** (list 8 idx1 w0 1986/1970, list 10 idx0 w0 384/80, list 10 idx1 w0 80/384). The comparator was self-tested against BP's published A/B and L/A results first. **P3 FALSIFIED** (it was labelled not load-bearing): pid 32 spent 79 words, not single digits - rule 23's corollary again, a bracket total is a sum over every subsystem in it. INCIDENTAL, and it is a rule-28 practice-4 case: **the 3-40-turn fuse consumer 0x0069dbb0 DOES draw - on the LOAD path, before the bracket, on each client's own (pinned) generator** (census 0x0069dc02 and 0x0069dc2e: 2+1 words for client 32, 1+1 for 496 and 512, all inside life_in). Its turn-time behaviour is still untested. FREE MEASUREMENT FROM THE DUMPS: section 2.2's LFH precondition now holds on FOUR processes (list-3 node addresses in four different relative orders for an identical allocation sequence - including between L and A, whose autosaves are byte-identical), AND a negative that matters for stage 2 - **the emitted command nodes' relative address order does NOT track the visit order** (BR and A share a visit order and differ in node order; BR and B share a node order and differ in visit order), so the block cannot substitute for the container hook. NEXT (unchanged, now unblocked): one bounded static read of AssignFleetsAndIssueOrders 0x006c16c0 + the gathering hub TO PLACE A HOOK on the group walk, log (element addr, systemId, minted id) in visit order, x2 processes. Artefacts: `verify/results/shim/br/` **SCOPED 2026-09-09 (lane BS, independently and on a DIFFERENT lineage)**: the three-words-one-site measurement **reproduces exactly** (`calls=3 words=3`, same return address, whole process). **BUT "only mints seeds" holds only on a turn with NO ENCOUNTER.** On the AR continuation's turn 38 - a deep-space encounter auto-resolved peacefully - the same generator ends the process at **87 words**: the 3 seed words plus ~80 `Chance` at `0x006fb6a1` and two `NextInt` pairs. Those 84 words fall **between** the client sweeps, in an interval containing the encounter, and were **NOT bracketed**, so attributing them to the encounter is a **reading, not a measurement**. **H2's verdict is untouched** - the question is whether a foreign draw fires INSIDE an AI bracket, and `foreign_words=0` in 14 of 14 brackets across BS's two runs as well. Only the summary sentence needed the scope. Rule 28's shape, applied to a row I wrote. | | THE FIRST REPLAYABLE RICH-TURN RECORD - a deep AI command block for ad-turn27, on the 80-first branch | control-flow | verified | high | 100% | 2026-09-09 | Lane BR run 2, VM146, the Rung B record of `findings/resolutions/2026-09-09-fleet-id-order-residue.md` section 6 (`findings/control-flow/ai-visit-order-probe.md` section 4.2). `shim.cfg.brdeep` = `shim.cfg.bppin` with ONE non-comment line changed (`aiorders.deep=off` -> `on`); `airng` stays off. Verified: `aicfg words=12 deep=1 research=0 seed=pin pins=4 detours=2`, three `pinned=1`, zero unknown keys. **The record: (`ad-turn27-two-raiders.sav` 1c8baa27..., LOAD -> one End Turn, seeds 32=156ebbbd/496=fe7b2826/512=0ed341d1, build bp-989c692-20260909T0505Z, visit order = list 10's order in the captured block) -> pre `16f63adb...`, post `724528ffde9a7514b69ab9e82ed3b8c8ade63d622c0720de30503a73a92df11e`** - BYTE-IDENTICAL to lane BP's run B (`cmp`, not just the hash). The resolution's stated target was `e913ff41...`; it landed on the OTHER branch and **that costs the record nothing**, because the residual input is written into the block (section 6's own logic): list 10 records the visit order on every captured run. THE DEEP DUMP FOLLOWS EVERYTHING IT WAS SUPPOSED TO: 35 `aivec` rows and 3 `aistr` rows. **List 10's ship vectors** - idx0 (80,1970)<-[5264], idx1 (384,1986)<-[6976], idx2 (384,2002)<-[6992], idx3 (816,7072)<-[11 ship ids]. **List 8's routes** - (2002)->[256], (1970)->[384], (1538)->[240]. Plus list 1's names as strings ("Egg Thief Mk 4", "Egg Thief Mk 5", "Bravestar Mk 3"), list 3's and list 12's vectors (12 elements resolving 3/15/1/5/4/6/20/22/11/7/1/7 ship ids). Under BP's noise mask the deep run's shallow words are ELEMENT-FOR-ELEMENT IDENTICAL to BP's run B, so `deep=on` is additive and does not disturb the block. **TWO CROSS-CHECKS NOW POSSIBLE FOR THE FIRST TIME, BOTH PASS: (1) the block's ship<->fleet pairing matches the save it produced** - list 10 gives fleet 1970 <- ship 5264 at system 80, and `bp-pinB-turn28.sav` is exactly the save where Flt[1970] holds Ship[5264]; the resolution's "the visit order is written into the block" is now verified END TO END, block -> save. **(2) The list-8 move goes to the group at system 80 in BOTH orders** (fleet 1970 with route [384] here; fleet 1986 with the same route in run A - both are the system-80 group), which confirms the resolution's section 3 qualification from the command stream instead of by inference. OUTCOME SET AFTER FIVE PROCESSES ON THIS STATE: `e913ff41...` x3 (BP's L unpinned, BP's A pinned, BR's probe pinned+airng, all 384-first), `724528ff...` x2 (BP's B, BR's deep, both 80-first). **NO THIRD FILE IN FIVE PROCESSES, ACROSS THREE INSTRUMENT CONFIGURATIONS**, with both members reproduced at least twice - the residue is a small enumerable order, which is what C-set's shape needs. Not a proof that k=2. Artefacts: `verify/results/shim/br/BR2-deep-aiorders.txt`, `BR2-shim.log`, `shim.cfg.brdeep`; the save is byte-identical to `verify/results/saves/bp-pinB-turn28.sav` and is deliberately not duplicated | | CORRECTION: the raid-intercept species gate has THREE short-circuits, and HIVER is in two of them | control-flow | verified | high | 100% | 2026-09-09 | **Lane AZ**, static, `findings/control-flow/raid-intercept-species-word.md`. The campaign's published sentence - lane AR section 4.2, lane AG section 5.2, and my own brief - is *"a Human or Zuul raider draws nothing; every other species draws a word"*. **Incomplete on both sides of the relation.** `FUN_00820af0` short-circuits on THREE disjuncts, decoded to the next function start: **SC1 `cmp [routeOwner+0x5c],1` at 0x00820bc2** - the ROUTE OWNER's `Species`, so a HIVER-owned route is intercepted with no draw WHOEVER raids it; **SC2 `cmp eax,1` at 0x00820bd7** on `StarFleet_GetCrewSpeciesForIntercept(raider)` - a HIVER raider draws nothing, and this is an ordinary `== 1` test with nothing to do with `SpeciesDef+0x144`; **SC3 `SpeciesDef_HasInterceptFlag` at 0x00820bed** - Human (0) and Zuul (5) only, which is the one the campaign had. So `0x00820c1b` draws only for a raider of species **2 Tarkas, 3 Liir, 6 Morrigi** (or 4 `_NPC`) against a route owned by a **non-Hiver**. **AND THE POLARITY IS INVERTED IN BOTH PUBLISHED RENDERINGS**: the short-circuit arm sets **frac = 0.0**, not 1.0 (`fldz; fstp [ebp+0xc]` at 0x00820bf8; the draw arm computes `0.0 + (1.0-0.0)*NextFloat()`), so a Human/Zuul/Hiver interception happens at the raided route's SOURCE end. Word counts unaffected; the sentence is wrong (rule 28 practice 6 - read the polarity before the count). **Species enum named from the image**: `SpeciesDef_InitTable 0x005453a0` dispatches through the jump table at **0x00545b60**, whose seven entries READ AS BYTES give `0 Human, 1 HIVER, 2 TARKAS, 3 LIIR, 4 _NPC, 5 Zuul, 6 MORRIGI` - the case bodies are NOT laid out in case order, so reading the disassembly top-to-bottom gives the wrong enum. This agrees with lane AP's independent decode of the save's `ISsp` list on all seven. **And the tech data closes SC2 for players**: `CCC_ComRaid` is **0% for Hiver** on both of its edges (`CCC_FTLBrdB->CCC_ComRaid` and `CCC_FTLEcon->CCC_ComRaid`), so a Hiver empire can never raid and SC2 is unreachable through `vslot13` for any player | | FIRST TARKA SAVE IN THE CORPUS - and two AI raiders are already parked on sector nodes | verify | verified | high | 100% | 2026-09-09 | Lane AZ, VM141, `verify/results/saves/az-turn23-tarka-comraid.sav` (`3d5eb826...`, 89,285 B, turn 23, `--strict` 0 error 0 warn, resyncs 0, hint-failures 0). A fresh 2-player custom game with the species pool cut to **Tarkas only** (lane V's Zuul trick), so **both empires are species 2** - the first playable non-Human, non-Zuul empire the campaign has. `CCC_FTLBrdB` came free in the 15 starting techs, `CCC_FTLEcon` took 4 turns and `CCC_ComRaid` 3 more at Research Efficiency 150%, so **Commerce Raiding by turn 10**. Three AI trade routes (`tro 32`, `trfr` 4, 27, 27). **FIVE AI TARKA FLEETS ARE PARKED ON TRADE-SECTOR NODES WITH `Pos` BIT-EQUAL**, and two of them clear G0-G4: `Rho Fleet` (274, 6 ships, `LocID 768`, `FtFlg 0x80c`) and `Escorts` (3344, 6 ships, `LocID 752`, `FtFlg 0xc00`). The other three are rejected at **G3c** exactly as lane AG's decode says - `tsct` bit 1 is set on 752 and 800 (the AI trades in its own sectors) and they lack `FtFlg & 0x800`; `Escorts` sits on the SAME NODE as `Freighters` 3248 and differs only in that bit. **COMMITTED PREDICTION, one `probes=8` run to settle: `k = 2` on this save with the player owning NO fleets, so `Slot13RngCalleeA` is entered exactly twice per turn and `0x00820e18` reads calls == words == 2.** `B` will still cost 0 - every route is `tro 32` and the qualifying raiders are owned by 32, so `PlayerAlliances_Relation` returns 3 for self and `G_B3` empties the candidate list | @@ -443,3 +443,6 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | WORKLOAD BLOCKED, and the failed conjunct is G_B3 not the species gate | control-flow | in-progress | — | 60% | 2026-09-09 | Lane AZ. `z` - the `NextFloat` at `0x00820c1b` charged to `Slot13RngCalleeB` - is **still unobserved**, and this lane did not run an instrument at all (`hooks=off` throughout, no `shim.cfg.hp8` ever copied). What it built is a state that satisfies **SC1, SC2, SC3 and G0-G4** and fails only **G_B3**: the qualifying raiders are the AI's and every route is the AI's own, so `PlayerAlliances_Relation` returns **3 for self**, `B` rejects on `> 0` and returns at `G_B4` with 0 words. **THE CHEAPEST NEXT WORKLOAD IS NAMED FROM THAT CONJUNCT AND NEEDS NO FLEET MOVEMENT AT ALL**: give **player 0** a trade route sourced at `Ku'Paaka` (index 17) or `Ka'Palum` (index 26), both player-0 colonies and both members of **sector 768**, where the AI's `Rho Fleet` is already parked and already clears G0-G4. Then a success for `Rho Fleet` puts a player-0 route in `B`'s candidate list at relation **0 = war**, `0x0088b613` fires, and `FUN_00820af0` runs with a Tarka raider against a Tarka owner - all three short-circuits fail and **`z` draws**. Two failures worth not repeating: the 16-destroyer raider fleet was **destroyed** staging through `Ku'Valt`, a sector-752 MEMBER SYSTEM that is an AI colony (order to the NODE, never through a member), and a blind "auto-resolve peacefully" click sequence **does not resolve a real battle** - peaceful is not offered when both sides have ships | | GUEST GOTCHA: `rdrag` ROTATES the star map, and that is how you aim at a crowded sector node | meta | verified | high | 100% | 2026-09-09 | Lane AZ, VM141. Lane AR's recipe - fit `screen = (A*wx+B*wz+C, D*wx+E*wz+F)` from two known points and land on any node first try - **does not generalise to a crowded map**. On lane AZ's map the two route-sourcing sector nodes lie **2.4 ly from `Ke'Sothram`** and **2.6 ly from `Ka'Sogroth`**, the Move-mode hover snaps to the nearest **system** over a radius of well over 100 screen pixels, and twelve grid probes all named a system. The offset from star to node points nearly **along the camera axis** and foreshortens to ~30 px however far you zoom in. **THE FIX IS ONE GESTURE: `rdrag` on the star map ROTATES the camera** (verified, reversible, the whole field re-projects). Left-drag does NOT pan, the arrow keys do nothing, and **the camera does not follow the selection** - it moves only when the game moves it (a combat, a fleet order). Also: **`wheel` DOES zoom, on the star map AND the research tree**, toward the screen centre - board row 374's "wheel-zoom does nothing useful" is true of PANNING the tech tree, not of zooming, and `wheel x y -120 3` is what made the top-row `CCC` nodes clickable when the `Research` title bar and `Savings` panel were sitting on top of them. **A research node under a HUD panel is not clickable and the click is eaten silently** - no preview appears and nothing tells you why | | MY BRIEF TO LANE AZ NAMED THE WRONG GATE | meta | verified | med | 100% | 2026-09-09 | I told AZ that `0x00820c1b`'s only species short-circuit was `SpeciesDef+0x144` and that **five** species qualify for the `z` word. **Both halves wrong**, and AZ found it statically before touching a guest: there are **three** short-circuits, and **HIVER is in two of them** - once as the route owner, once as the raider's crew, the latter a plain `cmp eax,1` with nothing to do with `SpeciesDef+0x144`. Four species qualify, not five. I inherited the incomplete sentence from lanes AG and AR and passed it on as fact in a brief whose whole purpose was to test that gate. **The lane checked the gate it was sent to test rather than trusting the brief** - which is the behaviour the brief asked for and the reason nothing was measured wrongly | +| THE PER-HISTORY RESIDUE IS A TASK THAT THE SAVE DOES NOT CARRY - a Colonize task alive on turn 39 by continuation and ABSENT after a load, measured end to end | control-flow | verified | high | 100% | 2026-09-09 | **Lane BS**, VM144, `findings/control-flow/per-history-residue.md`. Predictions committed before the build was deployed (commit 15c4471). Two instrumented runs of the AR lineage to turn 39, `aiorders=on` + 16 aiprobes + the `airng` OnResumePlaying bracket, no pin, all 27 template hooks off by name. **INSTRUMENT NEUTRALITY CHECKED AT k = 1 ON BOTH ROUTES AND PASSED BYTE FOR BYTE** - continuation `15b99255...`/`7a8b3d5e...` (lane AR's three hooks=off processes), load `33e30092...`/`4c356f59...` (lane BQ's two). **THE ANSWER: `AITColonize::Execute` is entered TWICE (once per pass) in the continuation and ZERO times after a load**, while `RunTaskList` is 6 in both (3 AI clients x 2 passes), `AcquireFleetsForTask` is 12 in both and six of the eight task Execute entries are identical. It is the FIRST task in pid 32's list on both of the continuation's turns, and it is the task that reaches the pass-1 emission exits: `AssignFleetsAndIssueOrders` 2 vs **0** and `IssueRouteForFleets` 2 vs **0** - the fleet-gathering hub is NOT REACHED AT ALL on the load route. Consequence in the block: the continuation's turn-39 pid-32 block carries `list=8 idx=0 ints=[ 1570 ... ]` (Zeta Fleet V) and one extra `list=12` element `[ 914 ... ]` (Nu Fleet III), and the load's block carries NEITHER - list 8 is entirely absent. **EVERY ONE OF THE 23 DIVERGING SAVE LEAVES HAS A BLOCK-SIDE COUNTERPART** (15 on Flt[1570], 3 on Sys[432], 2 on Flt[914], plus ModCount/Checksum/NPrvVa), so nothing diverged in the SERVER's application of the block and candidate 3 (server-side state) is disfavoured. **RNG IS EXCLUDED BY MEASUREMENT: `foreign_words=0 foreign_calls=0 residual=0` in 14 of 14 brackets across both runs, and the per-process global generator 0x00af6e58 took ZERO words inside any AI bracket** (it moved 3 -> 87 words across the continuation's turn 38, entirely OUTSIDE the AI brackets - that is the combat turn). Per-client words turn 39: pid 32 = 4 (continuation) vs 5 (load), 496 and 512 = 0 on both; the ONE extra word is in the LOAD, a Chance at ret_rva 0x0029086f inside AITBuildPoliceShips::Execute - downstream of the task difference, not its cost. Pre-turn states differ in EXACTLY ONE LEAF, `/CD[1]/NPrvVa` +5.00 (BQ's correction re-measured under an instrument). VERDICT: **resolution 09-09 §9.2 candidate 1 SURVIVES and is now measured rather than inferred**; candidate 2 (stream position) does not explain a task that is not there (and the routes DO differ in stream position, so this run does not exclude it on that ground - the seed-insensitivity of both routes does); candidate 3 is disfavoured. FALSIFIER, one lane-hour: hook the task vector at `RunTaskList` entry and log `{count, per-element vtable}` for pid 32 on both routes - under this verdict the continuation's list holds a colonise task at turn-39 entry and the load's does not, and the counts differ by exactly one. **SCOPE CONFIRMED: every byte-match claim in every rung is a claim about a load->turn procedure, and that is the definition of the comparison, not a defect to fix** | +| TWO PREDICTIONS FAILED, BOTH BECAUSE THE LOAD ROUTE DOES LESS THAN ANYONE EXPECTED - and one block difference nobody predicted | meta | verified | high | 100% | 2026-09-09 | Lane BS, from the same runs. (1) **P1's list-14 clause FALSIFIED**: the continuation's turn-39 block has NO list 14 AT ALL - list 14 is emitted on turn 38 (six elements, for the two fleets minted there), and on turn 39 `IssueRouteForFleets` is entered twice and emits nothing. So "a list-8 element and its list-14 pair" was wrong about the shape of a move order. (2) **P2's "probe 11 is entered in BOTH routes" FALSIFIED**: `AssignFleetsAndIssueOrders` is entered 2x in the continuation and **0x** in the load. The brief and I both expected the load to run the same machinery to a different answer; it does not run the machinery. (3) **UNPREDICTED AND IT STRENGTHENS THE RESULT**: the block ALSO differs by one `list=12` element, fleet **914**, which is the counterpart of the OTHER save-side divergence (`Flt[914 "Nu Fleet III"]` HLay False->True, Lay only-in-load). I predicted half the block difference and the other half was there waiting - which is what turns "the AI emitted a move order" into "**every** diverging leaf is in the block". List 12's elements are fleet ids (274 290 306 322 626 642 786 882 [914] 930 1746 2338); its meaning is NOT decoded and the causal direction is NOT established (rule 20) - one watchpoint would settle it | +| A TURN THAT MINTED TWO NEW FLEET IDS DID NOT VARY - four processes, byte-identical, on a turn whose visit order was exercised | control-flow | verified | med | 100% | 2026-09-09 | Lane BS, VM144, a by-product of the continuation run. Turn 38 of the AR lineage IS a fleet-assignment turn: `AssignFleetsAndIssueOrders` entered **6x**, list 10 carries four `{systemId, fleetId}` elements `(384,2466) (384,2178) (336,2482) (384,2338)`, and decoding by `id = (counter << 4) | node` (Player[32] = node 2) all four are CLIENT-MINTED - with **2466 (counter 154) and 2482 (counter 155) absent from `ar-turn37-816raiders.sav`**, i.e. two fleets minted on this turn, in that order. That turn's output is `15b99255...`, produced by **lane AR's three `hooks=off` processes AND this instrumented run - four processes, byte for byte**. So the fleet-group visit order was exercised over two new fleets and its **outcome set was 1**. This does NOT contradict lane BP (different turn, different groups, and BP's outcome set of 2 rests on two observations) but it BOUNDS the claim: **a turn that mints new fleet ids is not thereby a turn whose visit order varies.** One turn, one datum, handed to lane BR for stage 2 - if the container is address-keyed, this turn is a case where two same-size allocations landed in the same relative order in four processes, which the LFH randomisation model has to accommodate | diff --git a/guides/method-rules.md b/guides/method-rules.md index fffb94e..b1b2d8e 100644 --- a/guides/method-rules.md +++ b/guides/method-rules.md @@ -418,7 +418,12 @@ mechanism. > *"no combat occurs"* — the defender's planet still fires, and its kill count varied. > * **A fourth term is not a predicate on the save at all.** The same turn ran one way by > continuation and another way after a load, **both reproducibly** — so exposure is a property of -> `(save, procedure, load history)`, not of `(save, turn)`. The instruction to record a pair as +> `(save, procedure, load history)`, not of `(save, turn)`. **The mechanism is now measured +> (lane BS): the difference is that the load route does not run the machinery at all.** A +> `Colonize` task alive in the AI agent by continuation is simply *absent* after a load — +> `AITColonize::Execute` fires twice one way and zero times the other, and the fleet-gathering hub +> is never reached. AI agent state that the save does not carry is a real input, and no amount of +> reading the save will find it. The instruction to record a pair as > `(save, procedure, hashes)` was already right, and is now load-bearing for a reason it did not > anticipate. >