Commit graph

105 commits

Author SHA1 Message Date
alex
069d7e649b board: lane E3 visibility - 128 leaves across five pairs, 0 regressed; the gate is AFlags not VFlags 2026-09-08 13:42:36 -04:00
alex
d617285b0c board: lane AI1 - the AI is a StrategyClient running after the autosave; orders go through the TurnCommands we already own; P2 routed to the VM 2026-09-08 13:39:38 -04:00
alex
f6a914beee board: lane E2 census wired; ship construction identified as a new blocker by a falsified prediction 2026-09-08 13:28:52 -04:00
alex
c4f1c2407a roadmap: rewrite around the engine as the product; milestone split into Rung A (modulo command stream) and Rung B (needs AI); 13 stale board rows marked superseded 2026-09-08 13:04:13 -04:00
alex
90fba303ac board: lanes A2 and D2 - alliance rule, ModCount rule, ship designs do have a serializer 2026-09-08 12:52:20 -04:00
alex
ab79e16843 board: multiplayer revival - direct IP joins without GameSpy; identity constants; ranked plan 2026-09-08 12:51:39 -04:00
alex
1754cc20ac board: lane P2 nav classifier; type 2 is the Liir drive, a naming error not a gap 2026-09-08 12:45:27 -04:00
alex
52581efbfb board: VM140 holder = lane H 2026-09-08 12:15:33 -04:00
alex
f328b82b67 board: lane N output term closed and live-verified; blocker moves to the income tail; VM released 2026-09-08 12:13:40 -04:00
alex
58e3d85f3f board: lane V2 vtable inversion; 5,045 functions with no direct callers; tail draw surface is unobserved not absent 2026-09-08 12:06:22 -04:00
alex
ef458bb3c8 board: lane B5 retreat pipeline; OID allocation closed; predicted original bug 2026-09-08 12:02:32 -04:00
alex
0253941d16 board: lane Y generator gap measured and attributed; BnkEl inversion oracle; divisor defect understated 2026-09-08 11:42:25 -04:00
alex
95b2bc81cf board: VM140 holder = lane N 2026-09-08 11:01:06 -04:00
alex
a77b1c3427 board: RNG ledger closed with zero residual; trade-raid generation behind a virtual edge; VM released 2026-09-08 11:00:56 -04:00
alex
f8f5581204 board: standalone scaffold runs on all 11 saves; 5 leaves closed, 0 regressed; ranked byte-match blockers 2026-09-08 10:39:39 -04:00
alex
c15a45d0c6 board: lane I complete inlined-draw inventory; corrects lane J's 14 to 11; residual stated honestly 2026-09-08 10:07:18 -04:00
alex
1d7c6ef63e board+rules: lane J combat resolver; inlined draws invisible to call-graph sweeps; Ghidra sizes untrustworthy 2026-09-08 09:38:55 -04:00
alex
7364e62986 board: lane Q 100% named coverage, three-cause reconciliation, second defect found at main 2026-09-08 09:07:47 -04:00
alex
49f1af466e board: VM140 holder = lane Z 2026-09-08 08:55:23 -04:00
alex
66bed1d6b1 board: lane K combat-done tail, autosave mechanism, tail RNG threat to the standalone milestone 2026-09-08 08:55:07 -04:00
alex
f490d69695 board: lane O built 7 workload saves; TurnCommands unblocked; waypoint type-2 negative result; click-helper correction 2026-09-08 08:37:13 -04:00
alex
46aebc9b13 board: VM140 holder FREE 2026-09-08 08:35:26 -04:00
alex
9de77f7e5e lane O: 7 purpose-built saves - issued turn commands, node routes, research-roll-pending
Produces the game states several board rows were blocked on, and reads each
one back out of the save before claiming it.

- CD/TurnCommands_v5 decoded: three saves with issued orders (research target,
  research boost, build orders, system rates, colonize, fleet move). Layout in
  SAVE_FORMAT.md section 11; ids cross-checked against the same file's Sys/Flt.
- Waypoint type 3 (NodeRoute) now has 16 instances in one save and the player's
  own fleet is a mover in two. Type 2 is shown NOT to be produced by a Move
  order for either node-drive race (Zuul and Human both emit type 3).
- research_roll_pending true at load in two saves; the ProcessTurn gate constant
  at 0x00a2c788 is a float 0.5, so the flag survives into ProcessResearch only
  while progress/cost <= 0.5 at the start of the turn.
- Budget tail: construction and a large maintenance are live; Nexp is empty in
  all 11 saves and the 1.8 UI has no expense slider, so slot 12 looks dead.

VM140 restored to the original 8-file SavedGames set (autosaves byte-identical)
and left at the main menu; VM140 row set FREE.
2026-09-08 08:35:13 -04:00
alex
136f98b564 guides: the 15 earned method rules, each traced to the finding that produced it 2026-09-08 08:29:20 -04:00
alex
1df8d39047 board: lane T turn-driver map, two corrections, ResearchRollPending settled 2026-09-08 08:14:49 -04:00
alex
996f445313 board: lane A AIAgent blocks, 99.9% named coverage, StreamableEnum correction 2026-09-08 07:36:40 -04:00
alex
164f14fa7f board: lane W wire sections closed, oracle fixes byte-neutral, CD negative result 2026-09-08 07:09:06 -04:00
alex
a0dd707261 board: lane U research slice closed; claim VM140 for lane O 2026-09-08 07:00:52 -04:00
Alex
5a3f986f38 lane U: the unlock cascade, implemented and live-verified
Reads: TechTree::PrereqsMet 0x0057d8e0 (AND of ORs; zero groups TRUE, an empty
group FALSE), the prerequisite layout at TechDef+0x88/+0x98, the tail collector
0x00587cc3, and the head of OnTechResearched (RecordObservedTech unconditional;
the research-event roll gated on ResT == def && ResearchRollPending).

Live: 35 compared calls over three workloads, 0 divergences, tracecmp exit 0,
End-Turn oracle hashes unchanged. The EVENT_TECHS_UNLOCKED residual lane P
predicted and lane V measured is closed by running the cascade, not by posting
on completion.

12 new addresses in ghidra/addresses.d/lane-u.json (header 615 -> 627).
2026-09-08 06:57:37 -04:00
alex
314ca20352 board: lane G wire-schema channel, named coverage 38->97%, four reader defects 2026-09-08 06:36:54 -04:00
alex
48fcc3ff3a lane G: wire-schema channel — layouts.json -> generated stream schema for sots-engine
objects/layouts.json is a memory-layout projection: 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. Both losses are the substance of the on-disk format.

tools/streams.py is a second projection of the same recovery that keeps the
program order Lab.layout() already computes and the repeated tags, and drops
every memory fact — no off, size, sizeof, gaps or strides. The engine must read
and write the format, not inherit the original's ABI.

tools/gen_stream_schema.py emits sots-engine's include/generated/sots_stream_schema.h
under the same discipline as gen_addresses.py: generated, provenance header,
never hand-edited.

386 classes, 2042 wire items.
2026-09-08 06:29:30 -04:00
alex
545c715359 board: VM140 holder = lane U 2026-09-08 06:03:32 -04:00
alex
ce73fa95be board: lane V advance prediction held; Zuul closed; RNG 15/15 claim corrected 2026-09-08 06:03:17 -04:00
alex
857db3426e board: record a third instance of the add -A sweep (lane V's addresses.json edit) 2026-09-08 06:00:36 -04:00
alex
7eabfefff2 lane V: live verification of the event-posting model against an advance prediction
Lane P wrote the expected numbers into sots-engine docs/P-events-wiring.md §4 before
this run existed. Every one held.

First End Turn (ref-turn2 -> Launch -> End Turn, shim.cfg.recapb3 unchanged, build
eventlive-dd38117-20260908T0916Z, main dd38117 with no source change): 3 calls, 3
compared, 0 divergent, tracecmp exit 0 — where lane R's run exited 1 on
side.events.after.v.next_id orig=4 ours=3. Call 0 read turn=3,
events_turn_bucket_exists=true, events_next_id_in=3, events_in_turn_bucket=1,
events_dedup_risk=0, no events_scan_truncated, next_id 3->4 on both sides,
turns/turns_bytes 2/48 unchanged, node[144].progress 2879->5768, flag 1->2, rng
identical — the whole predicted list.

Five End Turns: exit 1 with 2 divergent calls instead of 3, each short by exactly 1
(next_id orig 7 ours 6, orig 12 ours 11) = the deliberately unmodelled
EVENT_TECHS_UNLOCKED. A 0-divergence result there would have been suspicious.

sizeof(Game::ObservedTech) = 44 measured live: observed_techs.bytes grew by exactly
44 on both completion calls (440->484, 484->528), confirming lane X's static pin
behaviourally. Non-researching players measured 880 = 20 x 44 and never moved.

One deviation from lane R, and it is a workload effect, not a defect: rng diverged on
call 9 because the completed tech had research_roll_pending set and the
OnTechResearched callback drew one word ours does not (left 374 vs 375). Lane R's
"RNG matched 15 of 15" was workload luck; the honest statement is that the rng region
matches on every call that does not complete a roll-triggering tech.

Zuul double roll CLOSED. No species-5 save existed, so this lane made one: a custom
game with only Zuul in the Available Species pool, 4 End Turns under the same compare
config. 8 calls, 8 compared, 0 divergent, exit 0; all four researching calls have
species=5 and advance the generator by two, not one (left 540->538, 522->520,
504->502, 485->483), and ours reproduced every post-state bit-for-bit. Save added as
verify/results/saves/zuul-turn5-species5.sav.

End-Turn oracle byte-identical to lane R's on the first turn, so none of this
perturbs the game. clean_room_check OK and host ctest 33/33, run as separate commands.
VM140 restored to the recap build at the main menu and released.
2026-09-08 05:59:22 -04:00
alex
3fcfd7f522 board: lane D mass struct recovery; fragment-dir structural fix 2026-09-08 05:55:27 -04:00
alex
0d84eb2d4c board: lane D serializer struct recovery (386 classes, 1,682 fields, 0 wrong on the 305-field regression set) 2026-09-08 05:52:07 -04:00
alex
795aa471d4 board: claim VM140 for lane V; record briefing error on fpu_cw parameters 2026-09-08 05:14:19 -04:00
alex
d4f868f823 board: std::string contradiction resolved (0x1c correct, 65 layouts audited, zero wrong); enumeration rule 2026-09-08 05:13:50 -04:00
alex
4606fc5585 board: fpu_cw experiment verified, VM140 released
Marks the fpu_cw sensitivity row verified with the result and the correction to
the briefed control-word values, annotates the state-checksum and determinism-
oracle rows, and sets VM140 exclusivity back to FREE with the lane-F gotchas
(the >60 s startup is real and cost a wasted run; pin the SavedGames file set so
the Load dialog rows do not move; PowerShell-over-SSH quoting).

NOTE: campaign/board.md is shared and was already modified in the working tree
when lane F started, so this commit also carries another lane's in-flight rows
for ObservedTech / std::string. Those are not lane F's edits.
2026-09-08 05:07:59 -04:00
alex
d523d27f50 board: lane X scanner verified; ObservedTech pinned; std::string size contradiction; audit row 11 corrected 2026-09-08 04:46:54 -04:00
alex
460cb7ca2b lane X: x86 displacement xref scanner; pin sizeof(ObservedTech) and its append site
Ghidra does not index ModRM displacements, so `lea reg,[reg+disp]` -- the MSVC
idiom for taking a member's address -- is invisible to find-constant-uses. That
blind spot parked ServerPlayer+0x274 and covers every non-trivial member of the
~1,600 classes still to map.

tools/x86disp.py: full x86-32 length decoder (prefixes, 1/2/3-byte opcodes,
ModRM, SIB, sign-extended disp8, disp32, every immediate form) swept from
Ghidra's 41,089 function starts so decodes begin on real instruction boundaries.
2,174,504 instructions, 612,166 displacement sites, 100.0% code coverage, 70
desyncs (0.17%), zero unknown opcodes. Excludes no-base disp32 forms
(mod=0/rm=5, sib.base=5) which are absolute globals, not member offsets.
Commands: build/query/cohort/func/dis/stats/brute. Works off a gitignored local
cache in dumps/ rather than hammering CT111.

Validated before use: re-finds lea eax,[ecx+0x29c] in ServerPlayer::GetEventStorage
(0x0080db00) and both known OnTechResearched +0x29c sites, plus a new one in
ProcessTurn. Positive control: the ServerPlayer serializer scores 50/50 known
offsets.

sizeof(Game::ObservedTech) = 0x2c (44), proven three ways: the exact magic
divide 0x2e8ba2e9 sar 3 at 0x0087239f, imul reg,reg,0x2c at 0x0087243a and
0x007b735b, and the search stride add edi,0x2c at 0x007ba257.

Append site: RecordObservedTech+0xdf (0x007ba27f) --
  lea ecx,[player+0x274]; call vector_ObservedTech_push_back 0x007b7320
RecordObservedTech (0x007ba1a0) is a direct callee of OnTechResearched and
de-duplicates by tech name before appending. The realloc through 0x007b5820 is
why lane R's guard saw all three vector words move. Element carries a vptr
(RTTI .?AVObservedTech@Game@@) at +0 and a 0x18-byte std::string at +0x0c; the
four on-disk ints map onto +0x04/+0x06/+0x08/+0x24/+0x28 in an order this read
does NOT determine, and is not guessed.

Also corrects harness-audit row 11: ComputeBudget has no store to Budget+0x64
(its only +0x64 accesses are loads off a different base), and ProcessResearch's
int* overbudget arg is a ProcessTurn stack local, not Budget+0x64. Agrees with
lane R's guard seeing 0 changes in 4284 calls.

Honest limits are recorded in the note and the board: this is a recall tool, not
an oracle. Class-level precision at 0x274 is ~13% by function, i.e. a ~900x
search-space cut that still needs one call-graph check. Cohort ranking must not
be used as a hard filter -- it would have discarded the correct answer here.

Ghidra writeback: labels + plate comments on RecordObservedTech,
vector_ObservedTech_push_back, ObservedTech_ctor, vector_ObservedTech_assign,
vector_44B_grow, vftable_ObservedTech.
2026-09-08 04:44:18 -04:00
alex
1a58bcdf90 board: lane P host-verified, VM run queued; TECHS_UNLOCKED residual and ObservedTech gap recorded 2026-09-08 04:20:55 -04:00
alex
b0ef139928 board: VM140 holder = lane F 2026-09-08 03:54:10 -04:00
alex
ada10f43d3 board: lane M verified (mechanism match, live 8->0); lab rule on path-scoped staging 2026-09-08 03:54:05 -04:00
alex
f5b37c2b34 lane M: MoveFleet position rounding closed; VM140 released; types 2-5 still uncovered
The mechanism, read off the instruction stream rather than fitted: Mars_Vec3_Normalize
(0x00422520, 123 callers) narrows to float32 four separate times, and MoveFleet stores
each dest.c - pos.c back to a float32 slot before calling it and takes the leg distance
from that same call's return value. Live 8/45 -> 0/45 with a control run of the unchanged
build, identical inputs and identical original outputs on all 45 calls.

Board: the two MoveFleet rows go verified; VM140 exclusivity back to FREE with two new
click-path gotchas; a new backlog row for waypoint types 2-5, which this lane attempted
and could not reach - ref-turn2 structurally cannot produce a node-line move because the
only player that would travel one has no ships.

(Most of this lane's files were swept into 9d385a7 by another lane's `git add -A` on the
shared repo; this commit carries what was left.)
2026-09-08 03:51:39 -04:00
alex
9d385a7683 board: lane C state-checksum landed; fpu_cw experiment queued; event-posting lane 2026-09-08 03:47:21 -04:00
alex
fdd0b72b7a state-checksum: whole-state diagnostic checksum harness (lane C)
The complement to the per-function compare harness. Instead of "did this
function's declared outputs match", it asks "is the entire simulation state
still identical" -- so no region-declaration mistake can hide from it.

Coverage is PROVED, not declared: the digest tree is re-serialised and compared
byte-for-byte against the inflated save on every run. When that reconstruction
reproduces the stream, the whole file is a function of the digest's inputs. A
run that cannot account for the file says so and exits non-zero. This is the
direct answer to B4's three hooks that printed "0 diverged" over an empty
region set.

It localises. The root is the fold of a per-subsystem / per-object tree with
named objects, so the known load->re-save delta reports as exactly five leaves
-- /Summary/Checksum and four /Sim/players/Player[...]/Status 4->0 -- naming the
two Singularity players by id where the raw byte diff could only say "1st of
two". One real End Turn reports as 108 fully attributed differences.

Float-parity policy is explicit and strict by default (STATE_CHECKSUM.md 3):
raw IEEE-754 bits; a `canonical` policy for signed zero and NaN payloads only;
and deliberately NO tolerant hashing mode, because quantisation moves the cliff
rather than removing it and destroys the roll-up. Tolerance lives in the differ
as --ulps, applied after localisation. Corpus census: 0 NaN, 0 -0.0, 0
subnormals across 4,474 float leaves, so the strict default costs nothing today
and a test fails the day that changes.

Validated on the real saves (verify/results/state-checksum/): 10 files, 4
distinct contents, all STABLE + COVERED; chain record/verify works on the real
turn1-3 saves. The VM-driven replay loop is designed (section 5) but UNRUN.

Section 3.5 names the one question the host side cannot settle -- whether the
turn pipeline depends on x87 intermediate precision -- and the experiment that
would: force fpu_cw to 0x027f / 0x127f / 0x137f across End Turn and checksum
the three autosaves.

Also recorded: Summary.Checksum is NOT a byte sum over the inflated stream nor
a sum over the int leaves (both ruled out), so nobody repeats those two.

38 tests; sots-engine untouched, clean_room_check.sh OK.
2026-09-08 03:46:34 -04:00
alex
6f81b048e0 board: VM140 holder = lane M 2026-09-08 03:09:44 -04:00
alex
5b74b98778 board: claim VM140 for lane M; MoveFleet ULP + ObservedTech rows 2026-09-08 03:09:37 -04:00