diff --git a/docs/B6-ship-construction.md b/docs/B6-ship-construction.md new file mode 100644 index 0000000..28f1932 --- /dev/null +++ b/docs/B6-ship-construction.md @@ -0,0 +1,71 @@ +# B6 — ship construction: the build queue, and where the missing destroyer actually comes from + +Lane B6. Branch `wip/build` off `main` `0f1c007`. + +This file was written and committed **before** the code (earned rule 2). Section 1 is the +prediction as first written; section 2 is the falsification list; sections 3 onward are filled +in after the measurement and correct section 1 in place where it was wrong. + +--- + +## 1. Prediction, written before the build + +The brief's target is `hist[*]/stats[*]/shpt[0]` on both reference pairs — the archived ship +census is one destroyer higher than ours, and lane E2 concluded that no phase we run builds a +ship. That conclusion is right. The inference drawn from it — that `S11`'s build-queue +sub-pass is what closes it — is **wrong**, and this lane predicts the pass closes **nothing**: + +> **Both reference pairs: closed 0, regressed 0.** +> +> `turn1-state.sav` and `turn2-state.sav` each carry exactly **three** `BQ` frames (one per +> owned system: players 16, 32 and 576), and **every one of them holds zero orders**. Every +> `hbq` in both files is `false`, so there is no ship-borne `BQ2` queue either. The only +> `TurnCommands_v5` block belongs to player 16 and is the byte-identical empty one. So at the +> moment the standalone loads either save, **the whole game contains no build order at all**, +> and a faithful build-queue pass has nothing to advance. +> +> The destroyer the archive counts is created *inside* the turn: on the reference pair the +> owner is player 32 ("Fane Lao"), an AI, and the same turn shows `NumDes` 5 → 6 (a design the +> AI designed during the turn), `FNG/FNGNum` 0 → 1 (a fleet named), `Maint` 0 → 500, +> `ShipRecs/srb[0]` 0 → 1 and a new `ShipRecs` design record, with `NMnx` 106 → 109 — three +> ids issued in the order design(107), ship(108), fleet(109). The order that fed the queue was +> issued by the AI and consumed in the same turn. +> +> **`shpt[0]` is blocked on AI order generation (`game/ai`, Rung B), not on S11.** This lane +> moves the blocker; it does not close the leaf. + +What this lane does deliver, and what it is worth: + +* the build-queue advance read byte for byte from `Game::BuildQueue::ProcessTurn` + (`0x00890d50`, real end `0x00891240` — Ghidra says 1230 bytes, the body runs 1264), which + **independently confirms** lane B4's `sim::ProcessBuildQueue` and finds **one divergence** + in it (§4); +* the `ShipRecords` update the pass performs, whose per-class counter has **exactly one + writer in the whole image**; +* the pass wired into the standalone's S11 as its own reported sub-pass; +* a real oracle for the pass that the campaign already owns and had not noticed: + `zuul-turn16-noderoute.sav` → `zuul-turn17-rollpending.sav` is a genuine consecutive-turn + pair (frames 16 and 17) in which **six orders complete and one is partially advanced** + across two systems (§5). + +## 2. How this prediction could be wrong, and the symptom of each way + +1. **A build order exists somewhere I did not look.** The reader types unknown regions as + `raw`; a queue hidden inside one would not show up in a tag scan. *Symptom:* the standalone + reports a non-zero order count on a reference pair, and `closed` is not 0. +2. **The order is created before the spine rather than during it.** If the AI's orders were + applied at load time by something the standalone also runs, the queue would be non-empty by + S11 and the pass would build. *Symptom:* same as (1). (The measured `PvSav` says otherwise: + Fane Lao's savings are 50,000 in the input file and the previous-turn snapshot in the output + file is 38,100, so 11,900 left the treasury *between the save and phase 0* — the queue-time + deduction of a build order the file does not contain.) +3. **The FIFO + stop-at-the-first-short-order model is wrong.** *Symptom:* on the + `zuul-turn16 → zuul-turn17` pair there is **no** single non-negative integer point total per + system that turns the observed before-queue into the observed after-queue. This is a real + test: a per-order point budget, a non-FIFO order, or a "skip and continue" rule instead of + "stop" each fail it. +4. **The `points <= 0` gate on the removal sweep is wrong.** Unobservable in this corpus + (§4) and therefore carried as a labelled hypothesis, not a result. +5. **`shpt` is not the fleet walk.** If the census leaf were fed by `ShipRecs` rather than by + walking fleets, the fix would be different. Lane E2 already falsifies this: the fleet walk + reproduces 480/480 archived census leaves.