port: both of my H3 conclusions were wrong, and check-all stays red on a sixth-screen divergence

The Decoder answered H3 in both halves (a482d9a, against a pre-registration
committed before they read the capture) and refuted two things I published an
hour earlier. Both are struck in place, not deleted.

1. units/frame is 2, not the 5 I inferred. Three consecutive gap-free steps of
   exactly 23 on ptbtn00's own ramp; 255*2/22 = 23.18. My 4.4-frame prediction
   is excluded by more than 2x.

   My derivation was sound arithmetic on two unsound premises, both mine to
   have used:
     - an alpha step is not a clock rate. dA/frame = 255*(units/frame)/T, so
       elements with different declared T show different steps at ONE clock.
       Splash quads step 34 with T=15; the plate steps 23 with T=22.
     - my "onsets" were first submissions, and on splash A both quads are
       already at a=85 when first submitted -- biased late, and by a different
       amount per element because the bias scales with T.
   The three intervals agreed with each other because they SHARED the bias.
   Three measurements with a common error are one measurement. That is the
   shape I should have checked for and did not.

2. My claim that the t=160 anchor collapses `clock: "shared"` is WITHDRAWN. The
   anchor is indeed t=160 -- ptcopyright, calibrating to t~168-176 -- but I
   falsified the model using the 2.135 s figure, which is the one number the
   same capture puts in dispute. Falsifying a model with the quantity that is
   itself under dispute is the error. Against the new capture's own labels the
   declared 54 and 76 units reconstruct at 44 and 66 -- short by 13-19 % in the
   same direction, with empty labels a named candidate for the residual.
   `clock: "shared"` stands, and the port keeps it.

Still open and now the only thing left on H3: units/second = 2 x guest fps, and
whether the guest is 30 Hz or 60 Hz is unestablished. 2x60 = 120 units/s puts
the plate at 1.97 s instead of 3.93 s, which is the size of what the human
reported. The Decoder asked me not to move off 60 on their account yet; I have
not.

Separately -- check-all is RED and stays red. verify-screen newly DIFFERS on six
screens outside its allowed set (main_menu, extras, main_menu_jp, extras_jp,
build_12, build_15). Measured, not diagnosed:

  * not this iteration's doing, and excluded structurally rather than by a
    passing test: sprites are read as bytes and built with
    Image.load_png_from_buffer, so they never enter Godot's import pipeline and
    the new `--import` step has no path to the drawn pixels;
  * the difference is FULL-FRAME, exactly zero on unblended pixels (18 081 of
    them agree to a hundredth of a level at ref 199/204/255) and gamma-shaped on
    every blended one. That is a blend-SPACE divergence, not moved content;
  * scored against live-main-menu.png the port is 16 % closer than the reference
    (RMSE 3152 vs 3770) -- an ordering only, since both sides carry this
    script's --pose=rest contamination, which has produced a false finding here
    before.

Not widened. This allowance has twice been broadened with a reason that turned
out false, and "I measured it but cannot say which renderer is right" is not a
reason. New ask H4: what colour SPACE is the blend evaluated in -- the Decoder
has the equation from shader ucode, not the space.

Refutation attempts: both of this iteration's hits are against my own page from
last iteration. The Decoder's units/frame law and their anchor measurement both
survived the only check I could make of them -- their steps reproduce this
export's declared T on two screens at one clock.

Not settled: guest fps; which renderer's blend space is right; H1 (key repeat).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
This commit is contained in:
Sylpheed port agent
2026-09-01 16:56:29 +00:00
parent 6eccfa84d8
commit da7864e499
4 changed files with 237 additions and 17 deletions

View File

@@ -106,7 +106,7 @@ method finding that applies to the Decoder's harness as much as this one:
|---|---|---|
| **H1** | **Does a held direction REPEAT in the menus, and at what rate?** Initial delay and repeat interval, for the d-pad and for the left stick separately if they differ. | Behavioural. The port now does **one step per deflection**`authored`, and deliberately the conservative half: it cannot run away and it invents no rate. If the game repeats, a human will feel it as *"I have to flick it again"*. |
| **H2** | ✅ **ANSWERED 2026-09-01, and the port's own premise was wrong.** The Decoder found **no post-process pass** on either splash (`auto/frame-blend-draw-path` `3cc1b51`). The blur is **in the asset**: every logo ships a pre-blurred copy ~21×20 px larger and concentric, drawn alone first and crossfaded out as the sharp logo fades in — which is the human's *"blurred to clear/sharp, in about a second"*, with no shader. | 🔴 **"The port applies no blur at all" was FALSE and this page said it.** The port draws all seven quads of the developer splash, the three companions included, and always has. Verified by a frozen sweep, 3 units a step: companions alone at u=315, all seven at u=1842, sharp only from u=45. Writing down what the renderer was *believed* to do instead of running it is what produced the claim. What remains is the **extent**, and it is the same unit question as H3 — asked there, once. See [`plate-arrival-halves.md`](plate-arrival-halves.md). |
| **H3** | 🟢 **NARROWED 2026-09-01, port half eliminated. The ask is now one question: what does your "title settled" anchor correspond to on the declared timeline?** You define it operationally — *glyph counter first reads its no-plate value 154*. Our export offers **two** anchors 42 units apart: **t=118** (`pteff01`, `pteff02`, `ptlogoall_eff` end their ramps together) and **t=160** (`ptcopyright` reaches full alpha — the *last* element to finish building in, and the only one made of **glyphs**). At 118 the shared-clock reading reproduces your 2.135 s to 8 %; at 160 it misses by 41 % and `clock: "shared"` collapses. 🔴 **AND A SECOND, SHARPER HALF, ADDED AFTER YOUR SPLASH CAPTURE LANDED: your two captures imply keyframe rates a factor of 2.7 apart.** `splash-quad-timeline.txt` gives **5 units per guest frame** on three independent intervals of the publisher splash (companion onset→logo onset, companion onset→peak, logo onset→full: 3 frames each, against 15 declared units each) — against the declared **2**. At 30 fps that is ~150 units/s, the plate would land at **1.57 s** instead of 3.93 s, and this port would be **~2.4 s late**, which is the right magnitude for what the human saw. But `title-plate-delay-measured.md` implies **~55 units/s** from the same game. Both are yours; we cannot pick. ⚠️ Caveat we can see from here: the splash capture's frame index **skips** (5, 8, 12 are absent from Q7's eight draws), and whether those are unsubmitted quads or dropped presents changes the arithmetic. | All three candidates the play-test named are eliminated, with evidence, in [`plate-arrival-halves.md`](plate-arrival-halves.md) — derived from `export/` at port `HEAD` `6db49f5`, HANDOFF at `9ca1eb5`. **`rest.t`**: not in the causal path — the plate's onset is a declared keyframe (transparent to t=214, opaque at t=236), and rest.t only picks the parking pose. **Clock origin**: the two builds share one clock exactly — 85 of 85 filmed title frames have `view_units == overlay_units` to 3 dp. **Unit constant**: eliminated by *sign* — making the port earlier needs units/s **above** 60, while 28.1 fps presentation and 28.5 fps idle title both say the game's units run slower. And the port is **0.17 s early** on the interval you measured (1.967 s vs 2.138/2.132) and **between your two runs** on first-drawn→plate (3.933 s vs 3.781/4.263). 🔴 Also corrected: `ptbtn00` reaches a=255 at **t=236**, not 238 — so the cited `238 118 = 120` is `236 118 = 118`. |
| **H3** | **ANSWERED IN BOTH HALVES 2026-09-01** by `h3-units-per-frame-measured.md` (`origin/auto/frame-blend-draw-path` at `a482d9a`), against a pre-registration committed before the capture was read. **units/frame = 2** (three consecutive gap-free steps of exactly 23 on `ptbtn00`'s own ramp; `255×2/22 = 23.18`). **The anchor is t=160** `ptcopyright`, calibrating to t≈168176, 816 units from B and 5058 from A. | 🔴 **Two of the port's own conclusions were refuted by this and are struck in [`plate-arrival-halves.md`](plate-arrival-halves.md), not deleted.** (1) My **5 units/frame** was an artefact of two errors: an alpha step is not a clock rate (`Δα/frame = 255×(units/frame)/T`, and I read steps off elements with different `T`), and my "onsets" were first-submissions already at α=85. The three intervals agreed because they shared the bias, not because they corroborated. (2) My claim that the t=160 anchor **collapses `clock: "shared"`** is **withdrawn** — I falsified it using the 2.135 s figure, the one number the same capture puts in dispute. Against the new capture's own labels the declared 54 and 76 units reconstruct at 44 and 66, short by 1319 % in the same direction, with empty labels a named candidate for the residual. `clock: "shared"` stands. **Still open, and the only thing left: `units/second = 2 × guest fps`, and nobody has established whether the guest is 30 Hz or 60 Hz.** 2×30 = 60 (what the port ships); 2×60 = 120, which puts the plate at **1.97 s** instead of 3.93 s — the size of what the human reported. The Decoder asked the port not to move off 60 on their account yet, and it has not. |
**On H2, three things the port can say that narrow it**, none of which settle it:
@@ -130,6 +130,11 @@ at a known cadence, compared frame-by-frame against the port's ramp — and, if
they differ in shape rather than in extent, a draw capture naming what is
submitted per frame.
| # | ask | why the port cannot answer it |
|---|---|---|
| **H4** | **In what colour space is the UI alpha blend evaluated?** You decoded the *equation* from the pixel shader's ucode on 2026-09-01 — source-over, shader premultiplies, `ONE/INV_SRC_ALPHA`. This asks the space, not the equation: is the blend done on sRGB-encoded values, or linearised and re-encoded? | Behavioural / GPU state. `verify-screen` newly reports `DIFFERS` on six screens, and the divergence is **exactly zero on 18 081 unblended pixels** and gamma-shaped on every blended one — the signature of two renderers blending in different spaces. Ours is 16 % closer to `live-main-menu.png` than `sylpheed-cli` is, which is a direction and not a verdict. `check-all` is **left red** rather than the allowance widened. Derived from port `HEAD` `6eccfa8`; HANDOFF at `9ca1eb5`. See [`verify-screen-blend-divergence.md`](verify-screen-blend-divergence.md). |
## Still open — these block work
🔴 **This table's rows carry no derivation sha, and that is why they rot.** The standing instruction is to record the HANDOFF commit each row was derived from; every *prose* section added since does, and **every row in this table and the next does not**. On 2026-08-30 an audit found three stale rows here — one of them contradicted by a struck row four lines below it, claiming the boot ends on a plateless title when it had drawn the plate for weeks. The undated rows are exactly the ones that went stale, which is as close to a controlled experiment as this page is going to get.

View File

@@ -1,6 +1,11 @@
# H3 — the `PRESS Ⓐ` plate: which half the lateness is in
**Status:** the port's half is **eliminated**; the Decoder's half is **live and now has a number**.
**Status:** ✅ **both halves answered, and TWO of my own conclusions on this page
were refuted within the hour** — the `5 units/frame` reading and the claim that
`clock: "shared"` collapses. Both are struck in place rather than deleted,
because both were confident and both were wrong for reasons worth keeping.
The answers are the Decoder's `h3-units-per-frame-measured.md`,
`origin/auto/frame-blend-draw-path` at `a482d9a`.
Written 2026-09-01 by the Port, against `export/` regenerated from this
checkout, `HEAD` = `6db49f5` (merge of `origin/main` `1af103d` and
`origin/human/r1-retro-tick`). HANDOFF on this branch answers `9ca1eb5`.
@@ -10,15 +15,16 @@ arrives late and names three candidate causes: the **unit→seconds constant**
(the Decoder's), the **clock origin** and **`rest.t`** (both ours). The brief
asks which half it is, and how that was established. This page is the answer.
> **Short version: the two candidates that were ours are eliminated, and the one
> that is the Decoder's is not.** The port renders the plate exactly where its
> own export declares it, on a clock verified identical to build 4's frame by
> frame — so neither `rest.t` nor the clock origin can be the cause. The
> **unit→seconds constant** survives, and a capture the Decoder landed the same
> day puts it at **5 units per guest frame against the declared 2**, which would
> make this port ~2.4 s late — the right magnitude. That reading collides with
> the oracle's own plate measurement by a factor of 2.7, so it is asked, not
> acted on.
> **Short version, after the answer landed.** `rest.t` and the clock origin are
> eliminated and stay eliminated — those were the port's half and the evidence
> below still holds. **Units per *frame* is 2, not the 5 I inferred**; my
> derivation was sound arithmetic on an unsound premise and is struck below.
> **The anchor is t=160**, as I suspected. And my consequent claim that
> `clock: "shared"` therefore collapses is **withdrawn** — I computed the
> collapse against the one number now known to be in dispute. What is left open
> is **units per *second***, which is `2 × guest fps`, and whether the guest is
> 30 Hz or 60 Hz is not settled by anyone. At 60 Hz the plate lands at 1.97 s
> instead of 3.93 s, which is the size of what the human reported.
## What the export actually declares
@@ -102,9 +108,46 @@ constant** — from a screen with no bearing on the plate:
| sharp logo onset → full alpha | f7 → f10, **3 frames** | t=15 → t=30, **15 units** | **5.0** |
Three intervals, three ways, **5 units per guest frame** — against the declared
**2**. At 30 fps that is ~150 units/s rather than 60, and the plate at t=236
would land at **1.57 s**, not 3.93 s. The port would be **~2.4 s late**, which
is the magnitude of a thing a human notices without a stopwatch.
**2**.
## 🔴 STRUCK. It is 2 units per frame, and my 5 was an artefact of two things
Measured by the Decoder on `ptbtn00` itself — the plate, on the title, not a
splash — in `h3-units-per-frame-measured.md` (`a482d9a`), against a
pre-registration committed before the capture was read:
```
label 5372 5373 5374 5375 [5376] 5377 5378 [5379] 5380
alpha 46 69 92 115 — 197 220 — 255
step +23 +23 +23
```
`255 × 2 / 22 = 23.18`, and the plate's declared ramp is `t=214 → 236`, i.e.
`T = 22`. **Three consecutive gap-free steps of exactly 23 is 2.0 units per
frame on the nose.** Their prediction was 11 frames for the ramp and it measured
10, inside a stated ±1. My 4.4-frame prediction is excluded by more than 2×.
**Why my three intervals all read 5, and why the agreement between them was
worthless.** Two independent errors, both mine to have made:
1. **An alpha step is not a clock rate.** For a linear segment,
`Δα per frame = 255 × (units per frame) / T`. Two elements with different
declared segment lengths `T` show different `Δα` at an *identical* clock.
Splash B's quads step 34 with `T=15`; the plate steps 23 with `T=22`; both
are 2 units/frame. Reading a step as a rate is what produced the 2.7×.
2. **My "onsets" were not onsets.** I took each quad's *first submission* as its
`α = 0` time. On splash A, `Q7` and `Q0` are both already at **α = 85** when
first submitted. So all three intervals started late — and by a *different*
amount per element, because the bias scales with `T`. That the three then
agreed with each other is not corroboration; they share the error.
The three "independent" intervals were one measurement made three times with the
same two biases. That is the shape I should have checked for and did not.
⚠️ The Decoder records the published `splash-quad-timeline.txt` having no `T`
column as their own defect, now fixed. That does not make the inference mine any
less: **the arithmetic was sound and the premise was not, and a premise handed
to me is still a premise I used.**
⚠️ **Two caveats, and they are why this is asked rather than acted on.** The
capture's frame index **skips** — 5, 8 and 12 are absent from Q7's eight draws —
@@ -202,7 +245,43 @@ the point: *reproducing that capture is not the same as being right*, because
the splash capture says the unit is 2.5× off and would put the port 2.4 s late.
The two cannot both hold. The human's eye agrees with the splash capture.
## A second anchor question, also the Decoder's
## 🔴 WITHDRAWN: my claim that the t=160 anchor collapses `clock: "shared"`
The section below asked which anchor the glyph counter corresponds to and said,
of the t=160 answer, *"the shared-clock premise does not reproduce the
measurement at all and `clock: "shared"` is open"*. **The Decoder answered
t≈160176 — candidate B — and then repeated my consequence back to me**, noting
correctly that what it costs the port's model is the port's problem and not
evidence against their measurement.
**They were right to report it and I was wrong to have claimed it.** I computed
the collapse by comparing the declared 76 units against **2.135 s**, and 2.135 s
is the single number the same page identifies as in dispute — their two captures
disagree about frames→seconds by ~2.9×. *Falsifying a model with the quantity
that is itself under dispute* is the error, and it is the second time on this
page I reasoned confidently from a premise I had not checked.
Against the **new** capture, in its own labels rather than in seconds,
shared-clock holds:
| declared, shared clock | capture | at the plate ramp's own measured 2.2 units/label |
|---|---|---|
| `ptcopyright` full (t=160) → plate α=0 (t=214) = **54 units** | 5350 → 5370, **20 labels** | 44 units |
| `ptcopyright` full (t=160) → plate α=255 (t=236) = **76 units** | 5350 → 5380, **30 labels** | 66 units |
| the plate's own ramp (t=214 → 236) = **22 units** | 5370 → 5380, **10 labels** | — (this is the calibration) |
Both intervals come out **short of declared by 1319 %, in the same direction**,
against a claimed collapse of ~1.7×. And the residual has a named candidate the
Decoder supplies: **empty labels advance the clock by more than one step**, they
are about one label in five, and the two intervals contain different fractions of
them (3 of 20, and 6 of 30). Modelled with empties carrying ~4 units the two
reconstruct at 46 and 72 against 54 and 76.
**So `clock: "shared"` is not falsified and the port keeps it.** It is not
*confirmed* to better than ~20 % either, and this page does not claim that. What
it is no longer is "collapsed on the port's own account".
## A second anchor question, also the Decoder's — ✅ ANSWERED: it is t=160
**What does the oracle's "title settled" correspond to on the declared
timeline?** It is defined operationally — *"glyph counter first reads its
@@ -223,8 +302,26 @@ measurement at all and `clock: "shared"` in `authored/flow.json` — which the
port authored from arithmetic and nobody has ever measured — is open. If it is
118, the reconciliation stands and H3 is not a timing defect.
**This cannot be settled here.** It is a question about what the Decoder's
instrument was looking at, and it is asked in [`BLOCKED.md`](BLOCKED.md) H3.
**Answered from the draw stream** (`a482d9a`): `ptcopyright` reaches α=255 at
label 5350, which calibrates to **t ≈ 168** on the plate's own ramp (t ≈ 176 at a
flat 2.0/label). Candidate B is 816 units away; candidate A is 5058. It is B.
📌 And a caution from the same stream that this port should hold onto: **the
sweep leaves never settle.** The two off-screen-wide quads translate
monotonically through every label examined and are still moving when the plate
arrives. *"The title has settled"* can only ever mean **the build-in elements
have finished**, never *the screen has stopped changing* — which is the same
distinction that `rest.t` keeps getting wrong.
### What is still open, and it is the only thing left
`units/second = units/frame × guest fps`. The first factor is now **2**. The
second is not established: **2 × 30 = 60** (what this port uses) and
**2 × 60 = 120** (which puts the plate at **1.97 s** instead of 3.93 s — the size
of what the human reported). The Decoder's capture ran at 27.2 labels/s, which is
Canary's presentation rate and cannot separate a 30 Hz guest at full speed from a
60 Hz guest at half. **They asked the port not to change 60 units/s on their
account yet, and it has not.** Asked in [`BLOCKED.md`](BLOCKED.md) H3.
## Refutation attempts this iteration

View File

@@ -0,0 +1,107 @@
# `verify-screen` DIFFERS on six more screens — measured, cause not settled
**Status:** 🟡 **measured, not diagnosed.** `check-all` is **red** on this and is
deliberately left red. Written 2026-09-01 by the Port at `6eccfa8` + this commit.
## What changed
`tools/port/check-all` allows `verify-screen` to report `DIFFERS` on exactly two
screens, `title` and `title_jp`, each with a per-screen reason. It now reports
eight:
| screen | max | mean | over3 | allowed? |
|---|---|---|---|---|
| `title` | 41 | 0.4431 | 4 500 | ✅ sweep phase |
| `title_jp` | 233 | 2.7715 | 65 329 | ✅ rest-pose sparkles |
| **`main_menu`** | 97 | **3.9363** | 236 149 | 🔴 |
| **`extras`** | 113 | **6.7422** | 387 419 | 🔴 |
| **`main_menu_jp`** | 26 | 0.7885 | 3 248 | 🔴 |
| **`extras_jp`** | 26 | 0.6592 | 3 163 | 🔴 |
| **`build_12`** | 17 | 0.0368 | 462 | 🔴 |
| **`build_15`** | 17 | 0.0368 | 462 | 🔴 |
## It is not this iteration's changes, and that was checked rather than assumed
The commit before this one touched `authored/flow.json` (comment fields only),
`docs/`, comments in `boot.gd`, `_film_capture`, and `check-all`. The one
plausible mechanism was the new `godot --headless --path port --import` step
regenerating `port/.godot/`.
**It cannot be that.** `ExportTree.texture()` reads each sprite as bytes and
builds it with `Image.load_png_from_buffer` + `ImageTexture.create_from_image`
the textures live outside `res://` and **never enter Godot's import pipeline at
all**, so the import cache has no path to the drawn pixels. The mechanism is
excluded structurally, not by a passing test.
## What the difference actually is
Not a moved or missing element. The `main_menu` diff covers the **whole frame**
(bounding box `1280x720+0+0`), and the transfer curve from the reference's value
to Godot's, over all 921 600 pixels and all three channels, is monotone,
**zero at both ends, and largest in the mid-to-upper range**:
```
ref 3 → 3.33 (+0.33) ref 100 → 111.38 (+11.38)
ref 20 → 21.12 (+1.12) ref 130 → 161.43 (+31.43)
ref 50 → 55.74 (+5.74) ref 158 → 227.14 (+69.14)
ref 80 → 86.60 (+6.60) ref 199 → 199.01 (+0.01) n = 8 425
ref 204 → 204.16 (+0.16) n = 1 276
ref 255 → 255.00 (+0.00) n = 8 380
```
🔴 **The rows that matter are the last three.** At 199, 204 and 255 — 18 081
pixels — the two renderers agree to **a hundredth of a level**. Those are the
opaque, unblended pixels. Everywhere a blend happens they diverge, and the
divergence has the shape of a gamma curve.
**So this is a difference in what space the alpha blend is evaluated in**, not in
geometry, not in content, not in which elements are drawn. Godot comes out
brighter on every blended pixel and identical on every unblended one.
## Which renderer moved: the port is **closer to the game**, by 16 %
Both frames scored against `docs/re/captures/title-builds/live-main-menu.png`,
cropped to the capture's 1279×675:
| | RMSE vs the live capture |
|---|---|
| Godot (`main_menu.godot.png`) | **3151.96** (0.0481) |
| `sylpheed-cli screen render` (`main_menu.ref.png`) | 3769.61 (0.0575) |
⚠️ **Read this as an ordering and nothing more.** `verify-screen` poses
`--pose=rest`, and its own header is emphatic that a `--pose=rest` frame must
never be scored against a capture — that mistake produced a published finding
once already. The absolute numbers here are contaminated by exactly that. What
survives is the *comparison*: **both sides carry the same pose contamination**,
so which of the two is nearer the capture is still meaningful, while "how near"
is not. Anyone quoting 0.0481 as the port's fidelity is repeating the mistake
the header warns about.
## Why it is left red
The `check-all` allowance carries its own warning — it was once *"a count with an
excuse"*, and the excuse was measurably false twice running. Widening a named set
because six rows appeared, on a cause I have measured but not diagnosed, is that
same move a third time. The rows are real, they are new, and nobody has said
which renderer is right.
Two facts point at a live answer rather than a stale allowance:
* **Thirteen commits touched `crates/` since the allowance was written**
(`ecd5e56`), so the reference has moved and the allowance has not been
re-derived against it.
* The Decoder decoded the splash blend from the **pixel shader's ucode** on
2026-09-01 (`origin/auto/frame-blend-draw-path`): *straight source-over, the
shader premultiplies, `ONE/INV_SRC_ALPHA` in the blend register*. That is a
statement about the equation. **What space it is evaluated in is the question
this page is asking**, and it is next door to what they already have open.
Asked in [`BLOCKED.md`](BLOCKED.md).
## What this does not claim
* That the reference is wrong. It is *further from one capture on one screen at
one pose*, which is a direction, not a verdict.
* That the port's blend is right. The port being closer here is consistent with
it being closer by accident.
* Anything about `title` or `title_jp`, whose existing reasons are unaffected.