Compare commits
2 commits
e935ec5880
...
0029d022f2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0029d022f2 | ||
|
|
1fecff8af0 |
6 changed files with 515 additions and 12 deletions
|
|
@ -1,16 +1,16 @@
|
|||
# SotS RE campaign — coverage dashboard
|
||||
|
||||
Generated 2026-09-09 04:39 UTC · `sots-re` @ c37eb0e,2026-09-09 · `sots-engine` @ 989c692,2026-09-08 (240 commits) · regenerate with `tools/dashboard.py`
|
||||
Generated 2026-09-09 04:56 UTC · `sots-re` @ 1fecff8,2026-09-09 · `sots-engine` @ 989c692,2026-09-08 (240 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)
|
||||
|
||||
418 targets · mapped-or-better **371/418** `[█████████░] 89%` · verified **329/418** `[████████░░] 79%`
|
||||
419 targets · mapped-or-better **372/419** `[█████████░] 89%` · verified **330/419** `[████████░░] 79%`
|
||||
|
||||
| Status | Count | % |
|
||||
|---|---:|---:|
|
||||
| verified | 329 | 79% |
|
||||
| verified | 330 | 79% |
|
||||
| mapped | 42 | 10% |
|
||||
| in-progress | 4 | 1% |
|
||||
| backlog | 41 | 10% |
|
||||
|
|
@ -24,21 +24,21 @@ Generated 2026-09-09 04:39 UTC · `sots-re` @ c37eb0e,2026-09-09 · `sots-engine
|
|||
| engine | 30 | 0 | 0 | 0 | 0 | 30 |
|
||||
| verify | 102 | 15 | 3 | 35 | 0 | 155 |
|
||||
| phase2 | 13 | 3 | 1 | 0 | 0 | 17 |
|
||||
| meta | 83 | 6 | 0 | 1 | 0 | 90 |
|
||||
| meta | 84 | 6 | 0 | 1 | 0 | 91 |
|
||||
| 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): **1282**, verified **1151** `[█████████░] 90%`
|
||||
- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1283**, verified **1152** `[█████████░] 90%`
|
||||
|
||||
## 3. Data layer
|
||||
|
||||
- Catalogs: **1,595/1,595** files parsed (91 block kinds in `schema_stats.json`), dangling cross-refs **0** (`crosslink.json`)
|
||||
- Oracle `mars-parse`: **1,531/1,531** files agree `[██████████] 100%`
|
||||
- Oracle `mars-text`: **64/64** files agree `[██████████] 100%`
|
||||
- Saves: **33/33** real saves strict-clean — strict exit 0, 0 errors, 0 warnings
|
||||
- Saves: **35/35** real saves strict-clean — strict exit 0, 0 errors, 0 warnings
|
||||
- Design rules: **127/127** stock designs pass `[██████████] 100%`
|
||||
- Value domains: **490/724** typed fields have been seen to vary `[███████░░░] 68%` — the other **234** have only ever held one value across the corpus, so their typing is untested (`value-domain-census.md`)
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ Detail: `verify/results/standalone/report.txt`.
|
|||
|
||||
## 7. Verification ledger
|
||||
|
||||
- ✅ Saves strict: 33/33 (strict exit 0, 0 errors, 0 warnings)
|
||||
- ✅ Saves strict: 35/35 (strict exit 0, 0 errors, 0 warnings)
|
||||
- ✅ Design rules: 127/127
|
||||
- ✅ oracle mars-parse 1531/1531 · ✅ oracle mars-text 64/64
|
||||
- ✅ Compare harness present (`verify/harness/compare/`)
|
||||
|
|
@ -133,11 +133,11 @@ Most recent open:
|
|||
|
||||
## 9. Delta since previous dashboard
|
||||
|
||||
- verified targets: 325 → 329 (+4) · mapped-or-better: 367 → 371 (+4)
|
||||
- verified targets: 329 → 330 (+1) · mapped-or-better: 371 → 372 (+1)
|
||||
- engine LOC: 58,647 → 58,647 (+0) · test files: 122 → 122 (+0) · checks: 4,257 → 4,257 (+0)
|
||||
- addresses verified: 1,152 → 1,151 (-1) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0)
|
||||
- addresses verified: 1,151 → 1,152 (+1) · 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
|
||||
<!-- dashboard-metrics {"verified": 329, "mapped_plus": 371, "targets": 418, "loc": 58647, "tests": 122, "checks": 4257, "addr_verified": 1151, "addr_total": 1282, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
||||
<!-- dashboard-metrics {"verified": 330, "mapped_plus": 372, "targets": 419, "loc": 58647, "tests": 122, "checks": 4257, "addr_verified": 1152, "addr_total": 1283, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`).
|
|||
| CORRECTION: `CreateRaidEncounter` success is not 0-or-1 words | control-flow | verified | high | 100% | 2026-09-09 | `tail-rng-ledger.md` 11.1's **"a success costs 0 or 1 further word"** is right about the **corpus** and wrong about the **code**. A success with a **non-empty** candidate list reaches **five** further draw sites through `0x00892640` (`0x0088f1eb`, `0x0088f356`, `0x0083b460`, `0x00848fd9`, `0x00820c1b`), each a `NextInt` with its own rejection loop. Lane AG 5.1. The firing-indexed table could not hold these because no corpus state has ever had a non-empty list |
|
||||
| `Mars::RNG::Chance` modelled, with the zero-word cases and the NaN word | engine | verified | high | 100% | 2026-09-09 | Acting on lane AG's warning. Body read in full at `0x008e6dd0` (94 bytes, via the ReVa HTTP fallback - the MCP link was down): **`p <= 0` returns false and `p >= 1` returns true, each WITHOUT a draw**; in between exactly one `NextFloat` compared with a **strict `<`**. Now `MT19937::chance()` in the engine with tests pinning all four cases, the accumulating 0.2f-per-turn pattern (4 words then nothing for ever), and the strict comparison. **The NaN case is reproduced, not smoothed**: both early-outs are pairs of ordered comparisons that a NaN makes false, so a NaN probability falls through, **draws a word**, and returns false - hiding that would hide a real divergence. Engine `989c692`; `docs/mars-rng.md` updated. Rationale: a model without the early-outs is one word out of step from the fifth turn of every counter-mission onward, permanently, and one word of drift is the whole determinism claim |
|
||||
| The trade-raid roll is PER FLEET: 2 raiders on one sector = 2 entries, 2 words; B returns without drawing | control-flow | verified | high | 100% | 2026-09-08 | Lane AD, VM141, `findings/control-flow/raid-gate-multiplicity.md`. Two single-cruiser fleets parked on sector 6 (TradeID 832) from ac-turn22-raider.sav: `TradeManager::Slot13RngCalleeA` entered **2x** per End Turn on BOTH measured turns against lane AC's 1, `OnAllCombatDone_Tail` costs **2** words against AC's 1, and the return-address ledger prices the site exactly - 0x00820e18 calls=2 words=2, bracket residual 0. H-sector (one roll per sector) is DEAD; the cost is `sum over qualifying fleets`. `vslot13` is still entered ONCE per turn, so the multiplicity is the caller's loop over StrategyServer+0x64, exactly as AC read it. Instrument `probes=8` (the byte-neutral set - NOT 11), shim `ad-0c6d0a3-20260909T0159Z`, cfg shim.cfg.hp8 unmodified, own build dir /srv/re-lab/build/sots-engine-ad rm -rf'd first. CONSTANTS READ FROM THE IMAGE (rule 23, all WIDENED FLOATS): ODDS_CR 0x009e20d8 = (double)0.2f, ODDS_DE 0x009e5060 = (double)0.05f, PER_SHIP 0x009e31c0 = (double)0.01f, and a per-ship scale 0x009f8d48 = 0.33f that REDUCES the odds when ship+0x18 & 0x100000. One-cruiser fleet odds = 0.21000000275671482; six rolls across AC+AD gave two successes (expectation 1.26) - consistent, not validated. `Slot13RngCalleeB` entered 1x on turn 28 and cost **0 words** by return-address attribution - and lane AG's reading that RNG_NextInt has NO zero-bound early-out turns that into a PROOF that B returned before its target pick, i.e. the candidate list was empty (G_B4), reproduced with a fleet AC never had. trdmgr holds 3 routes, trfr 18/14/14, sourced in sectors 816 and 768 - NONE in 832 |
|
||||
| NO ORACLE PAIR for the turn-27 raider state - the control varies, but ONLY in the AI's decisions, and /Sim/RNG is bit-identical across three processes | meta | verified | high | 100% | 2026-09-08 | Lane AD (rule 26). Two `hooks=off` runs of one End Turn from ad-turn27-two-raiders.sav in two fresh processes gave DIFFERENT post-turn autosaves (a634510e / 676b1778); the pre-turn autosave is byte-identical in all three processes (16f63adb), so the load path is deterministic and the divergence is inside the turn. So NO rung-A calibration pair came out of this state and none is proposed. BUT the state-checksum localises the variation completely: 94 leaves, ALL of them Player[32 "The Eternal Empire"] designs/ShipRecs/odes/build queues/fleet ids and positions, plus ModCount, NumFlts, the three id lists and Summary.Checksum. `/Sim/RNG` = 1e458a997f51bbdf and `/Sim/trdmgr` = 89643da6fabb386b in ALL THREE post-turn saves (two hooks=off and one probes=8), and NO trade-sector, trdmgr or player-0 fleet leaf appears in either diff. Two consequences: (a) every number lane AD reports is read off a sub-tree the control reproduces bit-for-bit; (b) RULE 19, on this state: the probes=8 + draw_sites + boundary-ledger instrument is behaviour-neutral on every leaf OUTSIDE the AI-decision sub-tree, including the serialised strategic generator. The named next step is a RUNG B pair - `--turn-commands` replay runs no AI, so a captured command stream should make this state reproducible where Rung A cannot |
|
||||
| NO ORACLE PAIR for the turn-27 raider state - the control varies, but ONLY in the AI's decisions, and /Sim/RNG is bit-identical across three processes | meta | verified | high | 100% | 2026-09-08 | Lane AD (rule 26). Two `hooks=off` runs of one End Turn from ad-turn27-two-raiders.sav in two fresh processes gave DIFFERENT post-turn autosaves (a634510e / 676b1778); the pre-turn autosave is byte-identical in all three processes (16f63adb), so the load path is deterministic and the divergence is inside the turn. So NO rung-A calibration pair came out of this state and none is proposed. BUT the state-checksum localises the variation completely: 94 leaves, ALL of them Player[32 "The Eternal Empire"] designs/ShipRecs/odes/build queues/fleet ids and positions, plus ModCount, NumFlts, the three id lists and Summary.Checksum. `/Sim/RNG` = 1e458a997f51bbdf and `/Sim/trdmgr` = 89643da6fabb386b in ALL THREE post-turn saves (two hooks=off and one probes=8), and NO trade-sector, trdmgr or player-0 fleet leaf appears in either diff. Two consequences: (a) every number lane AD reports is read off a sub-tree the control reproduces bit-for-bit; (b) RULE 19, on this state: the probes=8 + draw_sites + boundary-ledger instrument is behaviour-neutral on every leaf OUTSIDE the AI-decision sub-tree, including the serialised strategic generator. The named next step is a RUNG B pair - `--turn-commands` replay runs no AI, so a captured command stream should make this state reproducible where Rung A cannot **EXPLAINED IN PART 2026-09-09 (resolver)**: the variation is the AI's **build / fleet-assignment / colony** layer and the **id-allocation ORDER** downstream of it - **NOT** the design content (the two bodies are byte-identical apart from `DesID`) and **NOT** a research pick (`ResTNm` held). **Consumer unidentified**; the pin probe on this state (VM146) decides whether it is the seed at all. |
|
||||
| Sector 816 is UNREACHABLE from lane AC's empire - the AG probe needs a 27 ly hull, and one is already buildable | control-flow | verified | high | 100% | 2026-09-08 | Lane AD, measured from ad-turn27-two-raiders.sav geometry + the Build screen. Node distances from the human's only two colonies (Epsilon Eridani idx 0, Downbelow idx 12) against a 9.0 ly cruiser range: sector 816 = 15.66 / 12.12, sector 768 = 11.53 / 10.14, sector 752 = 12.85 / 8.43, sector 800 = 9.37 / 11.77, sector 784 = 9.36 / 3.49, sector 832 = 4.99 / 4.56. The only two sectors IN range (832, 784) source no route; the only two that source routes (816 via trfr 18, 768 via trfr 14 x2) are out of range. With Trade View on, only sector 6's cube renders at any zoom, so no other sector node is even a clickable move target. THE FIX IS ALREADY UNLOCKED: the stock `Extended Range` DESTROYER has Range 27.0, construction cost 2,252, node speed 4.0 - ~1-2 turns to build, ~4 turns to sector 816's node, so AG's probe is ~6 turns of play and needs no research. TWO WARNINGS: a destroyer takes the nDE odds branch, 0.05f + 0.01f = 0.06 (0.12 if the AI Freighters fleet in 816 satisfies the doubling), i.e. a 1-in-8 success per fleet per turn - send several fleets or measure many turns; and sector 816's tsct = 2 is the AI's bit, not player 0's, so no FtFlg & 0x800 is required there, exactly as on 832 **REACHED 2026-09-09 (lane AR) exactly as costed**: five stock Extended Range destroyers (Range 27.0, 2,252 each) built at Epsilon Eridani over turns 28-31, split into four fleets, ETA 4 turns, parked on sector 5's node turn 35. **AD's geometry table and its build costing are exact.** Two things AD's recipe did not say: a new ship **JOINS an existing fleet** and a fleet's Range is the **MINIMUM over its ships**, so the 9-ly cruiser must be split off before the node is a legal target; and the sector node is clickable even though its cube is not drawn. |
|
||||
| the route set MOVES between turns - AG's 816 prediction needs restating for AD's state | control-flow | verified | med | 100% | 2026-09-09 | Not a contradiction between the lanes, but it would read like one. Lane AG read **four** routes out of `ac-turn22-raider.sav` with `trfr` 18/16/14/20 (sectors 816/816/768/752); lane AD read **three** out of `ad-turn27-two-raiders.sav` with `trfr` 18/14/14 **[AD'S READ WAS WRONG - lane AR re-read the same save and found FIVE, `trfr` 18/16/14/20/14. So sector 816 had TWO candidate routes at turn 27, not one, and my inference below that it had one was built on AD's bad number. The route set does still move (four at turn 22, five at turn 27), so the standing instruction to re-read `trfr` on the state you build survives - but the arithmetic I used to justify it did not.]**. Different saves, five turns apart - **the AI's route set is not static.** Consequence for the sector-816 probe: on AC's turn-22 route set 816 had **two** candidates (`NextInt(bound=1)`, mask 1, no rejection possible); on AD's turn-27 set it has **one** (`NextInt(bound=0)`, mask 0, accepted on the first draw). **Both still cost exactly one word**, so AG's committed prediction of 1 word on a failing turn and 3 on a succeeding one survives - but whoever runs the probe must re-read `trfr` on the state they actually build rather than inheriting either number |
|
||||
| THE SPY DETECTION ROLL FIRES - 1 word, gated on an asteroid belt; `spies2` and `deat` closed | verify | verified | high | 100% | 2026-09-09 | **Lane AS, VM144, build `as-c172c99-20260909T0205Z`, `probes=8` (never 11).** `Mars::RNG::Chance` at **0x00887c8a**, in the BODY of `ServerSpyManager::vslot13` (tail phase 23 call 9), fired **1 call / 1 word / no_draw_calls=0 / strategic=true** at `ret_rva 0x00887c8f`; `OnAllCombatDone_Tail` went **363 -> 364**, against 0 on every turn any lane has ever measured. Turn total 19, per-site sum 19, **residual 0**. THE ENTRY PROBE ON `SpyManager::Slot13RngCallee 0x008408e0` READ **0 ON THE SAME TURN** - that zero was never a statement about the subtree, only about which function the call sits in (rule 28 practice 4, demonstrated rather than argued). **CORRECTION: the roll is NOT inline** (the resolution and AC §2.2 both say so) - it is a plain `E8` to the `Chance` entry point in the caller. **THE PREDICATE**, decoded to save fields: `spy.deat != 0 && spy.sdet == -1 && sys(deat).ARes2 > 0 && (sys(deat).TerrFl & 1)`; **corpus count 0 of 22, failed conjunct `deat != 0`**. `ServerSystem_BeltUsableFlags 0x00743f80` (16 bytes) returns `TerrFl` with bit 0 cleared when `ARes2 <= 0`; `ARes2>0` and `TerrFl&1` agree on all 616 corpus system records AND on the new map, which also has `TerrFl = 2` and `3`, so bit 0 is the belt specifically. **POLARITY: belt gone => NO DRAW AND THE SPY IS DETECTED ANYWAY** (`je` past the roll to `sdet := turn`) - a zero here is two different results. Cost: `sdo` starts at 0, `SpyCraft_AccumulateDetectionOdds 0x0081f570` ACCUMULATES `0.7*(0.01 + [cA]0.01 + [cB]0.02 + 0.001*cC) * species(1.0/0.75/0.5)` and CLAMPS AT 1.0, so `Chance` costs 1 word until sdo reaches 1 and 0 thereafter. Measured `sdo` 0 -> 0.0084 -> 0.0168 (= 0.7*0.012 exactly, a value no run had produced). **`spies2` IS CLOSED**: `ServerSystem::AddSpy 0x007514c0` sets `spy.deat = system handle` and pushes `spy.sid` into `ServerSystem+0x1cc` in the same two instructions - `spies2` is the per-system DEPLOYED-spy id vector; L3's "not the spy list" was half right, AC's P4 was right. Measured: `count=1 element=1` at Kepler, 0 in the other 27. **NEW DRAW SITE NOBODY HAS**: `0x0078c97f` NextFloat in the SHIPACTION_DEPLOYSPY handler `0x0078c930` (`cbh = NextFloat()*2pi`), strategic generator, in the ProcessTurn bracket - decoded, NOT measured, and its predicate is on the COMMAND STREAM not the save, a column the gate-indexed audit lacks. Oracle: input byte-identical in 3 processes; A vs B differ in **22 leaves, all inside one AI player's research pick** (the known per-process client seed, resolution 2026-09-08) - so this is NOT a calibration pair and must not enter `determinism-hashes.txt`. `probes=8` run came out byte-identical to control A. Saves: `as-turn15-spydeployed.sav`, `as-turn14-predeploy.sav`; findings `findings/subsystems/spy-detection-roll.md` |
|
||||
|
|
@ -421,5 +421,6 @@ 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 |
|
||||
| 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 |
|
||||
| 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. |
|
||||
| `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) |
|
||||
|
|
|
|||
207
findings/control-flow/raid-intercept-species-word.md
Normal file
207
findings/control-flow/raid-intercept-species-word.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
# `z` — the raid interception word, and the species that pays it
|
||||
|
||||
- **Type:** control-flow (static decode of the gate + live measurement)
|
||||
- **Owner / date:** lane AZ · 2026-09-09 · guest **VM141** (`sots-re-win10-b`, 192.168.10.143)
|
||||
- **Status:** predictions committed; results to follow
|
||||
- **Decides:** the `z` term of lane AR's `k + s + z` tail model
|
||||
(`findings/control-flow/raid-target-pick-verdict.md` §4.2) — **never observed through
|
||||
`Slot13RngCalleeB` by any lane**, because every raid this campaign has run was Human
|
||||
- **Instrument:** lane Z's return-address ledger (`draw_sites`) + lane H's entry probes at
|
||||
**`probes=8`**, the byte-neutral set. **Not `probes=11`** (lane H bisected index 8 as not
|
||||
byte-neutral, and lane AC's turn totals are not calibration data because of it)
|
||||
|
||||
---
|
||||
|
||||
## 1. Predictions, committed before the build (rule 2)
|
||||
|
||||
*Everything in §1 was written and committed before the shim was built, before the workload was
|
||||
played and before any counter was read. It is not edited after the fact — only annotated with
|
||||
verdicts below the line.*
|
||||
|
||||
### 1.0 What the brief said, and the two ways it is incomplete
|
||||
|
||||
My brief — inherited from lane AR's §4.2 and lane AG's §5.2 — states the gate as:
|
||||
|
||||
> A **Human or Zuul** raider intercepts and draws nothing. **Every other species draws a word.**
|
||||
|
||||
That is **wrong in two places**, and both were found by reading `FUN_00820af0` from the
|
||||
instruction stream on the host before any guest was touched (rule 18's corollary: static reading
|
||||
is for explaining, but here it is also for *not wasting a workload*). The function has **three**
|
||||
short-circuits and they are a disjunction; the campaign has only ever named the third.
|
||||
|
||||
```
|
||||
FUN_00820af0(TradeManager* this, Vector3* out, TradeRoute* rt, StarFleet* fleet) ; 0x00820af0
|
||||
|
||||
ebx = registry_lookup(S+0x84, rt->tro) ; the ROUTE OWNER (ServerPlayer)
|
||||
...
|
||||
00820bc2 cmp DWORD PTR [ebx+0x5c],0x1 ; ServerPlayer+0x5c is the serialised `Species` tag
|
||||
00820bc6 je 0x820bf6 ; SC1 -- route owner is species 1
|
||||
00820bcf call 0x81a2d0 ; StarFleet_GetCrewSpeciesForIntercept(fleet)
|
||||
00820bd7 cmp eax,0x1
|
||||
00820bda je 0x820bf6 ; SC2 -- RAIDER's crew species is 1
|
||||
00820bdd call 0x81a2d0 ; again, same value
|
||||
00820be3 call 0x545cc0 ; SpeciesDef_Get(k) -> 0x00b10a00 + k*0x184
|
||||
00820bed call 0x53baf0 ; SpeciesDef_HasInterceptFlag: [ecx+0x144] != 0
|
||||
00820bf4 je 0x820bf8 ; SC3 -- flag clear: fall through to the draw
|
||||
00820bf6 mov al,0x1
|
||||
00820bf8 fldz ; fstp [ebp+0xc] ; frac = 0.0
|
||||
00820bfd test al,al
|
||||
00820bff jne 0x820c33 ; short-circuited: NO DRAW
|
||||
00820c1b call 0x47d830 ; <<< NextFloat, ONE WORD -- this is `z`
|
||||
```
|
||||
|
||||
**Correction 1 — species 1 short-circuits too, and species 1 is Hiver.** `SC2` is a plain
|
||||
`== 1` test on the raider's own crew species and has nothing to do with `SpeciesDef+0x144`.
|
||||
It is not mentioned in AR's §4.2 disjunct list as a *species* test at all (AR annotates it
|
||||
"raider is Species 0 -- no", which is true of AR's state and hides the rule).
|
||||
|
||||
**Correction 2 — the route owner's species is a gate too.** `SC1` tests the *route owner*, not
|
||||
the raider. A route owned by a species-1 empire is intercepted with **no draw whoever raids it**.
|
||||
My brief does not mention this conjunct at all, and it is a way for this lane's run to come out
|
||||
zero for a reason that has nothing to do with the raider.
|
||||
|
||||
### 1.1 The species enum, named from the image
|
||||
|
||||
`SpeciesDef_InitTable 0x005453a0` selects the `Species/%s/...` data-path prefix through
|
||||
`jmp DWORD PTR [eax*4+0x545b60]`. Reading the seven-entry jump table **as bytes** (not by the
|
||||
order the case bodies happen to be laid out in, which is a different order and would give the
|
||||
wrong answer):
|
||||
|
||||
| index | jump-table target | string |
|
||||
|---|---|---|
|
||||
| **0** | `0x005453f2` | **`Human`** |
|
||||
| **1** | `0x005453f9` | **`Hiver`** |
|
||||
| **2** | `0x00545400` | **`Tarkas`** |
|
||||
| **3** | `0x00545407` | **`Liir`** |
|
||||
| **4** | `0x0054541c` | **`_NPC`** |
|
||||
| **5** | `0x0054540e` | **`Zuul`** |
|
||||
| **6** | `0x00545415` | **`Morrigi`** |
|
||||
|
||||
`SpeciesDef_Get 0x00545cc0` bounds-checks `k <= 6`, so **there are exactly seven**, and
|
||||
`0x00b10a00 + k*0x184` is the element. This independently confirms lane AR's "species 5 = Zuul"
|
||||
and "species 0 = Human", and it names 1, 2, 3, 4 and 6 for the first time in this campaign.
|
||||
|
||||
The `+0x144` flag word is written only at `0x0054562f` (`or [ebx+0x144],2` when the element's
|
||||
index is **5**) and `0x00545638` (`or [ebx+0x144],1` when it is **0**) — AR's read, reproduced.
|
||||
|
||||
### 1.2 The gate as a predicate, and the corpus counted against it (rule 28 practices 1 and 5)
|
||||
|
||||
> **`0x00820c1b` draws one word through `Slot13RngCalleeB` iff**
|
||||
> **(a)** the route's owner is **not species 1 (Hiver)**, **and**
|
||||
> **(b)** the raider fleet's crew species is **not 1 (Hiver)**, **and**
|
||||
> **(c)** the raider fleet's crew species is **not 0 (Human) and not 5 (Zuul)**.
|
||||
>
|
||||
> Equivalently: the raider's crew species is one of **2 Tarkas, 3 Liir, 4 _NPC, 6 Morrigi**,
|
||||
> and the route owner is not Hiver.
|
||||
|
||||
`StarFleet_GetCrewSpeciesForIntercept 0x0081a2d0` returns the fleet **owner's** `Species`
|
||||
(`FUN_0071e280(fleet)->+0x5c`) on every path except one: when that species is **4 (`_NPC`)** it
|
||||
scans the fleet's ships for a `design->+0x14->+0xac..+0xb4` record and returns that record's
|
||||
`+0x4`. So for a player-owned fleet, crew species == owner species, full stop.
|
||||
|
||||
**Corpus count, all 30 saves in `verify/results/saves/`, read with `save_reader.py --json`:**
|
||||
|
||||
| species present | saves |
|
||||
|---|---|
|
||||
| 0 Human (player 0) + 2 Tarkas (the AI) + 4 `_NPC` | **24** |
|
||||
| 5 Zuul (both players) + 4 `_NPC` | 6 |
|
||||
| 1 Hiver, 3 Liir, 6 Morrigi | **0** |
|
||||
|
||||
**Corpus count against the predicate: 0 of 30.** And the near miss is instructive: **24 saves
|
||||
already contain a Tarka empire**, which is a *drawing* species — but it is the **AI**, and
|
||||
`tscr` is `253` in every one of them (bit 0 set = player 0 permitted, **bit 1 clear** = the AI has
|
||||
no Commerce Raiding). So the AI never rolls, `A` never fires for it, and no amount of patience on
|
||||
an existing save reaches `z`. **The "an AI of another species already raids" option my brief asked
|
||||
me to consider is dead, and the corpus count is what killed it** — the state has to be built.
|
||||
|
||||
**And the tech data says which species can even be a raider.** From
|
||||
`verify/results/data-catalogs/tech_tree.json` (`MasterTechList.tech`, per-race
|
||||
availability percentages as written):
|
||||
|
||||
| edge | rp | Human | Zuul | Hiver | Tarkas | Liir | Morrigi |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| `CCC_FTLBrdB -> CCC_FTLEcon` | 18,000 | 100 | **0** | 100 | 100 | 100 | 100 |
|
||||
| `CCC_FTLBrdB -> CCC_ComRaid` | 5,000 | 0 | **100** | 0 | 0 | 0 | 0 |
|
||||
| `CCC_FTLEcon -> CCC_ComRaid` | 12,000 | 100 | 0 | **0** | **100** | **100** | **100** |
|
||||
|
||||
So **Hiver can never research Commerce Raiding at all** (0% on both edges) — which makes `SC2`
|
||||
unreachable for a Hiver *player* through `vslot13`, and leaves it as either a defensive test or
|
||||
the path for an `_NPC`-owned fleet with a Hiver-crewed design. And the species that can both raid
|
||||
and draw are exactly **Tarkas, Liir and Morrigi**.
|
||||
|
||||
**This lane picks Tarkas (species 2).** Liir is rejected on movement (their early game is a
|
||||
sublight crawl, and this workload lives or dies on parking a fleet on a distant node), Morrigi on
|
||||
their fleet-size-dependent drive. Tarkas is a plain node-drive empire with a 100% path to
|
||||
Commerce Raiding, and it is the species the AI already is in the lineage every other trade lane
|
||||
has used, so the route-owner side is a known quantity.
|
||||
|
||||
### 1.3 The workload
|
||||
|
||||
A **new single-player game on VM141** with the species pool cut to **Tarkas only** — lane V's
|
||||
trick from the Zuul save, which makes *both* players Tarkas and so pins the route owner's species
|
||||
to 2 as well, satisfying `SC1` by construction rather than by luck. Create-game parameters as
|
||||
close as I can get to lane AC's `MyGamel3trade` (`NSys 28`, `MaxP 2`, `PCol 10`,
|
||||
`PSav 9,850,000`, `PTech 15`, `IncM 1.48`, `ResM 1.46`), because that is the setup that put a
|
||||
human raider on a trade sector by turn 20 and gave the AI four trade routes by turn 22.
|
||||
|
||||
Then: research `CCC_FTLBrdB -> CCC_FTLEcon -> CCC_ComRaid` (34,000 RP on this branch), build
|
||||
**several separate single-ship long-range fleets**, and park them on a trade sector that **sources
|
||||
a route**. Separate fleets, not one fleet — the roll is per fleet (lane AD) at
|
||||
`ODDS + 0.01·nShips`, so `m` one-ship fleets roll `m` times and one `m`-ship fleet rolls once.
|
||||
|
||||
**Cruisers if their range reaches, destroyers if not.** Cruisers roll at
|
||||
`(double)0.2f + (double)0.01f = 0.21` per fleet-turn against a destroyer's `0.06` — three and a
|
||||
half times the signal per fleet-turn — and a raider is **displaced off the node by its own
|
||||
success** (AR §4.3), so each fleet contributes at most one success per parking and the arm
|
||||
exhausts itself. That is the structural constraint on this workload and it is why hull choice
|
||||
matters more than turn count.
|
||||
|
||||
**The route set moves between turns and this map is not AD's map.** Lane AR's geometry table is
|
||||
for the `MyGamel3trade` lineage only. I will re-read `trdmgr` on the state I actually build and
|
||||
pick the target sector from *that* `trfr` set, preferring a sector that sources **one or two**
|
||||
routes: `bound = n - 1`, so `n = 1` gives mask 0 and `n = 2` gives mask 1, and in both cases
|
||||
`RNG_NextInt` **cannot reject** and `0x0088b613` costs exactly one word. At `n >= 3` the rejection
|
||||
loop is live and `s` stops being one word per success.
|
||||
|
||||
### 1.4 The numbered predictions
|
||||
|
||||
| # | prediction |
|
||||
|---|---|
|
||||
| **P0** | The species enum is `0 Human, 1 Hiver, 2 Tarkas, 3 Liir, 4 _NPC, 5 Zuul, 6 Morrigi`, read from the jump table at `0x00545b60` as bytes. Falsifiable live: the save I build will carry `Species 2` on both `ServerPlayer` records and the game will have been created with **Tarkas** selected in the UI |
|
||||
| **P1** | `FUN_00820af0` short-circuits on **three** conjuncts, not one. The campaign's published sentence ("Human or Zuul draws nothing, every other species draws") is incomplete: **Hiver raiders draw nothing** (`SC2`), and **a Hiver-owned route is intercepted without a draw whoever raids it** (`SC1`) |
|
||||
| **P2** | The short-circuit sets `frac = **0.0**`, **not `1.0`** as both lane AG §5.2 and lane AR §4.2 write it. Traced through the x87 stack at `0x00820bf8`–`0x00820c33`: `fldz; fstp [ebp+0xc]` on the short-circuit arm, and `0.0 + (1.0 - 0.0)*NextFloat()` on the draw arm. The interception point is therefore at the route's **source** end for a Human or Zuul raider, not its destination. Word count unaffected; the published sentence is wrong (rule 28 practice 6 — read the polarity before the count) |
|
||||
| **P3** | Corpus count against the predicate is **0 of 30**, and the "an AI of another species already raids" option is **dead**: 24 saves hold a Tarka AI, but `tscr = 253` in every one, so the AI lacks Commerce Raiding and never rolls |
|
||||
| **P4** | **`OnAllCombatDone_Tail` costs `k + 2s` words** on this state, where `k` = permitted Tarka raiders parked with `Pos` bit-equal and `s` = successes on a route-sourcing sector. This is `k + s + z` with **`z = s`**, and it is the term no lane has ever observed |
|
||||
| **P5** | `draw_sites` shows, on a turn with `s` successes: `NextFloat 0x00820e18` `calls == words == k`; `NextInt 0x0088b613` `calls == words == s`; and **`NextFloat 0x00820c1b` `calls == words == s`**. Bracket residual **0** on every turn |
|
||||
| **P6** | **The `0x00820c1b` row is attributable to `B` and not to `CreateRaidEncounter` exactly when `NextInt 0x008939ee` reads `calls = 0` on the same turn.** Proof, and it is proof-carrying rather than a convention: `FUN_00820af0` has **exactly two `E8` callers in the whole image** — `0x0082cf65` and `0x0088b62c` — verified by an image-wide relative-call scan; `0x0082cf65` sits in `FUN_0082ce00`, whose only caller is `0x00892700` inside `FUN_00892640`, which `CreateRaidEncounter` calls at `0x00893a25`; and `0x008939ee` is on the **straight-line path** from the empty-list gate to `0x00893a25` with no branch around it (`0x008939c9 -> 0x008939ee -> 0x00893a25`, decoded). So `0x008939ee` at zero means the other caller never ran. If it is non-zero on a measured turn I will call that turn's attribution ambiguous and use another turn, not argue |
|
||||
| **P7** | `B`'s cost on a success is **2** words for a Tarka raider. Lane AG §5.2's "1 (NextInt) + 1 (NextFloat)" is right for a drawing species; lane AR's measured **1** is right for Human and Zuul; AG's committed §3.3 figure of "3 words on a succeeding turn" is right for `k = 1` **and a drawing species**, and was wrong only because the lineage was Human |
|
||||
| **P8** | The `hooks=off` control **will agree with itself** (two fresh processes, byte-identical autosaves) — I am predicting lane AR's outcome, not lane AD's, **and I am not confident**. AD's variation was confined to one AI player's decision sub-tree on a state ten turns earlier in a *different* game; a resolver is looking at the discrepancy now and neither outcome is safe to assume. If my control varies I will localise it by sub-tree with `state_checksum.py --tree` and state exactly which leaves my measurement depends on and whether *those* reproduce |
|
||||
| **P9** | With `k` one-cruiser fleets at `p = 0.21` per fleet-turn (`(double)0.2f + (double)0.01f`) I expect the first success within the first two or three instrumented turns. Any zero is reported as a **binomial probability**, never as "unremarkable" (rule 20), and an entry probe on `B` separates "did not fire" from "fired and found nothing" |
|
||||
| **P10** | **Not settled by this lane, predicted in advance** (rule 15): the freighter doubling of the raid odds; the `design+0x12c > 1` short-circuit; `bestScale` (`0x009f8d48 = 0.33f` when `ship+0x18 & 0x100000`); the rejection loop at `0x0088b613` for a candidate list of three or more; and whether `SC2` is reachable at all for a *player* (the tech data says no) |
|
||||
|
||||
### 1.5 The falsifier, stated as the sentence I will have to write
|
||||
|
||||
> **If a Tarka raider parked on a route-sourcing sector succeeds, `Slot13RngCalleeB` is entered,
|
||||
> `NextInt 0x0088b613` fires — and there is still no `NextFloat 0x00820c1b` row — then the species
|
||||
> flag is not the only thing gating that draw**, and the two conjuncts ahead of it become the live
|
||||
> suspects. In that case I will report, per rule 28, exactly which conjunct I satisfied and which I
|
||||
> did not: `SC1` is checkable in the save I built (the route owner's `Species`), `SC2` is checkable
|
||||
> the same way (the raider's owner's `Species`), and if both check out then `SpeciesDef+0x144` is
|
||||
> not what `0x0053baf0` is reading and the static decode is retired.
|
||||
|
||||
That is a real result and it is the more interesting one, because it would mean two lanes' static
|
||||
reads of the same twelve-byte function produced a confident wrong answer.
|
||||
|
||||
### 1.6 What could go wrong with the *workload*, and what each failure looks like
|
||||
|
||||
| way it fails | symptom |
|
||||
|---|---|
|
||||
| the Tarka AI never builds a trade route in the turns I can afford | `trdmgr` holds zero `rt` records; no sector sources a route; `A` fires and `B` returns at `G_B4` with 0 words — the exact zero lanes AC and AD measured, for AC's reason not mine |
|
||||
| no Tarka hull reaches a route-sourcing sector | `A` never fires (`G4` fails, `Pos` not bit-equal); probe 5 reads 0 |
|
||||
| I cannot get Commerce Raiding in the session | `tscr` stays `252`; `vslot13`'s `G3b` rejects; probe 2 fires and probe 5 reads 0 |
|
||||
| the target sector sources three or more routes | `0x0088b613` `words > calls` and `s` stops being one word per success — reported, not hidden |
|
||||
| the encounter query eats a scripted End Turn | detected from the `Done` pixel at (233,673) before every End Turn, per AR §10 |
|
||||
|
||||
---
|
||||
|
||||
*Results, and the verdicts, follow below. Nothing above this line is edited after the run.*
|
||||
265
findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md
Normal file
265
findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
# Resolution — the seed is in every process; it reaches the save only through an *exposed* decision, and exposure is a predicate on the pre-turn save
|
||||
|
||||
- **Type:** resolution (course-setting; one new measurement taken here, from saves already on disk)
|
||||
- **Trigger:** lane AR's P7 falsified — `raid-target-pick-verdict.md` §6 (two `hooks=off` processes
|
||||
byte-identical on `ar-turn37-816raiders.sav`) against lane AD's §5 (94 leaves apart on the same
|
||||
lineage ten turns earlier) and lane AS's §5.1 (22 leaves apart on a fresh map)
|
||||
- **Date / author:** 2026-09-09 · re-resolver
|
||||
- **Touches:** board rows 326 / 415 (AD's oracle row) / 424 (AR's oracle row); `backlog.md` §2 Rung A;
|
||||
`determinism-oracle.md`; `determinism-hashes.txt`; `method-rules.md` rule 26 (corollary, not a rule)
|
||||
|
||||
---
|
||||
|
||||
## 0. Decision
|
||||
|
||||
1. **Reading 2 wins, restated: on AR's two turns the AI reached no decision whose outcome set is
|
||||
larger than one given the state.** Not "no live decisions" — Player[32] changed ~100 leaves a
|
||||
turn, formed a fleet, built ships, finished a tech. Not "lucky" either: the pre-turn saves say why
|
||||
each turn went the way it did. On AD's turn 28 the AI entered with a batch of thirteen ships
|
||||
completing, created a design and colonised a system; on AS's turn 16 it entered with
|
||||
`ResTNm == ''` and had to pick a tech; on AR's turns 38 and 39 it entered with a target held,
|
||||
completed it, created no design, and put two freighters a turn into existing freighter fleets.
|
||||
§3 has the numbers, read off the saves.
|
||||
2. **The organising fact: the seed is present in every process on every turn; it reaches the save
|
||||
only through a consumer whose outcome depends on the draw, and whether such a consumer is reached
|
||||
is a predicate on the pre-turn save** — rule 28's shape applied to determinism. One predicate is
|
||||
already decodable: `ResTNm == ''` at turn start names a research-pick turn. The build/fleet
|
||||
consumer that fed AD's variation is **unidentified** (it is not the composer — AD's two
|
||||
"Bravestar Mk 3" designs are byte-identical apart from `DesID`). §4.
|
||||
3. **Reading 3 (a non-seed per-process cause) is not excluded on AD's state and is cheap to
|
||||
exclude.** Row 360 proved pinned seeds collapse three processes to one on `turn1-state`, an
|
||||
early-game turn. AD's turn 28 is the richest AI turn we own and has never been pinned. One
|
||||
config-only run settles it. §6, probe 2.
|
||||
4. **AR's pair: yes, with a named precondition.** It certifies exactly
|
||||
`ar-turn37-816raiders.sav` → (End Turn, Auto Resolve Peacefully, End Turn) → `15b99255…` /
|
||||
`7a8b3d5e…`, and nothing else. The half the standalone should use is the **second** turn,
|
||||
`ar-oracle-A-pre.sav` (Frame 38) → `7a8b3d5e…`: one End Turn, no encounter, four raid rolls at
|
||||
one word each — the first pair anywhere that exercises the trade-raid roll. Precondition: one
|
||||
load→End Turn run of that file must reproduce `7a8b3d5e…` (it has only been reached by
|
||||
continuation, never by load). And **turn 40 is predicted to vary** — `ar-oracle-A-post.sav`
|
||||
carries `ResTNm == ''` for Player[32] — so the pair must not be extended by a turn. §5.
|
||||
5. **No rule 29.** Rules 23 and 26 produced the right behaviour without prompting — AR wrote "a
|
||||
pair is a statement about that procedure" before anyone asked. Nothing wrong was published;
|
||||
rules are written from damage. Rule 26 gets a corollary carrying the predictive tool (§7).
|
||||
6. **Three probes, ranked, two guests, none longer than a session** — §6. The one to run first is
|
||||
the pinned-seed run on `ad-turn27`, because it tests C-exact on a rich state and the whole Rung C
|
||||
restatement leans on it.
|
||||
|
||||
---
|
||||
|
||||
## 1. The surprise, stated precisely
|
||||
|
||||
Two `hooks=off` processes loading `ar-turn37-816raiders.sav` and taking the same two End Turns
|
||||
produced byte-identical autosaves at both snapshot points; a third, instrumented process matched
|
||||
them. Ten turns earlier on the same lineage, two `hooks=off` processes from `ad-turn27-two-raiders.sav`
|
||||
differed in 94 leaves; on a different map, lane AS's differed in 22. AR predicted (P7) that its control
|
||||
would fail like AD's. It did not.
|
||||
|
||||
The evidence is as strong as reported. All three lanes used their own fresh build directories
|
||||
(rule 24), unmodified `shim.cfg.hoff`, sha256 on the files and `state_checksum --floats bits --mask
|
||||
none` with coverage proved. AR reproduced the control *before* running the instrument, so the `1/k`
|
||||
coincidence caveat does not apply. This is a real surprise, not a stale binary.
|
||||
|
||||
## 2. The instrument and the comparison — reading 4 exonerated
|
||||
|
||||
The three comparisons are equivalent in every way that matters: same tool, same policy, same
|
||||
snapshot semantics (`(Autosave EndTurn)` = state when End Turn is pressed, `(Autosave)` = post-turn),
|
||||
same `hooks=off` config. The only structural difference is that AR's procedure contains an encounter
|
||||
query between the two End Turns, resolved identically (`Auto Resolve Peacefully`) in all three
|
||||
processes. That is part of the procedure the pair certifies (§5), not a non-equivalence. Reading 4 is
|
||||
out.
|
||||
|
||||
## 3. What the saves say — the measurement this resolution adds
|
||||
|
||||
All five saves are in `verify/results/saves/`. Three turn transitions, diffed with `state_checksum
|
||||
--no-audit`, Player[32] = "The Eternal Empire" on the AD/AR lineage, "Revenge Fleet" on AS's map:
|
||||
|
||||
| transition | ModCount | Player[32] leaves | research | `NumDes` | ships completed → where | fleets ± | colonies | control |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| **AD** 27→28 | 1428→1496 (A) / **1500 (B)** | 117 | `BIO_TerBac` held → **completed**, `ResTNm` → `''` | **46→47** (`Bravestar Mk 3`) | **13** (`ShipIDs` +13 −1) → five new fleets | **−3 +7** | **`NumOwn` 15→16** | **varies**, 94 leaves |
|
||||
| **AR** 37→38 | 2057→2108 | 107 | `BIO_EnvTail` held, `TResDone` 15495→31283 | 47 | 2 → existing `Freighters` 6880 / 8704 | −3 +1 (Omikron VIII; human's Zeta lost in the encounter) | — | **agrees** |
|
||||
| **AR** 38→39 | 2108→2147 | 93 | `BIO_EnvTail` **completed**, `ResTNm` → `''`, tech 5 unlocked | 47 | 2 → existing `Freighters` 6880 / 8704 | none | — | **agrees** |
|
||||
| **AS** 15→16 | — | 22 differ | **`ResTNm == ''` at turn start** → pick (64 in A, 62 in B) | 15 | — | — | — | **varies**, 22 leaves |
|
||||
|
||||
Three further facts from the same files:
|
||||
|
||||
- **AD's varying design is not the composer varying.** `Des["Bravestar Mk 3"]` in `ad-oracle-A-post`
|
||||
and `-B-post` are byte-identical apart from `DesID` (2002 vs 2018). What differs between A and B is
|
||||
*which id the design and the new fleets drew* (in B a fleet took 2002 first — the command block
|
||||
was applied in a different **order**), *which design was queued at `Sys[272]`* (978 vs 962), *how
|
||||
the thirteen ships were split into fleets* (B has one more fleet, `ModCount` four higher,
|
||||
`Maint` 2,500 lower), and the `ShipRecs` per-design counts that follow. That is the AI's
|
||||
build/fleet-assignment layer, plus id allocation downstream of it.
|
||||
- **AD's variation was not a research pick.** Player[32] entered turn 28 with `ResTNm = 'BIO_TerBac'`
|
||||
and completed it; the pick is deferred to the next turn. AS's was: its Player[32] entered turn 16
|
||||
with `ResTNm == ''` (PlyrIdx 1 in `as-turn15-spydeployed.sav`), exactly the shape row 326 recorded
|
||||
on `turn1-state`.
|
||||
- **AR's Player[32] enters turn 40 with `ResTNm == ''`** (`ar-oracle-A-post.sav`, PlyrIdx 1). By
|
||||
the AS precedent that is a pick turn.
|
||||
|
||||
So the three lanes measured three different things: AD a heavy build/fleet/colony turn, AS a pick
|
||||
turn, AR two quiet-consumer turns. The seed was per-process in all three. It showed in two.
|
||||
|
||||
## 4. The readings, ruled
|
||||
|
||||
| reading | verdict | what falsifies it |
|
||||
|---|---|---|
|
||||
| **1 — convergent by luck:** every AI decision happened to land the same regardless of seed | **Rejected as stated, and the half-truth in it is reframed.** The agreement is not a random pick landing twice; it is the AI not reaching a consumer whose outcome set is larger than one. The saves show *why* (no pick, no design, forced ship placement), so it is explicable, not lucky. What *is* true: the same lineage becomes exposed again one turn later. | A per-client draw ledger (probe 3) showing a non-singleton-outcome site firing on AR's turns 38/39 with the same return addresses as on AD's turn 28 — i.e. the same decision being made with the outcome coinciding. I predict it will not show that. |
|
||||
| **2 — the state pins the AI:** eliminated players, exhausted research, no live decisions | **Wins, restated as "no *exposed* decision reached".** Player[32] is alive, rich, researching, building; it simply had no decision on those two turns whose result depends on the client stream. Exposure is a property of (state, turn), decidable from the pre-turn save for the research consumer and observable after the fact (`NumDes`, completions, `NumOwn`) for the others. | Probe 1: if `ar-oracle-A-post → turn 40` agrees across two processes, the pick went through producer A/B and the predicate needs the producer gate — the reading survives, the predicate narrows. If it disagrees in the TechTree leaves, the predicate is confirmed. |
|
||||
| **3 — a non-seed per-process cause** behind AD/AS that AR's state does not trigger | **Not excluded on AD's state.** AS's variation has the row-326/360 signature exactly. AD's is a *reordering plus one different choice* in the command block — the shape an ASLR-ordered container would also produce, and the shape the 09-08 resolution withdrew for the research pick but never tested on a build turn. Row 360 pinned an early-game turn. | Probe 2: pinned seeds on `ad-turn27`, two processes. Identical ⇒ dead. Different ⇒ alive, and the diff localises it; that becomes a new resolution trigger, because C-exact would then be false on rich states. |
|
||||
| **4 — non-equivalent comparisons** | **Excluded** (§2). | — |
|
||||
|
||||
**Inference vs measurement, marked.** Measured: the three transitions above, the design bodies, the
|
||||
pre-turn `ResTNm` values. Inference: that the build/fleet consumer draws on the client stream at all
|
||||
(the six direct `NextInt` sites in the AI band are three in `DesignNameGen_Read` and three in the
|
||||
schedule family at `0x0069dbxx`; `cl_RandRange`/`cl_Chance` façade calls and any inlined draw are
|
||||
not in that list — rule 16), and that AS's and AD's variation share a cause. Probes 2 and 3 convert
|
||||
both.
|
||||
|
||||
**One consumer with a fuse, worth writing down.** `0x0069dbb0` draws `NextInt(37)` **once per agent,
|
||||
lazily**, and schedules something at `now + 3 + rand(0..37)`. If `agent+0x36c` is not persisted
|
||||
(the 35 `StrategyAIAgent` tags do not obviously carry it), it is re-drawn on every load — a
|
||||
per-process quantity that *cannot* fire inside a two-turn window from load and *can* fire on any
|
||||
turn from the third onward. AR's two-turn pair is structurally shielded from it; AR's six-turn R1 was
|
||||
not, and R1 was one process. This is the concrete reason a certification cannot be extended by
|
||||
turns even in principle. Inference; the ledger reads it.
|
||||
|
||||
## 5. The standing claims
|
||||
|
||||
| claim | verdict | scope / correction |
|
||||
|---|---|---|
|
||||
| Row 326 / resolution 09-08: the AI client seed is per-process; variation on `turn1-state` is a seed effect | **survives** | Scope is now explicit: the seed exists on every turn; it is *visible* only on exposed turns. The seed is a fact about the process; exposure is a fact about the (save, turn). |
|
||||
| Row 360: pinned seeds collapse three processes to one | **survives**, with a scope | Proved on `turn1-state` (early game, five build orders, one candidate walk). Not yet proved on a rich turn — probe 2. |
|
||||
| Lane AD §5 / row 415: "no oracle pair for this state; the variation is the AI's decisions" | **survives with a qualification** | The variation is the AI's build/fleet-assignment/colony layer and the id allocation downstream of it — **not** the design content, **not** a research pick (`ResTNm` held). Its consumer is unidentified. AD's attribution "the per-process AI seed" is the likeliest cause and is untested on that state (probe 2). |
|
||||
| Lane AS §5.1: 22 leaves, the research pick, the known per-process seed | **survives unchanged** | Pre-turn `ResTNm == ''` confirmed from `as-turn15-spydeployed.sav`; the pick turn was predictable from the input. |
|
||||
| Lane AR §6: "a rung-A oracle pair … AD's result is a fact about that state, not the lineage or the engine; no explanation offered" | **survives, and is now explained** | The explanation is §3. AR's refusal to infer was right and the inference would have been wrong in both obvious directions ("the AI is forced here" / "luck"). |
|
||||
| AR §6.1: `probes=8` + `draw_sites` + boundary ledger is behaviour-neutral **at whole-save granularity** | **survives, scoped** | On a state with no exposed decision. It is the strongest neutrality statement available for that instrument; it says nothing about an instrument's effect on an exposed decision, which no lane has measured. |
|
||||
| AR §7: "this state now has an *unconditional* rung-A pair" | **qualified** | Conditional on the procedure (two turns, one peaceful auto-resolve, this build), and on the load→turn precondition for the single-turn form (§5). Not unconditional; nothing is. |
|
||||
| Backlog §2 Rung A: canonical pair `turn2-state → turn3-state` | **survives** | AR's pair joins it as the first trade-raid pair, after the precondition is discharged. |
|
||||
| Backlog §2 Rung C-exact: "nothing else per-process reaches the turn" | **survives as a measured property of one turn; open on rich turns** | Probe 2 is the test. If it fails, C-exact is restated as "given seeds *and* whatever else is per-process", and that something must be named. |
|
||||
| Resolution 09-08 §6: "combat turns are not yet known to be cross-process reproducible" | **survives; one datum added** | AR's turn 38 carried an encounter query auto-resolved peacefully and reproduced across three processes. "Peacefully" almost certainly bypasses `RunCombatRound` and its per-process consumer, so this does **not** discharge the warning; it shows the query/resolution *plumbing* is reproducible. Inference on the bypass. |
|
||||
| Rule 26's control discipline | **survives; gets a corollary** | §7. |
|
||||
|
||||
## 6. The probes, in order
|
||||
|
||||
**Probe 2 first — pinned seeds on the heavy turn. VM146 (free).** `ad-turn27-two-raiders.sav`,
|
||||
`aiseed=pin` (lane CB's `shim.cfg.cbpin` mechanism — the ctor-argument overwrite, *not*
|
||||
`airng.pin_seed`, which re-seeds at bracket entry and is a declared perturbation), two fresh
|
||||
processes, one End Turn each, compare. The save has seven non-human players, so use the wildcard
|
||||
(`aiseed.values=*=<hex>`) or list every net id from one `aiseed=log` run first; a half-applied pin
|
||||
set is refused by design. Every other hook off. **Prediction, committed:** the two autosaves are
|
||||
byte-identical; `state_checksum` prints IDENTICAL over ~67k leaves. If they differ: reading 3 is
|
||||
alive on rich states, the diff localises the non-seed input, and C-exact is restated — that is a
|
||||
resolution trigger, not a lane result. Cost: two loads, two turns, ~25 minutes on that guest.
|
||||
|
||||
**Probe 1 — the predicate's own prediction. VM145 (free), two runs.**
|
||||
*(1b, the precondition)* load `ar-oracle-A-pre.sav` (Frame 38, `15b99255…`), `hooks=off`, End
|
||||
Turn once. **Prediction:** `(Autosave).sav` = `7a8b3d5e…`. Holding ⇒ the single-turn pair is
|
||||
certified as load→turn and enters `determinism-hashes.txt`. Failing ⇒ the pair is valid only as the
|
||||
two-turn procedure from turn 37, and the resave canonicalisation (`determinism-oracle.md`,
|
||||
round-trip section) is the first suspect.
|
||||
*(1, the exposure test)* load `ar-oracle-A-post.sav` (turn 39, `7a8b3d5e…`) in two fresh
|
||||
processes, `hooks=off`, End Turn once, resolve any query peacefully in both. **Prediction:** the two
|
||||
files **differ**, confined to `Player[32]` `TechTree/*`, `ResTNm`, `otch`, `Events`,
|
||||
`turnstats/…/tch` and `Summary/Checksum`; `/Sim/RNG`, `/Sim/trdmgr`, every `Player[16]` leaf and
|
||||
every player-0 fleet identical. If they **agree**: producer A or B supplied the target (as for
|
||||
player 32 on `turn1-state`) and the predicate needs the producer gate — one run with lane L4's
|
||||
`airesearch=on` dump names which producer returned non-null. Either outcome is a result.
|
||||
|
||||
**Probe 3 — the per-client draw ledger, on both states.** Lane Z's `RngLedger` shape keyed on
|
||||
`this == StrategyClient+0x134` per AI client, return-address attributed, on `ad-turn27 → 28` and on
|
||||
`ar-oracle-A-pre → 39`. The sites that fire on AD's turn and not on AR's are the consumers behind
|
||||
the build/fleet variation; the bound of each `NextInt` gives its outcome-set size, which is the
|
||||
predicate in machine-readable form. This is the C-exact prerequisite row 360 already names — not
|
||||
new work, the next rung of it, now with two states that make it decisive. **Prediction:** AR's turn
|
||||
39 shows per client the surrender `cl_Chance` (one word, 0 % — forced) and the composer's price
|
||||
query (`ship-design-composer.md` §5.6 shape); AD's turn 28 shows those plus sites in the fleet-task
|
||||
and build paths with bounds > 0.
|
||||
|
||||
Do not spend a static lane on the build consumer before probe 3 has named its return addresses
|
||||
(rule 18).
|
||||
|
||||
## 7. Rule 26, corollary (c) — draft for `method-rules.md`
|
||||
|
||||
Append to rule 26, after (b):
|
||||
|
||||
> **(c) A control that agrees certifies a procedure, not a state — and it means "no exposed
|
||||
> decision was reached", never "the AI is deterministic here."** Three lanes in one day:
|
||||
> `ad-turn27 → 28` varied in 94 leaves (the AI's build, fleet-assignment and colony choices on a turn
|
||||
> where thirteen ships completed, a design was created and a system colonised); `as-turn15 → 16`
|
||||
> varied in 22 (a research pick, on a turn the AI entered with `ResTNm == ''`); `ar-turn37 → 39`, the
|
||||
> same lineage as AD ten turns on, agreed byte-for-byte across three processes — on two turns where
|
||||
> the target was held then completed, no design was created and two freighters a turn joined
|
||||
> existing fleets. The per-process seed was present in all three. It reaches the save only through a
|
||||
> decision whose outcome set is not a singleton given the state, and whether such a decision is
|
||||
> reached is a **predicate on the pre-turn save** — rule 28's shape: `ResTNm == ''` names a pick
|
||||
> turn; `NumDes` moving names a design turn; a batch of completions names a fleet-assignment turn;
|
||||
> one consumer (`0x0069dbb0`) has a 3–40-turn fuse and cannot show inside two turns of a load.
|
||||
> So: record the pair as (save, procedure, hashes) and write the exposure facts next to the hashes;
|
||||
> never extend a certified pair by a turn without its own two-process agreement (`ar-oracle-A-post`
|
||||
> enters turn 40 with `ResTNm == ''` and is predicted to vary); and when a control *does* vary,
|
||||
> decode which consumer was reached before reasoning from the leaves — "the AI varies per process"
|
||||
> is a fact about a turn, not about the engine.
|
||||
|
||||
Ranked by damage: none this time. AR applied the discipline unprompted and refused the inference;
|
||||
that is why this is a corollary and not rule 29. Rule 23 already carries the general principle
|
||||
("a statement about the states that occurred"), and rule 26 already demands the two-process
|
||||
agreement; (c) adds only the predictive tool and the standing instruction not to extend.
|
||||
|
||||
## 8. Course
|
||||
|
||||
**VM146 — probe 2, now.** Brief, one paragraph: *Load `ad-turn27-two-raiders.sav` in two fresh
|
||||
processes with the AI client seeds pinned by lane CB's `aiseed=pin` (wildcard or all seven net ids
|
||||
from a prior `aiseed=log` run; the shim refuses a partial pin set), every other hook off, one End
|
||||
Turn each. Compare sha256 and `state_checksum --floats bits --mask none`. Prediction committed above:
|
||||
IDENTICAL. If not, do not analyse — post the leaf diff and stop; that is a resolver case. Do not
|
||||
compare any pinned file to AD's unpinned files (rule 19: the pin is a declared perturbation).*
|
||||
|
||||
**VM145 — probe 1, now.** Brief: *Two runs from saves on disk, `hooks=off`, no build needed.
|
||||
(1b) `ar-oracle-A-pre.sav` + one End Turn: expect `7a8b3d5e…`. (1) `ar-oracle-A-post.sav` + one End
|
||||
Turn in two fresh processes: expect the files to differ inside Player[32]'s research leaves and
|
||||
nowhere else; localise with `state_checksum` and report the leaf list whichever way it goes. Record
|
||||
the pre-turn `ResTNm` of every AI player next to each hash. If a query appears, `Auto Resolve
|
||||
Peacefully` in both.*
|
||||
|
||||
**Lanes AP (VM144) and AZ (VM141) — no redirect; one addition to each brief.** *Any `hooks=off`
|
||||
control you take: record, next to the hashes, each AI player's pre-turn `ResTNm`, `NumDes`, `NumOwn`
|
||||
and the number of ships completing that turn. If the two processes disagree, localise with
|
||||
`state_checksum` and name the consumer class (pick / design / fleet-assignment) from the leaves
|
||||
before reading any number off the run; your numbers are valid on the sub-tree that agrees, as AD's
|
||||
were.*
|
||||
|
||||
**Probe 3** goes to whichever of VM145/VM146 frees first, as a lane with lane Z's ledger and
|
||||
`this` recorded — it is the C-exact prerequisite and RB/CB's capture format should carry its output.
|
||||
|
||||
**Backlog §2, Rung A bullet — append:**
|
||||
|
||||
> Second pair, first to exercise the trade-raid roll: `ar-oracle-A-pre.sav` (turn 38) → `7a8b3d5e…`
|
||||
> (lane AR, three processes, one instrumented), four raiders parked, `OnAllCombatDone_Tail` = 4
|
||||
> words, no encounter. Enters `determinism-hashes.txt` once one load→End Turn run reproduces the
|
||||
> hash (probe 1b). The two-turn form from `ar-turn37-816raiders.sav` is also certified but carries a
|
||||
> peaceful auto-resolve between the turns. **Do not extend either by a turn**: Player[32] enters
|
||||
> turn 40 with `ResTNm == ''` — a predicted research-pick turn.
|
||||
|
||||
**Docs to correct in place (rule 11):** `determinism-oracle.md` — add the exposure paragraph
|
||||
(§3/§4 here) under "Qualified"; `determinism-hashes.txt` — AR's pair after probe 1b, with the
|
||||
exposure facts on the same line; `raid-gate-multiplicity.md` §5 — footnote that the variation is the
|
||||
build/fleet layer with the design content identical, consumer unidentified, pin probe queued.
|
||||
|
||||
---
|
||||
|
||||
## Proposed `campaign/board.md` rows
|
||||
|
||||
New row:
|
||||
|
||||
```
|
||||
| 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) |
|
||||
```
|
||||
|
||||
Edits to existing rows:
|
||||
|
||||
- **Row 424** (AR's oracle pair) — append: `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, 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 after 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 (resolution 09-08 §6) stands.`
|
||||
- **Row 415** (AD's oracle row) — append: `EXPLAINED IN PART 2026-09-09 (resolver): the variation is the AI's build/fleet-assignment/colony layer and the id-allocation order downstream of it - NOT the design content (byte-identical apart from DesID) and NOT a research pick (ResTNm held). Consumer unidentified; the pin probe on this state (VM146) decides whether it is the seed at all.`
|
||||
- **Row 326** — append: `The shape recurs and is now a predicate: pick turns (ResTNm == '' at turn start: turn1-state, as-turn15) and heavy build turns (ad-turn27) expose the seed; quiet-consumer turns (ar-turn37 -> 39) do not. Resolver 2026-09-09.`
|
||||
- **Row 360** — append: `SCOPE: proved on turn1-state (early game). The rich-turn test is ad-turn27 pinned, queued on VM146.`
|
||||
- **Row 62** — VM145: probe 1 (two saves on disk, hooks=off, no build); VM146: probe 2 (`aiseed=pin` on ad-turn27). VM140 untouched.
|
||||
12
ghidra/addresses.d/az.json
Normal file
12
ghidra/addresses.d/az.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"entries": [
|
||||
{
|
||||
"name": "SpeciesDef_NameJumpTable",
|
||||
"addr": "0x00545b60",
|
||||
"convention": "data",
|
||||
"prototype": "void*[7], the switch jump table SpeciesDef_InitTable 0x005453a0 dispatches through at 0x005453eb (`jmp [eax*4+0x545b60]`) to choose the `Species/%s/...` data-path prefix. READ AS BYTES, the seven entries are 0x005453f2 \"Human\", 0x005453f9 \"Hiver\", 0x00545400 \"Tarkas\", 0x00545407 \"Liir\", 0x0054541c \"_NPC\", 0x0054540e \"Zuul\", 0x00545415 \"Morrigi\" -- so the species enum is 0 Human, 1 HIVER, 2 TARKAS, 3 LIIR, 4 _NPC, 5 Zuul, 6 MORRIGI. NOTE the case bodies are NOT laid out in case order (index 4 jumps PAST index 5's body), so reading the disassembly top to bottom gives the wrong enum; only the table bytes settle it. SpeciesDef_Get 0x00545cc0 bounds-checks k <= 6, so there are exactly seven. This confirms lane AR's species 0 = Human / species 5 = Zuul from an independent direction and names 1, 2, 3, 4 and 6 for the first time",
|
||||
"status": "verified",
|
||||
"source": "findings/control-flow/raid-intercept-species-word.md (lane AZ 2026-09-09); disassembled from dumps/sots.exe"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -369,6 +369,24 @@ all three streams differed every run; two empires never reach the seed-sensitive
|
|||
Before reasoning from *which* items varied, establish whether the others were even exposed to the
|
||||
mechanism.
|
||||
|
||||
> **(c) A control that agrees certifies a procedure, not a state — and it means "no exposed
|
||||
> decision was reached", never "the AI is deterministic here."** Three lanes in one day:
|
||||
> `ad-turn27 → 28` varied in 94 leaves (the AI's build, fleet-assignment and colony choices on a turn
|
||||
> where thirteen ships completed, a design was created and a system colonised); `as-turn15 → 16`
|
||||
> varied in 22 (a research pick, on a turn the AI entered with `ResTNm == ''`); `ar-turn37 → 39`, the
|
||||
> same lineage as AD ten turns on, agreed byte-for-byte across three processes — on two turns where
|
||||
> the target was held then completed, no design was created and two freighters a turn joined
|
||||
> existing fleets. The per-process seed was present in all three. It reaches the save only through a
|
||||
> decision whose outcome set is not a singleton given the state, and whether such a decision is
|
||||
> reached is a **predicate on the pre-turn save** — rule 28's shape: `ResTNm == ''` names a pick
|
||||
> turn; `NumDes` moving names a design turn; a batch of completions names a fleet-assignment turn;
|
||||
> one consumer (`0x0069dbb0`) has a 3–40-turn fuse and cannot show inside two turns of a load.
|
||||
> So: record the pair as (save, procedure, hashes) and write the exposure facts next to the hashes;
|
||||
> never extend a certified pair by a turn without its own two-process agreement (`ar-oracle-A-post`
|
||||
> enters turn 40 with `ResTNm == ''` and is predicted to vary); and when a control *does* vary,
|
||||
> decode which consumer was reached before reasoning from the leaves — "the AI varies per process"
|
||||
> is a fact about a turn, not about the engine.
|
||||
|
||||
## 27. A ratchet is meant to break when the corpus grows — do not move it, and scope your control
|
||||
|
||||
The save corpus went from 11 to 19 in one evening as lanes finally manufactured workloads nobody had
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue