Commit graph

92 commits

Author SHA1 Message Date
lane P
f3c6d551de lane P: post the research events from ours (count-only), declare ObservedTech
TechTree::ProcessResearch's events region now compares a modelled value instead of
reporting a known defect. ours posts the pass's events into its own
sots::events::EventStorage, seeded from a scan of the owner's list taken BEFORE the
original runs, and writes only the counts into the region's scratch copy. The game's
PostEvent is never called and no live byte moves; replace mode still posts nothing,
because a bumped EvNxID with no record behind it would corrupt the oracle's save.

- game/events: PostResearchPassEvents (the decision half, pure) + KeylessEventText
- shim/hooks/event_inputs (new lib shim_events, host-tested): the live<->model adapter,
  carrying game pointers as explicit uint32 so a 64-bit host build cannot alias them
- research hook: the wiring, a new observed_techs region for ServerPlayer+0x274, and
  turn / events_next_id_in / events_dedup_risk in the args so the count model's own
  assumption is measured rather than assumed
- EVENT_TECHS_UNLOCKED is NOT posted: its trigger is pinned but needs SetResearched's
  unlock cascade, which ours does not run. The driver takes the unlock list as an input
  and is handed 'no list', so a missing input cannot look like a modelled negative.
  Predicted residual: next_id short by exactly 1 on a completion call.

ctest 33/33 (shim_events_unit is new), clean_room_check OK. The shim TU is
syntax-checked only: no MinGW cross toolchain on this box.

See docs/P-events-wiring.md for the exact prediction for the next VM run.
2026-09-08 04:16:22 -04:00
alex
2aa8cba614 movefleet: reproduce the original's float32 normalise; 8 of 45 live divergences -> 0
The behavioural compare found 8 of 45 StrategyServer::MoveFleet calls diverging by
one ULP on a position component. Read off the instruction stream, the cause is that
the engine's vector normalise narrows to float32 four separate times and we kept
everything in double:

  delta.c = f32(dest.c - pos.c)     stored back to a float32 slot before normalising
  sumsq   = f32(x*x + y*y + z*z)    products/adds in 53-bit regs, only the SUM stored
  len     = f32(sqrt(sumsq))
  inv     = f32(1.0 / len)          a reciprocal, MULTIPLIED through, not three divides
  dir.c   = f32(delta.c * inv)

and the same call returns the leg distance, so it is never recomputed in a wider
precision either. The position tail was already right, which is why the error was a
constant absolute ~1.2e-7 (half an ULP of the inputs) rather than a formula error.

Adds NormalizeVec3 / StraightLeg / StraightLegDistance / AdvanceAlongUnitDirection
and rebuilds AdvanceAlongDirection on them; the movement hook now takes both the
direction and the distance from one StraightLeg call, as the original does. The
arrival test is an exact float compare, so the distance has to be that same float32.

Tests pin float32 BIT PATTERNS, not tolerances: one case per narrowing plus four
independent legs component by component. A CHECK_NEAR would pass against the old
arithmetic.

sim::Distance is left in double on purpose and flagged at its declaration: it now
serves only the node-line/stutter geometry, which very likely needs the same
treatment but has zero behavioural coverage to correct it against.

Live, same VM/save/workload, run twice by this lane:
  control recap-7584bad-20260908T0615Z  45 calls, 45 compared, 8 diverged, exit 1
  fixed   mf-45bdf7d-dirty-20260908T0721Z 45 calls, 45 compared, 0 diverged, exit 0
with identical arguments, identical pos.before and identical ORIGINAL pos.after on
all 45 calls. The control reproduced the eight divergent call_ids exactly.

Coverage unchanged and still thin: all 15 moving calls are the same straight-run
waypoint type; types 2-5 were attempted and could not be reached (the only player
that would travel a node line has no ships on this save). See docs/M-movefleet.md.

ctest 32/32; tools/clean_room_check.sh OK.
2026-09-08 03:50:04 -04:00
alex
a7348be72c game/events: the player event log and the five research events
Recovers the game's event-posting API so the engine can post events and the
compare harness can see them. Until now the owner's event list was invisible to
every layer: B3's replace-mode oracle failed by exactly one item across 40,300
(an unposted EVENT_RESEARCH_OVERBUDGET) while its compare read clean, and B2's
clean compare bounds the economy fields only.

New pure module src/game/events:
  * EventStorage / TurnEvents / PlayerEvent -- the list is bucketed by TURN, not
    flat, which the save-editor struct notes had wrong.
  * EventStorage::Post reproducing the original's rules, including the four that
    change save bytes: the FLT_MAX (not infinity) default position; action 0 with
    no subject and no position storing as 2; per-bucket dedup that compares
    message/image/location/position/action but NOT summary; and EvNxID starting
    at 0 and being promoted to 1 on the first post.
  * PruneOldTurns reproduced with its off-by-one: of a leading run of buckets
    older than turn-50 it erases n-1, so one stale bucket always survives. The
    survivor is serialized, so correcting it would diverge.
  * research_events: the five events the research path raises, their EvImg
    identifiers and string-table keys, and the 0.8 completion split evaluated
    against (double)0.8f rather than the decimal 0.8.

Localized text is deliberately absent: only the EVENTSUM_/EVENTMSG_ keys are
here and the text resolves through a caller-supplied lookup, as the game does.

The four event offsets the B3 hook carried as local literals now come from the
generated header; they are read off instructions rather than inferred from the
save schema.

tests/game_events: 112 checks including a replay of the event list
turn3-state.sav actually holds. ctest 31/31 -> 32/32.

docs/E-events.md carries the proposed region and Coverage wording for the next
B3 recapture.
2026-09-08 02:45:57 -04:00
alex
3f0721f443 merge harness audit (coverage + guards) 2026-09-08 01:28:35 -04:00
alex
c110fb245b harness: compile-time Coverage on every descriptor, guard regions, replace-mode records; audit of 23 undeclared side effects 2026-09-08 01:28:35 -04:00
alex
a5ffe187ea merge b2 live verification (header regenerated) 2026-09-08 01:18:39 -04:00
alex
bbba536d99 b2 live: 3 completions compared 0 divergences; float32 confirmed on the game; RollResearchEvent RNG region added; xenotech block size bug fixed 2026-09-08 01:18:39 -04:00
alex
4abf654983 b4: colony + movement hooks; 22 formula corrections (growth curve has no capacity term, range margin +0.05f, ties-to-even rounding); 3 verified signatures 2026-09-08 00:57:55 -04:00
alex
4a6e11d1ce b2: OnTechResearched hook + 10 effects-table corrections (float32, xenotech block size, no already-researched guard, sticky mask, AI bonus values) 2026-09-08 00:01:04 -04:00
alex
9cd997da93 merge b1 (ComputeBudget verified: 4437 compares, 0 divergences, oracle byte-identical); union shim hooks; regenerate header 2026-09-07 23:24:59 -04:00
alex
16f3aa90e5 b1: ComputeBudget hook + adapter; fix researchMoneyKept to be charged only with a research target; budget out-param is int[22] 2026-09-07 23:24:10 -04:00
alex
dd97137fb0 b3: research hook + RNG-snapshot compare design; fix draw mapping to y/(2^32-1), NextInt inclusive, float32 odds, spend floor, decay constants 2026-09-07 23:14:08 -04:00
alex
da679cd79f m2: manifest/id dictionary hooks + manifest_loader; thiscall support in Hook template; struct sizes pinned (+0x14 word) 2026-09-07 22:41:42 -04:00
alex
16ce9ab6ee merge sim-pin (pinned formulas + tech effects) 2026-09-07 22:32:16 -04:00
alex
f83f6af62d game/sim: pin all five low-confidence formulas; game/effects: TechId table + 44 typed strategic effects 2026-09-07 22:32:16 -04:00
alex
8b231c0a86 merge m1 config loader (cmake union) 2026-09-07 22:16:55 -04:00
alex
16e9d927af m1: GlobalConsts::LoadFile hook + game/config loader; trace 19 calls, compare 0 div, replace passes End-Turn oracle 2026-09-07 22:16:55 -04:00
alex
683d2b130e tests: restore test_catalog fixture text (rename only member accesses) 2026-09-07 22:15:20 -04:00
alex
b404f89e16 tests: restore remaining 'requires' data-key text in fixtures 2026-09-07 22:14:37 -04:00
alex
4dc323f674 tests: restore 'requires' data key in sample fixtures (rename touched string text) 2026-09-07 22:13:11 -04:00
alex
587e4ab9fb game/data+design: rename member 'requires' -> requires_tech (C++20 keyword, -Werror under design tests) 2026-09-07 22:12:26 -04:00
alex
ab2f58ed63 game/design: assembly/fit/gating rules + derived stats on game/data; 127/127 designs, 197/197 DOpts, oracle-identical 2026-09-07 22:10:35 -04:00
alex
4f0a9dbd82 game/data: adapt to engine-parity parse API (items->key_quoted pairs; lenient unterminated quote) 2026-09-07 22:01:25 -04:00
alex
4d5b573668 merge engine parity 2026-09-07 18:10:18 -04:00
alex
9ccde259aa mars/parse + mars/text: engine parity (Mars::Script tokenizer, first-wins keys, trailing-pair drop); oracles 1531/1531, 64/64 2026-09-07 18:10:18 -04:00
alex
7e0b446a96 merge game/data 2026-09-07 17:55:08 -04:00
alex
9065c26829 game/data: typed catalogs (weapons, sections, turrets, ids, tech tree, strings), cross_check; oracle 229k values 0 diffs 2026-09-07 17:55:08 -04:00
alex
9e110b43ba merge shim/trace; ctest foreach union 2026-09-07 17:51:19 -04:00
alex
23696875cc shim/trace: JSONL emitter (byte-exact port), tracer, snapshot/diff, Hook<Descriptor> template, self-test; ctest 7/7 + tracecmp exit codes 2026-09-07 17:51:02 -04:00
alex
dcc3f583d2 ctest: register mars_stream + mars_rng suites 2026-09-07 17:48:34 -04:00
alex
563dbe3a87 merge mars/stream + mars/rng; single vendored miniz (3.1.2); wire into builds 2026-09-07 17:46:48 -04:00
alex
b594a0a90d mars/stream + mars/rng: Streamable reader/writer/shapes, MT19937; 3 real saves exact + byte-identical round-trip 2026-09-07 17:46:06 -04:00
alex
08a129e453 merge mars/vfs 2026-09-07 17:40:51 -04:00
alex
56608af3fd mars/vfs: gob ZIP reader + native override, miniz 3.1.2; oracle-verified 8352+2035 entries 2026-09-07 17:40:51 -04:00
alex
43fc8836e1 ctest: register mars_parse and game_sim suites (host ctest 9/9) 2026-09-07 17:37:27 -04:00
alex
d149cf826c merge game/sim 2026-09-07 17:28:45 -04:00
alex
72ecc74684 game/sim: strategic formulas as pure functions (economy, research, colony, movement), 356 checks 2026-09-07 17:28:45 -04:00
alex
43852ed041 merge mars/text 2026-09-07 17:25:34 -04:00
alex
0170f5e7ff mars/text: flat-kv, id-manifest, csv readers; oracle-verified 64/64 2026-09-07 17:25:34 -04:00
alex
e2617a9d6e merge mars/parse 2026-09-07 17:24:04 -04:00
alex
922be00e43 mars/parse: brace-block + .effect parsers, node model, oracle-verified 1531/1531 2026-09-07 17:24:04 -04:00
alex
5f5bc41fd5 m0: binkw32 proxy shim, minhook, trace hook on Application::Initialize; build/deploy tooling 2026-09-07 17:22:15 -04:00