Files
Sylpheed/docs/port/options-screens.md
Sylpheed port agent e57eda14e4 recover: the OPTIONS menu work from the deleted auto/port-p6-audio
The nine files touched by the OPTIONS commits of 2026-09-03 (77f1d18,
fda417a, 3efe1cc, 80042cb, 4c24e06, a921c1e, 41f1331, 6b4b1df, edf8979),
taken as of 0148cb8, the tip of auto/port-p6-audio. The branch was deleted
from the server on 2026-09-17 during the consolidation cleanup; issue #6
asks for this work as a reviewable PR, so it is recovered here before the
commits are garbage collected.

This is a review slice, not a self-consistent tree: the OPTIONS work and
the F5/F6 work interleaved in the original history and cannot be separated
by file, so each file carries whatever else had changed in it by
2026-09-04, and files it depends on are absent. The complete state is
recover/port-f5-f6.

Refs #6.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 20:48:48 +02:00

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_menu ptbtn04 still has goto: null.
  • po_pad_slider1 has no sprite in the export and reports NOT DRAWN.
  • All 14 are NEVER COMPARED by verify-screen — reported, not asserted; both its allowance and the reference renderer were calibrated on GP_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 | 0x3003two 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_btn2po_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.