# Live unit definitions from a running Stage 02 (2026-08-12) The Route-B question — what value does a field that the disc leaves **defaulted** actually take at runtime — needs the game running. This is the first snapshot of the parsed definition objects taken straight out of guest RAM, plus the recipe that works in the box today, because getting there was most of the work. ## The recipe that works Everything must happen inside **one blocking foreground call**. A process that outlives the call that started it is reaped — `nohup`, a harness background job and a `wait`-holding wrapper were all tried and all died within a minute of the turn ending (see the session-lifetime notes). ```bash tools/re-capture/launch_mission.sh fly # title → LOAD → slot 01 → READY ROOM → TAKE OFF python3 tools/re-capture/gmem.py find hex:820af844 400 # live definition objects python3 tools/re-capture/gmem.py words 96 # dump each one ``` Two environment facts that cost an hour each: - **Audio must be `--audio --apu=sdl` with `SDL_AUDIODRIVER=dummy`.** There is no PulseAudio server in the box, so muting (`--apu=nop`, `run-canary`'s default) looks like the safe choice. It is not: the log then fills with `AudioSystem::RegisterClient: CreateDriver failed for index=0`, the guest never gets past the movie, and the window stays black for 8+ minutes. `nav_probe.sh` and `launch_mission.sh` already pass the right pair — do not "fix" them. - **Boot is fast once the caches are warm.** The first boot took minutes; with the shader/code cache populated, `launch_mission.sh` reached the flight HUD in **25 s**, which is what makes a launch-and-dump fit in a single call. `entities2.py`, `flight_probe.py` and the other analysis scripts **do not run here** — no `numpy` (and no `PIL` for image work). `gmem.py` is pure stdlib and works, so the pattern is: dump raw words to disc inside the call, analyse afterwards. ## What came out 14 live definition objects (vtable `0x820af844`), 96 words each: [`captures/stage02-live-unit-definitions.txt`](captures/stage02-live-unit-definitions.txt), with the flight screenshot they were taken from. | object | `+0x30` | `+0x34` | `+0x38` | `+0x54` | |---|---|---|---|---| | `0xbd3b6a00` | 2500 | 3100 | 2600 | 10000 | | `0xbd3d2d80` | 80 | 80 | 350 | 4000 | | `0xbd3da100` | 10 | 7 | 29 | 1500 | | `0xbd3db980` | 350 | 70 | 200 | 10000 | | `0xbd3dbd00` | 10 | 5 | 20 | 300 | | `0xbd3dea80` | 20 | 9 | 22 | 100 | | `0xbd3dfc00` | 10 | 7 | 29 | 1000 | | `0xbd3e0680` | 300 | 300 | 2800 | 3000 | | `0xbd3e1f00` | 400 | 400 | 1400 | 25000 | | `0xbd3e6f80` | 300 | 300 | 2100 | 10000 | | `0xbd3ee300` | 200 | 200 | 2000 | 10000 | | `0xbd3faa80` | 100 | 40 | 50 | 500 | | `0xbd3fd800` | 600 | 600 | 3800 | 30000 | | `0xbd40e200` | 700 | 700 | 3800 | 30000 | This **corroborates** the layout solved earlier from a single in-mission snapshot (`+0x054` = HP, `+0x30…0x38` = `Size_X/Y/Z`) rather than re-proving it: the `+0x54` column reads as hull values across three orders of magnitude (100 for something small, 30 000 twice for capital ships), and the sizes scale with them. It also gives independent support to the **`Size_Y` inherits `Size_X`** default rule — five of the fourteen have `+0x30 == +0x34` exactly (300/300, 400/400, 200/200, 600/600, 700/700) while the rest differ. ❔ **Not yet resolved: which unit each object is.** Nothing in the first 96 words is an obvious name pointer, so these cannot be matched to their disc records yet — and that match is what turns the snapshot into defaulted-field *values*. The next step is to dump further into the object (and the entity that points at it) looking for the id or name field, which is one more single-call run.