sots-engine/docs
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
..
B1.md 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
B2.md 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
B3.md b3 live results: 13/15 zero-divergence, RNG post-state 14/15; research target is state 3 (no decay); oracle gap = unposted overbudget event 2026-09-08 00:29:44 -04:00
B4.md b4 live: 36 calls 0 divergences, no colony RNG draws as predicted; fix 3 hook bugs (stale args, two-base StrategyServer, raw Ghidra offset) 2026-09-08 02:07:28 -04:00
E-events.md game/events: the player event log and the five research events 2026-09-08 02:45:57 -04:00
game-data.md 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
game-design.md 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
game-effects.md 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
game-sim.md 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
harness-audit.md 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
M-movefleet.md movefleet: reproduce the original's float32 normalise; 8 of 45 live divergences -> 0 2026-09-08 03:50:04 -04:00
M0.md m0: binkw32 proxy shim, minhook, trace hook on Application::Initialize; build/deploy tooling 2026-09-07 17:22:15 -04:00
M1.md 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
M2.md m2: live verification results (weapons compare 0 div, oracle passes; section compare crash documented) 2026-09-07 23:52:50 -04:00
mars-parse.md 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
mars-rng.md 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
mars-stream.md 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
mars-text.md 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
mars-vfs.md mars/vfs: gob ZIP reader + native override, miniz 3.1.2; oracle-verified 8352+2035 entries 2026-09-07 17:40:51 -04:00
R-recapture.md recapture: golden traces with guards on the live game 2026-09-08 03:04:34 -04:00
shim-trace.md 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