From 1bf619460a0f96cf979d0886c0c1645d375883fe Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Mon, 31 Aug 2026 01:51:03 +0000 Subject: [PATCH] re: menu focus does not survive a reboot -- six fresh boots, three following a session that ended elsewhere No new boot was spent: six runs had already captured the first menu entry of a fresh boot, and all six read NEW GAME. Three of them follow a session that ended with the cursor on EXTRAS or OPTIONS, which is what makes it a test of persistence rather than a repeated observation. Reach stated rather than implied: every session ends with the emulator KILLED, so a game that writes menu state on a clean shutdown would never get the chance. This measures 'does not survive a killed session'. Refutation attempt on the port's extras/initial_focus: ptbtn11 -- it SURVIVES. ptbtn11 is the top button on the EXTRAS build, with the main menu as a control where ptbtn01 is top and is known to be NEW GAME. Incidentally corrects ring_row.py's stated calibration. It cited capture_y = 49.5 + 1.060*design_y, fitted against menu_focus.py's row centres, which are NOT the disc's button rows -- the disc says 162/242/322/401/482, spacing 80, and menu_focus.py drifts up to 17 px against them. Re-fitted: 64.82 + 0.9919*design_y, residuals under 0.7 px. No item assignment changes. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- .../examples/extras_button_order.rs | 44 ++++++++++++++++ docs/re/REFUTED.md | 19 +++++++ .../data/focus-does-not-survive-a-reboot.txt | 52 +++++++++++++++++++ tools/re-capture/ring_row.py | 19 +++++-- 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 crates/sylpheed-formats/examples/extras_button_order.rs create mode 100644 docs/re/data/focus-does-not-survive-a-reboot.txt diff --git a/crates/sylpheed-formats/examples/extras_button_order.rs b/crates/sylpheed-formats/examples/extras_button_order.rs new file mode 100644 index 00000000..35b56f75 --- /dev/null +++ b/crates/sylpheed-formats/examples/extras_button_order.rs @@ -0,0 +1,44 @@ +//! Is `ptbtn11` the TOP item of the `EXTRAS` screen? +//! +//! `sylpheed-port` authors `extras/initial_focus: ptbtn11` and states it is +//! correct under the surviving reading — "a submenu resets to the item it opens +//! on". The oracle shows EXTRAS opening on `MISSION SELECT`, the first of +//! MISSION SELECT / MOVIE THEATER / BACK. So their value is right only if +//! `ptbtn11` is that first item. This checks it against the disc. +//! +//! CONTROL: the same read on the MAIN MENU build, whose five buttons have a known +//! top-to-bottom order (NEW GAME first). If the ordering rule cannot reproduce a +//! known screen it cannot be trusted on an unknown one. +//! +//! cargo run -p sylpheed-formats --example extras_button_order +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::path::PathBuf; + +fn report(ar: &PakArchive, entry: usize, what: &str) { + let Ok(by) = ar.read(&ar.entries()[entry]) else { return }; + let Some(b) = ui_layout::parse_build(&by) else { return }; + let mut rows: Vec<(i32, String, u32)> = b + .elements + .iter() + .filter(|e| e.name.starts_with("ptbtn") && !e.name.contains('f')) + .map(|e| { + let y = e.rest().map(|k| k.y).unwrap_or(e.pivot_y as i32); + (y, e.name.clone(), e.kind) + }) + .collect(); + rows.sort_by_key(|r| r.0); + println!("\n{what} (entry {entry}) — buttons top to bottom:"); + for (y, n, k) in &rows { + println!(" y {y:5} {n:14} kind 0x{k:04x}"); + } + if let Some((_, first, _)) = rows.first() { + println!(" => TOP item is {first}"); + } +} + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE.pak"); + report(&ar, 5, "CONTROL: main menu (NEW GAME must be top)"); + report(&ar, 6, "EXTRAS"); +} diff --git a/docs/re/REFUTED.md b/docs/re/REFUTED.md index a5302e19..23193f8a 100644 --- a/docs/re/REFUTED.md +++ b/docs/re/REFUTED.md @@ -818,3 +818,22 @@ here, against the **19–20 dB** an unrelated movie gave them. A 0.66 dB thresho an 8× margin against that floor rather than a 30× one, so **the safety of the threshold depends on how different the chosen known-negative is**, not on the method. [data](data/impossibility-scope-sweep.txt) + +### Refutation attempt on `sylpheed-port`'s `extras/initial_focus: ptbtn11` — ✅ SURVIVES (2026-08-31) + +**Target:** their statement that `EXTRAS` keeps `ptbtn11` and is "correct under the +surviving reading" — i.e. that a submenu resets to the item it opens on, and that +`ptbtn11` is that item. + +**My attempt:** the oracle shows `EXTRAS` opening on `MISSION SELECT`, the first of +three. So their value is right only if `ptbtn11` is the **top** button on that +screen. Checked against the disc, with the main menu as a control +(`examples/extras_button_order.rs`): + +| | buttons top to bottom | +|---|---| +| **control** — main menu (entry 5) | `ptbtn01` y162, `ptbtn02` y242, `ptbtn03` y322, `ptbtn04` y401, `ptbtn05` y482 → top is `ptbtn01` = `NEW GAME` ✅ | +| `EXTRAS` (entry 6) | `ptbtn11` y282, `ptbtn12` y362, `ptbtn13` y442 → **top is `ptbtn11`** | + +**The claim survives**, and the control confirms the ordering rule reproduces a +screen whose answer is independently known. diff --git a/docs/re/data/focus-does-not-survive-a-reboot.txt b/docs/re/data/focus-does-not-survive-a-reboot.txt new file mode 100644 index 00000000..8491839f --- /dev/null +++ b/docs/re/data/focus-does-not-survive-a-reboot.txt @@ -0,0 +1,52 @@ +# Does the main menu's cursor survive a REBOOT? ✅ NO -- MEASURED 2026-08-31. +# +# The main menu PERSISTS its cursor across menu -> title -> menu within one boot +# (focus-persists-across-title.txt). Whether it survives a reboot has been listed +# as untested since, and it decides whether "initial focus = NEW GAME" is a fresh +# -start value or merely what the last session happened to leave. +# +# NO NEW BOOT WAS SPENT. Six runs already captured the FIRST menu entry of a fresh +# boot (each `reach/1-F1.png`), read here with the calibrated ring reader: +# +# run ring y first menu entry +# focuspersist 225.5 NEW GAME +# extrasfocus 225.5 NEW GAME +# submenusweep 225.5 NEW GAME +# submenu3 227.0 NEW GAME +# submenu4 225.5 NEW GAME +# difficulty 225.5 NEW GAME +# +# ✅ SIX INDEPENDENT FRESH BOOTS, ALL NEW GAME. +# +# 📌 AND THREE OF THEM FOLLOW A SESSION THAT ENDED ELSEWHERE, which is what makes +# this a test of persistence rather than a repeated observation: +# 22:06 extrasfocus ended INSIDE EXTRAS -> 22:17 submenusweep opened NEW GAME +# 22:17 submenusweep ended on OPTIONS -> 00:42 submenu3 opened NEW GAME +# 01:21 submenu4 ended on OPTIONS -> 01:46 difficulty opened NEW GAME +# +# => Menu focus does NOT carry across a reboot. The port's authored NEW GAME is +# correct for a fresh start, and is not an artefact of session history. +# +# ⚠️ REACH, and it is the important line: EVERY ONE of these sessions ends with the +# emulator being KILLED (ensure_single_emulator terminates the process). A game +# that writes menu state on a CLEAN shutdown would never get the chance, so this +# measures "does not survive a killed session", not "the game never saves focus". +# A clean-exit path is untested and this harness has no way to exercise one. +# +################################################################################ +# INCIDENTAL, and it corrects a number of mine. +# +# The disc says the main menu's five buttons sit at design y 162 / 242 / 322 / +# 401 / 482 -- spacing 80 (examples/extras_button_order.rs). +# menu_focus.py's row centres are [166, 241, 315, 390, 465], spacing 75, drifting +# +4, -1, -7, -11, -17 against the real rows: over a QUARTER of a row by the +# bottom item. That drift is why the old reader was fragile. +# +# 🔴 So ring_row.py's stated calibration was wrong. It said +# capture_y = 49.5 + 1.060 * design_y +# fitted against those approximate rows. Re-fitted against the DISC rows: +# capture_y = 64.82 + 0.9919 * design_y residuals all < 0.7 px +# The surface is offset ~65 px in the capture and essentially NOT scaled; the +# 1.060 was an artefact of the wrong reference. +# ⚠️ No item assignment changes -- ROW0 and SPACING are measured off captures +# directly and never used the bad fit. diff --git a/tools/re-capture/ring_row.py b/tools/re-capture/ring_row.py index d30733a1..defe7b80 100755 --- a/tools/re-capture/ring_row.py +++ b/tools/re-capture/ring_row.py @@ -13,9 +13,22 @@ passed on a reader that was two items wrong. So this returns the ring's measured ROW, and callers compare rows; naming an item needs a calibration, below. Measured on the x11grab frames of 2026-08-30: - spacing 79.25 px per item (design spacing 74.75 -> surface scaled 1.060) - capture_y = 49.5 + 1.060 * design_y -Checks: design 241 -> 305 predicted vs 304.75 measured; 315 -> 383.4 vs 384.0. + spacing 79.25 px per item, ROW0 225.5 (both read off captures directly) + +🔴 CALIBRATION CORRECTED 2026-08-31. This said "design spacing 74.75 -> surface +scaled 1.060, capture_y = 49.5 + 1.060 * design_y". That was fitted against +menu_focus.py's row centres [166,241,315,390,465], which are NOT the disc's button +rows. The disc says the main menu's five buttons sit at y 162/242/322/401/482 -- +spacing 80, not 75 -- and menu_focus.py's values drift from +4 to -17 px against +them across the five rows (examples/extras_button_order.rs). + +Re-fitting against the DISC rows: + capture_y = 64.82 + 0.9919 * design_y residuals all < 0.7 px +i.e. the surface is offset ~65 px in the capture and essentially NOT scaled. The +old 1.060 was an artefact of the wrong reference rows. + +⚠️ No item assignment changes: ROW0 and SPACING below are measured from captures +directly and never used the bad fit. ring_row.py FRAME.png [FRAME.png ...] """