sots-re/findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md

26 KiB
Raw Permalink Blame History

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.