Files
Sylpheed/docs/port/plate-arrives-on-time-but-never-blinks.md
MechaCat02 a23c321831 port: land the play-tested work, and only that
Takes the port branch up to 77320d5e -- the state the human play-tested on
2026-09-02 -- for SOURCE paths only. Not a branch merge: `auto/port-p6-audio`
is 366 commits and 938 files, and most of that must not land.

WHAT COMES IN (76 files, all human-confirmed working):
  * the logo splash animation. 08ed3dd1 found it: `pose_at` ASSIGNED the settle
    instant instead of clamping to it, so the splash never animated at all --
    and the same bug manufactured a passing harness result, because the harness
    photographed t past the settle. Confirmed by play-test: "cannot notice any
    obvious difference from the actual game."
  * gamepad input -- (A)/(B) bound additively (`ui_accept` ships with NO joypad
    binding), stick latched with hysteresis at the game's own 61% digitise
    threshold. This is what made (A), video-skip and Extras work at all.
  * menu navigation and flow, menu audio, the exporter, the authored
    declarations, and 23 verification tools under tools/port/.

WHAT IS DELIBERATELY LEFT ON THE BRANCH:
  * everything after c0ae460a -- the F5/F6 title-timing investigation, whose own
    tip commit calls itself a "hand-off for one-minute human checks". Unchecked
    by definition; it goes through the new review gate like anything else.
  * the OPTIONS menu work of 2026-09-03. Real, probably good, NOT play-tested.
  * the F1 repeat mechanism, which its own commit calls "deliberately inert".

WHAT MUST NOT LAND, AND WHY THE .gitignore CHANGED:
  545 MB of extracted game content was committed on that branch -- 850 sprite,
  audio and transcoded video files under `export-probe/` and `export-probe2/`,
  plus 246 MB of loose .wav and .tsv at the repo root. This repository's own
  rule, in this file, is "never game content".

  The rule was not missing. It was written, and it was tightened on that very
  branch, with a careful comment explaining why BOTH `export/` and `data/base/`
  had to be listed -- while the exporter was writing to a third name that
  nobody had thought to list. Enumerating names is the thing that failed. So
  the ignore rules now describe the SHAPE: any top-level `export*/`, game media
  by extension, and loose capture output at the root. Verified both ways -- it
  catches all four offenders and ignores nothing currently tracked.

Verified: `cargo check --workspace` clean; all nine GDScript files parse in
project context, with a positive control (an injected syntax error is detected,
3 lines) so the clean result means something. `tools/port/check-all` was NOT
run -- it needs the container, the export tree and a display.
2026-09-04 16:17:14 +02:00

5.7 KiB
Raw Blame History

H3 re-asked after the animation fix: the plate is on time, and it never blinks

Status: the "arrives late" observation does not reproduce as a timing error — measured on the current build, and the plate's onset sits on its declared keyframe. 🔴 A different divergence in the same element is real and was not being looked for: the port holds PRESS Ⓐ lit permanently, where the disc declares a 30-unit pulse. Written 2026-09-02 by the Port at 6263686.

PLAYTEST-2026-09-02.md asks for exactly this, in its own words: "Worth re-asking now: the animation fix changed what the whole boot looks like, so the original observation may simply no longer reproduce." And there is a specific reason to re-ask rather than assume — the previous plate numbers were taken through the pose_at bug, the same way the 0.01 % that manufactured H2's false green was.

What the disc declares

export/screens/title/press_start.json, one element ptbtn00:

0:0   214:0   236:255   238:255   244:0        rest [383,550], sprite 513x50

Invisible until 214, full at 236238, gone by 244. A 30-unit pulse.

The instrument, and the two controls it went through first

Filmed a real boot (--skip-at=1 --linger=8 --film-interval=0.05), no --time, no pinning. Then two attempts at isolating the plate failed before one worked, which is the part worth keeping:

  1. 🔴 A rect around the plate. Contaminated — the rect overlaps the developer splash earlier in the boot, so the onset detector fired on the wrong screen.
  2. 🔴 A control band 55 px above the plate. Still wrong. The title's background sweep moves, so a spatially displaced control samples it at a different phase and cannot cancel it. It showed a "rise" that was the sweep.
  3. The plate sprite's own transparent holes. Same rectangle, same rows, interleaved with the glyphs at pixel scale — 7 672 glyph pixels against 10 412 hole pixels, both built from the sprite's alpha channel. A co-located background sample, so glyph hole is the plate and nothing else.

⚠️ Control 2 is the same defect as everything else on this project: an instrument that cannot see the thing it is measuring separately from the thing it is measuring against. It produced a plausible curve. The tell was that the "plate" and the background rose together in phase.

Result 1 — the arrival is correct

glyph hole, dark baseline 0.003:

overlay units 205 214 222 230 238 246
plate 0.005 0.005 0.222 0.434 0.586 0.601

Flat through 213.9 and risen by 222.1. The declared onset t=214 sits inside that bracket, and the bracket is 8 units wide because that is the film's sampling interval, not a measurement of anything. By t=238 the plate is at 88 % of its lit level, against a declared full alpha at 236.

The plate is not late. Whatever the human saw in the 2026-09-01 play-test, the port's own clock puts ptbtn00 on its declared keyframe.

Result 2 — 🔴 and it then stays lit forever

The declared ramp returns to 0 at t=244. It does not:

dark baseline, t < 214 0.003
minimum at any point after t = 250 0.587 (at ou 342)
maximum after t = 250 0.664
span measured ou 6 → 19748.1 declared cycles

Over eight cycles of its own declared timeline the plate never returns within 88 % of dark. The 11.6 % ripple that is there is not the plate: it is in phase with the hole channel, i.e. it is the title's background sweep leaking through the anti-aliased glyph edges.

Why, and it is a failure mode this port already wrote down

ptbtn00's rest.t = 236 and its settle instant is t=236the peak of the pulse. holding parks the element there, so the port shows a PRESS Ⓐ plate that lights once and stays on.

plate-arrival-halves.md names this exact class already, about a different element:

"It is still wrong for transients — ptlogo_back2eff1 is a two-frame flash (0 at t52, 0xff at t5456, 0 by t58) and its rest.t = 54 is the flash peak, so rest() leaves five of these burning at once."

The plate is an instance of the family that page predicted, and nobody had checked the plate itself — because that page was written to eliminate rest.t as a cause of lateness, which it correctly did, and having eliminated it as the cause of one defect nobody asked what else it was doing.

What I have NOT changed, and why

Nothing. The port still holds the plate.

Reading the disc's keyframes is mine; whether the running game pulses its PRESS Ⓐ plate is not. The keyframes describe a blink and blinking is what PRESS START prompts conventionally do, but "conventionally" is not evidence and this project has been burned by exactly that kind of inference. The change is proposed, not made, and the Decoder has been asked for the one fact that settles it: does the plate pulse in the guest, and with what period?

⚠️ This is not a regression from the animation fix. Before the fix pose_at assigned the settle instant, which parks the plate at t=236 too. The plate has been held for as long as the port has drawn it; the fix neither caused this nor was supposed to.

What this does not claim

  • That finding 3 was wrong when it was made. It says the port measures on time now, on a build whose boot the fix visibly changed.
  • That holding is wrong. It says the port's picture and the disc's keyframes disagree, and names who can adjudicate.
  • Anything about the plate's absolute alpha or position. Onset timing and whether it extinguishes, only.