tools: focus_persistence.py used the reader that was two items out

Now uses the shared measured reader, which refuses to name a row outside the
calibration rather than guessing. Replaying this run's stored frames through it
gives NEW GAME / TUTORIAL / TUTORIAL, which is what the corrected record says.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
This commit is contained in:
sylph-decoder
2026-08-30 22:08:10 +00:00
parent 4ed75e6c59
commit 1fa3ffd08b

View File

@@ -39,16 +39,23 @@ NEED, CEIL, HOLD = 500, 2500, 12 # title plate pulse band
MENU_LO, MENU_HI, MENU_HOLD = 250, 420, 6 # glyph-327 menu detector
PAD = os.path.join(os.path.dirname(os.path.abspath(__file__)), "pad.py")
# menu_focus.py's geometry, byte for byte: the focus RING sits in the gutter
# left of the label and nothing else is bright there.
NAMES = ["NEW GAME", "LOAD GAME", "TUTORIAL", "OPTIONS", "EXTRAS"]
YS = [166, 241, 315, 390, 465]
# 🔴 This used menu_focus.py's DESIGN-SPACE rows [166,241,315,390,465] against
# x11grab frames, which carry Xenia's window chrome and a surface scaled 1.060 --
# and reported item names TWO POSITIONS OUT for a whole session. The control
# ("2 DOWNs move 2 items") could not catch it, because a constant offset
# preserves relative motion exactly. See data/menu-focus-reader-offset.txt.
# Now measured, via the shared reader, which REFUSES to name an out-of-range row.
import os as _os
sys.path.insert(0, _os.path.dirname(_os.path.abspath(__file__)))
from ring_row import ring_row as _ring_row, main_menu_item as _mmi, NAMES
def focus(a):
g = np.asarray(Image.fromarray(a.astype(np.uint8)).convert("L"), dtype=float)
v = [g[y - 20:y + 20, 500:542].max() for y in YS]
return int(np.argmax(v)), v
y = _ring_row(Image.fromarray(a.astype(np.uint8)))
i = _mmi(y)
if i is None:
return None, [y]
return i, [y]
def deliveries(vk):
@@ -139,6 +146,8 @@ while True:
p, a = fresh(p)
Image.fromarray(a.astype(np.uint8)).save(f"{OUT}/1-F1.png")
F1, v = focus(a)
if F1 is None:
print(f"🔴 no main-menu ring row in the F1 frame (y={v[0]}) — stopping", flush=True); break
print(f"[{el:7.1f}s] MENU (glyph {c}) F1 = {NAMES[F1]} ring "
+ " ".join(f"{x:5.0f}" for x in v), flush=True)
# 🔴 Run 1 pressed DOWN twice through pad.py with NO delivery
@@ -153,6 +162,8 @@ while True:
p, a = fresh(p)
Image.fromarray(a.astype(np.uint8)).save(f"{OUT}/2-F2.png")
F2, v = focus(a)
if F2 is None:
print(f"🔴 no main-menu ring row in the F2 frame (y={v[0]}) — stopping", flush=True); break
print(f"[{el:7.1f}s] after 2x DOWN F2 = {NAMES[F2]} ring "
+ " ".join(f"{x:5.0f}" for x in v), flush=True)
want = (F1 + 2) % len(NAMES)
@@ -181,6 +192,8 @@ while True:
p, a = fresh(p)
Image.fromarray(a.astype(np.uint8)).save(f"{OUT}/4-F3.png")
F3, v = focus(a)
if F3 is None:
print(f"🔴 no main-menu ring row in the F3 frame (y={v[0]}) — stopping", flush=True); break
print(f"[{el:7.1f}s] MENU AGAIN F3 = {NAMES[F3]} ring "
+ " ".join(f"{x:5.0f}" for x in v), flush=True)
print(f"\nF1={NAMES[F1]} F2={NAMES[F2]} F3={NAMES[F3]}")