diff --git a/campaign/DASHBOARD.md b/campaign/DASHBOARD.md index ba2ee3b..d84def3 100644 --- a/campaign/DASHBOARD.md +++ b/campaign/DASHBOARD.md @@ -1,16 +1,16 @@ # SotS RE campaign — coverage dashboard -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` +Generated 2026-09-09 07:39 UTC · `sots-re` @ 696935e,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) -441 targets · mapped-or-better **393/441** `[█████████░] 89%` · verified **351/441** `[████████░░] 80%` +442 targets · mapped-or-better **394/442** `[█████████░] 89%` · verified **352/442** `[████████░░] 80%` | Status | Count | % | |---|---:|---:| -| verified | 351 | 80% | +| verified | 352 | 80% | | mapped | 42 | 10% | | in-progress | 5 | 1% | | backlog | 41 | 9% | @@ -19,7 +19,7 @@ Generated 2026-09-09 07:14 UTC · `sots-re` @ 1bae655,2026-09-09 · `sots-engine | Type | verified | mapped | in-progress | backlog | blocked | total | |---|---:|---:|---:|---:|---:|---:| | objects | 46 | 6 | 0 | 3 | 1 | 56 | -| control-flow | 40 | 2 | 1 | 0 | 0 | 43 | +| control-flow | 41 | 2 | 1 | 0 | 0 | 44 | | subsystems | 4 | 8 | 0 | 2 | 1 | 15 | | engine | 31 | 0 | 0 | 0 | 0 | 31 | | verify | 105 | 15 | 3 | 35 | 0 | 158 | @@ -133,11 +133,11 @@ Most recent open: ## 9. Delta since previous dashboard -- verified targets: 348 → 351 (+3) · mapped-or-better: 390 → 393 (+3) +- verified targets: 351 → 352 (+1) · mapped-or-better: 393 → 394 (+1) - engine LOC: 58,647 → 58,647 (+0) · test files: 122 → 122 (+0) · checks: 4,257 → 4,257 (+0) -- addresses verified: 1,160 → 1,163 (+3) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0) +- addresses verified: 1,163 → 1,163 (+0) · 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 09bb824..7c02f4f 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. **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. | +| 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. **VM146 = FREE (lane BU released 2026-09-09 03:40 restored** and hash-verified: SavedGames back to the 9-file pre-BU set, autosaves byte-identical to `ui\preBU\`, `shim.cfg` `hooks=off`, `binkw32.dll` restored, game **not running, exactly as found**). Load geometry re-verified in all three runs, unchanged. **THREE NEW GOTCHAS.** (1) **The file to restore over `C:\SOTS\binkw32.dll` is `ui\preBP\binkw32.dll`, NOT `binkw32_real.dll`** - BU restored the real DLL first and had to correct it. (2) **PowerShell `.ps1` execution is DISABLED**: run helpers as `powershell -NoProfile -ExecutionPolicy Bypass -File `. (3) **`scp` refuses two remote files with parenthesised names at once** - fetch autosaves one at a time. **TIMING CORRECTION: the turn-27 load is ~1.5 min on a WARM guest, not BP's 3.5-4**, and **the AI client seeds are minted on the LOAD path, ~40 s before the map draws**. | | 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 | @@ -446,3 +446,4 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | 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 | +| THE AI'S FLEET-VISIT ORDER IS AN ADDRESS-KEYED CONTAINER AND THE KEY IS THE FLEET'S `Location*` - H1 CONFIRMED, H1b DEAD, and the campaign's two-file outcome set IS the two orderings of two heap pointers | control-flow | verified | high | 100% | 2026-09-09 | Lane BU, VM146, stage 2 of the chain lane BR unblocked (`findings/control-flow/fleet-visit-order-mechanism.md`). Build `bu-55408a9-20260909T071101Z`, fresh CT111 tree (rule 24), lane worktree (rule 21), `shim.cfg.bupin` = `shim.cfg.bppin` with EXACTLY THREE non-comment lines added (`aivisit=on/.out/.ships`), diffed against the real bppin PULLED OFF THE GUEST and quoted in the finding, marked `# exhaustive` so `tools/check_shim_configs.py` ENFORCES that all 27 registered hooks are named. THREE fresh processes, route LOAD, seeds pinned to lane L's observed values; 28 of 28 hooks off, zero unknown keys, zero COVERAGE, 3/3 `pinned=1` in every run, three `aivisit ... MH_OK` in every run, `exe base=0x005e0000` for the 8th process on this guest. THE HOOK: `AssignFleetsAndIssueOrders 0x006c16c0` walks a `std::vector` by index (cursor `[ebp-0x38]`, `_Mylast` REFETCHED every iteration, back-edge `jne 0x6c17e0` at 0x006c21be), and that walk is BRACKETED BY TWO LOOPS OVER THE SAME VECTOR that call one function each - **`StrategyAIAgent::ClaimShipsOfFleet 0x006a4290` and `ReleaseShipsOfFleet 0x0069da10`, which have EXACTLY ONE CALLER EACH IN THE WHOLE IMAGE and it is that function**. So the instrument is two ordinary function-entry detours plus a bracket on 0x006c16c0, with NO return-address filter and NO mid-function patch - the loop body could not be patched anyway, its first instruction 0x006c17e6 IS a branch target. **RESULT: the visit order is NOT ascending element address (0 of 6 multi-element sequences over three processes), NOT ascending fleet id (0/6), NOT ascending systemId (0/6), NOT ascending minimum ship id (0/6). It is ASCENDING `fleet->Location` (StarFleet+0xa0): 6 OF 6**, with the fleet pointer breaking the one tie (two fleets at system 384 share one interned Location object and are ordered by element address within it). So the container is address-keyed and the comparator is lexicographic in (Location*, StarFleet*), BOTH heap addresses. **P3 - the committed prediction, "the visit order is ascending element address" - IS FALSIFIED, and the hypothesis class it tested is CONFIRMED with a sharper key.** THE CROSS-PROCESS PROOF, and it does not rest on one sample: three processes visited THE SAME SIX FLEETS IN THREE DIFFERENT ORDERS (run1 1970/1602/1986/354/1570/1346; run2 1602/1970/1986/354/1346/1570; run3 1970/1986/1602/354/1570/1346) and EVERY difference is a pair whose Location addresses exchanged relative order. Runs 1 and 2 wrote BYTE-IDENTICAL autosaves and still visited in different orders - the reordered pairs were pre-existing fleets, which is why the save did not move. **AND THE BRANCH FLIP IS MEASURED: run 3's `loc(system-80 group) = 0x333ed4c8 < loc(system-384 group) = 0x333ed710`, the OPPOSITE of runs 1 and 2, it visited system 80 first, and its autosave is `724528ff...` BYTE-IDENTICAL (cmp) to lane BP's run B - while runs 1 and 2 have `loc(384) < loc(80)`, visit 384 first, and are BYTE-IDENTICAL to BP's runs A and L.** So the campaign's two-file outcome set on `ad-turn27` IS the two orderings of two heap pointers. **H1b (an uninitialised-word comparator) is EXCLUDED for this path**: an uninitialised key cannot reproduce a strict total order by a specific live pointer field in 6 of 6 sequences and cannot track that field across a branch flip. **A SECOND FINDING THE STATIC READ HAD MISSED: the newly minted fleet ids are ALREADY ON THE FLEET OBJECTS when the head loop first touches them** (`fid=1970` on the element at idx=0 of the first burst, before the pass gate and before any emission), so `AssignFleetsAndIssueOrders` INHERITS the id-to-group pairing rather than deciding it; the mint is upstream in the gather (`AcquireFleetsForTask 0x006ceef0` + 0x006abf80/0x006b7c90/0x006cb310), and since the delivered vector is Location-ordered and the ids follow that order, the natural reading is that the SAME container orders the mint (INFERENCE - the gather was not hooked). ENGINE CONSEQUENCE, and it MOVES deliverable 2 by one level: the canonical order must be imposed WHERE THE GROUP SET IS GATHERED AND THE IDS ARE MINTED, not at the assignment step, or the engine canonicalises the emission order while leaving the minting order to its own container. On the choice of canonical order this lane has evidence rather than convention: the original's order is NOT ascending systemId and NOT ascending minimum ship id in ANY of the three processes, so THERE IS NO ORIGINAL ORDER TO MATCH and `(systemId, min ship id)` is as good as any - keep it, and keep the tie-break, because the original's own tie-break is a second pointer. RULE 26(d) AND RULE 19, BOTH MET BY MEASUREMENT: runs 1 and 2 are BYTE-IDENTICAL to lane BP's UNPINNED run L, so a process carrying a seed pin PLUS three new detours inside the AI's fleet-assignment path reproduced a natural run byte for byte, twice; run 3 reproduced BP's other branch byte for byte. `aivisit` is behaviourally neutral on this state, measured, not argued. P1/P2/P4/P5 all hold; under BP's noise mask every run's block differs from BP's same-branch run in NOTHING outside the noise set and from the other branch in EXACTLY the three transposition words. Rule 17 discharged: 0x006c16c0's body is 0x006c16c0-0x006c247a `ret` with a FOUR-ENTRY JUMP TABLE living PAST the ret at 0x006c247c (target of `jmp [eax*4+0x6c247c]` at 0x006c22fb). Six more per-process AI seeds, none shared - L1 reproduced a 6th and 7th time. Artefacts: `verify/results/shim/bu/`; the three output saves are byte-identical to `bp-pinA-turn28.sav` x2 and `bp-pinB-turn28.sav` x1 and are deliberately not duplicated |