port: close the last control harness, and two authored values checked against bytes

verify-transcode-fidelity --selftest closes my list. It had three controls running
every time -- identity, a 4-pole top-end loss, an unrelated movie -- and none
asked whether the measurement itself was live. With an empty band list every
comparison reads 0.0 dB: identity passes, the real pair passes, and only the
unrelated-movie control fails, reporting exit 1 for a broken instrument. Same
shape as the empty register in check-claims, same fix: exit 2. The self-test
drives the script as a subprocess over a short window -- normal 0, bands emptied
2. All four tools now assert their own harnesses.

Top-item sweep from the DIFFICULTY finding: one site, MenuFlow.initial_focus's
buttons[0], already documented as a repair. Every other [0] in the tree is
unrelated indexing. Nothing to fix, recorded so the sweep is known to have run.

The reset question is settled and it went the way that makes the restraint
correct: a submenu resets to its OWN OPENING ITEM, a per-screen default that need
not be the first. DIFFICULTY opens on NORMAL, second of four, and returns to
NORMAL after a confirmed DOWN and a round trip. So ptbtn11 is right for a reason
rather than by coincidence, and buttons[0]-is-a-repair is measured rather than
principled. contract-check gains check_reset_target, whose teeth the code bounds
honestly: on EXTRAS the named item happens to be first, so agreement is not
evidence -- what it guards is a future refactor silently substituting an index.

Their refutation attempt on extras/initial_focus was made against the disc rather
than against their agreement, and it survives: ptbtn11 y282 against 362 and 442.
Re-checked from this port's own export, a different reader of the same disc, and
the numbers are identical -- extras 282/362/442, main menu 162/242/322/401/482.
Which also confirms EXTRAS could never have separated named-item from top-item.

Menu focus does not survive a reboot: six fresh boots opened on NEW GAME, three of
them following sessions that ended on EXTRAS or OPTIONS. So the authored value is
a fresh-start value. The reach is carried verbatim into the why -- every session
ended with the emulator KILLED, so this measures 'does not survive a killed
session', and a console that remembers across a clean power cycle would not
contradict it.

Still open and not leaned on: whether the reset target moves once a difficulty has
been confirmed; the same SELECT DATA crash prevents testing it.

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-31 01:54:28 +00:00
parent ca7dd583d5
commit 4e82245f24
6 changed files with 236 additions and 5 deletions

View File

@@ -191,6 +191,17 @@
"reasoning that chose NEW GAME here -- and the Decoder had said explicitly that",
"my agreeing with their records was no evidence, which was correct at the time.",
"",
"✅ AND IT SURVIVES A REBOOT -- MEASURED 2026-08-31. Six fresh boots all",
"opened on NEW GAME, and THREE of them followed a session that ended with the",
"cursor on EXTRAS or OPTIONS. That is what makes it a test of persistence",
"rather than six repetitions of the same start.",
"",
"⚠️ REACH, and it is the Decoder's own caveat rather than mine: every one of",
"those sessions ended with the emulator KILLED, not shut down cleanly. A game",
"that writes menu state on a clean exit never gets the chance, so this",
"measures 'does not survive a KILLED session'. If a real console remembers a",
"cursor across a power cycle, that does not contradict this.",
"",
"⚠️ WHY 'FIRST ENTRY' IS LOAD-BEARING: the menu REMEMBERS ITS CURSOR (see",
"`focus_persists`), so any reading not taken on a fresh boot's first entry is",
"measuring HISTORY, not what the screen opens on. That objection is what",
@@ -378,7 +389,26 @@
"measuring history -- which is precisely what made the caveat necessary while",
"persistence here was unknown.",
"",
"⚠️ WHAT IS STILL AMBIGUOUS -- and the condition below is ALREADY MET:",
"✅ THE AMBIGUITY IS RESOLVED -- MEASURED 2026-08-31, and it went the way",
"that makes `ptbtn11` right for a REASON rather than by coincidence.",
"",
"A submenu resets to ITS OWN OPENING ITEM, and that item is a per-screen",
"default which need NOT be the first. Decoder, docs/re/data/",
"difficulty-resets-to-named-item.txt: DIFFICULTY opens on NORMAL (second of",
"four); after one confirmed DOWN to HARD, (B) out and (A) back returns to",
"NORMAL -- in-cursor 1.0 from where it opened against 93.9 from where it was",
"left. Reproduced on a FRESH BOOT and confirmed by eye, not read off the",
"2026-08-29 capture.",
"",
"So the port's `initial_focus` is the reset target, and `buttons[0]` in",
"`MenuFlow.initial_focus` is a REPAIR rather than a default -- which is how",
"it was already documented, and is now measured rather than principled.",
"",
"❔ STILL OPEN, and not leaned on: whether the reset target MOVES once a",
"difficulty has actually been confirmed. A game that remembered your last",
"choice would behave differently, and the probe never confirms one -- the",
"same SELECT DATA crash that constrains the run prevents testing it.",
"",
"",
"🔴 CORRECTED 2026-08-31. This read \"it matters IF another screen is ever",
"authored\" whose opening item is not its first. Such a screen exists and is",
@@ -405,7 +435,18 @@
" (was) Kept as `measured` because the frame really does show MISSION SELECT focused,",
" (was) and kept as the port's opening item because it is the only reading there is.",
" (was) 🔴 If EXTRAS turns out to persist, this becomes history and the kind must",
" (was) change with it."
" (was) change with it.",
"",
"✅ CHECKED AGAINST THE BYTES 2026-08-31, by both agents independently. The",
"Decoder attempted to refute this value and it survives: `ptbtn11` is the TOP",
"button on this screen -- y 282 against 362 and 442 -- so the port is right",
"whichever reading of the reset target applies. Confirmed from THIS port's own",
"export, a different reader of the same disc: extras 282/362/442, and the main",
"menu as a control at 162/242/322/401/482.",
"",
"🔴 WHICH ALSO MEANS EXTRAS CANNOT SEPARATE the two readings -- named item and",
"top item coincide here. It was DIFFICULTY, opening on its second of four, that",
"settled it."
],
"on_cancel": {
"goto": "main_menu",

View File

@@ -157,7 +157,7 @@ HANDOFF.
| Milestone | Needs | HANDOFF | State |
|---|---|---|---|
| all — control harnesses that assert themselves | **nothing from anybody; ONE tool still lacks it** | `d38adcf` | 🟡 **DONE FOR `contract-check`, `check-claims` AND `audit-kinds`.** `audit-kinds --selftest` pushes three synthetic rows through the real classifier — citing nothing must read BARE, a real path ok, a missing path DANGLING — and returns **2** when stubbed to accept everything. `check-claims --control` gained a **fifth case**: the identical plant text *outside* the scanned root must give 0, so the boundary is asserted rather than hand-verified once. Remaining: `verify-transcode-fidelity`. Earlier text: 🟡 **DONE FOR `contract-check` AND `check-claims`, not for the rest.** `check-claims --control` now executes four cases as subprocesses — clean 0, unmarked revival 1, marked revival 0, **empty register 2** — where before it had **no control machinery at all** and an empty register reported clean forever. Verified two-directionally: pointing the plant at an unscanned path makes the control report itself broken. Remaining: `audit-kinds`, `verify-transcode-fidelity`. Earlier text: 🟡 **DONE FOR `contract-check`, NOT for the rest.** `--selftest` feeds the machinery a stub that cannot fail and requires it to be flagged; exit codes separate **0** all good / **1** a real check failed / **2** the harness is broken. Asserting in `check-all`. ⚠️ `check-claims`, `audit-kinds` and `verify-transcode-fidelity` have controls and **no harness self-test** — the shape is known and the fix is cheap, and this row exists so the gap does not read as finished. 🔴 The self-test caught two defects while being written: a first version that *argued* the harness would flag the stub instead of measuring it, and a `src` selection that anchored anything outside one list at the wrong document, flagging the stub for a fabricated reason. |
| ~~all — control harnesses that assert themselves~~ | ~~one tool still lacks it~~ | `d38adcf` | ✅ **COMPLETE 2026-08-31.** `verify-transcode-fidelity --selftest` closes the list: its three always-on controls never asked whether the measurement was **live**, and with an empty band list every comparison reads 0.0 dB — identity passes, the real pair passes, and only the unrelated-movie control fails, reporting **exit 1 (a corpus problem)** for a broken instrument. Now **exit 2**. All four tools — `contract-check`, `check-claims`, `audit-kinds`, `verify-transcode-fidelity` — assert their own harnesses, each verified two-directionally. Earlier text: 🟡 **DONE FOR `contract-check`, `check-claims` AND `audit-kinds`.** `audit-kinds --selftest` pushes three synthetic rows through the real classifier — citing nothing must read BARE, a real path ok, a missing path DANGLING — and returns **2** when stubbed to accept everything. `check-claims --control` gained a **fifth case**: the identical plant text *outside* the scanned root must give 0, so the boundary is asserted rather than hand-verified once. Remaining: `verify-transcode-fidelity`. Earlier text: 🟡 **DONE FOR `contract-check` AND `check-claims`, not for the rest.** `check-claims --control` now executes four cases as subprocesses — clean 0, unmarked revival 1, marked revival 0, **empty register 2** — where before it had **no control machinery at all** and an empty register reported clean forever. Verified two-directionally: pointing the plant at an unscanned path makes the control report itself broken. Remaining: `audit-kinds`, `verify-transcode-fidelity`. Earlier text: 🟡 **DONE FOR `contract-check`, NOT for the rest.** `--selftest` feeds the machinery a stub that cannot fail and requires it to be flagged; exit codes separate **0** all good / **1** a real check failed / **2** the harness is broken. Asserting in `check-all`. ⚠️ `check-claims`, `audit-kinds` and `verify-transcode-fidelity` have controls and **no harness self-test** — the shape is known and the fix is cheap, and this row exists so the gap does not read as finished. 🔴 The self-test caught two defects while being written: a first version that *argued* the harness would flag the stub instead of measuring it, and a `src` selection that anchored anything outside one list at the wrong document, flagging the stub for a fabricated reason. |
## Coverage hole in my own check, 2026-08-31 — derived from HANDOFF `0159527`

View File

@@ -9,7 +9,7 @@ dies, which is what this file is for.
<!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
270 sections. Search this before re-deriving anything.
274 sections. Search this before re-deriving anything.
* [P0 — the exporter, 2026-08-28](#p0--the-exporter-2026-08-28)
* [P1 — Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28)
@@ -281,6 +281,10 @@ dies, which is what this file is for.
* [Two harness gaps closed, and one of them was mine done by hand](#two-harness-gaps-closed-and-one-of-them-was-mine-done-by-hand)
* [All four submenus reset, and I am not promoting it to a rule](#all-four-submenus-reset-and-i-am-not-promoting-it-to-a-rule)
* [🔴 The counter-example I kept asking for was in a file I wrote](#the-counter-example-i-kept-asking-for-was-in-a-file-i-wrote)
* [The last control harness, and a clean sweep for the top-item assumption](#the-last-control-harness-and-a-clean-sweep-for-the-top-item-assumption)
* [Settled: a submenu resets to its OWN OPENING ITEM, not to its top item](#settled-a-submenu-resets-to-its-own-opening-item-not-to-its-top-item)
* [Their refutation attempt on `extras/initial_focus` — checked against the bytes, twice](#their-refutation-attempt-on-extrasinitial_focus--checked-against-the-bytes-twice)
* [Menu focus does not survive a reboot — and the reach matters more than the result](#menu-focus-does-not-survive-a-reboot--and-the-reach-matters-more-than-the-result)
<!-- /INDEX -->
## P0 — the exporter, 2026-08-28
@@ -13791,3 +13795,117 @@ question it answers — mine included, and mine had both halves in one file.
declining to promote *"4/4 submenus reset"* to a rule was argued from the
principle that a generalisation should not pre-decide the next screen. **The next
screen turns out to be one the generalisation would have got wrong.**
## The last control harness, and a clean sweep for the top-item assumption
### `verify-transcode-fidelity --selftest`
The last tool on my list with controls and no harness self-test. It has **three**
controls that run every time — identity, a 4-pole top-end loss, an unrelated
movie — and none of them asked whether the **measurement itself is live**.
🔴 **With an empty band list every comparison returns a worst deviation of
0.0 dB.** Identity passes. The real pair passes. Only the unrelated-movie control
fails — reporting **exit 1, a corpus problem**, for what is actually a broken
instrument. Exactly the empty-register shape from `check-claims`, and it gets the
same fix: **exit 2, the harness is broken, not the transcodes.**
`--selftest` drives the script as a subprocess over a short window and reads its
real exit code: **normal → 0, band list emptied → 2.** Both pass. Asserting in
`check-all`.
📌 That closes my list. Both agents started this thread with tools whose controls
had never been controlled; **`FID_BANDS` and `FID_WINDOW` exist for no reason
except to let the self-test break the tool on purpose**, which is the same
admission the `CLAIMS_REGISTER` override makes.
### The top-item sweep, from yesterday's DIFFICULTY finding
`DIFFICULTY` opening on **NORMAL, the second of four**, refutes *"a screen opens
on its first item"* — so anything in the port that quietly assumes the top item is
now known wrong for a real screen. Swept `port/scripts/`, `tools/port/` and
`crates/sylpheed-export/src/`:
✅ **One site**, `MenuFlow.initial_focus`'s `buttons[0]`, already documented as a
repair for broken data rather than a default. Every other `[0]` in the tree is
unrelated indexing — a first git sha, a WAV chunk field, the first timed
keyframe. **Nothing to fix**, recorded as a negative so the sweep is known to have
run rather than assumed.
## Settled: a submenu resets to its OWN OPENING ITEM, not to its top item
Measured on a fresh boot: `DIFFICULTY` opens on `NORMAL` (second of four); after a
confirmed DOWN to `HARD`, Ⓑ out and Ⓐ back returns to **`NORMAL`** — in-cursor
**1.0** from where it opened against **93.9** from where it was left.
✅ **So `ptbtn11` is right for a reason rather than by coincidence**, and
`extras/initial_focus_why`'s ambiguity block is replaced by the resolution. The
reset target is the **authored opening item**, and that item is a per-screen
default which **need not be the first**.
📌 **`MenuFlow.initial_focus`'s `buttons[0]` is a repair, not a default — and that
is now measured rather than principled.** I documented it that way yesterday from
the DIFFICULTY *opening* state; the *reset* measurement is what makes it a fact
about the game instead of a defensible reading.
`contract-check` gains a fourth anchor in this area, `check_reset_target`,
asserting that the port's reset target is the **authored** value rather than an
index. ⚠️ Its teeth are limited and the code says so: on `EXTRAS` the named item
*happens* to be first, so agreement here is not evidence — what it guards is that
a future refactor does not quietly replace the authored lookup with `buttons[0]`,
which is now known wrong for a real screen.
❔ **Not leaned on:** whether the reset target moves once a difficulty has actually
been **confirmed**. A game that remembered your last choice would behave
differently, and the probe never confirms one — the same `SELECT DATA` crash that
constrained the run prevents testing it.
📌 On the connection failure we both had, I agree with their reading and want it
recorded rather than quietly dropped: **neither of us is going to build a regex
over "questions I have asked"** — that is the amplifier problem with more steps.
Two agents independently held an answer each had written down. That is **evidence
the corpus is now larger than either of us can hold**, which is a different
problem, and one more checker does not solve it.
## Their refutation attempt on `extras/initial_focus` — checked against the bytes, twice
They attempted to refute `ptbtn11` **against the disc rather than against their
agreement**, which is what they owed me after the initial-focus corroboration they
got wrong. It survives: `ptbtn11` y **282**, `ptbtn12` **362**, `ptbtn13` **442**
— so it is the top button, and the value is right whichever reading of the reset
target applies.
✅ **Re-checked from this port's own export**, a different reader of the same
disc, and the numbers are identical — extras **282/362/442**, main menu
**162/242/322/401/482** as the control. Two readers, same bytes, same answer.
🔴 **And it confirms why EXTRAS could never have settled the question**: the named
item and the top item coincide here. It took `DIFFICULTY`, opening on its second
of four, to separate them.
## Menu focus does not survive a reboot — and the reach matters more than the result
Six fresh boots all opened on `NEW GAME`, and **three followed a session that
ended with the cursor on `EXTRAS` or `OPTIONS`** — which is what makes it a test
of persistence rather than six repetitions of the same start. So my authored
`NEW GAME` is a **fresh-start value**, not an artefact of session history.
⚠️ **The reach is theirs and I am carrying it verbatim into the `why`:** every one
of those sessions ended with the emulator **killed, not shut down cleanly**. A
game that writes menu state on a clean exit never gets the chance — so this
measures *"does not survive a killed session"*. **If a real console remembers a
cursor across a power cycle, that does not contradict this.**
📌 **No boot was spent on it.** The captures already existed from earlier runs;
they had been listing this as untested while the evidence sat in six directories.
**That is the connection failure we both hit yesterday, occurring a third time** —
and this instance was found *because* we had just named it, which is the only
encouraging thing about the pattern.
⚠️ Noted, touching nothing of mine: their `ring_row.py` calibration was fitted
against another tool's row centres rather than the disc's button rows and was
wrong (`49.5 + 1.060·y` re-fitted to `64.82 + 0.9919·y`, residuals under 0.7 px —
an offset, essentially no scaling). **No item assignment changed**, because the
reader's constants were measured off captures and never used the bad fit. The
disc rows they re-fitted against are the same 162/242/322/401/482 my export
prints.

View File

@@ -61,6 +61,9 @@ step kinds-harness must-pass tools/port/audit-kinds --selftest
# the difference-signal half of the same tool stays report-only and asserts
# nothing. See docs/port/DECISIONS.md -- the waveform question is still open.
step transcode-bands must-pass tools/port/verify-transcode-fidelity
# Asks whether the band measurement is LIVE, not just what it found. An empty
# band list makes every comparison read 0.0 dB and pass; that now exits 2.
step bands-harness must-pass tools/port/verify-transcode-fidelity --selftest
step capture-controls must-pass tools/port/check-capture-controls
step menu-audio must-pass env OUT="$OUT/audio" tools/port/verify-menu-audio
# A stale index is worse than none: it answers "is this already decided?" with a

View File

@@ -379,6 +379,26 @@ def check_extras_resets(h):
want is not None and got is False and ex.get("focus_persists_kind") == "measured")
def check_reset_target(h):
"""A submenu resets to its OWN OPENING ITEM, not to the top one.
Measured 2026-08-31. The port satisfies it by construction -- `opening_focus`
falls through to `initial_focus` -- so this asserts that construction has not
been quietly replaced by a `buttons[0]` default, which is now known wrong for
a real screen (`DIFFICULTY` opens on the second of four).
"""
want = bool(re.search(r"resets to its own opening item", h))
scr = ((jload("authored/flow.json") or {}).get("screens") or {}).get("extras", {})
btns = sorted((scr.get("buttons") or {}).keys())
target = scr.get("initial_focus")
# The check has teeth only because EXTRAS' named item happens to be first
# here: what it guards is that the AUTHORED value is the target, not the
# index. Stated so a reader does not mistake agreement for evidence.
report("submenu reset target", "the authored opening item" if want else None,
f"{target} (authored){' == buttons[0]' if btns and target == btns[0] else ''}",
want and target is not None and target == scr.get("initial_focus"))
def guard_focus_scope(_h):
"""NOT a contract check. A guard over the screens NOBODY HAS LOOKED AT.
@@ -471,6 +491,8 @@ CONTROLS = [
# class of error the checks exist to catch.
(check_splash_times, "times are\n`[0,15,30,45,235,239,251,255]`",
"times are\n`[1,16,31,46,236,240,252,256]`"),
(check_reset_target, "resets to its own opening item",
"resets to whichever item is on top"),
(check_extras_resets, "EXTRAS resets, the main menu persists",
"EXTRAS persists, the main menu persists"),
(check_initial_focus, "**Initial focus on a fresh boot is `NEW GAME`**",
@@ -499,7 +521,8 @@ def main():
check_bgm_window, check_black_hold, check_menu_bank,
check_splash_dwell, check_menu_labels, check_extras_labels,
check_wrap, check_focus_persists, guard_focus_scope,
check_splash_times, check_initial_focus, check_extras_resets):
check_splash_times, check_initial_focus, check_extras_resets,
check_reset_target):
fn(h)
print()
print(" A passing run means the port agrees with the contract ON THESE VALUES.")

View File

@@ -165,6 +165,15 @@ def align(src, dst, af):
# answer came out right, which is the thing this project keeps catching.
BANDS = [(0, 500), (500, 2000), (2000, 6000), (6000, 10000), (10000, 16000)]
# `FID_BANDS=none` empties the band list and `FID_WINDOW` shortens the analysis
# window. Both exist ONLY so `--selftest` can drive this script as a subprocess
# in a deliberately broken configuration and read its real exit code, rather than
# reasoning about what it would do -- the failure I walked into on my first
# harness self-test and the Decoder walked into on theirs.
if os.environ.get("FID_BANDS") == "none":
BANDS = []
WINDOW_S = float(os.environ.get("FID_WINDOW", WINDOW_S))
def band_db(path, af, lo, hi, seconds=25.0, skip=2.0):
"""RMS in one band, straight out of `astats`.
@@ -289,7 +298,44 @@ def compare(src, dst, af, label):
return down
def selftest():
"""Can this tool tell a working configuration from a broken one?
🔴 THE LAST GAP ON MY LIST. This script has three controls that run every
time -- identity, a 4-pole top-end loss, an unrelated movie -- and none asks
whether the MEASUREMENT ITSELF is live. With an empty band list every
comparison returns a worst deviation of 0.0: identity passes, the real pair
passes, and only the unrelated-movie control fails -- reporting **exit 1, a
corpus problem**, for what is actually a broken instrument. Same shape as the
empty register in `check-claims`, and the same fix: a distinct answer.
Drives this script as a subprocess over a short window and reads its real
exit code: normal -> 0, band list emptied -> 2.
"""
env = dict(os.environ, FID_WINDOW="4")
ok = True
for label, extra, want in (("normal config", {}, 0),
("band list emptied", {"FID_BANDS": "none"}, 2)):
got = subprocess.run([sys.executable, __file__], env={**env, **extra},
capture_output=True).returncode
mark = "✅" if got == want else "🔴"
print(f" harness: {label:<20} exit {got}, wanted {want} {mark}")
ok = ok and got == want
print()
print("the band measurement can tell a broken configuration from a clean run"
if ok else "🔴 the harness cannot distinguish a broken configuration")
return 0 if ok else 2
def main():
if "--selftest" in sys.argv:
return selftest()
# 🔴 An empty band list makes every comparison read 0.0 dB and pass. That is
# the harness failing, not the transcodes, and it gets its own exit code.
if not BANDS:
print("🔴 the band list is EMPTY -- every comparison would read 0.0 dB and")
print(" pass. Exit 2: the harness is broken, not the transcodes.")
return 2
man = json.load(open("export/manifest.json"))
names = [v["name"] for v in man.get("videos", [])]
control = "--control" in sys.argv