Unblocks the phase experiment, which was stuck because '38 enemies died' could not say whether the right ones did. Chasing craft->squadron was the wrong angle: the script VM keeps that table itself, indexed by the .ssb symbol-table-2 index. Route: find the .ssb header in guest memory (0xAB840010 for a Stage 02 run), code base = filebase + 0x24, scan for a word equal to it, then VALIDATE arithmetically -- [ScriptMission+44] must equal filebase + symtab1 offset + 4. Measured 0xAB874C94, predicted 0xAB874C94, exact. A second candidate that also pointed at the code base failed that check and was discarded; without it either would have looked plausible. ScriptPhase+324 -> +4 is an array of 122 per-unit records -- exactly the size of Stage 02's symbol table 2, an independent confirmation of the index space. [ScriptMission+40] reads 1 in a phase-1 mission. The mirror at [*(0x828F35F8)+236] that three earlier runs polled reads 0, because ChangePhase only posts once the ordinal exceeds 1 -- so +40 is the real counter and is reachable from /dev/shm with no debugger. Flagged rather than asserted: the three objective squadrons read state=1 with a LIVE object pointer in a mission where nothing has been shot, which does not fit the built-in table's '1 = gone'. Reading state != 2 as destroyed would be a plausible-but-wrong inference; the encoding needs pinning first. New tool tools/re-capture/squadron_state.py, verified end to end against the manual reading.