docs: B6 measured -- prediction held, closed 0 regressed 0 on both reference pairs

209 -> 158 (closed 51, regressed 0) and 108 -> 87 (closed 21, regressed 0), identical to the
pre-lane baseline, measured on CT111. Falsification hypotheses 1 and 2 refuted by measurement
(three empty BQ frames per reference save, every hbq false, the one command block empty);
hypothesis 3 refuted by the corpus oracle; hypothesis 4 stands as a labelled hypothesis.

construction.h also carries the ship/fleet birth shape as read but NOT implemented, with the
reason stated: the newborn hull copies four cached stat words the engine does not yet compute.
This commit is contained in:
lane-b6 2026-09-08 14:54:21 -04:00
parent 0fcbb69ba5
commit db3909bcd4
2 changed files with 131 additions and 3 deletions

View file

@ -39,14 +39,14 @@ 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);
in it (§4, "What changed in the engine");
* 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).
across two systems (§3, "The corpus oracle").
## 2. How this prediction could be wrong, and the symptom of each way
@ -65,7 +65,98 @@ What this lane does deliver, and what it is worth:
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.
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.
---
## 3. Measured
Built on CT111 (`/srv/re-lab/build/sots-engine-b6`), report run there with
`tools/standalone_report.py --binary …`. Host gates run separately, never `&&`-chained.
| pair | baseline | after | **closed** | **regressed** |
|---|---:|---:|---:|---:|
| `turn1-state.sav` → `turn2-state.sav` | 209 | 158 | **51** | **0** |
| `turn2-state.sav` → `turn3-state.sav` | 108 | 87 | **21** | **0** |
Identical to the pre-lane baseline, which is the prediction holding: **this lane closed 0 and
regressed 0.** `regressedPaths` is empty on both pairs.
The prediction's own numbers, checked one by one:
* three `BQ` frames per reference save (systems owned by players 16, 32 and 576), **0 orders in
all three**, on both sides of both pairs — the standalone now prints this on its own line;
* every `hbq` in `turn1/2/3-state.sav` is `false` (15, 16 and 17 of them), so **0 ship-borne
orders**;
* the four `CDT` ids are `Player.00000016.TurnCommands_v5` plus three `AIAgent` blobs, and the
one command block is the 36-node empty one.
Falsification hypotheses 1 and 2 are therefore both refuted by measurement rather than by
argument, and hypothesis 3 is refuted by the corpus oracle below. Hypothesis 4 stands as a
labelled hypothesis; hypothesis 5 was already refuted by lane E2.
### What the pass does on the saves that are not the reference pair
`sots_turn <save> --phases` now prints a `build queue:` line under S11 on every save:
| save | queues | pending orders | demand (points) |
|---|---:|---:|---:|
| `turn1/2/3-state.sav` | 3 | 0 | 0 |
| `human-turn2-orders.sav` | 20 | 0 | 0 |
| `zuul-turn5-species5.sav` | 4 | 4 | 7,120 |
| `zuul-turn16-noderoute.sav` | 4 | 7 | 12,099 |
| `zuul-turn17-orders2.sav` | 4 | 2 | 5,109 |
| `zuul-turn23-fleet23.sav` | 4 | 1 | 370 |
Five of eleven saves exercise the pass the moment points exist. Nothing is committed: an order
that advanced with no ship behind it leaves a state the game never produces.
### The corpus oracle, which the campaign already owned
`zuul-turn16-noderoute.sav` (frame 16) → `zuul-turn17-rollpending.sav` (frame 17) is a real
consecutive-turn pair. Two systems, six completions, one partial advance:
| system | owner | before (`desID`:`conleft`) | after | solved points |
|---|---|---|---|---:|
| 384 | 16 | 608:1753, 576:1860, 576:1860 | 576:**1291** | **4182** |
| 80 | 32 | 114:959, 114:1889 ×3 (+816:6974 appended in-turn) | 816:**3818** | **9782** |
`test_construction.cpp` does not assume those totals — it **searches** 0..200,000 and asserts a
solution exists and is **unique**. A per-order budget, a non-FIFO drain, or skip-instead-of-stop
each make the search come back empty. The completions then reproduce the `ShipRecs` deltas the
same two files carry (class-0 `srb` 2→4 and 53→57; design 608 2→3; a new record for 576;
design 114 18→22; design 816 unchanged because its order did not finish).
## 4. What changed in the engine
* **`game/sim/construction.{h,cpp}`** — `ShipRecords` and the completion bookkeeping. The
per-class `built` counter's indexed increment has **exactly one writer in the whole image**
(an image-wide byte scan for the form at that displacement returns one site, inside this
pass), so a hull on the wire with that counter bumped came through the build queue and
nothing else — the encounter spawner that also creates ships touches no `ShipRecords`.
`RunSystemConstruction` wraps the point pass and keeps each completion's design id.
* **`game/sim/colony.{h,cpp}`** — one corrected rule: with `points <= 0` the original skips the
**removal sweep** as well, because the entry test branches to the epilogue. Carried as a
labelled hypothesis; no corpus save can reach the state that shows it, and the workload that
would is named in the header.
* **`app/construction_phase.{h,cpp}`** — S11's build-queue sub-pass, reported on its own line.
* **`app/phase_catalog.cpp`** — S11's blurb no longer calls the build queue the input boundary
for the census leaf.
## 5. What this lane did NOT do, said plainly
* **It did not close `shpt[0]`, and no build-queue work can.** The blocker moves to `game/ai`.
* **It did not model the ship or the fleet at birth in code.** The chain is read end to end and
written up in the RE repo (`findings/subsystems/ship-construction.md` §4): `StarShip` is 0xb0
bytes, its id comes from the object-id allocator and lands in `+0x04`, `FltID` is born NULL;
the hull joins its system's **cached home fleet** (`ServerSystem+0x238`) and a fleet is created
only when that slot is empty; every fleet born that way gets `FtFlg |= 0x400` — which
**corrects lane B5**, that bit is not a retreat marker. It is not implemented because the
newborn hull's stats are copied from design words the engine does not yet compute, and because
no save exercises the path with an oracle behind it.
* **The money charge has never fired.** No design in the corpus costs money, so the slot-9
refusal path is read from the bytes and never observed.
* **`srl`, `srk`, `sri` carry no model.** Losses and kills are zero in all eleven saves.

View file

@ -106,4 +106,41 @@ struct SystemConstructionResult {
// CONFIDENCE: high -- see colony.h's ProcessBuildQueue for the rules and their evidence.
SystemConstructionResult RunSystemConstruction(std::vector<BuildOrder>& queue, int points);
// ---------------------------------------------------------------------------------------
// The hull and the fleet at birth -- READ, NOT YET IMPLEMENTED
// ---------------------------------------------------------------------------------------
//
// This is written down here rather than coded because the newborn hull copies four cached
// stat words out of its design, and those words are recomputed by the design's own stats
// pass, which this engine models only far enough to get a hull class. Coding it now would be
// writing fields we cannot compute. The whole chain is read instruction by instruction in
// the RE repo; the shape, for the lane that gets the design stats:
//
// THE SHIP. 176 bytes. The object id comes from the network-node id allocator --
// `(counter << 4) | (node & 0xF)`, per-node counters, PRE-incremented, never issuing 0 --
// and is written into the object by the id-map insert, not by the constructor. At birth:
// the owner is the queue's owner and the design is the order's design; range, health,
// construction capacity, refuel capacity and repair capacity are copied from the design's
// cached stat words; the plague and one other word are -1 and everything else is zero.
// Two fields matter to a reimplementation:
// * the FLEET LINK IS NULL at birth and is set by the fleet-join step, not here;
// * the TURN-BUILT stamp is the sim's frame counter, i.e. the number of the turn being
// produced -- MEASURED: the six hulls the zuul frame-16 -> frame-17 pair adds all
// carry the NEW turn number, which is independent evidence that the frame counter is
// incremented before the spine runs.
//
// THE FLEET. 288 bytes. A system caches ONE home fleet; every hull built there joins it,
// and a fleet is created only when that cache is empty. So a second turn of building at
// the same system creates no fleet. A created fleet takes an id from the same allocator,
// is born at the system's position, and always carries flag 0x400 -- which is NOT a
// retreat marker (that reading is corrected) and is NOT the design flag of the same
// numeral that game/design/hull.h warns about. The build path adds 0x20 on top. There is
// NO scalar ship count: the wire's count is the length of the fleet's ship vector.
// A fleet created with no name override asks the player's name generator, which is what
// bumps the generator's counter -- one bump per generated name.
//
// Ships are also created OUTSIDE this pass, by the trade manager's encounter spawner. That
// path touches no ShipRecords at all, which is what makes the per-class built counter a
// clean discriminator between player-built hulls and spawned ones.
} // namespace sots::sim