# ✅ The stage drift is my NAVIGATION, not the save — slot 01 is deterministically Stage 02 Settled 2026-08-26, **statically** — no emulator needed. ## ❌ Refuted: "slot 01 is the auto-save, so the restored mission moves between runs" [The previous note](two-entity-enumerations.md) blamed save drift for one run loading the S01 training area (with `UN_S01_Asteroid_cmesh_*`) and another loading a Stage-02-style escort roster. The file says otherwise: ``` 2026-08-23 16:37 278 .../535107D4/00000001/game01/savedata 2026-08-26 22:18 26596 .../FFFE07D1/.../535107D4.gpd ``` **`savedata` has not been written since 23 August.** Every run today left it untouched; only the `.gpd` profile/achievement files moved. And there is exactly **one** save (`game01`), so a wandering save-list cursor cannot explain it either. ## ✅ What the save actually holds: Stage 02 The save is `GDHA` + a zlib payload at `0x92` (545 bytes decompressed), carrying `GDAA`, `GHAD`, `NETA`, 2 × `BUNK` and the 16-record `SHAB` table. ``` rec 0 (stage 1): (2, 4101, 324773, ...) rec 1 (stage 2): (0, 0, 0, ...) ... rec 15 (stage 16): (0, 0, 0, ...) ``` **Only record 0 carries clear data**; records 1–15 have zeros in all three result fields. Three independent readings agree on what that means: 1. `324773` ms = **05:24.77**, which [`SESSION-2026-08-11.md`](SESSION-2026-08-11.md) documents as exactly what MISSION SELECT displays as the Stage 01 best time. 2. `4101` matches [`structures/weapon-datasheet-runtime.md`](structures/weapon-datasheet-runtime.md), whose capture session is recorded as *"Stage 02, 'At Standby', 5 % clear, **4101 P**"* — the same save, already described in the corpus. 3. Reading the `GHAD` field block at **tag+4** gives `+52` = **2**, the documented 1-based `Stage` field. So `LOAD GAME → slot 01` restores **Stage 02** every time. It is deterministic. > ### ✅ The base is pinned — and it was not tag+8 > > The caveat here originally said brute force gave seven candidate offsets and > that I had picked **tag+8** because it agreed with the other readings rather > than because the search isolated it. The authoritative parser settles it: > `crates/sylpheed-formats/src/savegame.rs` documents the chunk stream, read off > the title's own serializer at `0x822C00E8`, as > > ```text > 'GDAA' payload magic > u32 len, char[len] current game phase, e.g. "GP_BUNK" > 'GHAD' + 122 bytes the progress block > u32 16, 16 x ('SHAB' + 5 x u32) the per-stage record table > ``` > > and `FieldSpec.offset` is "Offset within the 122-byte GHAD block" — so the base > is **tag+4**, where the block begins. Reading there gives three fields at once, > two of which match values documented independently elsewhere in the corpus: > > | field | GHAD offset | value | corroboration | > |---|---|---|---| > | `Stage` | +52 | **2** | Stage 02 = the Acropolis escort mission | > | `Points` | +24 | **4101** | `weapon-datasheet-runtime.md`: "4101 P" | > | `FlightTime` | +4 | **324773** | the 05:24.77 Stage-01 best time | > > Two independently-documented values landing at once is what a correct base > looks like; tag+8 reproduced only the stage. The phase string in the same > payload reads **`GP_BUNK`** — the save sits in the bunk between missions. > > ❔ The `.header` **mirror** did not reproduce: `savegame.rs` lists `Stage` at > header offset `0x14`, but reading a big-endian u32 there gives `2097200` > (`00 20 00 30`), which looks like UTF-16 text rather than a mirrored word. Not > chased — the payload reading is confirmed and does not depend on it. ❌ And "stage = filled `SHAB` count + 1" must not be used: all 16 records are *present*, and the corpus already lists that rule as **refuted**. Presence is not filledness. ## ✅ So the S01 asteroid run was never the save Stage 02 is the `Acropolis` escort mission — which is precisely the roster the most recent run produced (`UN_f101_TCAF_Acropolis`, `UN_bf001_TCAF_SchlosBase`, cruisers, frigates). The odd run out is the earlier one, whose briefing read **"Glasner Training Area"** — a *tutorial*, not a story stage, and [`structures/unit-struct-runtime.md`](structures/unit-struct-runtime.md) confirms tutorials are separately reachable ("all six tutorials **and** Stage 02"). The cause is in my own driving: that run's navigation log shows the menu probe reading `other` repeatedly and the `dpad down` + Ⓐ being issued from a state that was not confirmed to be the main menu, so the selection landed on a tutorial entry instead of `LOAD GAME`. The nav taps a fixed sequence and never verifies *what it selected*. ## Consequence — the cheap fix Runtime rosters are reproducible after all, provided the route is verified. Two one-line guards, neither of which needs new tooling: * Confirm `screen_id.py` reads `menu` **immediately before** the `dpad down`, not merely at some point earlier in the loop. * After reaching flight, assert the definition table contains `UN_f101_TCAF_Acropolis` (Stage 02's signature) before trusting any comparison against an earlier run. ❔ Not settled: I did not re-run the emulator to demonstrate the tutorial mis-selection directly. The evidence here is the save file plus the earlier run's own screen log and briefing title, which is strong but circumstantial about *which* menu entry was hit.