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