sots-re/ghidra/addresses.d
alex ae47971316 AI4: what an AI turn emits, and what each command costs in ModCount
Joins the emission side (lanes AI1-AI3) to the counting side (A2, W2). Three
results.

The cost of applying a command is a property of its list, and the boundary is
sharp: lists 1-16 each advance ModCount once per element, lists 17-27 never do.
Four of the six prologue gates bump, one is free, and the sixth has no applier
anywhere in the application path -- its cost is unknown, not zero. The batch
applies the twenty-seven lists in a fixed order that is neither list nor offset
order, with the six gates split across three separate per-player loops at three
different points, and four of the sixteen bumps inlined into the batch rather
than living in a handler, which is why a call-graph sweep under-counts them.

Lane W2's four unnamed handler EIPs are named, and so are its two inlined ones,
and the ten measured command bumps then decompose with zero residual. Four of the
ten are the research-rate gate, one per submitted block, and one of those four is
the human's. Two are list 14, on a turn that moved exactly one fleet -- which
confirms lane AI2's P1 (an AI fleet order deposits two fleet-task elements where
the interface deposits one) from the counter side, at no VM cost.

The reference game is not what the record says. ref-turn2.sav IS turn2-state.sav;
there are THREE AI players, not one, and the two dormant ones do run -- all three
set a research rate and picked a research target on turn 1; and the four
monster-faction players submit no command block at all, which is the first direct
evidence that they have no client rather than an empty task list.

Prediction committed for turn1-state: the same 12, out of a different set of
commands -- 4 rate gates, 3 research targets, and three orders from the one AI
with an empire, which are predicted to be a new design, a build order and a
system-rates command, with NO fleet order on turn 1. The trap multiset it
predicts contains two EIPs W2 has never seen and omits three it did, so it is
cheap to falsify: one save swap on W2's unchanged watchpoint module.

Also: phase 2 of the AI's turn is Hiver-only (a fifth cross-check on the species
reading, and the reason one prologue gate has never been observed set), phases
29-33 are dead because the submit latches the client before it builds the send
buffer, and cl_SetResearchTarget is AI-only surface with exactly one caller.

14 addresses in ghidra/addresses.d/lane-ai4.json; validated to a scratch path,
1,138 -> 1,152, no duplicate names.
2026-09-08 16:27:58 -04:00
..
lane-a.json A: the AIAgent CD blocks - derivation, addresses, and what stays a hypothesis 2026-09-08 07:33:33 -04:00
lane-a2.json lane A2: the alliance mask read from the bytes, and every ModCount writer 2026-09-08 12:44:30 -04:00
lane-ai1.json lane AI2: the AI's task selection loop, the priority table, and the order-method -> TurnCommands map 2026-09-08 14:43:41 -04:00
lane-ai2.json lane AI2: the AI's task selection loop, the priority table, and the order-method -> TurnCommands map 2026-09-08 14:43:41 -04:00
lane-ai3.json findings: lane AI3 -- the AI stepping order is save player order, and pass 0 writes nothing 2026-09-08 15:29:53 -04:00
lane-ai4.json AI4: what an AI turn emits, and what each command costs in ModCount 2026-09-08 16:27:58 -04:00
lane-b5.json B5: the combat resolver's sub-dispatcher is RETREAT, and it is the largest 2026-09-08 12:00:14 -04:00
lane-b6.json findings: ship construction -- the build queue read byte for byte, and the missing destroyer is the AI's 2026-09-08 14:54:03 -04:00
lane-c3.json lane C3: ComputeOutput on the turn path -- the money ComputeBudget actually sums 2026-09-08 14:50:50 -04:00
lane-d2.json lane D2: the ship-design catalogue -- how designs persist, hull size, and the 0x400 flag 2026-09-08 12:45:36 -04:00
lane-e1.json income-term: the output -> money chain read from the instruction stream; the BnkEl oracle goes 6/25 -> 25/25 2026-09-08 13:49:48 -04:00
lane-e3.json lane E3: ten addresses for the visibility record, and the standalone's new distance 2026-09-08 13:38:57 -04:00
lane-ev.json lane EV: what a turn actually posts, and two corrections to events.md 2026-09-08 15:40:07 -04:00
lane-g2.json 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
lane-g3.json lane G3: civilian growth read and measured; out[6] is not a repair number 2026-09-08 15:53:08 -04:00
lane-h.json lane H: five live probes, the oracle restored, and a harness perturbation bisected to one hook 2026-09-08 13:53:36 -04:00
lane-i.json lane I: the complete inlined-draw inventory, and the seven RNG entry points 2026-09-08 10:03:33 -04:00
lane-j.json lane J: the combat resolver, read from the instruction stream 2026-09-08 09:37:02 -04:00
lane-k.json lane K: field offsets belong in the offset schema, and off_RNG was already right 2026-09-08 08:48:25 -04:00
lane-n.json lane N: the population -> base-output term, read and live-verified 2026-09-08 12:11:52 -04:00
lane-o.json lane O: 7 purpose-built saves - issued turn commands, node routes, research-roll-pending 2026-09-08 08:35:13 -04:00
lane-p2.json lane P2: the path solver read from the instruction stream, and OrderFleetMove's three failure bits 2026-09-08 12:43:34 -04:00
lane-q.json lane Q: TurnCommands_v5 reconciled and typed; SAVE_FORMAT section 11 corrected 2026-09-08 09:03:26 -04:00
lane-t.json T: read ServerPlayer::ProcessTurn and StrategyServer::ProcessTurn from the instruction stream 2026-09-08 08:08:36 -04:00
lane-t2.json lane T2: the treaty-turn stamp, and Player.Status's real writer 2026-09-08 14:52:44 -04:00
lane-u.json lane K: StrategyServer::OnAllCombatDone_Tail mapped, 36 phases from the instruction stream 2026-09-08 08:47:08 -04:00
lane-v2.json lane V2: vtable inversion — resolve indirect call edges image-wide 2026-09-08 12:05:05 -04:00
lane-w.json lane W: SvSctOb variant factories; fix the four save_reader.py defects openly 2026-09-08 07:05:09 -04:00
lane-w2.json lane W2: multiplayer Tier 0 played end to end with no server; ModCount/Frame/Status watchpoints; rcex explained 2026-09-08 15:23:52 -04:00
lane-z.json Z: the dominant RNG consumer is trade-raid generation, behind a virtual call 2026-09-08 10:57:12 -04:00
README.md gen_addresses: per-lane fragment dir; duplicate names are a hard error 2026-09-08 05:55:03 -04:00

Per-lane address fragments

addresses.json is a single shared file. When several lanes run concurrently they edit the same lines, and three times on 2026-09-08 one lane's git add swept another's in-flight entries into the wrong commit. Nothing was lost, but authorship and atomicity were.

A lane may instead drop its own file here:

{ "entries": [ { "name": "...", "addr": "0x...", "convention": "...",
                 "prototype": "...", "status": "verified", "source": "findings/..." } ] }

Name it after the lane (lane-d.json). tools/gen_addresses.py merges every fragment in sorted order after addresses.json. A duplicate name across files is a hard error, not last-wins — two lanes disagreeing about an address is exactly the thing we must not paper over.

The integrator folds fragments back into addresses.json once the lane's work is merged.