Files
Sylpheed/docs/agents/PLAYTEST-2026-09-02.md
MechaCat02 d394c55cbb agents: the splash does not animate, and three instruments could not see it
A human on a GPU at ~140 fps: "the logos just switch, there is no animation at
all." Measured from a real boot with --film at 0.05 s, then per-frame change:

  splash moves        1.30 s of 7.95 s = 16.4 %
  publisher splash    0.30 s of motion, then 3.20 s FROZEN
  developer splash    0.35 s + 0.25 s, then 2.40 s FROZEN
  distinct luma states in 7.95 s   26

A 45-unit build-in cannot be drawn in 26 states, and a fade does not hold one
picture for 3.20 s. The frame counter says 24.8 fps achieved; both are true --
the port is DRAWING 25 times a second and CHANGING almost never.

🔴 Why every check passed, which matters more than the bug:

  frozen sweep     drives the clock BY HAND -- proves the renderer can draw
                   pose N, never that the poses are drawn in sequence
  settled compare  0.01 % against the capture -- a screen frozen 84 % of the
                   time matches a settled reference PERFECTLY, that is what
                   frozen means
  achieved fps     counts frames DRAWN -- the same pixels 25x/s scores
                   identically to animating

Every one measured throughput or a pose. None measured CHANGE. Same shape as
InputEventAction bypassing the input map: the instrument sat below the thing
that was broken, so the break could not appear in it.

tools/motion-census closes the class. It measures change and nothing else, and
its --selftest asserts it separates a fade (97.4 % moving) from a switch (2.6 %)
from a frozen film (0.0 %) -- a detector that cannot tell those apart would
report the same green line on all three.

Both briefs: this is the SOLE focus. The port reproduces before changing
anything and gates every fix on a film rather than a still. The decoder maps the
whole pipeline end to end -- disc bytes, the game's per-frame update (does it
interpolate between keyframes or hold?), what is submitted per frame, and what
Canary does to it before a capture records it -- delivered as a SERIES, not a
settled value.

The port should also record the refutation against itself: H2 reads ANSWERED on
the strength of the frozen sweep. The mechanism half stands, the blur is a baked
companion texture. The behaviour half does not.
2026-09-02 17:24:42 +02:00

5.5 KiB
Raw Blame History

Play-test, 2026-09-02 — the splash does not animate at all

This is the only thing either agent works on until it is fixed.

The human, watching the port on real hardware, on a GPU, at ~140 fps:

"The port does no blur animation at all! I cannot discern if there is any animation at all. The logos just switch without the animation."

Measured, not paraphrased

Filmed from a real boot at 0.05 s (--film), then per-frame change measured with tools/motion-census:

splash moves 1.30 s of 7.95 s — 16.4 %
publisher splash 0.30 s of motion, then 3.20 s frozen
developer splash 0.35 s + 0.25 s, then 2.40 s frozen
distinct luma states in 7.95 s 26

A 45-unit build-in cannot be drawn in 26 states, and a fade does not hold one picture for 3.20 s. This is a switch with a flicker on either side.

The frame counter says 24.8 fps achieved. Both are true: the port is drawing 25 times a second and changing almost never.

🔴 Why three instruments all said it was correct

This is the part that matters more than the bug, because it is the fourth time this shape has cost a milestone.

instrument what it proved what it could not see
frozen sweep (--time=, 3 units a step) the renderer CAN draw pose N whether the poses are ever drawn in sequence, while running
settled comparison (0.01 % against the capture) the resting pose is right a screen frozen 84 % of the time matches a settled reference perfectly — that is what frozen means
achieved-fps counter frames are being drawn drawing the same pixels 25×/s scores identically to animating

Every one measured throughput or a pose. Not one measured CHANGE.

That is why the port could write "the companion quads are drawn, verified by a frozen sweep" and be simultaneously right and useless: the sweep drives the clock by hand. It is the same defect as InputEventAction bypassing the input map — the instrument sat below the thing that was broken, so the thing that was broken could not appear in it.

tools/motion-census exists to close this class. It measures change and nothing else, and its --selftest proves it separates a fade (97.4 % moving) from a switch (2.6 %) from a frozen film (0.0 %) — because a detector that cannot tell those apart would report the same green line on all three.

What both agents do now

Nothing else. Not the clock rate, not the plate, not blend, not audio. This first.

Port

  1. Reproduce it with --film + motion-census before changing anything, and quote the numbers. If your run does not reproduce 16.4 %, say so — the disagreement is then the finding.
  2. Find why the clock does not advance the poses. Candidates, unranked and none established: the keyframe interpolation returns the same pose for a range of t; rest()/plateau logic snapping to an endpoint; the group clock not integrating; interpolation between keyframes not happening at all (nearest-keyframe rather than lerp); the screen advancing by keyframe index instead of by time.
  3. Every fix is gated by a film, never by a still. A change that improves a settled frame and leaves the film at 16 % has not fixed this.
  4. motion-census goes into check-all, so a future regression fails a check instead of waiting for a human.

Decoder — map the whole graphics pipeline, end to end

The human's instruction, in their words: "get the whole graphics pipeline, from the xex/pe + the disc files to the final screen displayed, and take Xenia Canary processing into account too."

So: one continuous account, each stage with evidence and each labelled by the instrument that produced it —

disc bytes  →  RATC/T8aD decode  →  what the GAME CODE does per frame
            →  the draw calls it submits  →  Canary's own processing
            →  the presented frame

Specifically, and none of it inferable from a file alone:

  • The game's per-frame update. Which code advances a UI group's clock, in what units, and what it does between keyframes — does it interpolate, or hold to the next key? That single question decides whether the port should lerp at all. It is in the image; find the function.
  • What the game submits per frame during the splash — the draw list frame by frame, not one settled frame. If the alpha changes, it changes somewhere observable: a vertex colour, a PS constant, a blend factor, a texture swap. Name which, with the per-frame series.
  • What Canary does to it. Present cadence, any resolve/scaling/gamma between the guest's draw and the pixels a capture records. A capture is evidence about Canary's output, and the difference between that and the guest's intent has bitten this corpus before (the kernel_display_gamma_type entry).

⚠️ Deliver a per-frame SERIES, not a settled value. Follow TEMPORAL-VERIFICATION.md: film it, align by content, report ordering/counts/durations. The port needs to know what the alpha trajectory is, and a single frame cannot carry one.

And this is a refutation the port should record against itself

BLOCKED.md H2 currently reads ✅ ANSWERED, on the strength of the frozen sweep. The mechanism half stands — the blur is a baked companion texture, that is decoded and correct. The behaviour half does not: the port draws those quads and does not animate them, so "the companions are drawn" was true and did not mean what the row used it to mean.