From 9eaec9ba2c6565db74e4eb335d2c22cd758bed67 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 8 Sep 2026 21:43:00 -0400 Subject: [PATCH] resolution: V2 vindicated, my Rung B claim corrected, AC's probes=11 caveat; rule 28 on gated negatives --- campaign/board.md | 5 +- findings/resolutions/2026-09-09-tail-draws.md | 304 ++++++++++++++++++ guides/method-rules.md | 27 ++ 3 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 findings/resolutions/2026-09-09-tail-draws.md diff --git a/campaign/board.md b/campaign/board.md index 4a51a81..f325fdf 100644 --- a/campaign/board.md +++ b/campaign/board.md @@ -396,8 +396,11 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`). | SD self-reported a rule-21 shaped error | meta | verified | high | 100% | 2026-09-09 | Twice it ran `verify/design-rules/stock_designs.py` inside the **shared** sots-re clone to identify a save's players; **the script writes stock_designs.json as a side effect** and it restored the file with `git checkout -- `. Clean afterwards, but that is exactly rule 21's shape - **and it would not have known if another lane had work in flight there.** Worth generalising: a read-only-looking script can have write side effects, so run analysis tools against a copy, not the shared tree | | REVERSAL: THE TAIL DOES DRAW - W3's risk is REALISED | verify | verified | high | 100% | 2026-09-09 | **Lane AC overturns the "retired by evidence" conclusion I reported.** OnAllCombatDone_Tail consumed **1 RNG word per turn** in the state AC built, against **0 in its own control** (same guest, same build, same probe config, one End Turn on L3's turn-15 save, run immediately after). `TradeManager::Slot13RngCalleeA` - **entered 0 times in every measurement any lane had ever taken** - was entered **1x/turn on both instrumented turns**; CalleeB on the turn the roll succeeded; CreateRaidEncounter once. All probes installed=true, watchpoint canary PASS every turn. **THE RNG LEDGER AND THE STANDALONE'S GENERATOR MODEL NEED EXTENDING BY ONE DRAW SITE** | | and the gate is a TECH, not container contents | verify | verified | high | 100% | 2026-09-09 | **Neither freighters nor a deployed spy is in the predicate** - AC disassembled the gate chain BEFORE building the state. `ServerTradeManagerImpl::vslot13` does not iterate routes or sectors; it iterates the **FLEET** vector and requires a fleet whose LocID resolves to a node of kind **2 (TradeSector)**, positioned **bit-equal** to the sector, whose owner's bit is set in the sector's **`tscr`** mask. `tscr` was **252 in every corpus save = exactly the six NPC slots**, and AC's own prediction P6 said that excluded real players and the callees would stay 0. **WRONG, AND INSTRUCTIVELY**: the mask is not fixed. Researching **`CCC_ComRaid` (Commerce Raiding, RP 12,000, one turn off CCC_FTLEcon)** takes tscr **252 -> 253** on every sector and sets the ServerPlayer flag serialised as **`CnRad`**. **The game says so in as many words**: before the tech, `Alpha Fleet cannot raid trade sector.`; after it the same click is accepted. **That dialog is the cheapest test of the whole chain** | -| CORRECTION: L3's own save falsified the freighter hypothesis | verify | verified | high | 100% | 2026-09-09 | L3 3.5 says "every trade sector has `tsnumflt = 0`". **Wrong about its own save**: `human-turn15-spyprogram.sav` sector TradeID 816 has **`tsnumflt 1`, `tsflt 2736` - the AI's Freighters fleet, on an active route, across all seven of L3's instrumented turns, with the callees at 0.** So "freighters in service" was falsified BEFORE lane AC started. Also **`tsflt` is not a freighter list** - at turn 20 sector 6 reads tsflt 3744, which is AC's WARSHIP fleet. And lane V2's "trade slot 13 is draw-free" was a statement about the states that occurred (rule 23), not about the code | +| CORRECTION: L3's own save falsified the freighter hypothesis | verify | verified | high | 100% | 2026-09-09 | L3 3.5 says "every trade sector has `tsnumflt = 0`". **Wrong about its own save**: `human-turn15-spyprogram.sav` sector TradeID 816 has **`tsnumflt 1`, `tsflt 2736` - the AI's Freighters fleet, on an active route, across all seven of L3's instrumented turns, with the callees at 0.** So "freighters in service" was falsified BEFORE lane AC started. Also **`tsflt` is not a freighter list** - at turn 20 sector 6 reads tsflt 3744, which is AC's WARSHIP fleet. **[CORRECTED 2026-09-09 by the resolver: LANE V2 IS VINDICATED AND WAS MISQUOTED.** `indirect-edges.md` 3.1 lists trade slot 13 as **DRAWING at 0x00820e18 - the exact site that fired.** "Closure 185, draw-free" is V2's row for **slot 9**, the route rebuilder lane L3 trapped. Lane AC carried the number to the wrong slot and I published it. V2's static reading was right all along.] | | spies2 NOT settled, and the deploy state is unreachable in that game | verify | backlog | — | 0% | 2026-09-09 | AC could not deploy a spy and **declined to infer around it**. `ARes2` on ServerSystem **is the asteroid-belt field** (non-zero values 1703-2531 sit inside SYSTEM_MIN/MAX_ASTEROID_RESOURCES 1500-3000); in L3's save only **5 of 28 systems have a belt and NONE is AI-owned** - the textbook deploy target does not exist in that game. **AND L3's "the next condition is spyon" UNDERSTATES IT BY THREE TURNS AND A DETECTION ROLL**: the chain needs `deat != 0`, then `sdet` set by a detection roll on an EARLIER turn, then `turn - sdet >= 3`. **That detection roll is itself an RNG draw, inline in vslot13, not inside P** - so a probe on P reading 0 does not mean the spy half is draw-free | | AC's coverage caveat, stated | verify | backlog | — | 0% | 2026-09-09 | Two turns, one fleet, one sector, one ship. **`Slot13RngCalleeA` has a short-circuit (`design+0x12c > 1` returns true without rolling) that AC's hull did not exercise**, so a different raider could cost **0 words while still firing B**. The one-word-per-turn figure is this raider's, not the site's | | ratchet warning: AC's saves carry new content | verify | backlog | — | 0% | 2026-09-09 | `ac-turn20-raider.sav` and `ac-turn22-raider.sav` (both --strict clean) carry **`CnRad`, `tscr = 253`, three `rt` route records, and a StarFleet whose `LocID` is a TradeSector id - the first fleet in the corpus located anywhere but a star.** Expect the coverage ratchet to break (rule 27); that is the content to type | | LAB: jmove reads but does not commit; static-link the shim | meta | verified | high | 100% | 2026-09-09 | **`jmove` (jiggle) is required to READ the star-map hover readout but SILENTLY FAILS TO COMMIT a move** - use plain `click` to confirm, and verify the order from `Flt.LocID` in the autosave, never from the fleet panel. And on the WSL dev box the mingw toolchain links **posix-threads**, so the shim DLL imports libwinpthread-1.dll and **the game dies at load with 0xC0000135 and NO LOG AT ALL**; `-DCMAKE_SHARED_LINKER_FLAGS=-static` fixes it. AC did not change the toolchain file - flagged for the integrator | +| MY ERROR: Rung B IS affected - replay runs the tail | meta | verified | high | 100% | 2026-09-09 | I told lane RB that command-stream replay was unaffected by a tail draw "because replay runs no AI". **Wrong.** The resolver: this is a **sim draw on S+0x16c keyed on save state**, and `--turn-commands` replay **runs the tail** (`command_replay.h:83`). **Rung B needs the same generator model as Rung A.** The canonical pair happens to be untouched by the predicate (tscr = 252, no fleet at a sector), so nothing measured is invalidated - but the reasoning I gave RB was wrong and would have bitten on any raid-turn replay | +| AC's numbers are at probes=11, which is NOT byte-neutral | verify | verified | high | 100% | 2026-09-09 | The resolver's exoneration is partial and precise. **The tail's +1 stands** - control 0 / active 1 under identical guest, build and config, with the callee going 0 -> 1 entries on the same turns. **But every AC number is at `probes=11`, which lane H bisected as NOT byte-neutral**, and AC's own predictions doc promised a `probes=8` primary reading **it never took**. Consequences: the turn totals 20/18 are **not calibration data**, and **no AC autosave is an oracle pair**. `ac-turn22-raider.sav` remains a valid INPUT state. A reminder that rule 19's control must be at the configuration you are quoting | +| lane Z's ledger: the method is sound, the AUDIT is not | meta | verified | high | 100% | 2026-09-09 | The resolver's structural ruling. A bracket state-difference **cannot miss a draw that happens** - the instrument is sound. But **the audit is indexed by FIRING**: a site enters the table when a state reaches it, so **it can only grow by luck** (hives, now the raid roll - two qualifications in two days). **What makes the next audit complete: GATE-INDEXED** - one row per statically reachable site (lane I's 22+28, V2's 8, L1's hive, node-line decay, the SVSO overrides), each carrying **either a measured firing or a decoded predicate on save fields plus the corpus count satisfying it**. Today's unfilled rows are named: 0x0088b613, 0x0082cdb8, 0x0088dc43, the spy-13 family, and the SVSO generator which is still unknown | diff --git a/findings/resolutions/2026-09-09-tail-draws.md b/findings/resolutions/2026-09-09-tail-draws.md new file mode 100644 index 0000000..be8b9f7 --- /dev/null +++ b/findings/resolutions/2026-09-09-tail-draws.md @@ -0,0 +1,304 @@ +# Resolution — the tail draws behind a tech gate; the ledger was firing-indexed, the audit must be gate-indexed + +- **Type:** resolution (course-setting; no measurement taken here) +- **Trigger:** lane AC's `findings/control-flow/trade-raid-rng-gate.md` — `OnAllCombatDone_Tail` + costs 1 word/turn with a permitted raider parked on a trade-sector node, 0 in its own control +- **Date / author:** 2026-09-09 · re-resolver +- **Touches:** board rows 186 / 207 / 373 / 399 / 62; `tail-rng-ledger.md` headline (third + qualification); `indirect-edges.md` §3.1 (vindicated, and misquoted by AC §6); `backlog.md` + §3 item 3, §4 item 3, §5; `sots-engine` `phase_catalog.cpp` T23 and `TurnResult::rngUnaccounted`; + `method-rules.md` (new rule 28) + +--- + +## 0. Decision + +1. **The surprise is real and the instrument is exonerated for the word it found.** Same guest, + build, config; control reads 0, active reads 1; the callee that holds the decoded `NextFloat` + went 0 → 1 entry on the same turns; the success-only callee `B` fired on one turn of two, + which is what a roll does. **One qualification that AC's own prediction doc promised and the + run did not deliver:** every active-state number was taken at `probes=11`, which lane H + bisected as *not* byte-neutral (it suppresses a `ProcessTurn` research draw). The tail delta + survives that (it is entry-attributed and the perturbation is elsewhere in the turn); the + turn totals 20 / 18 do **not** become calibration numbers and **no AC autosave is an oracle + pair**. `ac-turn22-raider.sav` is a valid *input* state regardless. +2. **Lane Z's ledger is sound as an instrument and was never a completeness proof.** It reads + generator state across a bracket, so it cannot miss a draw *that happens*; its site table lists + sites *that fired*. Twice now (hives, raid roll) a site outside the table cost 0 on every turn + Z measured and non-zero on a state nobody had built. The structural gap is not in the ledger + but in the **audit** built on it: indexed by firing, it can only grow by luck. The next audit is + complete when it is **gate-indexed** (§3). +3. **Lane V2's static reading is vindicated, not overturned — and AC §6 misquotes it.** V2 §3.1 + lists trade slot 13 (`0x0088ef80`, closure 84) as **drawing** `NextFloat, NextInt`, with the + `NextFloat` at **`0x00820e18` inside `0x00820ca0`** — the exact site AC fired. "Closure 185, + draw-free" is V2's row for **slot 9** (`0x00868060`, the route rebuilder L3 trapped), and + nothing contradicts it. Board row 399's last clause and AC §6's V2 paragraph are wrong and + must be corrected in place (rule 11). The static inventory was ahead of every measurement + here; what was missing was the step from *gate* to *save predicate*. +4. **The coordinator's "risk retired" row is overturned; L3's measurement survives.** L3's zeros + were true of its state. Its *inference* — "the next condition is freighters / `spyon`" — was + a guess at the nearest container, falsified by its own save (AI freighter on an active route + for seven turns) and by the predicate (freighters are not in it). Four lanes converged on a + false negative about reachability because none of them decoded the gate to a predicate on the + save and counted the corpus against it. **Rule 28, drafted in §6.** +5. **Rung B is affected exactly as Rung A is — the coordinator's reading is wrong.** The draw is + a *sim* draw on `S+0x16c`, keyed on state (`Flt.LocID` → `TradeSector`, `Pos` bit-equal, + `tscr` bit), not on the AI. `--turn-commands` replay runs no AI but **does run the tail** + (`command_replay.h:83`). Any pair whose input carries a permitted parked raider needs the + site modelled for both rungs. The canonical pair is untouched (`tscr = 252`, no fleet at a + sector node). No rung moves; §3 of the backlog gains an item. +6. **One probe, VM141, ~5 turns from `ac-turn22-raider.sav`:** a second raider of a different + hull on the same sector, measured with lane Z's **return-address** ledger (`draw_sites`) at + `probes=8` or `hooks=off`, two fresh processes. It separates per-fleet from per-sector cost, + prices the `design+0x12c > 1` short-circuit, catches `B`'s inner `NextInt`, and hands the + standalone its first raid-turn **oracle pair**. §4. +7. **The spy half is a lane, not a probe, and it needs a new game** (no AI-owned belt exists in + L3's map). Brief in §7; its instrument is `draw_sites`, not entry probes on `P`, for exactly + the reason AC gave. + +--- + +## 1. The surprise, precisely + +On VM141 under shim build `ac-7e726b9`, config `shim.cfg.l3probe`: one End Turn on lane L3's +`human-turn15-spyprogram.sav` gives `OnAllCombatDone_Tail` **355 → 355** and +`TradeManager::Slot13RngCalleeA` **0 entries**; two End Turns on AC's turn-21/22 lineage give +**468 → 469** and **487 → 488**, `A` **1 entry each**, `B` **1 then 0**. The difference between +the two states, read from the saves: `CnRad` true on player 0, `tscr` 253 not 252 on all six +sectors, and one `StarFleet` whose `LocID` is a `TradeSector` id with `Pos` bit-equal to the +sector's — the first such fleet in the corpus. AC's committed P6 predicted **no** firing on the +`tscr`-is-fixed reading; it was falsified, which is the strong form of rule 2. + +## 2. The instrument + +**Exonerated for the delta.** Three independent signals agree: the boundary ledger's +1, the +entry probe's 0 → 1 on the callee V2 had statically placed the `NextFloat` in, and `B`'s +success-only firing pattern. The control is the same instrument on the same guest minutes apart. +The `hooks=off` control on `ref-turn2` matched the three-process published oracle (rule 26's bar, +met by agreement with an already self-consistent control). + +**Qualified on byte-neutrality — and AC knew.** `docs/AC-predictions.md` §2: *"I will take the +primary reading at `probes=8` … and cross-check at `probes=11`."* The report is `probes=11` +only. Lane H showed that configuration suppresses `RollResearchEvent`'s draw earlier in the turn. +Consequences: (a) the tail's +1 stands — it is attributed by entry and decode, and the known +perturbation is a `ProcessTurn` site; (b) the turn totals and `left` positions in AC's traces are +**not** calibration data; (c) AC's `(Autosave).sav` files were produced by a perturbed process and +are **not oracle pairs** — the raid-turn oracle pair still has to be made (§4 makes it). None of +this touches the *state* in `ac-turn22-raider.sav`, which is an input like any other. + +## 3. Standing claims + +| claim | where | verdict | scope / correction | +|---|---|---|---| +| "18–22 words/turn, every word attributed, zero residual" | lane Z, board 186 | **survives as measurement; qualified a second time** | True of every turn measured. "Every word attributed" is per-turn; it was read as "the site set is complete", which the instrument never claimed. Now two sites outside the set: hives (`BeginProcessTurn`, L1) and the raid roll (tail T23 call 7, AC). The ledger's *method* — state difference across a bracket — is exactly right and would show any future site as residual the moment its state is reached | +| L1's qualification of Z (creation-turn hive draws) | `hive-creation-rng.md`, board 336 | **survives** | Same shape as this one; both are rule-6 sites that no corpus state reached | +| V2: trade slot 13 draws `NextFloat`/`NextInt` at `0x00820e18`/`0x0088b613`; spy 13 draws at `0x00887c8a` (inline) + three in `P`; trade 15 and spy 14 one `Chance` each; "hook them with a live workload" | `indirect-edges.md` §3.1, board 207 | **survives — vindicated** | The site AC fired is V2's `0x00820e18`. Its *negative* rows (slots 7/8/9/11/12/14, spy 15) remain lower bounds by V2's own §6 (inlined draws). Board 207's "our corpus has neither" was the wrong diagnosis of *why* — the containers were never the gate | +| AC §6 / board 399: "V2 recorded trade slot 13 as closure 185, draw-free" | AC, board 399 | **overturned (misattribution)** | 185 / draw-free is slot **9**, the route rebuilder; L3 §3.3 quoted it correctly for slot 9 and AC carried the number to the wrong slot. Correct both in place | +| H §3: four outer callees entered every turn, gated inside; P2b-alt falsified — "the per-fleet test chain is the gate and rejects every fleet on a 23-fleet save" | `tail-probes.md` §3.1 | **survives exactly** | H stopped one step short of decoding the chain. It also established `probes=8` as the neutral configuration, which AC then did not use | +| W3: "if either container ever fills, the ledger and generator model need extending; the trigger is now detectable" | `w3-containers-status-handlers.md` §1 | **survives as a risk; trigger overturned** | Filling the containers changed nothing; the extension was needed for a state the container watch cannot see. The detectable trigger is `Flt.LocID` resolving to a `TradeSector` id | +| L3 §3.5 measured zeros with 21 routes + 1 spy | `trade-and-spy-workload.md` | **survives** | True of that state, and the state had an AI freighter on an active route the whole time | +| L3 §3.5 "the next condition is `tsnumflt > 0` / `spyon != 0`"; coordinator's "risk retired by evidence" | L3, board 373 | **overturned** | Freighters are not in the predicate; `spyon` understates the spy chain by `deat != 0`, a detection roll on an earlier turn (itself a draw), and `turn − sdet ≥ 3` | +| L3: "`spies2` is not the spy list" | L3 §6 | **still open** — unchanged | Deploy not reached; AC's P4 (fills only for a deployed spy) is the live reading; rule-6 flag stays | +| AC: gate = fleet at `TradeSector` node, `Pos` bit-equal, `tscr` bit, `tsct` ⇒ `FtFlg & 0x800`; `CCC_ComRaid` sets `CnRad` and bit 0 of every `tscr` | AC §2.1, §3 | **survives** (verified, one state) | Coverage: 1 fleet × 1 sector × 1 ship × 2 turns. The per-fleet loop is read, not measured (§4) | +| AC: cost = 1 word/turn | AC §1.2 | **qualified** | That raider's cost. `A` short-circuits without drawing when any ship's `design+0x12c > 1`; `B` ran once at 0 words with a `NextInt` inside it gated on something unread. Cost per turn is `Σ_fleets [passes G0–G4] × (short-circuit ? 0 : 1) + B's cost on success` — the first term is inference, the rest unmeasured | +| AC §2.2: the spy detection roll is inline in `vslot13`, invisible to an entry probe on `P` | AC | **survives — and V2 already listed the site** (`0x00887c8a`) | The fix is instrument choice: lane Z's `draw_sites` keys on return address and sees every entry-point call wherever it sits; only an *inlined* MT (rule 16) escapes it, and `0x008e6dd0` is `Chance`, an entry point | +| Backlog §4 item 3: "four can draw and none has fired (no trade routes / spy program in the corpus)" | `backlog.md` | **overturned** | One has fired; the corpus reason was wrong. Restated in §8 | +| Backlog §2: Rung B "unaffected … replay runs no AI" (coordinator's reading in the brief) | brief | **overturned** | Sim draw; the tail runs under replay. Rung B needs the same generator model as Rung A | +| Standalone calibration pairs `z2-*`, `z-t6-*` | lane Y | **survive** | Both turns have `tscr = 252` and no fleet at a sector; the site costs 0 there by the predicate, not by luck | + +### 3.1 The ledger question, answered + +*Is the method sound and the scope narrower, or is there a structural reason it kept missing +sites?* Both, and they are different objects. The **instrument** (bracket state difference + +return-address attribution) is sound and complete *for the turn it measures* — an unlisted site +that fires shows up as residual, which is how L1's run announced the hive draws. The **audit** +(`tail-rng-ledger.md` §11 read as "the generator model's site list") is structurally incomplete +because it is **indexed by firing**: a site enters it when a state reaches it, and no instrument +on a state can enumerate the states it is not in. It kept "missing" sites because the corpus kept +not reaching them, and nothing in the audit could say so. + +**What makes the next audit complete rather than larger:** index it by **gate**, not by firing. +One row per statically-known draw site reachable from `BeginProcessTurn` ∪ `ProcessTurn` ∪ +`OnAllCombatDone_Tail` over direct + tail-jump + pinned-virtual edges (lane I's 22 + 28 inlined, +V2's 8, L1's hive site, node-line decay, and V2 §4.3's SVSO overrides — the last with *which +generator* still unknown). Each row must carry **one of two things**: a measured firing (save, +turn, words), or a decoded gate written as a **predicate on save fields** plus the number of corpus +saves satisfying it. A row with neither is the audit's own to-do list; a row with predicate and +count 0 is rule 6 with a recipe attached (`tscr` bit ⇒ research `CCC_ComRaid`). Completeness is +then a property you can check by reading the table, and the table can be *wrong* — a predicate +claim is falsifiable by one manufactured save — which the firing-indexed list never was. + +Today's unfilled rows, from V2's eight: `0x0088b613` (`B`'s `NextInt`; `B` ran, cost 0, gate +unread), `0x0082cdb8` (trade 15 `Chance`; loop is the route vector, L3 had 21 routes, cost 0, +gate unread), `0x0088dc43` (spy 14 `Chance`; loop is the spy vector, L3 had 1, cost 0, gate +unread), and the spy-13 family (`0x00887c8a` inline + `P`'s three) whose gate AC decoded and +whose corpus count is 0. Plus the SVSO slot-4/11/25 overrides with generator unknown. + +## 4. The one probe — a second raider, a different hull, the return-address ledger, an oracle pair + +**Load `ac-turn22-raider.sav` on VM141. Build one warship of a hull whose `design+0x12c > 1` +(AC's short-circuit field — a DN if that is hull class; whichever satisfies the read), keep it as +its own fleet, order it to sector 6 with a plain `click`, verify `Flt.LocID = 832` from the +autosave, then End Turn twice with lane Z's `draw_sites` detours armed and entry probes at +`probes=8`, in two fresh processes each, `hooks=off` once for the oracle bytes.** + +Live hypotheses it separates, with the number each predicts on the tail: + +- **H-fleet** (the decoded loop): cost = one draw per fleet passing G0–G4 that is not + short-circuited. Two raiders, one short-circuited ⇒ `A` entered **2×**, **1 word**, `B` entered + ≥ 1× (the short-circuited fleet succeeds without rolling, so `B` fires for it every turn). +- **H-fleet, no short-circuit** (if the hull read is wrong): `A` 2×, **2 words**, `B` 0–2×. +- **H-sector** (one roll per sector, AC's reading wrong about the loop): `A` **1×**, **1 word** + regardless of fleet count. + +Every outcome is informative and all three are cheap to tell apart. What rides along for free: +`draw_sites` prices `0x00820e18` and `0x0088b613` by return address (settling `B`'s cost on +success, which entry counting cannot), and the `hooks=off` run in two processes — agreeing, rule +26 — gives the standalone a **raid-turn calibration pair** it does not have, because AC's +autosaves were made under a perturbing configuration. Predictions to commit before the build: +`A` 2×/turn; 1 word if the short-circuit is real, 2 if not; `B` ≥ 1×/turn; `B` costs 0 on every +success; the un-instrumented pair reproduces in two processes. + +Do **not** spend this probe on the spy half. Nothing in that game can reach a deployed spy. + +## 5. The generator model, extended precisely + +For `sots_turn`, in `phase_catalog.cpp` **T23** (currently `"eight vtable calls, wholly +unidentified"` — they are all identified, V2 §3): call 7 of 8, `ServerTradeManagerImpl::vslot13` +(`0x0088ef80`, dispatched at `0x007d97f7`), after the slot-9 route rebuild (call 5) and before +slot 15 (call 8). Iterate `StrategyServer` fleets in vector order; for each fleet `F`: + +``` +sector = F.LocID resolved; require node.kind == 2 (TradeSector) -- G2 +require !(runtime flag pair +0xb8/+0xbc & 0x80000) -- G3a (not on the wire; assume clear) +owner = F.owner; require owner +require (sector.tscr >> owner.index) & 1 -- G3b (tscr is on the wire) +if ((sector.tsct >> owner.index) & 1) || owner.+0x5c == 4: -- G3c + require F.FtFlg & 0x800 +require F.Pos == sector.Pos, all three floats bit-equal -- G4 +if any ship in F has design+0x12c > 1: success, 0 words -- A short-circuit (read, unmeasured) +else: 1 × NextFloat via rng+4 (1 word, no rejection loop), success iff < odds +if success: B (0 words on 1 observation; contains NextInt 0x0088b613 behind an unread gate) +``` + +Odds: AC read `0.20` / `0.05` base, `+0.01·nShips`, ×2 with a freighter in the sector, scaled by a +per-ship float — **static, unvalidated** (two turns, one success); the standalone should carry the +**count** now and the decision as `rngUnaccounted`-style "not a prediction" until the odds are +checked, exactly as `trade_raid.cpp` already does for hits. Add the row to `TurnResult:: +rngUnaccounted` today as `"T23c7 raid roll: N fleets pass the gate"` computed from the save, so +that on the canonical pair it prints 0 by predicate and on `ac-turn22-raider.sav` it prints 1 — +that line is the standalone's own rule-28 check. + +**Interval:** unchanged at the ends (`BeginProcessTurn` → post-turn autosave). **Rung B:** same +model; additionally the *move order to a sector node* is a list-8 fleet move whose destination +is a non-star node, which `game/nav` cannot currently route — a new destination kind, noted for +RB, not urgent (no captured stream contains one). + +**Ratchet (rule 27):** `CnRad` on `ServerPlayer`, `tscr = 253`, three `rt` records, `tsflt` +holding a warship id, and `Flt.LocID` = a `TradeSector` id are the content to type. `tscr` is +already a named wire field (L3); the schema needs `CnRad` and the reader needs to accept a +non-star `LocID`. + +## 6. Draft rule 28 for `method-rules.md` + +> ## 28. A zero on a gated path is not a negative until the gate is a predicate on the save +> +> Four lanes measured the trade-raid callee at zero entries and each was right about its state. +> Lane H read that the loop is over fleets and that "the per-fleet test chain rejects every +> fleet"; lane L3 built both containers, measured zero again, and named the next condition by +> looking at the nearest container (freighters, a deployed spy); the coordinator published the +> risk as retired by evidence. Lane AC decoded the chain to four tests, three of them on fields +> the save carries, found `tscr = 252` in every corpus save, went looking for what writes it, and +> found a tech. Nobody had been wrong about a measurement. Everybody had been wrong about +> **reachability**, because the negative was never stated as *which predicate failed*. +> +> So, for any site that a static inventory says can draw and a measurement says did not: +> **(a)** decode the gate to a predicate over save-visible fields, and say which conjunct failed +> on the state measured; **(b)** count the corpus saves that satisfy the whole predicate — if +> the count is 0 the result is rule 6 with a recipe, not a negative; **(c)** name the next +> workload from the failed conjunct, never from the nearest container or vector. A field that +> holds the same value in every corpus save (`tscr = 252`, like rule 8's `ReqCL == (Species != 4)`) +> is a corpus coincidence until its writer is found — find the writer before calling it a +> constant. And when a lane's instrument counts *entries* to a function, a draw sitting in the +> caller is invisible to it: pair entry probes with the return-address ledger before reporting +> a subtree draw-free. +> +> Damage: three lanes on the wrong variable, a "retired" row on the board for a day, and a +> generator model that would have shipped without the site. Caught by a committed prediction +> (P6) being falsified — rule 2 again. + +Below rule 27, append as 28. + +## 7. Course — guests and briefs + +Five guests free. Spend two; keep VM140 as the oracle guest untouched. + +**Lane AD — VM141 (AC's guest: its dist, saves and click verbs are there).** The §4 probe. +One-paragraph brief: *Start from `ac-turn22-raider.sav`. Add a second raider fleet of a hull +that satisfies `design+0x12c > 1` (say which field that is and which hull you chose); park it on +sector 6; confirm `Flt.LocID 832` from the autosave, not the panel. Measure two End Turns with +`draw_sites` armed and `probes=8` — not 11 — in two fresh processes; then `hooks=off` twice from +the same save for the oracle pair, and cite the agreement. Commit before the build: `A` entries, +words, `B` entries per turn under H-fleet, H-fleet-no-short-circuit, and H-sector. Report per-site +words by return address for `0x00820e18` and `0x0088b613`. The pair you produce is the +standalone's raid-turn calibration; hash it into `determinism-hashes.txt`.* + +**Lane AS — VM144 (L3's guest: the research/design/Build Spy click paths and the tender +recipe live there).** The spy half, as a lane. Brief: *L3's map has no AI-owned belt; do not +reuse it. Start a new custom game at L3's settings, End Turn once, and read `ARes2 > 0` against +AI ownership in the autosave before investing a turn — regenerate until an AI colony with a belt +exists. Then L3's §5 recipe to a docked spy, move to the belt colony, `Special → Deploy Spy`. +Instrument: lane Z's `draw_sites` return-address ledger, not entry probes on `P` — the detection +roll at `0x00887c8a` (`Chance`, gated on `0x00743f80(system) & 1`) is inline in `vslot13`. Commit +before the build: `deat != 0` on the deploy turn; a tail draw on the first turn the system-side +bit is set (`sdet` stamped, `EVENT_SPY_DETECTED`); `P` entered on turn `sdet + 3` if the system +stays foreign-owned; `spies2` non-empty in exactly the deploy system (AC's P4). Report every +conjunct of the chain that was and was not satisfied per turn. This is ~20 turns; it is a lane.* + +**Lane AG — host, no VM.** The gate-indexed audit (§3.1): one table, every reachable draw site, +firing-or-predicate, corpus count. Decode the three unread gates (`0x0088b613` in `B`, +`0x0082cdb8` in trade 15, `0x0088dc43` in spy 14 — closures 54–84, small) to save predicates and +count the corpus. Do not measure; hand each count-0 row a recipe for whoever holds a guest next. +State which generator the SVSO overrides use where it can be read, and mark the rest unknown. + +**Engine (RB or the standalone owner).** §5: the T23 slot, the `rngUnaccounted` predicate row, +`CnRad` in the schema, non-star `LocID`. No `game/nav` work yet. + +**Docs to correct in place (rule 11):** AC §6's V2 paragraph (slot 9, not 13); board 399's last +clause; `tail-rng-ledger.md` headline gains a second qualification block pointing here (the +first is L1's); `indirect-edges.md` §3.1 gains a one-line "fired: `0x00820e18`, lane AC" note; +L3 §3.5's "next condition" paragraph gets a pointer to AC §2 rather than a rewrite. + +## 8. Roadmap — no rung moves; three lines change + +`backlog.md` §3, add after item 3: + +> | 3b | **the trade-raid roll in the tail** — T23 call 7; one `NextFloat` per fleet passing a +> four-test gate on `Flt.LocID`/`Pos`/`tscr`, 0 under a hull short-circuit; `B` on success +> (cost 0 on one observation) | `app` | lane AC decoded, lane AD measuring the loop | the +> `/Sim/RNG` leaf on any raid-turn pair; currently costs the canonical pair nothing by predicate | + +§4 item 3, replace with: *trade + spy managers — all 11 virtual targets named; four can draw; +**one has fired** (trade 13, behind `CCC_ComRaid` + a parked raider — lane AC). The gate was +never the containers. Spy 13 decoded, unreached; trade 15 / spy 14 / `B`'s inner draw: gates +unread (lane AG).* + +§5, replace "trade routes + spy program — the four tail draw sites" with: *a deployed-and-detected +spy at a foreign belt colony (lane AS); a second raider hull on a sector node (lane AD).* + +--- + +## Proposed `campaign/board.md` rows + +New row: + +``` +| RESOLUTION: the tail draws behind a tech — ledger firing-indexed, audit to be gate-indexed; V2 vindicated; Rung B affected | meta | verified | high | 100% | 2026-09-09 | Resolver on lane AC (`findings/resolutions/2026-09-09-tail-draws.md`). INSTRUMENT: exonerated for the +1 (same guest/build/config, control 0, callee 0->1, B success-only) — but every AC number is `probes=11`, the configuration lane H bisected as NOT byte-neutral, and AC's own predictions promised a `probes=8` primary reading it never took: the tail word stands, the turn totals are not calibration data, and NO AC AUTOSAVE IS AN ORACLE PAIR. LANE Z: instrument sound (state difference cannot miss a draw that happens); the AUDIT is structurally incomplete because it is indexed by FIRING — twice now (hives, raid roll) a site cost 0 on every measured state and fired on one nobody had built. Next audit must be GATE-INDEXED: every reachable site carries a measured firing OR a decoded predicate on save fields + the corpus count satisfying it (lane AG). V2 VINDICATED, NOT OVERTURNED: `indirect-edges.md` §3.1 lists trade slot 13 as DRAWING at 0x00820e18 — the exact site AC fired; "closure 185, draw-free" is SLOT 9, misquoted by AC §6 and row 399 — correct both. RUNG B IS AFFECTED: the draw is a SIM draw on S+0x16c keyed on Flt.LocID/Pos/tscr; replay runs the tail (command_replay.h:83). Canonical pair untouched (tscr=252, no fleet at a sector). Model: T23 call 7, per fleet passing G2/G3/G4, 1 NextFloat unless design+0x12c>1 (0 words), B on success (0 on one observation; NextInt 0x0088b613 gate unread). ONE PROBE, VM141 (lane AD): second raider of a short-circuit hull on sector 6 from ac-turn22-raider.sav, draw_sites + probes=8, two fresh processes, hooks=off pair for the oracle — separates per-fleet (A 2x) from per-sector (A 1x), prices the short-circuit, costs B by return address. Spy half = lane AS on VM144, NEW game (regenerate until an AI colony has a belt), draw_sites not entry probes (the detection roll 0x00887c8a is inline in vslot13). RULE 28 DRAFTED: a zero on a gated path is not a negative until the gate is a predicate on the save and the corpus is counted against it; name the next workload from the failed conjunct, never the nearest container; a corpus-constant field is a coincidence until its writer is found. No rung moves; backlog §3 gains 3b, §4 item 3 and §5 restated | +``` + +Edits to existing rows: + +- **Row 186** (`RNG LEDGER CLOSED - zero residual`) — prefix: `QUALIFIED TWICE (L1 2026-09-08, AC 2026-09-09; resolver): "every word attributed" is per-turn and TRUE; the site table is firing-indexed and NOT a completeness claim — hives (BeginProcessTurn) and the trade-raid roll (tail T23c7) both cost 0 on every turn here and fire on states this corpus never held. Calibration pairs z2/z-t6 still valid (both cost 0 there by predicate).` +- **Row 207** — append: `FIRED 2026-09-09: 0x00820e18 (trade 13), lane AC, behind CCC_ComRaid + a fleet parked on a sector node. The "our corpus has neither" diagnosis was wrong — containers were never the gate. Seven of the eight sites still unfired; gates for 0x0088b613 / 0x0082cdb8 / 0x0088dc43 UNREAD (lane AG).` +- **Row 399** — replace the final clause (`And lane V2's "trade slot 13 is draw-free" … not about the code`) with: `CORRECTION TO THIS ROW AND TO AC §6: V2 never said trade slot 13 was draw-free — §3.1 lists it as DRAWING NextFloat/NextInt at 0x00820e18/0x0088b613, the exact site that fired. "Closure 185, draw-free" is V2's row for SLOT 9 (the route rebuilder L3 trapped), which stands.` +- **Row 62** (guest holders) — `VM141 = lane AD (raid-loop probe + oracle pair, from ac-turn22-raider.sav); VM144 = lane AS (deployed-spy lane, new game); VM140 reserved as oracle guest; VM145/VM146 free.` diff --git a/guides/method-rules.md b/guides/method-rules.md index efd30a8..2d0932e 100644 --- a/guides/method-rules.md +++ b/guides/method-rules.md @@ -388,3 +388,30 @@ Two integrator lessons from the same episode: - **Scope that control by an explicit list, not by a name filter.** My first control excluded `*traderoutes*` and still failed, which briefly looked like the merge *was* at fault — the lane had added more saves under other names while I worked. Pin the control to the exact set you mean. + +## 28. A zero on a gated path is not a negative until you have the predicate + +Four lanes measured one call site at zero. Each reported it correctly. One lane read it statically and +placed the draw. The campaign nevertheless recorded "the tail does not draw" — and it does. + +The site is gated on a fleet standing at a trade-sector node whose owner's bit is set in a mask that +reads **252 in every save we own**. Nobody had the predicate, so everybody hunted the nearest visible +container: trade routes, then freighters, then a deployed spy. The actual switch is a **tech** +(Commerce Raiding, one turn's research) that flips the mask to 253. One lane's stated "next +condition" was falsified by its *own* save, which had a freighter on an active route the whole time +with the site still at zero. + +So, four practices: + +1. **A zero is a negative only once the gate is a predicate on save fields and the corpus has been + counted against it.** Until then it is "not reached in the states measured" — which is a different + sentence and should be written as one. +2. **Name the next workload from the failed conjunct, not from the nearest container.** Decode the + gate first, then build the state it names. Lane AC disassembled the chain *before* building + anything and found the predicate had nothing to do with what three lanes were chasing. +3. **A field constant across the whole corpus is a coincidence until its writer is found.** `tscr` at + 252 everywhere looked like a fact about the game; it was a fact about our saves. Compare rule 8's + eighteen fields that split a roster identically because nothing exercised them. +4. **Pair entry probes with the return-address ledger before calling a subtree draw-free.** An entry + probe on an inner function reading zero says nothing about an *inline* draw in its caller — which + is exactly where the spy half's detection roll lives.