board: lane G wire-schema channel, named coverage 38->97%, four reader defects

This commit is contained in:
alex 2026-09-08 06:36:54 -04:00
parent 2bb7b4debb
commit 314ca20352

View file

@ -110,3 +110,8 @@ Status flow: `backlog → in-progress → mapped → verified` (or `blocked`).
| CORRECTION: lane R's "RNG matched 15/15" was workload luck | verify | verified | high | 100% | 2026-09-08 | Lane V found rng diverges on call 9 (orig left 374/next_index 250, ours 375/249) = the RollResearchEvent draw in OnTechResearched, a boundary B3 and P-events-wiring 3 both declared out of scope. HONEST STATEMENT: ProcessResearch's rng matches on every call that does NOT complete a roll-triggering tech, and is short by one draw on every call that DOES. Lane R's 15/15 was a property of that workload, not of the model - exactly the kind of claim that survives only until the workload changes. The two "new" guard spans (player+0x196, player+0x3b4) are already-named fields (design-mask B, ResErrRoll) seen from the caller |
| Zuul double roll (behavioural) | verify | verified | high | 100% | 2026-09-08 | CLOSED by lane V. No species-5 save existed so it MADE one: custom game, only Zuul in the Available Species pool, 4 End Turns. 8 calls, 8 compared, 0 divergent, exit 0; all four species=5 researching calls advance the generator by TWO (left 540->538, 522->520, 504->502, 485->483) and ours reproduced every post-state bit-for-bit. Was disassembly-only since 2026-09-08 morning. Save: verify/results/saves/zuul-turn5-species5.sav (and zuul-turn5.sav on the VM). Does not yet contain a Zuul COMPLETION - one more End Turn gets there |
| VM click helper: `type` does not register | meta | verified | high | 100% | 2026-09-08 | The click helper's `type` action does not reach the game's text fields. WORKAROUND: accept the default name and rename the .sav afterwards. Costs a save-naming step in every workload-building lane |
| wire-schema channel (engine) | engine | verified | high | 95% | 2026-09-08 | Lane G REJECTED the brief's premise for good reason. objects/layouts.json is a MEMORY-layout projection and was the wrong input: serializers.py's build() sorts fields by off_abs (89 of 386 classes have offset order != WRITE order) and merges duplicate offsets into alt_tags - which is exactly the JewelsOfTheCrown double-tag trap. Lab.layout() already computed true disk order internally and it was being thrown away. New `tools/streams.py` is a SECOND projection keeping order and repeats and DROPPING EVERY MEMORY FACT (no off/size/sizeof/gaps/strides) - so the original's ABI never enters our runtime types, which was the design constraint. Offsets still have their home as `offset` entries in addresses.json for the shim, which legitimately needs them. gen_stream_schema.py -> include/generated/sots_stream_schema.h (386 classes, 2,042 items). SUBTLETY: the on-disk primitive is NOT layouts.json's `kind` - it comes from the stream vftable slot/helper, and a member held as int16/int8 is written by WriteInt and is FOUR BYTES ON THE WIRE |
| schema as CHECK not codec | engine | verified | high | 100% | 2026-09-08 | Lane G's key judgement: the table is a SPECIFICATION, not a program. The recovery is a LINEAR pass over Write, so it cannot see branches (StarShip's BQ2 is gated on hbq but listed unconditionally) and it flattens container loops - a codec driven off it DESYNCHRONISES ON THE FIRST BRANCH. So hand-written io() shapes stay the codec and a new SchemaProbe archive walks them WITH EVERY BRANCH TAKEN (the same view the recovery has), LCS-aligned against the table: 56 shapes bound, 657 items matched, 0 mismatches |
| NAMED coverage 38% -> 97% | engine | verified | high | 100% | 2026-09-08 | All four real saves round-tripped byte-identically BEFORE and AFTER - and lane G refused to call that a coverage claim, because `ar.any` bodies round-trip trivially by copying bytes nobody understands. New CoverageArchive separates items a FIELD NAMES from items a Node merely CARRIES: turn1/2/3 37.9/38.8/39.4% -> 97.1/97.2/97.2%; zuul-turn5 42.5% -> 97.6%. Ratchet at 95%. Newly typed: TechTree (both NumTechs sections), Events (3 nesting levels), ShipRecs, sprjs, civr, comms, spy2, spymgr, aid, Ojvs, AIEnf, FNG, trdmgr, Des section/gun-bank tree. STILL OPAQUE, honestly: CD custom data (744 items - TurnCommands_v5 is a NO-ORDERS snapshot, needs a save with issued orders), SvSctOb (147, eight EncObj variants), DOpts (94, read_elem lacks a std::string branch), spies2 (56, count 0 everywhere), RNG (2, correctly opaque) |
| FOUR reader defects invisible to round-trip | verify | verified | high | 100% | 2026-09-08 | Present in BOTH readers, none catchable by a round-trip test. (1) SystemParams field 1 is a STRING, not an int - it is the empty string in every save, four zero bytes, byte-identical to int 0; it round-tripped BY LUCK and a named planet would have desynced both parsers. (2) ObservedTech/ObservedWeapon `odet` is a BOOL not an int (lane D's own golden table already said so); byte-safe only because a 4-char tag makes bool and int items both 12 bytes. (3) SpeciesRatios::nv and (4) ShipRecords::srbd are COUNTS, not fields. Lane G deliberately did NOT patch save_reader.py: every fix is byte-neutral on available saves, and quietly editing the oracle mid-campaign is worse than recording the divergence. THE ENGINE IS NOW THE CORRECTED REFERENCE; the Python oracle carries a logged open item |
| RULE: interface stub -> look for the *Impl | objects | verified | high | 100% | 2026-09-08 | `trdmgr` RESOLVED, correcting the earlier "ServerTradeManager has no serializer" finding: the no-op Read/Write is real but THE CALL IS VIRTUAL - ServerTradeManagerImpl has the actual serializer. Same shape resolves IServerSpyManager -> ServerSpyManager. GENERAL RULE: when an interface's serializer is the inherited stub, look for the concrete *Impl. (Game::ShipDesign::Write genuinely still makes no stream call - but ShipDesignDef::Section IS recovered, so most of Des is typeable anyway) |