port: P6 gate verified with sound on the bus; tighten the backdrop guard to a positive primitive test

verify-menu-audio records the Master bus over the P5 walk under the Dummy
driver. A dead press is bit-identical to the bed alone; all three cues match
their exported wave in the recording with margin over a bed-only control; the
cue order matches the script order, which the correlator was never told.

The first version of this tool counted envelope bursts above a multiple of the
bed and gave 4 cues on one run and 0 on the next from the same script. Replaced
with template matching, which has no tuned constant. Cue LENGTH is deliberately
not asserted -- the bed masks the tail and I nearly filed that as a defect.

Also acts on the Decoder's .tbm self-refutation. No port verdict is affected --
all six forced elements are .prm solid black, and GP_TITLE has no full-screen
.tbm at all -- but the guard was sprite.is_none(), a symptom test of the same
shape as the one they say fixed their symptom not their cause. Now role ==
primitive. Six verdicts identical, 16 screens validate.

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-29 21:54:14 +00:00
parent 733e376366
commit df3ea68366
3 changed files with 222 additions and 1 deletions

View File

@@ -5361,3 +5361,88 @@ framing reaches significance**, which is where both of us landed anyway.
`--screen=NAME` render at t=0 both return a **complete, well-formed answer to a
different question**. That is why neither looks like an error — nothing inside
either view can tell you it is not the view you asked for.
## P6 gate — sound on the P5 walk, verified, and the tool I nearly shipped instead
`tools/port/verify-menu-audio`. Until now the evidence that P6's gate was met was
that `audio.play("move")` appears in `boot.gd` — evidence that a *call is
written*, not that a sound reaches the bus. Those differ, and this project has
the case to prove it: the black hold was implemented, called, and emitted nothing
for five milestones.
It needs no sound card. Godot records the Master bus to a WAV under the Dummy
driver. Three runs on `main_menu`: the walk (`down,down,accept,cancel,up`) and
two controls — `wait`×5 for the bed alone, and `left`×5 for **presses that reach
`_unhandled_input` and are bound to nothing** (Q5: left/right do nothing).
| check | result |
|---|---|
| a dead press is silent | **bit-identical** to the bed alone, 114 688 samples |
| `move` on the bus | r=0.201 at 1.85 s, bed-only 0.016, margin **+0.185** |
| `confirm` | r=0.945 at 2.14 s, bed-only 0.371, margin **+0.574** |
| `back` | r=0.660 at 2.42 s, bed-only 0.195, margin **+0.465** |
| cue order vs script order | **consistent** |
The order is the strongest line and it is free: the correlator is never told
where to look, so three different templates landing in script order is three
independent searches agreeing with the log. `move`'s absolute r is low because it
is the quietest cue under the loudest part of the bed; the margin over the same
template against the bed is what carries it.
🔴 **What it cannot conclude, and must never be read as:** that these are the cues
the *game* plays. That binding is HANDOFF Q8, the Decoder's, and nothing here
re-measures it. This tool cannot tell a correct cue from a confidently wrong one.
### The instrument I nearly shipped
The first version counted envelope bursts above a multiple of the bed level. It
reported **4 cues on one run and 0 on the next, from the same script** — its
answer was set by two hand-picked constants, the multiple and a minimum run
length, and the bed level is not constant across a run. I caught it only because
I ran it twice.
The replacement has no such constant: **the exported cue file is its own
template**, the search covers the whole recording, and the verdict is a margin
over that same template matched against the bed-only control.
⚠️ Cue *length* is deliberately not asserted. The audible part of a cue is far
shorter than its wave — 0.120.38 s against authored 0.3441.016 s — because the
bed masks the tail. "Elevated for 0.13 s" is a fact about the bed, not the cue,
and I came close to filing that gap as a defect.
### A check that could not be made independent
I tried to verify Q8's cue durations against the exported waves. They agree
exactly — 0.533 / 1.016 / 0.344 — **and the agreement is worthless**: the
exporter decodes from Q8's own offsets and packet counts, so the duration is
determined by the claim under test. It confirms the export is faithful to the
authored table, nothing more. Recording it because "I checked and it matched" is
exactly what a correlated instrument feels like from the inside.
## Their `.tbm` self-refutation does not reach this archive — and it fixes my guard anyway
The Decoder downgraded 38 of the forced-backdrop rule's 80 verdicts from decoded
to inferred: those elements are `.tbm`, declaring fade `ffffffff`, and a solid
white quad painted first at alpha 255 would make the screen white. No screen is
white, so a `.tbm`'s white is a modulation **on a texture** and its element alpha
says nothing about coverage — the `.t32` mistake one file extension further out.
**No verdict the port ships is affected.** All six forced elements here are
`palogo_eff0.prm` and `pgloading_eff00.prm`, `role: primitive`, `kind_raw 0x10`,
fade `0xff000000`. They fall in the 42 that stay decoded. And **no layerless
full-screen element anywhere in `GP_TITLE` has a non-black fade** — checked
across all 16 screens, so the downgrade cannot touch this archive.
But their diagnosis applies to my code regardless: *an element's alpha is not its
texture's opacity, and only an untextured primitive makes the two the same fact*.
My guard was `sprite.is_none()` — a **symptom** test, the same shape as the one
they say fixed their symptom and not their cause. It would keep admitting a
`.tbm` that this exporter happens not to emit a sprite for.
The guard is now the positive test, `role == "primitive"`. It changes no verdict
today — the six are identical before and after, 16 screens still validate — and
it is correct by construction if the corpus grows.
⚠️ Not adopted from their message: their reading that the blend question now
narrows to `pbafc.prm`. That is theirs to settle and the port draws no additive
quad either way.