{ "_note": "Lane PAR 2026-09-08 -- ROLL PARITY: does one run of a strategic AI client consume a fixed number of RNG words regardless of path? Live bracket on StrategyClient::OnResumePlaying over the per-client generator, plus a static classification of every draw site in the AI turn. Two entries: the client player-id offset the bracket needs, and a THIRD cl_* RNG facade nobody had recorded because it reaches the generator by a TAIL JUMP and so leaves no rel32 call edge to any RNG entry point.", "entries": [ { "name": "StrategyClient_off_PlayerId", "offset": "0x00000148", "convention": "offset", "prototype": "int -- the owning player's NET id on a Game::StrategyClient (0x708 bytes). Verified from the instruction stream in Game::StrategyApp::RunPendingAITurns 0x00838c60: the pending-AI vector at app+0x1c..+0x20 is walked in index order and each entry `edi` is matched against the client vector at app+0xc..+0x10 with `mov esi,[edx]; cmp DWORD PTR [esi+0x148],edi; je ...` at 0x00838cf0-0x00838cf8, where esi is a StrategyClient* and edi is a player net id. Corroborated by ClientOrder_FleetTask 0x007634d0, which passes `this->+0x148` as the first argument of the local validate 0x00821cf0. LIVE CROSS-CHECK: read out of the running game by lane PAR's OnResumePlaying bracket, it gives 16 / 32 / 496 / 512 on the reference board -- exactly the player ids the lane-L4 aiorders dump prints from the submitted TurnCommands blocks", "status": "verified", "source": "findings/subsystems/roll-parity.md -- lane PAR 2026-09-08; instruction-stream read of dumps/sots.exe swept to the next function start (rule 17), plus a live read on VM140 in two fresh processes" }, { "name": "cl_RandFloat", "addr": "0x00579c70", "convention": "cdecl", "prototype": "float () -- the THIRD member of the cl_* RNG facade, alongside cl_Chance 0x00578cf0 and cl_RandRange 0x005798e0. Whole 0x22-byte body: `eax = g_StrategyClients[g_CurrentClientIndex]; fldz; if (!eax) ret 0.0f; ecx = eax->+0x134; fstp st(0); lea ecx,[ecx+4]; JMP RNG_NextFloat` -- it reaches the generator by a TAIL JUMP, not a call, which is why an image-wide rel32 scan for the seven RNG entry points does not see it and why ai-turn-logic.md 5's \\\"zero calls from the AI module to NextFloat\\\" reads as true when it is not. Exactly ONE caller in the image, at 0x006ad873 inside the ship-design composer 0x006ad700, where the drawn unit is compared against 0.5. Because of the tail jump the draw-site detour records the return address 0x006ad878 -- the AI call site itself -- so this facade is the one whose consumer is directly visible in a draw-site table. Measured live: it spends exactly one MT word per call, 1 word on the reference turn 2->3 and 2 on turn 1->2", "status": "verified", "source": "findings/subsystems/roll-parity.md -- lane PAR 2026-09-08. Found twice independently: from the live draw-site table on VM140 (a NextFloat attributed to 0x006ad878, inside the AI band, which ai-turn-logic.md says cannot happen) and from a boundary-accurate image-wide rel32/rel8 scan that follows E9 tail jumps as well as E8 calls" } ] }