port: --focus was ignored on the menu path; focus rendering now verified against the oracle

live-main-menu-options-focused.png -- the only capture of a known focus state --
was untestable because --focus= parsed, was stored, and was overwritten by the
authored initial focus on every _menu_enter. Every run logged focus ptbtn01
whatever was asked for. Now pushed into the menu model so navigation continues
from where it was forced.

With it working, each capture picks out exactly one button: ptbtn04 at 0.1355%
against 0.70-0.82% for the others on the OPTIONS capture, and ptbtn01 at 0.0705%
against 0.72-0.84% on the plain one. 5x and 10x discrimination. First time the
port's focus rendering has been checked against the game at all -- the existing
main_menu row uses an authored focus and could never have caught a focus error.

Records in flow.json that live-main-menu.png shows NEW GAME focused, so the
authored initial_focus matches the one frame it can be checked against -- and
that this does NOT overturn Q5's measured instability. It stays authored.

Adds main_menu_options to verify-capture at 0.13%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
Sylpheed port agent
2026-08-30 01:45:47 +00:00
parent a170e1fbc6
commit 2fe1f06599
4 changed files with 100 additions and 3 deletions

View File

@@ -6054,3 +6054,53 @@ row, which makes it the most sensitive regression detector in the harness.
places it, found by sweeping. Choosing which frame to compare against is what
every row here does, but the 0.00093 % is a floor for *that pose*, not a general
statement of accuracy.
## `--focus=` did nothing on the menu path, and the corpus had an untested focus capture
Two unused live captures were sitting in `docs/re/captures/title-builds/`.
`live-main-menu-options-focused.png` is the menu with **OPTIONS** focused — the
only capture of a *known* focus state — and it was untestable, because
`--focus=` **silently did nothing on the `--menu` path**.
The flag parsed, was stored in `_force_focus`, and was applied to
`view.focused_id` at startup — and then `_menu_enter` overwrote it with the
authored initial focus on every entry. Every run logged `focus ptbtn01` whatever
was asked for, and all five buttons produced the same frame. It is now pushed
into the **menu model**, not just the view, so navigation continues from where it
was forced rather than jumping back on the first press.
### The port's focus rendering is right, measured against the oracle
Rendering each of the five buttons focused, against each capture:
| focused | vs `live-main-menu-options-focused` | vs `live-main-menu` |
|---|---|---|
| `ptbtn01` NEW GAME | 0.7352 % | **0.0705 %** |
| `ptbtn02` LOAD GAME | 0.8204 % | 0.8378 % |
| `ptbtn03` TUTORIAL | 0.7220 % | 0.7365 % |
| **`ptbtn04` OPTIONS** | **0.1355 %** | 0.7449 % |
| `ptbtn05` EXTRAS | 0.7029 % | 0.7236 % |
Each capture picks out exactly one button, by **5×** and **10×**. This is the
first time the port's focus rendering has been checked against the game at all —
the harness's own `main_menu` row uses an *authored* focus, so it could never
have caught a focus error.
### What that settles, and what it does not
✅ The port draws focus on the right button, distinguishably.
`live-main-menu.png` shows **NEW GAME** focused, so the authored
`initial_focus: ptbtn01` matches the one frame it can be checked against.
⚠️ **It does not overturn HANDOFF Q5**, which measured initial focus as *unstable
boot to boot* across four runs. One capture showing `ptbtn01` is consistent with
instability, not evidence against it. The value stays **authored**, with the
agreement recorded beside it. Reading this as "initial focus is settled" would be
exactly the over-generalisation from a single observation that this corpus keeps
having to withdraw.
`main_menu_options` joins `verify-capture` at 0.13 %.
⚠️ Still unused: `live-attract-title-press-a-band.png`, a 1279×**120** strip
rather than a full frame. It needs a banded comparison the harness does not do,
so it is named here rather than quietly left out.