port: build the correctness harness verify-screen has pointed at since P1

`tools/port/verify-screen` line 20 has said "use `tools/verify-capture` for the
correctness question" since P1, and there was no such file. The port has had a
harness comparing itself to sylpheed-cli -- two renderers sharing its assumptions
-- and none comparing it to the game, while its own docs said otherwise. That gap
is what ORACLE-CAPTURES.md warns about: this corpus has been bitten three times
by two renderers agreeing, and every one was obvious against a capture.

Five screens against framebuffer captures of the real game:

  main_menu        RMSE 14.79   0.25% differing   focus state may differ
  extras           RMSE 15.29   0.46%             focus state may differ
  title            RMSE 21.07   1.82%             ptloop sweeps never stop
  publisher_logo   RMSE 10.77   1.00%
  developer_logos  RMSE  9.37   0.39%

NO SCREEN SHOWS A LARGE CONNECTED BLOB -- the shape a missing element makes, and
the shape all three historical failures made.

And 74.1% of main_menu's differing pixels fall inside the ORACLE'S OWN focus
signature (live-main-menu vs live-main-menu-options-focused, the same screen with
a different button lit). So the bulk of that disagreement is a state mismatch,
not a defect.

REFUTATION ATTEMPT, on ui-render-tone-curve.md's `capture = 255*(render/255)^g`.
It survives where it was measured and not past it. Binning every structurally
matched pixel by render level gives the relationship directly, and the implied
exponent is NOT constant: 1.26 at render 16, 1.10 at 32, crossing 1.0 near 44,
down to 0.69 at 96. Above ~44 the capture is BRIGHTER than the render, which one
exponent cannot express -- and that is exactly why my whole-frame fits kept
returning 1.00, the two halves cancelling. The page's own stated reach ("nothing
constrains midtones or highlights") was not a hedge, it was the finding. Its 1.49
for this screen measures 1.18-1.26 in my darks; recorded as a disagreement rather
than resolved, since they fit selected flat patches and I binned everything.

Two earlier versions of this tool reported a best-fit gamma and were wrong both
times -- once fitting across a 74% structural mismatch, once extrapolating past
the measurement's stated reach. The fix was not a better fit but a different
instrument: it prints the curve, which somebody can argue with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
Sylpheed port agent
2026-08-29 17:18:14 +00:00
parent 33bb50e80d
commit ca23a5479a
2 changed files with 218 additions and 0 deletions

View File

@@ -3667,3 +3667,84 @@ artefact would look like it worked.
Its output is **byte-identical** to the control's own stripping, so the tool and
the experiment are the same operation rather than two implementations that agree.
## The correctness harness the docs promised for eight milestones did not exist
`tools/port/verify-screen`, line 20, since P1: *"Use `tools/verify-capture` for
the correctness question."* **There was no such file.** The port has had a harness
comparing itself to `sylpheed-cli` — two renderers sharing its assumptions — and
none comparing it to the game, while its own documentation said otherwise.
`docs/re/captures/ORACLE-CAPTURES.md` is blunt about why that matters: two
renderers agreeing proves nothing, and this corpus has been bitten three times —
the dropped `pteff05` background, the scale-0 rect, `rest()` — each invisible to a
render-vs-render diff and obvious against a capture.
`tools/port/verify-capture` now exists. **Five screens, against framebuffer
captures of the real game:**
| screen | RMSE | differing | note |
|---|---|---|---|
| `main_menu` | 14.79 | **0.25 %** | focus state may differ |
| `extras` | 15.29 | 0.46 % | focus state may differ |
| `title` | 21.07 | 1.82 % | `ptloop` sweeps never stop |
| `publisher_logo` | 10.77 | 1.00 % | |
| `developer_logos` | 9.37 | 0.39 % | |
**No screen shows a large connected blob** — the shape a missing or misplaced
element makes, and the shape all three historical failures made. The differences
are scattered, and the two largest have stated causes.
### 74 % of `main_menu`'s difference is the oracle's own focus signature
The corpus ships `live-main-menu.png` and `live-main-menu-options-focused.png`
the same screen with a different button lit. Their difference *is* what focus
changes, measured by the oracle against itself. Of the port's 2 159 differing
pixels, **1 599 — 74.1 % — fall inside that signature.** So the bulk of the
disagreement is a state mismatch (the port focuses `NEW GAME`, authored, because
HANDOFF Q5 measured initial focus as unstable), not a rendering defect.
## Refutation attempt — the tone curve survives in its stated reach and not past it
`ui-render-tone-curve.md` models the relationship as
`capture = 255·(render/255)^γ`, γ ≈ 1.341.49, **measured on dark flat patches
(render ~060), with "nothing constrains midtones or highlights"** written into
its own reach.
**I tried to fit that γ and got contradictory answers three times, and the
contradictions were mine.** Binning every structurally matched pixel of
`main_menu` by render level gives the relationship directly:
| render | capture | implied γ | pixels |
|---|---|---|---|
| 8 | 4.04 | 1.20 | 183 026 |
| 16 | 7.89 | **1.26** | 227 630 |
| 24 | 15.57 | 1.18 | 100 945 |
| 32 | 26.15 | 1.10 | 87 474 |
| 40 | 38.07 | 1.03 | 86 094 |
| 48 | 53.96 | **0.93** | 85 255 |
| 64 | 78.52 | 0.85 | 6 509 |
| 96 | 130.44 | **0.69** | 1 682 |
**The claim survives where it was measured.** In the darks the capture really
is darker than the render and γ > 1.
🔴 **It is not a single power law.** The implied exponent falls monotonically and
**crosses 1.0 near render ≈ 44** — above that the capture is *brighter*. One
exponent cannot express a curve that crosses unity, which is precisely why my
whole-frame fits kept returning γ = 1.00: the darks want more than 1 and the
midtones want less, and they cancel.
**So the corpus's stated reach was not a hedge, it was the finding.** ⚠️ And the
exponent in the darks measures **1.181.26 here against the page's 1.49 for this
screen** — a disagreement I am recording rather than resolving, since they fit
selected flat patches and I binned every matched pixel.
### The tool reports the curve, not a best exponent
Two earlier versions of `verify-capture` reported a best-fit γ and were wrong
both times — once by fitting across a 74 % structural mismatch, once by
extrapolating past a reach the measurement's own authors had written down.
**Extrapolating a measurement past its stated reach is how this tool got it wrong
twice**, and the answer was not a better fit but a different instrument: a table
somebody can argue with.