From 5a16ce5aba309b8fea260bb500d7e22e8361141f Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Mon, 31 Aug 2026 06:08:41 +0000 Subject: [PATCH] method: a refusing instrument, and a boot that outlasts its capture script Two traps this run paid for. ring_row.py's ROW0/SPACING are x11grab constants. On a /sylph-home/re/shots/shot-0001.png grab of the same live main menu the rows read 180.5/419.5/502.0 -- ROW0 is 45 px out, 0.57 of a step. The module refused rather than naming the wrong item, which is the good failure, and is_main_menu() therefore returned False ON A REAL MAIN MENU. A run gated on it would conclude 'not the menu' while sitting on the menu. Not recalibrated: three rows from one session are not a calibration and other tools share the constants; the module now says so where the numbers are. menu_draw_capture.sh's 420 s title deadline fired, and the emulator left running was at the settled title minutes later, took one A, and reached the menu first try. A timeout is a measurement of the timeout. Leaving the emulator up after a failed script rescued this run for one minute against a twenty-minute reboot. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- docs/re/METHOD.md | 42 ++++++++++++++++++++++++++++++++++++ tools/re-capture/ring_row.py | 17 +++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/docs/re/METHOD.md b/docs/re/METHOD.md index d1698637..35b5101c 100644 --- a/docs/re/METHOD.md +++ b/docs/re/METHOD.md @@ -3296,3 +3296,45 @@ description of the evidence standing in for the evidence. one `Read` away the whole time, and the wrong diagnosis would have gone into a data file as "the detector is locale-specific" — a plausible, tidy, false instrument finding that nothing downstream would have questioned. + +## An instrument that refuses is safe and can still cost you the run + +`ring_row.py` carries `ROW0 = 225.5`, `SPACING = 79.25`, measured off **x11grab** +frames. On 2026-08-31 the same live main menu, grabbed with the `screenshot` +wrapper (1279×675), reads its rows at **180.5 / 419.5 / 502.0** — `ROW0` is +**45 px out, 0.57 of a step**. + +The module behaved *correctly*: `main_menu_item()` refuses anything further than +half a step from a predicted row, so it declined rather than naming the wrong +item, and `is_main_menu()` returned **`False` on a real main menu**. That is the +good failure — the earlier version of this bug returned an item **two out** and +was only caught by ground truth ("the probe said EXTRAS and OPTIONS opened"). + +But a refusal is not free. A run gated on `is_main_menu()` concludes *"not the +menu"* while sitting on the menu, and there is nothing in its output to +distinguish that from the game genuinely not being there. **The lesson is not +"add a tolerance"** — widening it re-opens the wrong-item failure. It is that a +calibration belongs to a *capture path*, and a module that serves two paths needs +two calibrations selected by frame size, not one set of numbers that is right for +one caller and blind for the other. + +Recorded rather than fixed: three rows from one session are not a calibration, +and other tools share these constants. + +## The boot can take three times the budget a capture script allows + +`menu_draw_capture.sh` and its relatives wait **420 s** for the title and then +report `NEVER REACHED THE TITLE`. On 2026-08-31 that fired at 424 s — and the +emulator, left running, was **at the settled title minutes later**, took a single +Ⓐ, and went to the main menu on the first try. + +So the script's negative was about its own deadline, not about the game. Worse, +its classifier had reported `menu` at t=241/252 s and `flight` at t=331 s, all of +them attract-movie frames, so the log *looks* like a run that saw things. + +Two things follow. **A timeout is a measurement of the timeout**, and a run that +ends on one has produced no evidence about the game — this corpus already has +three withdrawn *"the title never appears"* claims for the same reason. And +**leaving the emulator up after a failed script is worth doing**: the run above +was rescued by attaching to it, gating on the plate pulse and tapping Ⓐ by hand, +which cost one minute against a twenty-minute reboot. diff --git a/tools/re-capture/ring_row.py b/tools/re-capture/ring_row.py index 5536f4a1..6750c978 100755 --- a/tools/re-capture/ring_row.py +++ b/tools/re-capture/ring_row.py @@ -41,6 +41,23 @@ DECOR_ROWS = 50 # window title bar + menu bar live above this FOOTER_Y = 620 # the button-legend strip is bright in the gutter too NAMES = ["NEW GAME", "LOAD GAME", "TUTORIAL", "OPTIONS", "EXTRAS"] ROW0, SPACING = 225.5, 79.25 # measured, main menu, x11grab +# 🔴 THESE ARE x11grab CONSTANTS AND THEY DO NOT FIT A `screenshot` GRAB +# (2026-08-31). Three rows read off `screenshot` frames of a live main menu, +# ground-truthed by eye against the rendered PNG: +# +# NEW GAME 180.5 OPTIONS 419.5 EXTRAS 502.0 (1279x675) +# -> ROW0 ~180.5, SPACING ~80.4, i.e. ROW0 is 45 px = 0.57 of a step out +# +# `main_menu_item()` therefore REFUSES on such a frame rather than returning a +# wrong item, and `is_main_menu()` returns False ON A REAL MAIN MENU. That is the +# safe failure and it is still a failure: a script that gates on +# `is_main_menu()` will conclude "not the menu" while sitting on the menu. +# +# Not recalibrated here on purpose: three rows from one session are not a +# calibration, other tools share these constants, and the x11grab numbers are +# correct for x11grab. Whoever needs the `screenshot` path should measure it +# properly and give the module TWO calibrations selected by frame size, rather +# than moving one set of numbers and silently breaking the other. MENU_GLYPH_LO, MENU_GLYPH_HI = 250, 420 # the glyph-327 menu detector