# Play-test, 2026-09-02 — the splash did not animate. **Now fixed and signed off.** ## ✅ CLOSED THE SAME DAY — the human's verdict, which is the only gate that counts > *"Looks good! Cannot notice any obvious difference from the actual game. > Mark logos as done."* — 2026-09-02 **The logo splashes are DONE.** Not "the check passes" — a person compared the port against the real game and could not tell them apart. That is the oracle, and it is the strongest result this port has produced. ⚠️ **Both agents: the sole-focus block is lifted.** Return to your milestones. What remains open from the play-tests is listed at the bottom of this page; none of it is this. ### The root cause was one word ```diff - t = settle_instant if settle_instant >= 0.0 else min(t, settle_units(element)) + t = min(t, settle_instant) # the comment above it already said "stop at" ``` `pose_at` **assigned** the settle instant instead of clamping to it, so every query returned the settled pose whatever the clock said. 🔴 **And the same line manufactured the false green.** The capture harness shoots after two frames, so it was photographing t ≈ 2 units — which *looked* settled only because everything looked settled. **The 0.01 % agreement that closed H2 was measured through the accident.** One bug produced the defect and the evidence that the defect was absent. ### Verified independently before it went to the human Filmed a real boot at 0.05 s, before against after: | | before | after | |---|---|---| | splash in motion | 1.30 s / 7.95 s (16.4 %) | **2.20 s / 7.95 s (27.7 %)** | | distinct luma states | 26 | **43** | | publisher ramp | 0.30 s, 6 steps | **0.65 s, 13 steps, one continuous run** | | developer splash | two bursts split by a **0.50 s freeze** | **one continuous 0.90 s run** | The publisher trajectory rises to a peak and settles back — the **crossfade signature**: glow alone, then both, then sharp only. The developer splash's interrupting freeze disappearing is the clearest single sign the clock now drives the poses. The port then closed a gap `motion-census` names in its own header — *"a wrong ramp that moves every frame passes here"* — with a shape check pre-registered from the disc, measured off a film, on a strip no other element overlaps, in **ratios** so the texture divides out: middle:last declared 0.203 / measured 0.213, rise:last declared 1.20 / measured **1.20 exact**. It agrees with the Decoder's independent measurement of the running game. ### 🔴 The lesson, which outlives the bug Three instruments passed a frozen screen. Keep this: **an instrument that sits below the thing under test cannot see it fail.** A frozen sweep drives the clock by hand; a settled comparison is *defined* to pass on a frozen screen; an achieved-fps counter counts frames drawn, not frames different. Ask of any new check: *what would this still report if the feature were entirely absent?* --- ## The original report, kept for the record 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`](../../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`](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. --- ## What is STILL OPEN after the sign-off The logos are done. These are not, and none of them blocks a milestone gate: | | | owner | |---|---|---| | **H1** | Does a held direction **repeat** in the menus, and at what rate? One step per deflection stays authored. The 61 % arm threshold is decoded and adopted; the 0.11 hysteresis gap is still authored. | Decoder | | **H3** | The `PRESS Ⓐ` plate. All four named causes are dead and the port measures fractionally **early**, so what the human saw is **unattributed** — deliberately not closed green. ⚠️ Worth re-asking now: the animation fix changed what the whole boot looks like, so the original observation may simply no longer reproduce. | both | | **pipeline** | The end-to-end graphics account — disc → decode → the game's per-frame update → submitted draws → Canary's processing → the presented frame. Cut short by the sole-focus order and **still the right work**: it is what would let the port know whether its ramp *duration* matches the game rather than only its own declared keyframes. | Decoder | **P5's gate is "a human clicks through it" and has NOT been claimed here.** The human has signed off the *logos*, and separately confirmed that Ⓐ, the stick and the submenus work. Nobody has said the milestone is met, and an agent must not say it on their behalf.