42 KiB
Resolution — the residue under pinned seeds is a visit order, it is written into the block, and it is not yet known to be RNG or heap
- Type: resolution (course-setting; two new measurements taken here, from BP's logs already on disk)
- Trigger: lane BP's P1 falsified —
findings/control-flow/pinned-seed-rich-turn.md§3 (probe 2 of2026-09-09-seed-exposure-is-a-predicate.md) - Date / author: 2026-09-09 · re-resolver
- Touches: board rows 326 / 333 / 360 / 415;
backlog.md§2 Rung B and Rung C;method-rules.mdrule 26 (c) wording, new corollary (d);id-allocation.md§5;determinism-oracle.md;verify/state-checksum/state_checksum.py(a new mode);src/shim/shim.cfg.cbpin
0. Decision
- BP's restatement is accepted and sharpened. Given (save, per-client seeds) the AI's command
block on
ad-turn27is determined up to the order in whichAssignFleetsAndIssueOrdersvisits the groups that need a new fleet. The ids are not the variable — the node-2 counter hands out 1970, 1986, 2002 in that order in every process (§2.1). The visit order is. On this turn the visit order changes exactly three things: which client-minted id each group receives, the element order of lists 8/10, and — downstream — the apply order, which is whyShipIDs[]comes out reordered. Every decision is invariant under it. - The residual input is not lost; it is written into the block. List 10 carries
{systemId, fleetId, ships[]}per group, so any captured original run records its own visit order for free. C-exact therefore survives literally, with one more per-run input that costs nothing to capture: (save, seeds, visit order as read off list 10) → byte match. C-set's shape covers the uncaptured case: our canonical order is one member of the original's outcome set of orders. §3 says what the engine and the comparison tool must do. - The pointer-order reading is not yet the leading hypothesis — it is one of two, and the
other is already named in the record. AI1's consumer list for the per-process global generator
at
0x00af6e58includes two AI-band sites nobody has named (0x0079ea90+0x73, anRNG_Chance, and0x005b9f00+0xc0); the seed pin does not touch that generator. What has moved since 09-08 is that pointer order now has a measured precondition (§2.2): in two processes with identical configuration, BP's own dumps show the same run of consecutive same-size heap allocations landing in different relative address orders. So the mechanism the reading needs is present in this process. That is a precondition, not the cause. - One probe, one run, no build, VM146, ~12 minutes (§4): BP's exact pinned procedure with
airng=onadded (pin_seed off). TheOnResumePlayingbracket attributes every draw on every generator during each AI client's turn to a return address and a generator address, and the inlined-draw inventory has no site in the AI band, so the observer is complete there. It is also run C. Prediction committed: zero foreign draws in Player[32]'s bracket — the global does not move — and the autosave is one of the two known files. If a foreign draw appears, its return address names the consumer and the follow-up is a global pin; if none, RNG is excluded by measurement and the follow-up is the container hook, placed by one static read. - Rung C is restated (§6). Rung B is not restated; its value is confirmed and it gains a
concrete target. Replay applies ids off the wire in block order, so it is insulated from this
residue by construction. One
aiorders.deep=onrun of BP's pinned procedure that lands one913ff41…is the first fully reproducible rich-turn record — (pre-turn save, seeds, deep block, autosave) — and the engine can be measured against it whenever the sim reaches that turn. - No rule 29. BP's third run is the right practice and it belongs in rule 26 as corollary (d):
when the instrument cannot be removed, pin it to a natural run's observed values and require it to
reproduce that run before reading anything from a pinned pair. BP's amendment to (c) is right in
substance and overreaches in one clause; corrected wording in §7. The
shim.cfgtrap BP found (an unnamed hook is silently installed) gets a structural fix, not a rule. - Lane BQ's result, which arrived mid-ruling, is folded in (§9) and does not change the probe.
Image base is constant across processes on both guests (
0x00f40000×5 on VM145,0x005e0000×3 on VM146), so "pointer order" can only mean heap order, which §2.2 measures as per-process. BQ's per-history input (a fleet moved by continuation, not after a load) is a different input from BP's per-process one, and the probe holds history fixed (every run is a load), so it is unconfounded. The leading mechanism for BQ's residue is AI agent state the save does not carry (inference;AISystem::Writeemits nothing), and the consequence for the rungs is a scope, not a loss: every byte-match claim is a claim about load→turn procedures. Rung A: BQ's reading is confirmed — the load-form pair entersdeterminism-hashes.txt, AR's continuation hash does not.
1. The surprise, and the instrument
Two fresh processes with the three AI client seeds pinned to identical words, identical build, identical config, identical input, identical pre-turn autosave, produced different turn-28 states — 35 leaves, one transposition. The prediction was IDENTICAL.
The evidence is as strong as reported, and stronger than a bare falsification, because the run that
should have been the weak one — L, unpinned — is byte-identical to A. Instrument: fresh tree (rule
24), lane worktree (rule 21), every registered hook off by name with the count in the log (27), zero
unknown keys, three of three pinned=1 in both pinned runs, identical config: lines, no wildcard
hit, no fourth client. The instrument is exonerated for the A/B difference — the two processes
carried the same instrument and one of them reproduced an unpinned run byte for byte, which a
perturbing instrument could only do by a 1/k coincidence. Rule 26 applies to the A/B pair exactly as
BP says: it does not agree with itself, so it certifies nothing. What carries weight is L = A.
What no hooks=off control could have said here, stated so nobody looks for one: a pin cannot be
applied without hooks, so "the un-instrumented pinned game" does not exist. The L/A agreement is the
control this design admits (§7, corollary (d)).
2. Two measurements this resolution adds, from BP's files
2.1 The ids decode, and they say the counter is deterministic
id = (counter << 4) | node (id-allocation.md, verified on twenty saves and the instruction stream).
Player[32] is PlyrIdx 1, so its client is node 2:
| id | hex | counter | node | what |
|---|---|---|---|---|
| 1970 | 0x7b2 | 123 | 2 | client-minted, first new fleet |
| 1986 | 0x7c2 | 124 | 2 | second |
| 2002 | 0x7d2 | 125 | 2 | third |
| 7072 | 0x1ba0 | 442 | 0 | server id, an existing fleet |
| 6976 / 5264 | 0x1b40 / 0x1490 | 436 / 329 | 0 | server-minted ships |
So the AI minted three fleet ids at emission, counters 123–125 contiguous, in both processes. List
10's elements in A are (384,1970) (80,1986) (384,2002) (816,7072); in B (80,1970) (384,1986) (384,2002) (816,7072). The id follows the visit; the group at system 80 was visited first in B and
second in A. The variable is the visit order of the first two groups; 2002's group and the
existing fleet came third and fourth in every process. (Two of three processes agree, so "third in
every process" is two observations, not a law.)
2.2 Same-size heap allocations land in different relative orders across processes — measured
The aielem dump records each command node's heap address (node=0x…). Runs A and B have identical
configuration and identical decisions, so the allocation sequence through the AI turn is the same
(inference: supported by the identical outputs, not proved). Player 32's list 3 — nineteen nodes
allocated in one pass — in visit order:
- A:
f838 f538 f898 f4f8 f518 fa38 fc98 …(idx1 < idx0, idx3 < idx2) - B:
e1c0 e320 e200 e380 e460 e500 e260 …(idx1 > idx0, idx3 > idx2)
Relative order differs between two processes for the same allocation sequence. That is what the Windows 8+ low-fragmentation heap does by design (randomised slot selection within a bucket), and it is the precondition any address-keyed container needs to walk in a per-process order. Measured: allocation order is per-process here. Inferred: that some container on the fleet-assignment path is address-keyed. The second half is what the probe chain settles.
The image, by contrast, does not move: exe base=0x005e0000 in all three of BP's processes on
VM146 and 0x00f40000 in all five of BQ's on VM145 — per boot, not per process. So any "ASLR"
reading that reaches for image-base randomisation is excluded on these guests; the only addresses
that vary between processes are heap (and stack). "Pointer order" in this document means heap order.
2.3 Time is not a live hypothesis with a mechanism
AIProcessMinTime is a trailing minimum-duration Sleep (ai-task-system.md), not a slice; the AI
turn runs synchronously inside StrategyClient::OnResumePlaying (lane PAR), and stepping order is
save order × stable priority (AI2). No wall-clock input to the visit order is in the record. Not
excluded — nothing is — but it has no mechanism and is ranked last.
3. Ruling on the restatement, and what "canonicalisable" means concretely
Accepted, sharpened as in §0.1. Two qualifications, both rule 23's shape:
- "Every decision is invariant under the visit order" is a statement about this turn. A visit
order can change a decision wherever an earlier visit consumes something a later one wanted (an
escort, a build slot, the one move order). On
ad-turn27the move in list 8 went to the group at system 80 in both orders. The general claim needs the mechanism named and its scope read. - The outcome set of orders has been observed at size 2 from two distinct observations. Its true size is unknown; run C (the probe run) is the first datum on it.
For sots-engine, three deliverables, ranked by what they unblock:
- Comparison side —
state_checksum.py --relabel-new-ids <pre-turn.sav>(sots-re, host only). Given the pre-turn save, compute the ids new in each post-turn save; among them, match fleets with node nibble ≠ 0 by a content key that does not depend on the id —(LocID or FPlan destination, sorted ship-id set)— and build the bijection π between the two saves. Apply π to every id-valued leaf (Flt[]keys,Sys[*]/Flt[*], ship→fleet references,FleetIDs[]entries, list-8/10/14 words when comparing blocks), treat the master id listsShipIDs[]/FleetIDs[]/DesignIDs[]as sets, and reportIDENTICAL modulo π = {1970↔1986}with π printed.Summary/Checksumis derived and its inputs are unmodelled (rule 18's open item), so it is masked with that reason on the line until the checksum is modelled. Acceptance: BP'sbp-pinAvsbp-pinBreads IDENTICAL modulo one transposition and nothing else; AD'sad-oracle-A/B-poststill DIVERGE (their difference is seed-driven and must not be absorbed). - Engine side —
game/ai, at the point where a task forms a fleet from a ship group (the original:AssignFleetsAndIssueOrders 0x006c16c0, pass 1, minting viaIDMap::AllocateOnLocalNodeon nodePlyrIdx+1, emitting list 10 then any list 8/14 for that fleet). Visit the groups in a canonical order that is a function of the save alone — ascendingsystemId, then ascending minimum ship id in the group — and mint in that order. This is deterministic across our own processes by construction and is one member of the original's outcome set. Nothing else inid-allocation.md§5 changes: mint at emission, carry the id in the command, the applier honours non-zero ids. - Engine side, exactness knob — an optional visit-order override read from a captured block:
--ai-visit-order <netid>=<systemId>/<minShipId>,…(or simply "take the list-10 order from the--turn-commandscapture when both are given"). With it, (save, seeds, order) reproduces the original's exact bytes on every captured run — C-exact literal. Three words per new fleet, the same cost class as--ai-seed. Build it after (1) and (2); it is what turns "modulo π" into "=".
The comparison should never accept a relabelling that is not a bijection between new ids of the same node, and it should refuse to relabel anything present in the pre-turn save. That is the guard that keeps (1) from absorbing a real divergence.
4. Hypotheses and the one probe
| hypothesis | mechanism in the record | what the probe shows | |
|---|---|---|---|
| H1 | an address-keyed container (or an unstable sort seeded by one) on the fleet-assignment path walks in heap order | precondition measured (§2.2); container not identified | zero foreign draws in the bracket; order then needs the container hook (stage 2) |
| H1b | an uninitialised word read by a comparator on that path | this codebase leaves uninitialised words in command elements (L4/CB's noise set) | same as H1 at stage 1; stage 2 separates: visit order tracks neither address nor id |
| H2 | a draw on the per-process global generator 0x00af6e58 inside the AI turn — AI1's 0x0079ea90+0x73 (Chance) or 0x005b9f00+0xc0, both unnamed; or on Seed record #2's object |
named consumers exist; none has been seen firing on a turn | ≥1 airngcensus row with rng != client+0x134 inside Player[32]'s bracket, with its return address |
| H3 | wall clock | none (§2.3) | — |
The probe — lane "BR", VM146, one fresh process, no build. C:\SOTS\shimdist-bp is still
deployed with BP's build; take shim.cfg.bppin verbatim (seeds 32=156ebbbd,496=fe7b2826, 512=0ed341d1 plus the wildcard, every hook off by name) and change exactly three lines: airng=on,
airng.pin_seed=off, airng.out=<path>. aiorders stays on with deep=0 so the block is comparable
with A/B. Load ad-turn27-two-raiders.sav, one End Turn, collect (Autosave).sav, shim.log, the
airng output and the aiorders dump.
Why this and not run C alone or probe 3's ledger alone: it is run C (a third pinned sample), and
it is probe 3 on AD's state (the per-client ledger with this), and the airng detour has a
measured neutrality — byte-identical to the published oracle in two fresh processes (roll-parity.md).
The seven draw entry points are the only way to draw in the AI band: lane I's inlined-draw inventory
has its eleven functions in the network, encounter, lobby and combat subsystems and none between
0x680000 and 0x6e0000, so a draw the observer does not see during the bracket would have to
come through a path the direct-call closure cannot reach — which the left_delta − observed
residual on the client generator reports for that generator, and the census reports for every other.
Predictions, committed before the run:
- P1.
(Autosave).sav∈ {e913ff41…,724528ff…}. A third file means either the order outcome set exceeds 2 or the added detour perturbed the turn; those are separated by one more run withairng=off(plain run C), which cannot land on a third file under the first reading with probability better than 1/3. - P2. In Player[32]'s
OnResumePlayingbracket:foreign_words=0 foreign_calls=0, noairngcensusrow whoserngis0x00af6e58or Seed record #2's object,residual=0. The same for clients 496 and 512. - P3. Player[32]'s own generator spends single-digit words in the bracket, at return addresses in the AI band; 496 and 512 spend fewer. (Not load-bearing; recorded so the ledger has a number to disagree with.)
- P4. The
aiordersdump differs from A and B only inside the proven noise set plus, at most, the three-word transposition.
Course after the probe, either branch:
- P2 fails (a foreign draw in the bracket): the return address names the consumer. Follow-up is
the global pin —
RNG_Seed(0xaf6e58, K)from the shim afterApplication::Initialize(09-08 resolution §6 named it for combat; ~20 lines), two fresh processes, prediction byte-identical. If the draw is on record #2's object, pin that object's seed in theSeeddetour instead. - P2 holds: RNG is excluded by measurement for the AI turn. Stage 2, one lane: read
AssignFleetsAndIssueOrders 0x006c16c0and the fleet-gathering hub it feeds (the 992-byte body AI2 mapped; result vector at[ebp-0x3c]) far enough to find the loop that visits the ship groups and the container it walks — that is a bounded static read to place a hook, not to derive an answer (rule 18). Hook the loop; log(element address, systemId, minted fleetId)in visit order; two fresh processes. Prediction under H1: visit order equals ascending element address in both, and the two processes' address orders differ exactly where their visit orders differ. Under H1b: order tracks neither. Either way the container's identity is whatgame/aineeds to know it is canonicalising the right thing.
Do not start stage 2's read before the probe returns; the probe is twelve minutes and a foreign draw would make the read moot.
5. Standing claims
| claim | verdict | scope / correction |
|---|---|---|
Row 326 / 09-08: the AI client seed is per-process and is the cause of turn1-state's variation |
survives unchanged | L1's per-process seeding reproduced a fourth time (nine distinct words, three processes). |
| Row 360: pinned seeds collapse three processes to one | survives with scope | True on turn1-state. On ad-turn27 pinning collapses 94 leaves to 35 and every decision leaf; it does not collapse the fleet visit order. |
| Row 415 / AD: "the variation is the AI's decisions" | survives with a qualification | Right for 59 of the 94 leaves and for every substantive choice (build at Sys[272], fleet split, design, money); incomplete — the remaining 35 are a non-seed per-process visit order. |
| 09-09 resolution §4 reading 3: "a non-seed per-process cause, not excluded on rich states" | confirmed, and localised | It is alive; it is confined to the fleet-assignment visit order on this turn; it is written into list 10. |
| 09-09 §3: "AD's varying design is not the composer varying" | survives, strengthened | BP extends it from two save bodies to the commands that created them: list 1 identical including the name bytes. |
| 09-09 §6 probe 2's cost/mechanism brief: "seven non-human players; wildcard or list every id" | corrected | Three AI clients (32/496/512); four NPC factions have no client. The wildcard would have pinned three and said nothing. BP's log run is what made the count a measurement. |
| 09-08 resolution: "pointer-ordered tie under ASLR — withdrawn" | survives as withdrawn for the research pick; re-opened as H1 for the fleet visit order | Different decision, different consumer, and now a measured precondition (§2.2). It was wrong there; it is untested here. |
| Backlog §2 C-exact: "nothing else per-process reaches the turn" | overturned as written; restated (§6) | One more per-process input reaches rich turns; it is observable in the block. |
| Backlog §2 Rung B: replay of a captured block byte-matches | survives, strengthened | The residual input is in the block; replay applies ids off the wire in block order. |
id-allocation.md §5 (mint at emission; honour ids off the wire; the client counter is a function of allocation order) |
survives; one addition | Add: the visit order that determines which group gets which counter is per-process in the original; game/ai visits canonically (§3.2). |
| Rule 26 (c) as BP amended it | survives with a wording fix | §7. |
determinism-oracle.md "Qualified" |
needs the paragraph BP proposed | Pinned seeds do not make a rich turn reproducible; the residual is the fleet visit order; comparison modulo π is defined in §3.1. |
6. Rungs
Rung C bullet in backlog.md §2 — replace the C-exact sub-bullet with:
- C-exact. Given the seeds captured from an original run (
sots_turn --ai-seed <netid>=<hex>), our AI's command block equals that run's block element for element and the autosave byte-matches — up to one further per-process input, measured onad-turn27(lane BP, 2026-09-09): the order in which the AI visits the ship groups that need a new fleet. The seed determines every decision on that turn (94 unpinned leaves → 35 pinned, all one transposition); the visit order determines which client-minted id each group gets and the element order of lists 8/10. That input is written into the block (list 10's{systemId, fleetId, ships[]}), so on every captured run it is available for free:(save, seeds, visit order)→ byte match, with the engine visiting canonically by default (ascending system id, then minimum ship id) and taking the captured order as an override for exact replay. Comparison isstate_checksum --relabel-new-ids: identical modulo a bijection on that turn's new ids, with the bijection printed andSummary/Checksummasked with its reason. Precondition unchanged: the per-client draw ledger. Scope (lane BQ, 2026-09-09): every byte-match claim in this rung is a claim about a load→one-turn procedure. The original's AI carries state across turns that no save holds (a fleet moved by continuation and not after a load, on the same file), so an engine run from a save can only be compared with an original run from that save; a continuation is not a target, by construction. Open: whether the visit order is heap order or a draw on the per-process global generator (probe BR), and whether it can change a decision on some other turn — on this one it cannot.
and append to the mechanism paragraph:
The residual visit order is not the seed and not the client stream. It is per-process, and the only mechanisms in the record are an address-keyed container (heap allocation order is measured per-process in this game — BP's node addresses) or a draw on the global generator at
0x00af6e58, which the seed pin does not touch. One run separates them.
Rung B bullet — append, no restatement:
2026-09-09. Lane BP's result makes the case for this rung from the other side: with seeds pinned, the only thing that still varies between processes is a visit order that the block itself records (list 10 carries the fleet id each ship group received). Replay applies ids off the wire in block order and is insulated from it by construction. The first rich-turn record is one
aiorders.deep=onrun of BP's pinned procedure away: if it lands one913ff41…it is (ad-turn27-two-raiders.sav, seeds32=156ebbbd,496=fe7b2826,512=0ed341d1, deep block,e913ff41…) — the workload that completes thirteen ships, creates a design and colonises a system, which no replay can be measured on until the sim runsProcessTurnon a state that rich.
Rung A: untouched.
7. Rules
Rule 26 (c) — BP's amendment, corrected. BP's inserted clause reads "for a player that has an AI
client and something to decide with … because they have NumOwn == 0 and the engine builds three AI
clients". The measured fact is the first half only: the four NPC factions have no client, so their
ResTNm == '' is inert. NumOwn == 0 is not shown to be a gate — players 496 and 512 have
NumOwn == 0 and do have clients (they held targets, so the pick was not exercised either way). Replace
the parenthetical with:
(lane BP, 2026-09-09:
ad-turn27has seven non-human players and the engine builds three AI clients —RunAIfires for net ids 32/496/512; the four NPC factions 528–576 get no client and theirResTNm == ''is inert. A save-field predicate must be read against who actually runs, which is a property of the player kind, not of the field. Whether a client withNumOwn == 0reaches the pick is untested: 496/512 held targets.)
Rule 26, new corollary (d) — draft:
(d) When the instrument cannot be removed, make it reproduce a natural run. A seed pin needs hooks, so "the un-instrumented pinned game" does not exist and rule 19's control is unavailable. Lane BP's answer: run the save once unpinned with the seeds logged, pin the next processes to those observed values, and require a pinned run to reproduce the unpinned one byte for byte before anything is read from a pinned pair. That agreement is the pin's own control — a perturbing pin could match a natural run only by a 1/k coincidence — and it is a noise mask: any word that differs between two runs with identical outputs cannot be a word the applier reads (lane CB's argument). On
ad-turn27that mask reduced a 9-block, 81-element comparison to three words. The wildcard form of a pin (every client to one constant) is a valid intervention and a worse one: it certifies nothing about a turn that happened, and it would have hidden that the save's seven non-human players produce three clients. Pin to what was observed; count what ran.
Ranked by damage: none — nothing wrong was published; BP stopped where the brief said to stop and the localisation is the best this campaign has produced on an AI turn. That is the brief working, not a rule. Corollary, not rule 29, on the same grounds as last time.
A structural fix instead of a rule, for BP's inherited defect. Under hooks=trace, a registered
hook not named in the config is silently installed in trace mode; shim.cfg.cbpin omitted six. The
fix is in the shim, not in discipline: when any pin or capture module is on (aiseed=pin,
airng.pin_seed, aiorders=on), an unnamed registered hook is a configuration error that aborts
before Application::Initialize, and shim.log prints the installed-hook count next to the
registered count on every run (BP read "27 of 28 off" by hand; make the shim print it). Also fix the
wrapped header comment on shim.cfg.cbpin line 4 and add the six hook.*=off lines. Engine item,
one lane-hour.
8. Course
VM146 — lane BR, the probe, now. Brief, one paragraph: BP's dist is still deployed at
C:\SOTS\shimdist-bp. Copy shim.cfg.bppin to shim.cfg.brprobe and change exactly three lines:
airng=on, airng.pin_seed=off, airng.out=<path>; diff the two configs' non-comment lines and quote
the diff in the report (BP's own check). Verify aiseed pinned=1 ×3 and airng: bracket … MH_OK in
shim.log before reading anything. One fresh process, load ad-turn27-two-raiders.sav (Load-dialog
row 1 at (400,260) per BP's row-62 note; wait 12–16 s before trusting a wall frame), one End Turn,
collect (Autosave).sav, shim.log, the airng output, the aiorders dump. Report: the autosave hash
and which of e913ff41… / 724528ff… it equals; for each of the three brackets the airng row
(left_delta, observed, residual, foreign_words, foreign_calls) and every airngcensus row
whose rng is not that client's +0x134, with return addresses; the aiorders diff against A and B
under BP's noise mask. Predictions are §4's P1–P4. If a foreign draw appears, stop and post its
return address; if none, stop and post the row. Do not read the binary. Do not compare any pinned
file with AD's unpinned files.
VM146, same lane, after the probe, if the guest is still warm: one more run of shim.cfg.bppin
with aiorders.deep=on and airng=off — the Rung B record (§6). Report only the hash and whether the
deep dump follows list 10's ship vectors and list 8's routes.
VM144 — lane "BS", BQ's per-history residue, now (§9.3). Two instrumented runs on the AR
lineage, both routes to turn 39: (continuation) load ar-turn37-816raiders.sav, End Turn, Auto
Resolve Peacefully, End Turn; (load) load ar-oracle-A-pre.sav, End Turn. Config: aiorders=on
(deep=off), airng=on (pin_seed off), aiprobes on every task Execute entry the probe table
carries, every template hook off by name. Both routes have self-agreeing controls, so instrument
neutrality is checkable at k = 1: the continuation must give 15b99255…/7a8b3d5e…, the load
33e30092…/4c356f59…. Predictions in §9.3. If either hash misses, stop: the instrument is not
neutral on that route and the run is void. Stage 2 of BR (the container hook) or the global pin goes
to whichever of VM144/VM146 frees first.
Lane AZ (VM141) — no redirect. BQ has released VM145; its next work is BS if it wants it, since
it holds the click path and the Done-pixel test for that lineage.
All lanes, one line: when you record pre-turn exposure facts next to a hash, record which
players have an AI client (the RunAI net-id list, or "not logged"), not just ResTNm/NumOwn —
and record the route (load or continuation) as part of the procedure.
Host, no VM — three items, in order: (1) state_checksum.py --relabel-new-ids per §3.1, with
BP's pair as the positive acceptance and AD's pair as the negative; (2) the shim config-strictness fix
and shim.cfg.cbpin repair per §7; (3) id-allocation.md §5 gets the canonical-visit-order item and
determinism-oracle.md gets BP's "Qualified" paragraph with §3.1's definition of "modulo π".
Docs to correct in place (rule 11): raid-gate-multiplicity.md §5 footnote — the 94 leaves are
59 seed + 35 visit-order; ai-order-emission.md §4.5 and turn-command-replay.md §4 row 5 — list 10
is StrategyServer::OnCommand_TransferShips (lane W3 named it; the AI-side notes still call it
"unnamed"); pinned-seed-rich-turn.md §2.4's "a player with no colonies has no research income and
does not reach the pick" — mark as inference; the measured fact is "no client";
determinism-oracle.md round-trip rule — BQ's /CD[1]/NPrvVa correction (+5.00 per load; not
covered by --mask resave); determinism-hashes.txt — the load-form AR pair (§9.3), route on the
line.
9. Lane BQ's result, folded in
BQ's seed-exposure-forward-test.md landed while this was being written. Three of its results bear
on this case; each is ruled here rather than in a second document, because they are one picture.
9.1 The frame of the probe is not wrong, but there are two residues and they get two names
- BP: two processes, same route (both loads), disagree → a per-process input.
- BQ: two processes, same route (both loads), agree; the other route (continuation from turn 37) disagrees with both → a per-history input, and no per-process input on that turn.
These are different inputs in the same layer, and the second is consistent with the first: BP's
residue lives in the visit order over groups that need a new fleet, and AR's turn 39 formed none
(two ships into existing Freighters fleets). The visit-order model therefore predicts, after the
fact, exactly what AR and BQ measured — no per-process variation on a turn with nothing to visit.
Retrospective, so worth one line and no more.
Probe BR holds the route fixed (every run is a load, as BP's were), so it is unconfounded by BQ's
input. BQ's proposal — the per-client ledger on ar-oracle-A-pre → 39 by both routes — is the right
probe for the second input and is adopted as lane BS (§8), with two additions: aiorders=on, and
the task-entry probes. The reason is §9.2: the leading mechanism for a per-history input is not a
draw, and a ledger alone would report it only indirectly.
9.2 What the per-history input can be, ranked — inference throughout
- AI agent state the save does not carry.
AISystem::Writeemits nothing and the threeAIAgentsave blocks are cache (backlog §4.1); tasks, claims and goals created on turn 38 exist on turn 39 only in the process that ran turn 38. A task that tookZeta Fleet Von turn 38 and issued its move on 39 is exactly a continuation-only order. This is the same class as two things already in the record — the0x0069dbb0fuse (agent+0x36cnot persisted) and the client id counter (id-allocation.md§3.2, restarts on load). Three named siblings; leading. - Client generator stream position — rejected as the mechanism. Both routes are seed-insensitive on this turn (AR's three continuation processes had three seed sets and agreed; BQ's two loads had two and agreed), so no draw-dependent decision is what differs.
- Server-side state not in the save — the sim reproduces by load on the canonical pair and on BQ's own 1b pair; nothing in the record points here. Last.
Predictions for lane BS, committed: (a) the continuation's turn-39 block for pid 32 carries a
list-8 element for fleet 1570 and its list-14 pair, and the load's block does not; (b) a task
Execute entry probe fires in the continuation and not in the load — or the same task fires in both
and gathers a different fleet set; (c) airng shows the two routes' per-client word counts
differing by at most that task's cost, with zero foreign draws in both; (d) the pre-turn autosaves
differ only in /CD[1]/NPrvVa. If (a) holds and (b) shows no task difference, the gathering hub's
fleet set is the next place to look, and that is BR's stage 2 territory — the two lanes converge on
the same 992-byte function from two directions.
9.3 Rung A — BQ's reading confirmed
ar-oracle-A-pre.sav → (load, one End Turn) → (Autosave EndTurn) 33e30092… / (Autosave) 4c356f59…
enters determinism-hashes.txt as the standalone's first trade-raid pair, with the route, the
exposure facts (Player[32] BIO_EnvTail held, no design, two completions into existing fleets, four
raiders parked, no encounter) and the NPrvVa mask on the line. ar-oracle-A-pre → 7a8b3d5e… does
not enter as a load→turn pair; AR's two-turn continuation from ar-turn37-816raiders.sav stays
certified as that procedure (three processes) and is not an engine target, because the engine runs
from a save. This is the §6 scope line: every engine comparison is load→turn. The canonical pair
turn2-state → turn3-state already satisfies it — it was reproduced by load (CB, ID §3.2) and
matched the continuation, which is the case where the agent carried nothing that mattered.
9.4 Rule 26 (c) — BQ's four amendments, ruled, and the consolidated text
(i) accepted: ResTNm == '' names a pick; exposure is |candidates| > 1, not readable from the
save but readable from one airesearch=on run of it. (ii) accepted with the §7 wording fix —
the false-positive class is "no AI client", and NumOwn is a proxy that has not been shown to gate
(496/512). (iii) accepted: the combat term, and BQ's sentence for it. (iv) accepted and
generalised: exposure is a property of (save, route); (c)'s "(save, procedure, hashes)" already
carries it, and the route is part of the procedure.
Replace the predicate sentence of rule 26 (c) — from "rule 28's shape:" to the semicolon before
"one consumer (0x0069dbb0)" — with:
rule 28's shape, with the terms measured so far: (1)
ResTNm == ''at turn start, for a player that actually runs an AI client (a property of the player kind — onad-turn27and the AR lineage seven non-human players yield three clients, and the four NPC factions'ResTNm == ''is inert), names a turn on which a pick is made; it is exposed only if the candidate walk is offered more than one candidate, which oneairesearch=onrun of the save reads (candidatesTried; lane BQ: 1 onar-oracle-A-post, and the pick agreed); (2)NumDesmoving names a design turn; (3) a batch of completions that forms new fleets names a fleet-assignment turn, and on such a turn a per-process visit order survives the seed pin (lane BP); (4) an AI fleet standing at an enemy colony names a combat turn, andAuto Resolve Peacefullymeans "I commit no ships", not "no combat occurs" — the planet fights andRunCombatRoundis per-process (lane BQ); (5) the route is part of the procedure: the same file reached by continuation and by load can run its next turn differently, both reproducibly (lane BQ), so a continuation's hash is never a load→turn target;
Proposed campaign/board.md rows
New row:
| THE PINNED-SEED RESIDUE IS A VISIT ORDER, IT IS WRITTEN INTO THE BLOCK, AND ONE RUN SEPARATES HEAP ORDER FROM A GLOBAL-RNG DRAW | meta | verified | high | 100% | 2026-09-09 | Resolver, on lane BP's falsified P1 (`findings/resolutions/2026-09-09-fleet-id-order-residue.md`). RULING ON BP'S RESTATEMENT: accepted and sharpened. The ids are NOT the variable - 1970/1986/2002 decode (id-allocation.md) to node 2 = Player[32]'s client, counters 123/124/125, minted in that order in every process. The variable is the ORDER in which AssignFleetsAndIssueOrders (0x006c16c0, pass 1) visits the ship groups needing a new fleet: A visited the group at Sys 384 first, B the group at Sys 80 first; 2002's group third in both. That order changes the id each group gets, the element order of lists 8/10 and the apply order (hence ShipIDs[] reordered) and NO decision on this turn. **AND IT IS WRITTEN INTO THE BLOCK**: list 10 = StrategyServer::OnCommand_TransferShips {systemId, fleetId, ships[]} records the assignment on every captured run, so C-EXACT SURVIVES LITERALLY with one more free input: (save, seeds, visit order) -> byte match; C-set's shape covers the uncaptured case (canonical order = one member of the outcome set). ENGINE: (1) `state_checksum --relabel-new-ids <pre.sav>` - bijection on that turn's new node-k ids matched by (location, ship set), master id lists as sets, Summary/Checksum masked WITH REASON, refuses to relabel anything in the pre-turn save; accept = BP's pair IDENTICAL modulo {1970<->1986}, AD's pair still DIVERGED; (2) game/ai visits groups canonically (ascending systemId, then min ship id) and mints in that order; (3) optional captured-order override for exact replay. RULING ON POINTER ORDER: not yet leading - ONE OF TWO. The record already names two unnamed AI-band consumers of the per-process global generator 0x00af6e58 (0x0079ea90+0x73 Chance, 0x005b9f00+0xc0; AI1's list) which the seed pin does not touch. What moved: pointer order now has a MEASURED PRECONDITION - BP's aielem dumps carry node heap addresses, and runs A and B (identical config, identical decisions) show the same run of consecutive same-size allocations in DIFFERENT relative address orders (list 3: A idx1<idx0, idx3<idx2; B idx1>idx0, idx3>idx2) - Win8+ LFH randomisation, live in this process. Precondition, not cause. Wall clock has no mechanism (AIProcessMinTime is a trailing Sleep; AI turn is synchronous in OnResumePlaying). THE PROBE (lane BR, VM146, one fresh process, no build, ~12 min): BP's shim.cfg.bppin + `airng=on` (pin_seed off) - the OnResumePlaying bracket attributes EVERY draw on EVERY generator in each client's turn by return address and generator (airngcensus rows, foreign_words/foreign_calls); lane I's inlined-draw inventory has NO site in the AI band so the observer is complete there; airng is measured behaviour-neutral (roll-parity.md). It is also run C. PREDICTIONS: P1 autosave in {e913ff41, 724528ff}; P2 foreign_words=0 in all three brackets, no census row on 0xaf6e58 or Seed record #2; P4 aiorders diff = noise set + at most the transposition. Foreign draw -> its retaddr names the consumer, follow-up = global pin (RNG_Seed(0xaf6e58,K) after Initialize) x2, predict identical. None -> RNG excluded by measurement; stage 2 = one static read of 0x006c16c0 + the gathering hub TO PLACE A HOOK on the group walk, log (element addr, systemId, minted id) in visit order x2 processes, predict order = ascending address. RUNG C restated (backlog text in §6); RUNG B not restated - value confirmed, replay is insulated by construction, and a `aiorders.deep=on` run of BP's pinned procedure landing on e913ff41 is the first rich-turn record. RULE 26(c): BP's wording corrected - the measured fact is "no client", NumOwn==0 is NOT shown to gate (496/512 have NumOwn==0 AND clients). NEW COROLLARY 26(d): when the instrument cannot be removed, pin to a natural run's observed values and require byte-identity with it before reading a pinned pair; the agreement is the pin's control AND a noise mask. No rule 29. STRUCTURAL FIX for BP's shim.cfg trap: an unnamed registered hook under a pin/capture config is a config error; print installed/registered counts. VM144 held for stage 2 / the global pin |
Edits to existing rows:
- Row 360 — take BP's proposed scope note, then append:
RESOLVER 2026-09-09: the residual is the AI's fleet-group VISIT ORDER, observable in list 10 of the block; C-exact survives with it as a third input. Heap order vs global-RNG draw separated by lane BR (VM146). - Row 415 — take BP's proposed append; add:
The 35 are a visit order, not a decision; see the resolver row of 2026-09-09. - Row 326 — take BP's proposed append unchanged.
- Row 333 — replace BP's proposed append with:
C-EXACT RESTATED 2026-09-09 (resolver, on lane BP): determined up to the fleet-group visit order in AssignFleetsAndIssueOrders, which the block itself records (list 10); engine visits canonically, comparison relabels new ids (state_checksum --relabel-new-ids). Rung B unchanged and strengthened. - Row 424 (AR's oracle pair) — take BQ's proposed append unchanged; add:
Resolver 2026-09-09: confirmed. The load-form pair enters determinism-hashes.txt; the continuation form is not an engine target. Every rung's byte-match claim is load->turn. - BQ's three proposed new rows — accept as written, with one wording change in the third: replace
Read the predicate only for a non-eliminated AI player with NumOwn > 0withRead the predicate only for a player that actually runs an AI client (RunAI's net-id list); NumOwn is a proxy not shown to gate - 496/512 have NumOwn == 0 and clients. - BQ's
determinism-oracle.mdcorrection (/CD[1]/NPrvVa+5.00 per load) — accept;--mask resavegains the leaf with its reason, and--relabel-new-ids(§3.1) must compose with it. - Row 62 — VM146: lane BR (probe, then the deep Rung-B record); VM144: lane BS (BQ's per-history residue, both routes,
aiorders+airng+ task-entry probes); VM145: FREE (BQ released, restored); VM141: AZ unchanged; VM140 untouched.