Files
Sylpheed/docs/re/menu-navigation-semantics.md
Sylpheed RE agent f290d96f92 re: one A skips the intro, and NEW GAME was never a hang
Two corpus claims died in one boot, and both were costing us.

Q9's last row: a movie IS skippable with a single A. One tap ~45s into
the boot put the title up at ~57s, against a ~193s no-input baseline
measured over three boots, and Canary's own keystroke counter went 3->4
so exactly one press was delivered. The skipped-to title is fully
functional -- it draws the PRESS A plate and a second A opens the main
menu. What actually breaks the boot is hammering: the 88-press run in the
traps doc. The scripts' "tapping breaks the title" comment is too broad
and costs every scripted boot two and a half minutes.

Q4's last row: A on NEW GAME does not hang. It opens DIFFICULTY
(EASY/NORMAL/HARD/BACK, focus on NORMAL), then SELECT DATA, and only then
does the guest throw -- at PC 0x82307128, which is inside sub_823070B0,
the cache-manager STL erase this corpus already documents and which has
nothing to do with the menu path. The screen sat unchanged for 90s
because it was a menu waiting for input from a loop that never pressed
anything. That is now a METHOD line: a screen that never changes is not
necessarily hung, and the fix is to look at it and press something.

Also METHOD: never run ps -ef in this container -- all three long-lived
processes carry the entire loop prompt as argv.
2026-08-28 18:45:59 +00:00

6.7 KiB

The title menu — how it moves, and where each button goes

Status: CONFIRMED (measured, by driving the running game) for the movement rules and for four of the five main-menu destinations. 🟡 the GamePart id behind each destination is a name match onto the decoded id table, not a measurement. NEW GAME deliberately untested.

Answers MISSION Q5 and most of Q4. Nothing here is on the disc in any form found so far — the port is authoring these rules from this page, not transcribing a field.

Q5 — movement

Two boots via tools/re-capture/boot_menu.sh, cursor read off the focus ring with tools/re-capture/menu_focus.py.

behaviour evidence
initial focus, main menu TUTORIAL — the middle item, not the top 2/2 boots, the first frame after the menu appears
initial focus, EXTRAS MISSION SELECT — the top item extras-wrap.png
up / down one item per press, no auto-repeat at the durations tried
wrap at the top ⬆ from the first item goes to the last wrap-montage.png, panels 1→2
wrap at the bottom ⬇ from the last item goes to the first same, panels 3→4, and 4 presses from EXTRAS landing on OPTIONS — i.e. wrapping — is what makes the count come out
left / right nothing, on the main menu cursor unmoved across one ⬅ and one ➡
Ⓑ on a submenu returns to the parent with focus restored to the item you entered fromLOAD GAMELOAD GAME, TUTORIALTUTORIAL, OPTIONSOPTIONS, EXTRASEXTRAS 4/4
Ⓑ on the main menu goes to the title, which re-draws PRESS Ⓐ BUTTON after a beat
Ⓑ on the title nothing

Wrap holds on both screens tested — the 5-item main menu and the 3-item EXTRAS submenu — so it is a menu rule, not a per-screen table.

🟡 Initial focus is reproducible but not established as invariant. Both of my boots opened on TUTORIAL, and both used boot_menu.sh. The run recorded in menu-state-in-memory.md reached EXTRAS with four downs from the main menu, which only works from NEW GAME. Either the harness path matters or something persists. Do not hardcode TUTORIAL without re-testing it; what is solid is that the menu does not open on the top item in this harness.

Q4 — where each button goes

Measured by driving: focus the item, press Ⓐ, read the screen's own title.

button screen it opens evidence GamePart id
NEW GAME not tested
LOAD GAME the save-slot list, LOAD GAME / Current Storage q4-destinations.png left 🟡 3 GP_LOAD
TUTORIAL the lesson list, TUTORIAL, Level 1 / Level 2 same, middle 🟡 25 GP_TUTORIAL
OPTIONS OPTIONS — GAME / CONTROL / SOUND / SCREEN SETTINGS / BACK same, right 🟡 8 GP_OPTIONS
EXTRAS GP_TITLE.pak build 6 — MISSION SELECT / MOVIE THEATER / BACK ui-title-build-map.md 🟡 5 GP_EXTRAS
EXTRAS ▸ MISSION SELECT the stage list + Wide Area Space Map 🟡 7 GP_MISSION_SELECT
EXTRAS ▸ MOVIE THEATER not tested 🟡 6 GP_MOVIE_THEATER

Say which, as the gate asks. The screen each button opens is measured — I pressed the button and read the title off the framebuffer. The GamePart id is not measured: it is the entry of the decoded 29-id table at .rdata 0x820A1630 (challenge-mission-gate.md §3) whose name matches the screen I saw. The table is decoded; the binding of a button to an entry in it is a name match I made by eye. The port should treat these ids as authored.

Worth noting that the ids and the paks are not one-to-one: GP_EXTRAS is id 5 with no pak of its own — its artwork is a build inside GP_TITLE.pak.

NEW GAME was deliberately not pressed. Ⓐ on it leads to a standing black-screen hang that ends the run (ui-paint-order-third-permutation.md), and this iteration needed the session. It is the one destination still unmeasured.

The cheap way to finish this, and to make it a measurement

0x828A690C holds a live screen id1 title, 3 main menu, 4 extras — and 0x828F38AC the cursor (menu-state-in-memory.md). Reading those while pressing Ⓐ turns "the screen said OPTIONS" into a measured transition, and works under --gpu=null with no screenshots at all. ⚠️ Note that those values are not GamePart ids — GP_TITLE is GamePart 0 and GP_EXTRAS is 5, but the word reads 1 and 4 — so it is a third enumeration and mapping it to the id table is itself unfinished work.

NEW GAME — measured 2026-08-28, and it is not a hang

The one destination this page could not test has been driven. Ⓐ on NEW GAME does not hang. It opens two more menus first:

NEW GAME  ->  DIFFICULTY  ->  SELECT DATA  ->  guest crash
  • DIFFICULTYEASY / NORMAL / HARD / BACK, footer Ⓐ : OK Ⓑ : Back, opening focused on NORMAL (capture). It sat unchanged for 90 s with the emulator healthy — a menu waiting for input, which is exactly what "a standing hang" looks like to a screenshot loop that never presses anything.
  • Ⓐ on NORMALSELECT DATA, a save-slot picker headed Current Storage: Dummy HDD, prompting to pick a file for the auto-save.
  • Then the guest throws, and Xenia pauses with PC: 0x82307128 (capture).

That crash is already in the corpus and is not new: 0x82307128 is inside sub_823070B0, the cache-manager STL erase documented in title-crash-stl-tree.md, whose trigger is an incomplete on-disc shader/code cache — not the menu path. The corpus also already holds captures/select-data-crash.png.

So Q4's last row closes as measured:

button screen it opens
NEW GAME DIFFICULTY (then SELECT DATA)

🟡 The GamePart ids for these two are unmeasured, like the rest — 24 GP_DIALOG and 3 GP_LOAD / 2 GP_SELECT_STORAGE are name-match candidates and nothing more.

Initial focus — a fourth data point, and it still varies

This boot opened the main menu on NEW GAME. Running tally across four boots of the same harness: TUTORIAL, TUTORIAL, NEW GAME, NEW GAME. Unchanged conclusion: do not hardcode it.