port: correct a check that asserted an absence of measurement as a finding

The pair I shipped this iteration -- focus_persists on for main_menu, off
everywhere else -- reported both halves as agreement with the contract. Nothing
measured that extras does not persist. The corpus has EXTRAS' opening item from
one entry and (B) restoring the PARENT's focus 4/4; neither says what a submenu's
own cursor does on re-entry. Caught by the Decoder.

It is the mirror of the trap it was written to avoid. I refused to let a derived
menu-wide rule overwrite a measured value, then let 'not measured here' become a
positive assertion of the negative. Both treat a gap in the corpus as if it
carried information and differ only in which direction they fill it. And the
failure mode was the bad one: if the game does persist EXTRAS, the check holds
the port to the wrong behaviour and passes while doing it.

check_focus_persists now asserts only the measured half. The scope became a
separate guard with its own outcome word -- 'only main_menu, AUTHORED DEFAULT,
unmeasured elsewhere' -- which still fails if widened, since that should be a
deliberate edit, but can no longer be read as the game being known to reset.
focus_persists_why records the correction rather than being rewritten.

It also weakens a label. EXTRAS' initial_focus is marked measured and was taken
on a single entry; now that the main menu is known to remember its cursor, a
one-entry reading of any screen may be measuring history rather than what the
screen opens on -- the same objection that reframed the TUTORIAL/NEW GAME
disagreement. The observation stands, its reading as an initial focus does not.
Caveat attached, kind left as measured with a note that it changes if EXTRAS
turns out to persist.

Not building on the non-persistence half until their EXTRAS re-entry run returns.

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 21:39:08 +00:00
parent 6e3347a338
commit b3da5c1d48
3 changed files with 127 additions and 12 deletions

View File

@@ -219,17 +219,46 @@ def flow_buttons(screen):
def check_focus_persists(h):
"""The menu remembers its cursor -- measured on the MAIN MENU, one screen.
"""The menu remembers its cursor -- MEASURED, on the main menu, one screen.
Checked as a pair: the behaviour must be on where it was measured and off
everywhere else. A one-sided check would pass a port that had quietly made it
a menu-wide rule, which would override `extras`' measured initial focus.
🔴 This checked a PAIR until 2026-08-30: on for `main_menu`, off everywhere
else. The second half asserted that `extras` does NOT persist, and **nothing
measured that**. What the corpus has is EXTRAS' initial focus from a single
entry and Ⓑ restoring the PARENT's focus 4/4 — neither says what a submenu's
own cursor does on re-entry. So one measured behaviour and one absence of a
measurement were being reported identically, and if the game does persist
EXTRAS the check would have held the port to the wrong behaviour AND PASSED.
The mirror of the trap it was written to avoid: refusing to let a derived
rule overwrite a measured value, then letting "not measured here" become a
positive assertion of the negative. Now only the measured half is asserted
against the contract; the scope is a guard, below.
"""
want = bool(re.search(r"the main menu remembers its cursor; re-entry is not a reset", h))
scr = (jload("authored/flow.json") or {}).get("screens") or {}
on = [n for n, v in scr.items() if isinstance(v, dict) and v.get("focus_persists")]
report("menu remembers its cursor", want or None, on == ["main_menu"] and on,
want and on == ["main_menu"])
got = (((jload("authored/flow.json") or {}).get("screens") or {})
.get("main_menu", {}).get("focus_persists"))
report("menu remembers its cursor", want or None, got, want and got is True)
def guard_focus_scope(_h):
"""NOT a contract check. A regression guard on an AUTHORED DEFAULT.
No screen but `main_menu` persists its cursor in this port, and that is the
port's choice, not a finding: it preserves EXTRAS' measured opening item and
invents the least. Guarded so that widening it is a deliberate edit with a
`why`, and labelled so a passing run cannot be read as the game being known
to reset.
"""
global FAIL
on = sorted(n for n, v in ((jload("authored/flow.json") or {}).get("screens") or {}).items()
if isinstance(v, dict) and v.get("focus_persists"))
if on == ["main_menu"]:
print(f" {'focus_persists scope':<30} guard only main_menu"
f" -- AUTHORED DEFAULT, unmeasured elsewhere")
else:
FAIL += 1
print(f" {'focus_persists scope':<30} 🔴 GUARD {on} -- widened past the"
f" one screen measured; needs a why and a measurement")
def check_menu_labels(_h):
@@ -295,7 +324,7 @@ def main():
for fn in (check_fade_quads, check_fade_out, check_plate_period,
check_bgm_window, check_black_hold, check_menu_bank,
check_splash_dwell, check_menu_labels, check_extras_labels,
check_wrap, check_focus_persists):
check_wrap, check_focus_persists, guard_focus_scope):
fn(h)
print()
print(" A passing run means the port agrees with the contract ON THESE VALUES.")