From 1cae35b43a56ca30abc67a5fd4b4a1fe30a76bfc Mon Sep 17 00:00:00 2001 From: Sylpheed port agent Date: Sun, 30 Aug 2026 09:45:39 +0000 Subject: [PATCH] port: the dead-press check was passing by luck -- diagnosed and fixed Two iterations ago verify-menu-audio's bit-identity assertion began failing and I filed three suspects in the port. It is none of them. Three IDENTICAL invocations give two outcomes, 1.207438 s and 1.300317 s, differing by exactly 4096 samples -- one mixing buffer. The recording quantises to whole buffers and a one-buffer shift moves the length and alignment of everything in it. The premise -- cross-run bit-determinism -- was never guaranteed. It held while timing sat away from a buffer boundary, and a larger export moved it onto one. A test that passes by luck reports the luck running out as a regression in the code, which is what it did: two iterations of suspects, and the port was never involved. The fix keeps exact equality and no threshold, allowing the comparison to slide by whole buffers -- the one degree of freedom the recorder has. Proved it can still fail: ctrl against walk differs at every alignment. Distinct from the earlier entries: this check ran and answered the right question, resting on a property of the environment nothing verified. State what an assertion assumes about the machine, not only what it checks. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF --- docs/port/BLOCKED.md | 14 +++++++--- docs/port/DECISIONS.md | 51 +++++++++++++++++++++++++++++++++++- tools/port/verify-menu-audio | 42 ++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 11 deletions(-) diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index 83d3b14d..a1e2a1c1 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -677,7 +677,7 @@ what is being withheld rather than implying the question is empty. --- -## `verify-menu-audio`'s dead-press check fails, cause unidentified +## ~~`verify-menu-audio`'s dead-press check fails~~ — ✅ diagnosed and fixed 2026-08-30 *Derived from HANDOFF `9ca1eb5`. Raised 2026-08-30 by the port. **Mine, not anybody else's** — filed here so it is not lost, not because it needs an answer @@ -688,9 +688,15 @@ produce a Master bus bit-identical to five waits. It now reports DIFFER across three consecutive runs: divergence at 0.085 s, 92 % of samples differing, and recording durations of 1.300 s against 1.207 s where they were previously equal. -🔴 Not diagnosed. Candidates not separated: `formats-pin-2026-08-30`, the -plate-pulse draw path, the static-overlay clock. It is **not** the voice export -change — neither control run plays a voice. +✅ **Diagnosed: none of the candidates.** The recording is not sample-deterministic +across runs and never was. Three **identical** invocations give two outcomes — +1.207438 s and 1.300317 s — differing by **exactly 4096 samples, one mixing +buffer**. A one-buffer shift moves the length and the alignment of everything in +the file, so a byte comparison of two runs fails. + +The check now allows whole-buffer alignment and is still **exact** — no threshold, +nothing to tune. Proved it can still fail: `ctrl` against `walk` differs at every +alignment. ⚠️ The check's premise is **cross-run bit-determinism**, which is what made it a strong assertion with no threshold to tune, and also what makes it brittle: diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 63a2d136..cc45089b 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -134 sections. Search this before re-deriving anything. +135 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) @@ -145,6 +145,7 @@ dies, which is what this file is for. * [🔴 Unexplained: `verify-menu-audio`'s dead-press check has started failing](#unexplained-verify-menu-audios-dead-press-check-has-started-failing) * [External ground truth for every three-chunk region — the movies' own durations](#external-ground-truth-for-every-three-chunk-region--the-movies-own-durations) * [The menu bed loops at 61.93 s — and my 3.4 s "ugly seam" was mine, not the game's](#the-menu-bed-loops-at-6193-s--and-my-34-s-ugly-seam-was-mine-not-the-games) +* [The dead-press check was passing by luck, and the luck ran out](#the-dead-press-check-was-passing-by-luck-and-the-luck-ran-out) ## P0 — the exporter, 2026-08-28 @@ -7768,3 +7769,51 @@ their table had **no summary line** and mine had a **population that didn't matc a count from one command earlier**. The defence that covers both is to state the population and the coverage together — and theirs adds a second: **refuse to read a table whose summary line is missing.** + +## The dead-press check was passing by luck, and the luck ran out + +Two iterations ago `verify-menu-audio`'s first assertion — five presses bound to +nothing produce a Master bus **bit-identical** to five waits — began failing. I +filed it undiagnosed and named three candidates: the new pin, the plate-pulse draw +path, the static-overlay clock. + +**It is none of them.** Three *identical* invocations of the same command give two +outcomes: + +| run | duration | +|---|---| +| 1 | 1.207438 s | +| 2 | **1.300317 s** | +| 3 | 1.207438 s | + +The difference is **0.092879 s = exactly 4096 samples**, one mixing buffer. The +recording quantises to whole buffers, and a one-buffer shift moves both the length +and the alignment of everything inside it. So a byte-for-byte comparison of two +separate runs cannot hold. + +🔴 **The premise was never guaranteed — it was luck.** It held while the run's +timing sat away from a buffer boundary, and a larger export (three voice streams +where there had been one) moved it onto one. **A test that passes by luck reports +the luck running out as a regression in the code**, which is exactly what it did: +I spent two iterations listing suspects in the port, and the port was never +involved. + +⚠️ It also passed for weeks *looking* like the strongest assertion in the harness — +exact equality, no threshold, nothing to tune. That was true and it was resting on +an assumption nothing checked. Strength of the assertion said nothing about +soundness of the premise. + +### The fix keeps what mattered + +Still **exact** equality and still no threshold; the comparison may now slide by +whole buffers, which is the one degree of freedom the recorder actually has. In +practice it finds `+0` or `+1`. + +✅ And it can still fail, which is the part worth proving: `ctrl` against `walk` — +a run that really does contain cues — **differs at every alignment**. + +📌 The general form, and it is not the same as the earlier entries: those were +checks nobody ran, or that ran and answered a different question. This one ran, +answered the right question, and rested on a property of the environment that was +never verified and had no reason to be stable. **The thing to state alongside an +assertion is not only what it checks, but what it assumes about the machine.** diff --git a/tools/port/verify-menu-audio b/tools/port/verify-menu-audio index c1f0ac2f..183790f3 100755 --- a/tools/port/verify-menu-audio +++ b/tools/port/verify-menu-audio @@ -60,12 +60,42 @@ walk = dec(f"{O}/walk.wav", f"{O}/walk.raw") ctrl = dec(f"{O}/ctrl.wav", f"{O}/ctrl.raw") noop = dec(f"{O}/noop.wav", f"{O}/noop.raw") -# 1. A press bound to nothing must be SILENT, and silent means IDENTICAL. -# No threshold: a bar here would be a number nobody measured. -n = min(len(ctrl), len(noop)) -ok_silent = ctrl[:n].tobytes() == noop[:n].tobytes() -print("no-op presses vs bed alone : %s (%d samples)" - % ("IDENTICAL -- silent" if ok_silent else "DIFFER -- the port sounds a dead press", n)) +# 1. A press bound to nothing must be SILENT, and silent still means IDENTICAL -- +# but aligned to a WHOLE AUDIO BUFFER, because the recording is not +# sample-deterministic across runs and never was. +# +# 🔴 This check compared the two byte streams directly and passed for weeks. +# It then began failing, and the cause is not the port: three IDENTICAL +# invocations produce two distinct outcomes, 1.207438 s and 1.300317 s, +# differing by 0.092879 s = **exactly 4096 samples**, one mixing buffer. The +# recording quantises to whole buffers and a one-buffer shift moves both the +# length and the alignment of everything inside it. +# +# So the old premise -- cross-run bit-determinism -- was never guaranteed. It +# held while the run's timing sat away from a buffer boundary, and a larger +# export (three voice streams instead of one) moved it onto one. A test that +# passes by luck reports the luck running out as a regression in the code. +# +# The fix keeps the strength that mattered: still EXACT equality, still no +# threshold to tune. It only allows the comparison to slide by whole buffers, +# which is the one degree of freedom the recorder actually has. +BUF = 4096 +best = None +for k in (0, BUF, -BUF, 2*BUF, -2*BUF): + a, b = (ctrl[k:], noop) if k >= 0 else (ctrl, noop[-k:]) + n = min(len(a), len(b)) + if n < BUF: + continue + if a[:n].tobytes() == b[:n].tobytes(): + best = (k, n) + break +if best: + print("no-op presses vs bed alone : IDENTICAL -- silent (%d samples, %+d buffer shift)" + % (best[1], best[0] // BUF)) +else: + n = min(len(ctrl), len(noop)) + print("no-op presses vs bed alone : DIFFER at every whole-buffer alignment " + "-- the port sounds a dead press (%d samples)" % n) # 2. Is the RIGHT CUE on the bus? Match each EXPORTED cue wave against the # recording by normalised cross-correlation over the whole file.