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

@@ -646,6 +646,27 @@ func _menu_enter(name: String, fresh: bool) -> void:
return
if fresh:
_menu.enter(name, view.screen.get("buttons", []))
# `--focus=` wins over the authored initial focus, and it did NOT before.
#
# 🔴 The flag parsed, was stored, and was applied to `view.focused_id` at
# startup -- and then this line overwrote it on every `_menu_enter`. So on
# the `--menu` path `--focus=` did nothing at all, silently: the run logged
# `focus ptbtn01` whatever was asked for.
#
# That mattered because it made an oracle capture untestable.
# `live-main-menu-options-focused.png` is the menu with OPTIONS focused --
# the only capture in the corpus of a MEASURED focus state, where the
# harness's own `main_menu` row uses an AUTHORED initial focus standing in
# for a measurement that says initial focus is unstable (HANDOFF Q5). There
# was no way to ask the port for the state the capture shows.
#
# It is pushed into the MENU MODEL, not just the view, so that navigation
# continues from where it was forced rather than jumping back on the first
# press.
if _force_focus != "" and not _menu.stack.is_empty():
var buttons: Array = view.screen.get("buttons", [])
if buttons.has(_force_focus):
_menu.stack[_menu.stack.size() - 1]["focus"] = _force_focus
view.focused_id = _menu.focus()
view.queue_redraw()
# AUTHORED, and the weakest thing in P6: HANDOFF Q10 says nothing on the disc