port: discriminate the blend -- additive halves alpha-over's error on both frames

Last iteration could say the shortfall scales with the background but not which
curve. That is decidable with no RE: an element rendered over two different
backgrounds gives two equations in a and aC, and the mod tree supplies the second
background by suppressing pteff10/pteff12, which moves it by a mean of 26 levels.
No placement, no coordinate transform, no texture decode assumed.

The control is exact. Alpha-over rebuilt from the solved per-pixel a and aC
reproduces the port's own render at RMSE 0.0000 on both screens, so the recovered
values are right rather than a fit that lands nearby.

RMSE against the capture, ptframe1 / ptframe3:
  additive     34.305 / 28.948
  screen       50.052 / 50.368
  alpha-over   65.046 / 71.299   <- what the port does
  not drawn    90.916 / 109.801

Same ordering on both. The frame is certainly drawn in the capture, and additive
roughly halves the error of what the port currently does.

What it is not: additive still leaves 28.9-34.3, so none of the three reproduces
the capture. This ranks candidates, it does not identify the equation, and the
absolutes are inflated by mapping the capture through the fitted LUT inverse --
the ranking is fair because all four go through the same mapping.

Nothing adopted. The Decoder established no blend is on the disc for .t32, so any
choice is authored, and the mission says propose rather than take. The renderer is
unchanged.

Refutation attempt, recorded as surviving: their kind-0 claim checked against my
own exporter's independently decoded kind_raw. Every sprite decoration on both
screens is 0x0, frames included, every button 0x3002. Two independent decodes
agree, which is also what makes the blend question sharp -- the frames are declared
identically to ptbase and pteff05, which the port draws at 1.31x and 0.92x.
This commit is contained in:
Sylpheed port agent
2026-08-31 05:45:21 +00:00
parent b6a4a079f9
commit 0a054d681b

View File

@@ -9,7 +9,7 @@ dies, which is what this file is for.
<!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
328 sections. Search this before re-deriving anything.
330 sections. Search this before re-deriving anything.
* [P0 — the exporter, 2026-08-28](#p0--the-exporter-2026-08-28)
* [P1 — Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28)
@@ -339,6 +339,8 @@ dies, which is what this file is for.
* [The residual map: no local displacement either, and the split I expected is not there](#the-residual-map-no-local-displacement-either-and-the-split-i-expected-is-not-there)
* [Suppression beats coordinates: the menu residual is two frame elements, drawn too dark](#suppression-beats-coordinates-the-menu-residual-is-two-frame-elements-drawn-too-dark)
* [The frames generalise, premultiplied alpha is refuted, and the shortfall tracks the background](#the-frames-generalise-premultiplied-alpha-is-refuted-and-the-shortfall-tracks-the-background)
* [Which blend? Additive halves the error, on both frames — proposed, not adopted](#which-blend-additive-halves-the-error-on-both-frames--proposed-not-adopted)
* [Refutation attempt: the Decoder's kind-0 claim survives, checked from my own data](#refutation-attempt-the-decoders-kind-0-claim-survives-checked-from-my-own-data)
<!-- /INDEX -->
## P0 — the exporter, 2026-08-28
@@ -16013,3 +16015,73 @@ they locate the remaining question rather than closing it.
⚠️ Not settled: whether it is additive, screen, or something else — `+0.77` and
`+0.80` say "scales with the background", not which curve. Two screens; I have not
checked the title.
## Which blend? Additive halves the error, on both frames — proposed, not adopted
Last iteration ended with *"`+0.77` and `+0.80` say 'scales with the background',
not which curve."* That is decidable without any RE, because **an element rendered
over two different backgrounds gives two equations in `a` and `aC`**:
```
base - bg = a(C - bg ) the frame over background 1
b2 - bg2 = a(C - bg2) the same frame over background 2
--------------------------------------------------------------
a = [(base-bg) - (b2-bg2)] / (bg2 - bg) aC = (base-bg) + a·bg
```
Both backgrounds are produced by the mod tree — suppress `pteff10`/`pteff12` and
the background under the frame changes by a mean of 26 levels. **No placement, no
coordinate transform, no texture decoding assumed.**
### ✅ The control is exact, and it is what makes the rest usable
Rebuilding **alpha-over** from the solved `a` and `aC` reproduces the port's actual
render at **RMSE 0.0000** on both screens. The recovered per-pixel values are
right; they are not a fit that happens to land nearby.
### The result, replicated
RMSE against the capture, all four candidates mapped the same way:
| composite | `ptframe1` (`main_menu`) | `ptframe3` (`extras`) |
|---|---|---|
| **additive** | **34.305** | **28.948** |
| screen | 50.052 | 50.368 |
| **alpha-over — what the port does** | **65.046** | **71.299** |
| frame not drawn at all | 90.916 | 109.801 |
📌 **Same ordering on both, and additive roughly halves alpha-over's error.** The
frame is definitely drawn in the capture (absent is worst by a wide margin), and
of the three standard composites additive is the only one that closes most of the
gap. Solved on 1 743 and 1 999 pixels; median `a` 0.429 and 0.594.
### ⚠️ What this is not
**Additive is not established as the answer.** It still leaves 28.934.3, so
*none* of the three reproduces the capture — this ranks three candidates, it does
not identify the equation. The absolutes are inflated by mapping the capture
through the fitted LUT's inverse; the **ranking** is fair because all four
candidates go through the same mapping, and the ranking is the claim. Grayscale
only.
🔴 **And I have not adopted it.** The Decoder established that nothing on the disc
selects a blend for `.t32`, so any blend the port picks is **authored** — and
`PORT-MISSION`'s rule is that a runtime dependency is *proposed*, not taken on my
own authority. The renderer is unchanged. What exists now is a measurement that
says: alpha-over is wrong here, additive is much closer, and the choice is a
human's.
## Refutation attempt: the Decoder's kind-0 claim survives, checked from my own data
They reported both frames as **kind 0, identical to `ptbase`, `pteff05`, `pteff10`,
`pteff12` and `ptmsg`** — read off the 60-byte `.t32` declaration.
My exporter decodes that field independently and stores it as `kind_raw`. Every
sprite decoration on both screens is `0x0` — `ptframe1`…`ptframe4` included — and
every button is `0x3002`. ✅ **Survives.** Two independent decodes of the same
field agree, and the claim is now stronger than when only one side had read it.
📌 That matters because it is what makes the blend question sharp: the frames are
declared *identically* to `ptbase` (drawn at 1.31× the frame mean) and `pteff05`
(0.92×). Same declaration, opposite accuracy — so whatever distinguishes them is
not in the field either of us can read.