The Decoder decoded bit 0 of kind as the PARENT FLAG, disc-wide: kind & 1 agrees
with 'has a parent' on 15493 elements, zero disagreements. So 0x3003 is 0x3002
parented, and carries no role information -- the OPTIONS rows were never a
different class, they just have a parent.
Detector now matches 0x3002 | 0x3003 as TWO LISTED VALUES, not a mask.
kind & 0xFFFE == 0x3002 would also match 0x73002/0x73003 -- 160 elements whose
0x70000 bits are undecoded -- silently, on screens neither agent has looked at.
Excluded by construction until somebody decides deliberately.
Impact measured BEFORE re-exporting: exactly two screens gain buttons, options
and options_jp, five rows each. No existing screen changes.
Verified: main_menu -> down x3 -> (A) -> OPTIONS, then down x2 moves
po_menu_btn2 -> po_menu_btn3, focus ring rendering on the highlighted row.
📌 Waiting was right. The rule I rejected -- 'carries a focus record therefore is
a menu item' -- would have reached this answer by a second inference from
structure and reclassified elements on unseen screens. The field cost one
question and needed no inference.
5.9 KiB
The OPTIONS menu tree exists, renders, and is named
2026-09-03. GP_OPTIONS joined export_archives and produced 14 screen
builds. All 14 render; all 14 are now named.
What they are
| entry | name | English | entry | name | |
|---|---|---|---|---|---|
| 19 | options |
the root — GAME / CONTROL / SOUND / SCREEN SETTINGS, BACK | 21 | options_jp |
|
| 16 | game_settings |
Auto-Save, View Point, Radio Log, Subtitles | 18 | game_settings_jp |
|
| 4 | control_settings |
Control Type, Throttle, sensitivities, Vibration | 8 | control_settings_jp |
|
| 3 | sound_settings |
Music / Movie / Voice / SFX Volume | 5 | sound_settings_jp |
|
| 6 | screen_settings |
Gamma Correction, R/G/B, NEXT PAGE | 9 | screen_settings_jp |
|
| 7 | screen_settings_page2 |
White / Black Level Adjust, PREVIOUS PAGE | 10 | screen_settings_page2_jp |
|
| 20 | control_customize |
per-action key remapping | 22 | control_customize_jp |
A clean EN/JP pair for every screen, which is itself a check: 14 builds, 7 pairs, no leftovers.
How they were identified, and why that is stronger than usual here
By the text the screen renders about itself. Each was exported, drawn by the port at rest, and read: the titles and row labels are legible.
📌 That matters because this project has been bitten three times by
identification via position, size or ordinal — the sweep strips confused by
size, the plate identified by screen position, ptcopyright mistaken for the
plate. A screen that renders the words SOUND SETTINGS above four volume rows is
not that kind of inference.
⚠️ What it still does not establish: which screen the game navigates to
from which. The tree above is read off content, so control_customize being
"reached from CONTROL SETTINGS" is a reading of its own legend
(Ⓨ : Customize on control_settings), not a measured transition. Wiring
anything beyond main_menu → options needs the real navigation.
Not yet done
- Nothing is reachable yet.
main_menuptbtn04still hasgoto: null. po_pad_slider1has no sprite in the export and reports NOT DRAWN.- All 14 are
NEVER COMPAREDbyverify-screen— reported, not asserted; both its allowance and the reference renderer were calibrated onGP_TITLE. - The screens are static: no navigation, no focus movement, no value editing.
✅ OPTIONS is reachable — and navigation inside it is blocked on a kind
main_menu ptbtn04 now has goto: "options". Walked with the menu harness:
main_menu → ⬇⬇⬇ → Ⓐ → the OPTIONS root renders. Ⓑ backs out.
✅ RESOLVED — the rows move. 0x3003 is 0x3002 with the parent bit set
The Decoder decoded it disc-wide: bit 0 of kind is the PARENT FLAG, and it
carries no role information. Over every .pak in dat/, kind & 1 agrees with
"has a parent" on 15 493 elements with zero disagreements
(docs/re/ui-kind-bit0-is-has-parent.md). The OPTIONS rows are parented; the
main-menu buttons are not. Same record class.
So the detector now matches 0x3002 | 0x3003 — two values listed, not a
mask. kind & 0xFFFE == 0x3002 would also catch 0x73002/0x73003, 160
elements whose high bits nobody has decoded, silently and on screens neither
agent has seen.
Impact measured before re-exporting, not after: exactly two screens gain
buttons — options and options_jp, five rows each. No existing screen changes.
Verified by walking it: main_menu → ⬇⬇⬇ → Ⓐ → OPTIONS, then ⬇⬇ moves
po_menu_btn2 → po_menu_btn3 with the focus ring rendering on the highlighted
row.
📌 The port was right to wait. The rejected rule — "carries a focus record ⇒ menu item" — would have reached the same answer here by a second inference from structure, and would have reclassified elements on screens nobody had looked at. The field cost one question and needed no inference at all.
The original section, kept for the shape of the block
The exporter's button detector is kind == 0x3002 && !focused. The OPTIONS rows
are kind_raw = 0x3003, so role comes out unknown, the export's
buttons[] is empty, and up/down move nothing.
| screen | element | kind | focus record | in buttons[] |
|---|---|---|---|---|
main_menu |
ptbtn01 |
0x3002 |
yes | yes |
extras |
ptbtn11 |
0x3002 |
yes | yes |
options |
po_menu_btn1 |
0x3003 |
yes | no |
What 0x3003 means is not the port's to decide, so the rule was not widened
here. The circumstantial case is strong — five rows, each carrying a focus
record, on a screen whose own text lists five options — and circumstantial is
precisely the standard that has cost this project three separate retractions.
Asked of the Decoder.
⚠️ A tempting alternative rule is "an element with a focus record is a menu item", which fits both screens. It is still an inference about semantics from structure, and it would silently reclassify elements on every screen in the export. Not taken.
The workflow cost this exposed, worth knowing before repeating it
A screen name is authored data, but it only reaches the port through a full re-export — which re-transcodes both movies. Renaming one screen costs the whole tree. Not worth fixing today; worth knowing before anyone plans a naming pass.
🔴 And a genuinely dangerous mistake, recorded because it nearly cost the session
Killing a background check with pkill -f "check-all" matched the container's
own entrypoint, whose command line contains the loop prompt — and that prompt
mentions check-all. pgrep duly reported the process as still running after it
had stopped, and a pkill -9 on that pattern could have killed the session
itself.
Match a process by its actual comm, or list with ps and check, before
sending a signal. A pattern that appears in your own instructions is not a
pattern that identifies a process.