docs: the dynamic-RE state was gone - rebuild it, measured rather than remembered
The baseline binary, the profile, the Stage 02 save and the caches all live outside both repos and had been wiped, and sylph-doctor reports 'all good' without them. This is the recipe, verified by driving it to Stage 02 flight rather than by inspecting files. Three things worth having found: * the baseline is an INCREMENTAL build, not a scratch one -- auto/upstream-baseline differs from the instrumented branch in 202 files and zero submodule gitlinks, so checking it out in the shared tree and rebuilding into the existing build dir takes ~9 min at -j4. git worktree prune first; a dead worktree still claims the branch. * the baseline CANNOT make a profile (--create_profile_if_none is one of our 50 commits) and the Sign In dialog cannot be typed into, so bootstrap the profile with the instrumented binary once and run the baseline against it. * the Xbox content .header is NOT needed -- ContentManager::ListContent falls back to the directory name when ReadContentHeaderFile fails, checked in the source. The LOAD GAME screen then shows date, difficulty, flight time and clear ratio anyway, which proves those come out of savedata itself. No header was fabricated. Trap paid for once: keep the file name xenia_canary. A copy saved as xenia_canary.baseline-... survives every pkill -x in the toolkit and holds the run-canary lockfile while ps -C xenia_canary shows nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
BIN
docs/re/captures/loadgame-slot01-headerless-install.png
Normal file
BIN
docs/re/captures/loadgame-slot01-headerless-install.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 673 KiB |
BIN
docs/re/captures/stage02-inflight-restored-state.png
Normal file
BIN
docs/re/captures/stage02-inflight-restored-state.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
135
docs/re/dynamic-re-state-restore.md
Normal file
135
docs/re/dynamic-re-state-restore.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# The container's dynamic-RE state is not durable — how to rebuild it
|
||||
|
||||
**Status: ✅ `CONFIRMED` by rebuilding it** (2026-08-23). Everything the dynamic
|
||||
side of this corpus runs on — the baseline emulator binary, the Xbox profile, the
|
||||
Stage 02 save, the shader/code caches — lives outside the two git repos and was
|
||||
**gone** at the start of this session. None of it is recoverable from a git pull,
|
||||
and `sylph-doctor` reports "all good" without it, so the first symptom is a boot
|
||||
that dies instantly with `NO PROFILE on disc`.
|
||||
|
||||
This file is the recipe, measured rather than remembered.
|
||||
|
||||
## What was missing, and what it blocks
|
||||
|
||||
| gone | consequence |
|
||||
|---|---|
|
||||
| `/sylph-home/re/pure/xenia-canary` (the `auto/upstream-baseline` worktree) and its build | no baseline binary. The instrumented branch stops at the Stage 02 briefing under 384 crash dumps ([`upstream-baseline.md`](upstream-baseline.md)), so **no in-mission work is possible at all** |
|
||||
| `~/.local/share/Xenia/` — the whole storage root | no profile, no save, no config, no caches |
|
||||
|
||||
`launch_mission.sh` needs all of it: it signs in `$(ls "$XENIA_CONTENT")` and
|
||||
navigates title → **LOAD GAME → slot 01** → READY ROOM → TAKE OFF.
|
||||
|
||||
## 1. The baseline binary — rebuild it *incrementally*, not from scratch
|
||||
|
||||
The branch itself survives (`auto/upstream-baseline`, tip `c1b57f93b` = upstream
|
||||
`a5a18f5c7` + the three file-pad commits + the lost-resume fix). What is gone is
|
||||
only the checkout and the build.
|
||||
|
||||
The cheap move is **not** a new worktree: a fresh build directory means building
|
||||
all of `third_party` again. Instead check the branch out in the shared
|
||||
`/work/xenia-canary` and let ninja do an incremental build into the existing
|
||||
`$XENIA_BUILD_DIR`, because the two branches differ in **202 files and zero
|
||||
submodule gitlinks**:
|
||||
|
||||
```bash
|
||||
cd /work/xenia-canary && git worktree prune # the dead worktree still claims the branch
|
||||
git checkout auto/upstream-baseline
|
||||
build-canary Release # ~9 min at -j4 here, vs a scratch build
|
||||
```
|
||||
|
||||
`git worktree prune` is not optional — without it the checkout fails with
|
||||
*"'auto/upstream-baseline' is already used by worktree at /sylph-home/re/pure/…"*
|
||||
for a directory that no longer exists.
|
||||
|
||||
**Keep both binaries**, because switching the branch back costs another build:
|
||||
|
||||
```
|
||||
/sylph-home/re/bin/baseline-c1b57f93b/xenia_canary XENIA_BIN=… run-canary
|
||||
/sylph-home/re/bin/instrumented-a60fe7d11/xenia_canary
|
||||
```
|
||||
|
||||
🔴 **Trap, paid for once here: keep the file name `xenia_canary`.** A copy saved
|
||||
as `xenia_canary.baseline-…` runs fine and then survives every `pkill -x
|
||||
xenia_canary` in the toolkit — `-x` matches the whole name. The emulator keeps
|
||||
the `flock` on `/tmp/xenia-canary.lock`, and the next launch fails with
|
||||
*"an emulator is already running"* while `ps -C xenia_canary` shows nothing. Put
|
||||
the variant in a **directory** and leave the file name alone.
|
||||
|
||||
**Tell the two apart by what is in them, not by the path**, since `build-canary`
|
||||
writes both to the same place and [has reported success on a failed
|
||||
build](upstream-baseline.md):
|
||||
|
||||
```bash
|
||||
strings -a "$BIN" | grep -c log_ui_draws # instrumented: 5 baseline: 0
|
||||
```
|
||||
|
||||
## 2. The profile — bootstrap it with the *instrumented* binary
|
||||
|
||||
`--create_profile_if_none` is one of our 50 RE commits (`7dbb24e64`) and is **not
|
||||
on the baseline branch**; the baseline cannot make a profile, and the Sign In
|
||||
dialog cannot be driven from a script (an ImGui text field, no synthetic key
|
||||
events reach it). So make the profile once with the instrumented binary and then
|
||||
run the baseline against it — the content root is emulator-build independent:
|
||||
|
||||
```bash
|
||||
XENIA_BIN=/sylph-home/re/bin/instrumented-a60fe7d11/xenia_canary \
|
||||
run-canary --create_profile_if_none=SylphRE
|
||||
# wait for: ProfileManager: RE bootstrap profile 'SylphRE' -> created
|
||||
pkill -x xenia_canary
|
||||
```
|
||||
|
||||
XUID is fixed at **`B13EBABEBABEBABE`**, which is what makes it scriptable, and
|
||||
`launch_mission.sh` picks it up on its own.
|
||||
|
||||
## 3. The Stage 02 save — from the repo, and **without** a `.header`
|
||||
|
||||
`docs/re/captures/savedata-stage02-5pct.bin` is a complete `GDHA` container
|
||||
(parses clean: `phase GP_BUNK`, slot 0 used, 2026-07-23 20:07). Drop it in at the
|
||||
path [`structures/savegame-format.md`](structures/savegame-format.md) records:
|
||||
|
||||
```bash
|
||||
C=~/.local/share/Xenia/content/B13EBABEBABEBABE/535107D4/00000001/game01
|
||||
mkdir -p "$C" && cp docs/re/captures/savedata-stage02-5pct.bin "$C/savedata"
|
||||
```
|
||||
|
||||
The companion `Headers/00000001/game01.header` is **not** in the repo and is
|
||||
**not needed** — checked in the source rather than assumed:
|
||||
`ContentManager::ListContent` (`src/xenia/kernel/xam/content_manager.cc`)
|
||||
enumerates *directories*, and when `ReadContentHeaderFile` fails it synthesises
|
||||
the record from the directory name. The slot is listed either way; only the
|
||||
display string differs (`game01` instead of
|
||||
`Game01 07/23/2026 21:08 STAGE02 EASY`). So there is no need to fabricate a
|
||||
328-byte Xbox content header, which would have been a guess with no oracle.
|
||||
|
||||
## Verified end to end — and one new trap in the scripted route
|
||||
|
||||
The restored state was checked by **driving it**, not by inspecting files:
|
||||
|
||||
1. `LOAD GAME` lists the slot ()
|
||||
as `01 · 07/23/2026 21:08 · EASY · 000:05:24 · 5 %`, with the Details panel
|
||||
reading `STAGE02 — Declaration of War`, `At Standby`, `4101 P`. Note what that
|
||||
settles: **every detail on that screen comes out of `savedata`**, not out of
|
||||
the Xbox content header that was not installed.
|
||||
2. → READY ROOM → TAKE OFF → launch cinematic → objective card →
|
||||
**Stage 02 flight** (),
|
||||
`TIME 00:18.01`, `REMAINING OB 004`, hull 1500 / shield 400. `pilot.py` bound
|
||||
and flew it (`ENGAGE … tgt=e010_ADAN_Attacker_S`), so the whole live-memory
|
||||
toolchain works against the restored profile.
|
||||
|
||||
🔴 **A fresh profile inserts an extra dialog, and it desynchronises
|
||||
`launch_mission.sh`.** After `LOAD GAME → slot 01 → YES` the title puts up
|
||||
**"Auto-Save is active. OK?"** (YES preselected) before the READY ROOM. The
|
||||
launcher's press sequence is fixed and has no slot for it, so every later press
|
||||
lands one screen early — this run ended up sitting in **OPTIONS → GAME SETTINGS**,
|
||||
and `wait_flight.sh` correctly reported `NEVER REACHED FLIGHT`. The mission above
|
||||
was reached by driving the menus by hand from there.
|
||||
|
||||
**Checked on the next boot: the dialog does not return** — the auto-save answer
|
||||
is kept in the profile. The launcher gets further (READY ROOM instead of
|
||||
OPTIONS) and still misses: it lands on **BRIEFINGS**, i.e. its
|
||||
`step up; tap A` for TAKE OFF is swallowed by the READY ROOM transition, because
|
||||
what precedes it is a fixed `sleep 28` rather than a wait for the screen. So
|
||||
`launch_mission.sh` is **one wait away** from working unattended on restored
|
||||
state, and both runs here were finished by hand from the screen it stopped on.
|
||||
That repair is left for whoever needs the launcher, and is noted in
|
||||
[`BACKLOG.md`](BACKLOG.md); nothing here depends on it.
|
||||
Reference in New Issue
Block a user