sots-re/ghidra/addresses.d/ar.json
alex df9431be64 AR: the raid target pick FIRES - TradeManager+0x0c is the per-system containing-sector table
Decides lane AG's section 3.3 final paragraph, which lane AD correctly reported
it could not separate on sector 832.

STATIC: FUN_00841700 is the writer AG's section 7 lists as not found. It resizes
the +0x0c vector to the length of the systems vector -- the container trfr indexes
-- and fills it with containingSector[system.Idx] = sector. It runs from the
deserialiser, so a loaded save has it populated. G_B1a cannot reject a valid trfr.

LIVE: four raiders parked (2 CR on sector 832, 2 DE on sector 816), probes=8.
Slot13RngCalleeA entered 4x/turn at 4 words every turn; on turn 42 the pick fired
at 0x0088b613, calls=1 words=1, and the tail cost 5 words against 4 elsewhere.
The same run carries its own control: B entered on 832 twice at 0 words.

B costs ONE word, not two: FUN_00820af0's third short-circuit is a flag word
InitTable sets only for Human and Zuul, so AG's committed 3-words-on-success is 2.

Two hooks=off processes gave byte-identical autosaves, and so did a probes=8
process -- an oracle pair and a whole-save byte-neutrality proof for the
instrument, both firsts on this lineage.

Also first firings of 0x008939ee (rule 20's case study) and 0x00820c1b.
2026-09-09 00:36:32 -04:00

52 lines
5.2 KiB
JSON

{
"entries": [
{
"name": "TradeManager_RebuildSystemToSectorTable",
"addr": "0x00841700",
"convention": "thiscall",
"prototype": "void __thiscall (TradeManager* this) // 214 B, 0x00841700-0x008417d5, decoded to the next function start. THE WRITER OF TradeManager+0x0c that lane AG's gate-indexed audit section 7 lists as NOT FOUND, and it settles AG section 3.3: (1) `lea ecx,[this+0x0c]; push 0; call 0x00459f70` clears the vector; (2) resizes it to `count(([this+4])+0x40 .. +0x44)` -- the SYSTEMS vector, the very container FUN_00841cd0 indexes with rt->trfr at 0x00841d36 -- growing with vector::_Insert_n 0x0050e6a0 (fill value NULL) or shrinking with erase 0x004ddfc0; (3) walks this->+0x1c (the SECTOR vector) x sector->+0x78 (that sector's MEMBER SYSTEM vector) and executes `mov [this->+0x0c + m->+0x5c * 4], sector` at 0x008417a8. ServerSystem+0x5c is the serialised `Idx` field (objects/layouts.md, grade verified), so this is literally `containingSector[system.Idx] = sector`. CONSEQUENCE: TradeManager+0x0c is a PER-SYSTEM table whose length is BY CONSTRUCTION the length of the container trfr indexes, so Slot13RngCalleeB's bounds check G_B1a can never reject a valid trfr and 0x0088b613 is reachable. Five callers; FUN_00858a10 is the DESERIALISER (ReadInt/ReadFloat throughout, calls this at 0x00858f07), so the table is rebuilt on load",
"status": "verified",
"source": "findings/control-flow/raid-target-pick-verdict.md (lane AR 2026-09-08); disassembled from dumps/sots.exe to the next function start"
},
{
"name": "TradeManager_GetSectorForSystem",
"addr": "0x00841c70",
"convention": "thiscall",
"prototype": "void __thiscall (TradeManager* this, ServerSystem* sys) // 83 B, RET 4. Reads TradeManager+0x0c back the same way the writer fills it: bounds-checks `sys->+0x5c` (= the `Idx` tag) against `(this->+0x10 - this->+0x0c)/4` and indexes `((TradeSector**)this->+0x0c)[sys->Idx]`, then passes `sector + 0x78` -- the sector's MEMBER SYSTEM vector, the same vector the writer iterates -- to FUN_0059ec00 with the system. Independent confirmation that +0x5c on the indexing object and +0x78 on the table element are the two halves of one relation. Tail-calls TradeManager_RebuildSystemToSectorTable 0x00841700",
"status": "verified",
"source": "findings/control-flow/raid-target-pick-verdict.md (lane AR 2026-09-08)"
},
{
"name": "Vector_ResizePtr",
"addr": "0x00459f70",
"convention": "thiscall",
"prototype": "void __thiscall (std::vector<void*>* this, size_t n) // RET 4. resize(n): when size > n it moves _Mylast down to _Myfirst + n (the shrink arm the trade manager uses with n = 0, i.e. clear); when size < n it calls 0x00538180 to grow",
"status": "verified",
"source": "findings/control-flow/raid-target-pick-verdict.md (lane AR 2026-09-08)"
},
{
"name": "SpeciesDef_InterceptFlagWord",
"addr": "0x00b10b44",
"convention": "data",
"prototype": "int, at g_SpeciesDefTable + 0*0x184 + 0x144 -- i.e. the +0x144 slot of SpeciesDef[0]. The SAME slot in every element is written ONLY by SpeciesDef_InitTable 0x005453a0 at 0x0054562f (`or [ebx+0x144],2` when the element's species index is 5) and 0x00545638 (`or [ebx+0x144],1` when it is 0). So the word is 1 for HUMAN, 2 for ZUUL and 0 for the other five species, and SpeciesDef_HasInterceptFlag 0x0053baf0 tests it. This is the value that decides whether TradeManager's raid interception draws a NextFloat at 0x00820c1b; the table base g_SpeciesDefTable 0x00b10a00 and accessor SpeciesDef_Get 0x00545cc0 were already named in addresses.json and this lane's independent derivation reproduced both",
"status": "verified",
"source": "findings/control-flow/raid-target-pick-verdict.md (lane AR 2026-09-09)"
},
{
"name": "SpeciesDef_HasInterceptFlag",
"addr": "0x0053baf0",
"convention": "thiscall",
"prototype": "bool __thiscall (SpeciesDef* this) // 12 B: `xor eax,eax; cmp [ecx+0x144],eax; setne al; ret`. TRUE for HUMAN (species 0) and ZUUL (species 5) only. This is the third disjunct of FUN_00820af0's short-circuit, so a HUMAN raider intercepts at frac = 1.0 and the NextFloat at 0x00820c1b IS NOT DRAWN -- correcting lane AG section 3.3's committed `3 words on a success` and section 5.2's `B costs 2 on a success`, both of which hold only for a raider whose species does not set this flag",
"status": "verified",
"source": "findings/control-flow/raid-target-pick-verdict.md (lane AR 2026-09-08)"
},
{
"name": "StarFleet_GetCrewSpeciesForIntercept",
"addr": "0x0081a2d0",
"convention": "cdecl",
"prototype": "int __cdecl (StarFleet* fleet) // returns the fleet owner's species (FUN_0071e280(fleet)->+0x5c) on the default path; only when that species is 4 does it scan the fleet's ship vector (+0xa4..+0xa8) for a ship whose design->+0x14->+0xac..+0xb4 slot is non-null and return THAT record's +0x4 instead. Called TWICE from FUN_00820af0 (0x00820bcf, 0x00820bdd) -- once compared against 1, once used as the index into SpeciesDef_Table",
"status": "verified",
"source": "findings/control-flow/raid-target-pick-verdict.md (lane AR 2026-09-08)"
}
]
}