Commit graph

69 commits

Author SHA1 Message Date
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
alex
05095e93da lane R: golden-trace recapture with guards on the live game
Five hooks recaptured, build recap-7584bad-20260908T0615Z, no source change.

- ProcessResearch: the over-budget event is now a compare divergence
  (side.events.after.v.next_id orig=4 ours=3) instead of a 609 KB save diff.
  15 calls over 5 turns, 3 diverged, RNG matched 15/15.
- ComputeBudget: 4284 compared, 0 diverged, guard quiet - but only 20 distinct
  states and 13 of 22 slots always zero.
- MoveFleet: 8 of 45 calls diverge by 1 ULP of position. B4's clean verdict was
  a one-sample verdict.
- First guarded captures for OnTechResearched (RollResearchEvent draw fired and
  matched), the colony turn and MoveFleet.
- Guards mapped SetResearched live and found an undeclared ObservedTech append.

VM140 released at the main menu, hooks=trace.
2026-09-08 03:06:43 -04:00
alex
d738b6b4bb board: lane C state-checksum harness; dashboard refresh 2026-09-08 02:52:05 -04:00
alex
e0c3e648d3 events: 161 call sites are spread over 113 functions, not 110 2026-09-08 02:47:42 -04:00
alex
0dff4941bd events: recover the player event-posting API (lane E)
Closes B3's oracle gap and B2's known gap. Both milestones write into the
owner's event list; nothing modelled it, so their clean compares bounded the
economy fields only.

Container: EventStorage embedded at ServerPlayer+0x29c (0x1c bytes), verified by
ServerPlayer::GetEventStorage 0x0080db00 whose whole body is 'lea eax,[ecx+0x29c];
ret'. EvNxID at +0x14 == player+0x2b0, exactly the byte run the harness guard
reports. The list is a vector<TurnEvents{int EvTurn; vector<PlayerEvent>}> --
bucketed by turn, not flat, which the save-editor struct note had wrong.

Entry point: int __thiscall EventStorage::PostEvent(this, std::string BY VALUE,
std::string BY VALUE, void* obj, Vector3* pos, int turn, const char* img,
int act), 0x008862b0, RET 0x4c. 161 call sites in 110 functions: this is the
whole simulation's event API, not a research helper. Dedup is per turn bucket on
message/image/location/position/action but NOT summary; act 0 with no subject and
no position is stored as 2; EvNxID starts at 0 and is promoted to 1 on first post;
PruneOldTurns drops buckets older than turn-50 with an off-by-one that always
leaves one stale bucket behind.

Record: 0x74 bytes, EvEID(+4) EvDsc(+8) EvMsg(+0x24) EvLoc(+0x40) EvPos(+0x44)
EvImg(+0x50) EvAct(+0x6c) EvCID(+0x70) -- confirmed field by field against
turn3-state.sav, which contains the EVENT_RESEARCH_OVERBUDGET record itself.

B3's defect is fully explained: 0x00587b97, reached only from the
completion-roll-FAILED branch, under !wasDone && nowDone && owner.

Three note corrections: EvPos defaults to FLT_MAX, not infinity (writing +inf
changes the save bytes); the save array is turn-bucketed, not flat;
EVENT_TECHS_UNLOCKED has no 'parent researched' clause.

56 entries added to ghidra/addresses.json (header regenerated); 11 prototypes,
13 labels, 12 comments and 2 structs written back to the Ghidra project.
2026-09-08 02:47:11 -04:00
alex
3b5eca29a2 reva_call.py: HTTP fallback for Ghidra when the MCP link drops; claim VM140 for recapture lane 2026-09-08 02:12:16 -04:00
alex
ff67ec0d9a b4 live artifacts; two-base StrategyServer hazard in the contract 2026-09-08 02:07:28 -04:00
alex
b878c4c48f harness audit merged; qualify B1/B4 claims with the blind spots it found 2026-09-08 01:30:33 -04:00
alex
84a0b7ceae B2 verified live; record the RollResearchEvent draw as behaviourally unproven 2026-09-08 01:19:47 -04:00
alex
2d1a097b07 board: B4 code-complete with 22 corrections; harness audit lane opened 2026-09-08 00:58:59 -04:00
alex
4d535028ed b4 static findings: 22 formula corrections, 3 verified signatures, contract -> 324 entries 2026-09-08 00:57:55 -04:00
alex
535d1c3b58 B3 live partial pass; record the undeclared-side-effect-list harness gap 2026-09-08 00:30:32 -04:00
alex
83107f91f0 board: B2 code-complete with 10 corrections; B4 colony/movement lane opened 2026-09-08 00:02:10 -04:00
alex
ead46e2608 M2 verified live (weapons); section compare crash recorded as a gap 2026-09-07 23:52:51 -04:00
alex
906858f60b B1 verified on the live game; record budget-tail coverage gap and the difficulty-mods shortcut 2026-09-07 23:26:54 -04:00
alex
1e7428d5aa board: B2 offline lane; VM queue M2/B3/B2 2026-09-07 23:15:46 -04:00
alex
6600382e12 b3 static findings: rng draw mapping, NextInt inclusive, float32 odds; address contract +17 2026-09-07 23:14:51 -04:00
alex
73f5f1e2ad board: B3 offline lane, VM queue M2 then B3 2026-09-07 22:44:02 -04:00
alex
f146a7616a m2 code merged (VM window pending); record the 3-word vector struct hazard 2026-09-07 22:43:05 -04:00
alex
01c3217b5c lab rule: VM140 shim deploys are exclusive; record the holder 2026-09-07 22:36:11 -04:00
alex
23b8eda585 board+dashboard: sim formulas pinned, game/effects merged, B1 in progress 2026-09-07 22:34:17 -04:00
alex
cea76e2771 rng: verify Seed/Twist/NextFloat signatures; lazy twist confirmed; flag x87 float-parity risk 2026-09-07 22:28:56 -04:00
alex
87a39b6731 plan the behavioral slice: B1 ComputeBudget, B2 OnTechResearched, B3 ProcessResearch (RNG); gate on RNG signatures 2026-09-07 22:24:44 -04:00
alex
8116f9e0c8 P2-M1 verified on the live game: golden trace, 0-divergence compare, replace passes the End-Turn oracle 2026-09-07 22:18:22 -04:00
alex
e76e39ac03 board+dashboard: game/design merged 2026-09-07 22:11:29 -04:00
alex
de7a2bef04 tech effects (196-entry TechId table, OnTechResearched), 8 formula gaps answered, std::string settled 2026-09-07 22:05:49 -04:00
alex
8cdf3cd81d board+dashboard: engine parity merged 2026-09-07 22:01:26 -04:00
alex
436a51fa04 save-reader: real tag names (byte-confirmed), 36 tests, strict 3/3 2026-09-07 17:56:59 -04:00
alex
c61a35f1e8 board: game/data verified; allows default resolved 2026-09-07 17:56:07 -04:00
alex
66511bf03b board+dashboard: shim/trace merged; M1 in progress 2026-09-07 17:53:18 -04:00
alex
e4adf2fb31 board: parity + tag-fix lanes 2026-09-07 17:49:31 -04:00
alex
1eb967756b verified: End-Turn oracle byte-identical cross-process; stream tag corrections 2026-09-07 17:46:20 -04:00
alex
078dbbbcc7 loader prototypes M1-M4 + app spine signatures; address contract 80 entries; first-wins parity bug logged 2026-09-07 17:45:24 -04:00
alex
1ee49da917 board+dashboard: mars/vfs merged 2026-09-07 17:41:29 -04:00
alex
d0cfcadce8 board: shim trace lane 2026-09-07 17:29:49 -04:00
alex
4547f6c8fe verify: compare harness (trace format, tracecmp, replay, oracle bridge); board catch-up; sim formula gaps 2026-09-07 17:28:37 -04:00
alex
2d298b1e98 phase 2: address contract + generator, turn-internals filed, M0-M4 rows; sibling repo sots-engine 2026-09-07 17:08:40 -04:00