port: the additive-capable reference collapses the divergence 6x, measured at the tag

The Decoder taught `ui_layout::blit` the additive blend at
formats-pin-2026-09-01b, on the argument this port made: the comparison was
structurally incapable, and the refutation keeping additive out was
⟨render-vs-capture⟩ -- that renderer disagreeing with itself while it had a stale
keyframe association, no leaf geometry and no rotation.

MEASURED WITHOUT PULLING THEIR BRANCH INTO MINE: a detached worktree at the tag,
sylpheed-cli built there, verify-screen pointed at it through SYLPHEED_CLI. My
branch is untouched and the reference on `main` is unchanged.

Pre-registered: the diffs caused by the gap should collapse, and whatever remains
is a different cause.

  main_menu     7.2580 max 105  ->  1.2068 max 28   6.0x
  main_menu_jp  7.3440 max 108  ->  1.2111 max 31   6.1x
  extras        6.9757 max 113  ->  1.0229 max 28   6.8x
  extras_jp     7.0734 max 115  ->  1.0255 max 30   6.9x
  title         1.0335 max  88  ->  0.5685 max 41   1.8x
  title_jp      4.4944 max 233  ->  2.8225 max 233  1.6x
  build_12/15   0.0772 max  60  ->  0.0463 max 17   1.7x
  build_00/01   0.0676 max  60  ->  0.0366 max  4   DIFFERS -> OK

build_00 and build_01 stop differing entirely, over3 3422 -> 0.

And the twins agree to a third of a percent: main_menu 1.2068 vs main_menu_jp
1.2111 (0.36 %), extras 1.0229 vs extras_jp 1.0255 (0.25 %). Under the name-keyed
map those pairs were 4.1x and 7.8x apart. Nothing was fitted -- they converged
once when the PORT took the decoded field and again now that the REFERENCE draws
the same blend.

The residual is smaller and its causes are the documented ones: title_jp 2.82 is
the --pose=rest sparkle handling, title 0.57 the ptloop sweep phase, both
untouched by any of this. main_menu/extras and twins sit at ~1.0-1.2 max ~28-31,
new and undiagnosed -- additive was the dominant cause, not the only one. And
build_12/15 do NOT return to their pre-change 0.0368, so pgloading_loop5 carries a
small residual of its own beyond the blend. Recorded, not chased.

🔴 THE ALLOWANCE SHOULD NARROW AND HAS NOT, ON PURPOSE. Its justification is gone,
but check-all builds the reference from the WORKSPACE crate and the additive path
is at a tag, not on `main`. Narrowing now would turn check-all red against a
reference that still cannot draw additive -- a wall of failures meaning one thing,
which is the defect the display guard exists to prevent. The trigger is written
into the script so it does not rot: when `grep -q additive
crates/sylpheed-formats/src/ui_layout.rs` succeeds, drop the export-derived clause
and keep the two named legacy rows. The set that should then differ is measured
above.

H5 confirmed from the other side. And a trap worth carrying: the Decoder nearly
reported my H5 claim as a contradiction because `loop5` is not a sprite -- it is
an ELEMENT, pgloading_loop5.rat, resolving to sprite pgloading_ring.t32. Any
census keyed by sprite name will miss it.

Not settled: the ~1.0-1.2 residual on the menus; pgloading_loop5's own residual;
finding 3, where the Decoder is taking the clock origin; and the 8 claims R1 has
re-opened against ⟨render-vs-capture⟩, including BOTH legs of the rest() pair
that this port's settle behaviour rests on.

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 19:09:03 +00:00
parent c01580740e
commit 94e44b5ba4
3 changed files with 98 additions and 9 deletions

View File

@@ -171,7 +171,7 @@ submitted per frame.
| # | ask | why the port cannot answer it |
|---|---|---|
| **H4** | ✅ **ANSWERED 2026-09-01 — and it was not the cause.** The game blends in the **encoded** space: `RB_COLOR_INFO.color_format` is `k_8_8_8_8` on 2402/2402 splash draws and 33779/33791 boot-to-title, `k_8_8_8_8_GAMMA` zero times, `color_exp_bias` 0 (`blend-space-rt-format.txt`). | 🔴 **My premise was wrong and the answer exonerates everybody.** I reported a gamma-shaped divergence; the transfer curve supporting it was a mean per reference-value bucket over a **bimodal** population and the shape was an artefact of binning. Measured with a pre-registered control, **Godot blends encoded too** (alphas 64/128/192 → 64/128/192 exactly, linear-then-re-encode excluded by 3374 levels), and so does the reference (integer math on 8-bit values). All three agree; no change needed anywhere. **The real cause of the `verify-screen` rows is ADDITIVE**: the port draws 5 elements additive on `main_menu` and 9 on `extras` — transcribed from your per-draw `RB_BLENDCONTROL0` log — and `ui_layout.rs` has no additive path at all. The divergence tracks the set size (9 → 6.74, 5 → 3.94, 0 → ~0.7). See [`verify-screen-blend-divergence.md`](verify-screen-blend-divergence.md). |
| **H5** | ✅ **CLOSED 2026-09-01 — it was ADDITIVE all along, and the decoded blend answered it as a side effect.** `pgloading_loop5` — the element I had localised all 951 differing pixels to — carries `blend_additive: true`, and `ui_layout.rs` has no additive path, so the reference cannot reproduce that draw by construction. `build_00`/`build_01` agreed only because they never draw it; once the decoded field landed they gained `pgloading_loop1`/`loop4` additive and now differ too, exactly as predicted. | The `main_menu_jp` and `extras_jp` rows are answered by the same change. 🟢 **And the strongest corroboration of the decoded field came from these rows, unfitted:** the EN/JP twins were 4.1× and 7.8× apart under the name-keyed map and are now **1.1 % and 1.3 %** apart (`main_menu` 7.26 vs 7.34, `extras` 6.98 vs 7.07). A disc-wide field predicts locale twins render identically; a screen-name map cannot. |
| **H5** | ✅ **CLOSED, and now confirmed from the other side too.** `pgloading_loop5` is additive, which is why `build_12`/`build_15` differed and `build_00`/`build_01` did not — the latter never draw it. With the reference taught the additive blend (`formats-pin-2026-09-01b`) **`build_00`/`build_01` go DIFFERS → OK** (`over3` 3422 → 0) and `build_12`/`build_15` fall 0.0772 → 0.0463. | ⚠️ They do **not** return to their pre-change 0.0368, so `pgloading_loop5` carries a small residual of its own beyond the blend — recorded, not chased. 📌 The Decoder nearly reported my H5 claim as a contradiction because `loop5` is not a sprite: it is an **element**, `pgloading_loop5.rat`, resolving to sprite `pgloading_ring.t32`. **The element/sprite name split is a trap for any census keyed by sprite name** — worth knowing before writing one. |
| **H6** | ✅ **CLOSED — and my counter-example FAILED, which is the honest outcome.** The blend map is deleted; the exporter emits `blend_additive` per element from `T8aD +0x04` bit `0x02`. | ❌ I reported `pteff10` as a possible counter-example. **It is not** — the oracle measures it additive on `main_menu` in all three menu sessions, every frame, and my premise was a stale coverage table sitting upstream of its own correction. **I treated a summary as the log.** The 10.88 → 13.02 is characterised rather than excused: max difference **32 levels** over 36 % of the frame, zero pixels past 60 — broad and shallow, which is what moves an **area-weighted** RMSE 20 % while being invisible to an eye. Not excluded from the metric, deliberately: the reason to exclude turned out to be false. See [`blend-decoded-adoption.md`](blend-decoded-adoption.md). |
| **H7** | ✅ **CLOSED 2026-09-01 — WITHDRAWN BY THE DECODER, same day.** `splash-rate-withdrawn.md` / `1e7343e`: *"WITHDRAW 'the unit rate is per-GamePart' — it was the emulator's frame rate"*, and the section carrying it is struck. §1 of `splash-declared-vs-captured.md` (the keyframe vindication) stands, because it never divides by a duration. | The port never moved, so nothing had to be undone. The refutation is kept in [`splash-rate-contradiction.md`](splash-rate-contradiction.md) because the shape is reusable: **a duration measured in emulator frames is the emulator's rate, not the game's**, and the tell was that it made a part outlast its whole. `keyframe_units_per_second` remains **60**, now unchallenged on the splashes. |

View File

@@ -1,7 +1,8 @@
# `verify-screen` DIFFERS on six more screens — it is ADDITIVE, and the port is ahead of the reference
**Status:****diagnosed for `main_menu` and `extras`**, 🟡 **open for four
others.** `check-all` stays **red**, on the four. Port `HEAD` `da7864e` + this
**Status:****RESOLVED.** The reference gained an additive path
(`formats-pin-2026-09-01b`) and the divergence this page is about collapses **6×**.
Everything below stands; the last section is the measurement that closes it. Port `HEAD` `da7864e` + this
commit; HANDOFF at `9ca1eb5`.
> 🔴 **This page said, in its first version, that the cause was a blend-SPACE
@@ -324,3 +325,77 @@ in this corpus recorded which one produced a diff, and for eight months there wa
only one so it never mattered. Any diff quoted from here on should say what drew
it — the same discipline `TEMPORAL-VERIFICATION.md` already demands for capture
rate, applied to the thing that rasterises rather than the thing that clocks.
---
# ✅ Closed: the reference can draw additive now, and the divergence collapses 6×
The Decoder taught `ui_layout::blit` the additive blend at
`formats-pin-2026-09-01b`, on the argument this page made — that the comparison
was **structurally incapable**, and that the refutation which had kept additive
out was `⟨render-vs-capture⟩`, i.e. that renderer disagreeing with itself while
it had a stale keyframe association, no leaf geometry and no rotation.
**Measured without pulling their branch into mine**: a detached worktree at the
tag, `sylpheed-cli` built there, and `verify-screen` pointed at it through
`SYLPHEED_CLI`. My branch is untouched and the reference on `main` is unchanged.
## Pre-registered (R2)
> With the reference finally able to draw additive, the diffs caused by that gap
> should collapse. `main_menu`/`extras` and their JP twins should fall sharply
> from ~7, and whatever remains is a *different* cause.
| screen | alpha-over reference | **additive reference** | factor |
|---|---|---|---|
| `main_menu` | 7.2580, max 105 | **1.2068, max 28** | **6.0×** |
| `main_menu_jp` | 7.3440, max 108 | **1.2111, max 31** | **6.1×** |
| `extras` | 6.9757, max 113 | **1.0229, max 28** | **6.8×** |
| `extras_jp` | 7.0734, max 115 | **1.0255, max 30** | **6.9×** |
| `title` | 1.0335, max 88 | **0.5685, max 41** | 1.8× |
| `title_jp` | 4.4944, max 233 | **2.8225, max 233** | 1.6× |
| `build_12` / `build_15` | 0.0772, max 60 | **0.0463, max 17** | 1.7× |
| `build_00` / `build_01` | 0.0676, max 60 | **0.0366, max 4** | **DIFFERS → OK** |
**`build_00` and `build_01` stop differing entirely** — `over3` 3 422 → **0**.
## And the twins agree to a third of a percent
| | |
|---|---|
| `main_menu` 1.2068 vs `main_menu_jp` 1.2111 | **0.36 % apart** |
| `extras` 1.0229 vs `extras_jp` 1.0255 | **0.25 % apart** |
Under the name-keyed map these pairs were 4.1× and 7.8× apart. Nothing was fitted
to make that happen — the locale twins converged first when the *port* took the
decoded field, and again now that the *reference* draws the same blend.
## The residual is smaller and its causes are the documented ones
* `title_jp` 2.82 at max 233 remains the largest, and its named reason —
`--pose=rest` sparkle handling — is untouched by any of this.
* `title` 0.57 at max 41 is the `ptloop` sweep-phase residual, also untouched.
* `main_menu`/`extras` and twins now sit at ~1.01.2, max ~2831. **New, small,
and undiagnosed** — additive was the dominant cause and not the only one.
* `build_12`/`build_15` do **not** return to their pre-change 0.0368: they land at
0.0463 with both renderers drawing `pgloading_loop5` additive. So that element
carries a small residual of its own beyond the blend.
## 🔴 What must happen to `check-all`, and why it has NOT happened yet
The allowance widened when the reference could not draw additive. **That
justification is gone**, so the allowance should be narrowed back and the check
should regain its teeth.
**It is not narrowed in this commit, deliberately.** `check-all` builds the
reference from the **workspace** `crates/sylpheed-formats`, and the additive path
is at a tag that has not landed on `main`. Tightening now would turn `check-all`
red against a reference that still cannot draw additive — a wall of failures
meaning one thing, which is the exact defect the display guard was added for.
**The trigger is mechanical**: when the additive path is on `main`, drop the
export-derived clause and leave the two named legacy rows. The set that should
then differ is measured above and is `title`, `title_jp`, `main_menu`, `extras`,
`main_menu_jp`, `extras_jp`, `build_12`, `build_15` — with `build_00`/`build_01`
expected to pass.

View File

@@ -198,12 +198,26 @@ differs=$(grep -c DIFFERS "$OUT/verify-screen.log" || true)
# excused if it happens to carry an additive element anywhere, and this check
# will not say so.
#
# 📌 THE REAL FIX IS NOT HERE. `verify-screen` compares two renderers and one of
# them cannot express a blend mode the disc declares, so the comparison is
# structurally incapable on 12 screens. Giving `ui_layout.rs` an additive path
# would make it meaningful again -- that is the Decoder's crate and their
# refutation of additive predates the RB_BLENDCONTROL0 measurement that overturned
# it, so it is PROPOSED here and not done.
# THE REAL FIX HAS LANDED -- AT A TAG, NOT YET ON `main`, WHICH IS WHY THIS
# CLAUSE IS STILL HERE. `ui_layout::blit` draws additive as of
# formats-pin-2026-09-01b, so the comparison is capable again and this widening
# has lost its justification.
#
# Measured at that tag, in a detached worktree, with SYLPHEED_CLI pointed at it:
# main_menu 7.26 -> 1.21, extras 6.98 -> 1.02, both JP twins likewise, and
# build_00/build_01 go DIFFERS -> OK (over3 3422 -> 0). A 6x collapse.
#
# 🔴 NOT NARROWED YET, AND ON PURPOSE. This script builds the reference from the
# WORKSPACE crate, and the additive path is not on `main`. Narrowing now would
# turn check-all red against a reference that still cannot draw additive -- a
# wall of failures meaning one thing, which is the defect the display guard above
# exists to prevent.
#
# TRIGGER, so this does not rot: when `grep -q additive crates/sylpheed-formats/src/ui_layout.rs`
# succeeds, delete the export-derived clause and keep only `-e title -e title_jp`.
# The set that should then differ is measured in
# docs/port/verify-screen-blend-divergence.md: title, title_jp, main_menu, extras,
# main_menu_jp, extras_jp, build_12, build_15 -- and build_00/build_01 pass.
additive_screens=$(python3 -c "
import json, glob, os
out = []