sots-engine/docs
alex 0ebc222f45 lane N: the population -> base-output term, live-verified
Reads the whole colony output chain off the instruction stream (every range
disassembled to the next function start) and compares two of its functions
against the running game.

The population -> output law is linear and is carried by the executable:
output points per head are typeOutputModifier x 1.8 / 500000, and the
three-row population-type table is built in code rather than loaded, so the
imperial (1.0) and civilian (0.33f) modifiers are facts about the binary.

A system's total output is a SUM of three terms, not one multiplicative
chain. The station bonus scales only the imperial term and morale only the
civilian one, so OutputModifiers no longer carries either; they belong to
GroupOutputInputs. The function previously described as the base-output term
is the over-harvest RESOURCE demand, and it is corrected in place.

Live on VM140, both hooks in compare mode over two species and two workloads:
GroupOutput 13,105 calls / 0 divergences; ComputeTotalOutput 11,252 calls /
1 divergence of one ulp, in a value its caller rounds to an integer. Both
functions declare a whole-object Guard: 0 undeclared writes in 24,357 calls,
which is what makes the side-effect-free claim a measurement.

sim::Narrow forces the double rounding a 32-bit x87 build otherwise skips;
without it every civilian row came out one ulp low.

Also fixes ComputeBankruptcyLimits' elimination divisor, which was the
decimal -0.15 rather than the image's widened float -0.15000000596046448.
The two disagree for every maximum income divisible by 3 and for essentially
every empire above ~3,000,000.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARBgSooAfokKUy6wKUKEyZ
2026-09-08 12:11:36 -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
G-wire-schema.md A: type the AIAgent custom-data blocks; named coverage 98.0% -> 99.9% 2026-09-08 07:33:06 -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 lane P: post the research events from ours (count-only), declare ObservedTech 2026-09-08 04:16:22 -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 mars::rng: the seven draw entry points, with their word costs 2026-09-08 09:59:05 -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
N-output-term.md lane N: the population -> base-output term, live-verified 2026-09-08 12:11:36 -04:00
P-events-wiring.md lane P: post the research events from ours (count-only), declare ObservedTech 2026-09-08 04:16:22 -04:00
R-recapture.md recapture: golden traces with guards on the live game 2026-09-08 03:04:34 -04:00
S-standalone.md src/app: the standalone -- load a save, run a turn, write a save 2026-09-08 10:35:45 -04:00
shim-trace.md shim: force and verify the x87 control word around the turn gate 2026-09-08 05:09:16 -04:00
T-turn-driver.md lane T merge fixups: name the roll-succeeded branch instead of its FUN_ id (clean-room); mark describe_i32 maybe_unused so the shim cross-builds 2026-09-08 08:13:39 -04:00
U-unlock.md U: live verification - 0 divergences on 35 calls, three workloads 2026-09-08 06:57:15 -04:00
V-eventlive.md V: live verification of lane P's event posting; the advance prediction held 2026-09-08 06:00:01 -04:00
Y-standalone-rng-and-tail.md Y: correct the divisor-defect numbers -- 6 of 25 corpus records, and the rate rises with magnitude 2026-09-08 11:39:36 -04:00
Z-tail-rng.md Z: P9 outcome -- turn 64, one word, every clause held 2026-09-08 10:24:17 -04:00