diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 6140ff3d..67cfab20 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -321 sections. Search this before re-deriving anything. +322 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) @@ -332,6 +332,7 @@ dies, which is what this file is for. * [They have taken the relay finding, and it now has a direction](#they-have-taken-the-relay-finding-and-it-now-has-a-direction) * [The independent pair was an accident — the rule that would make it deliberate](#the-independent-pair-was-an-accident--the-rule-that-would-make-it-deliberate) * [A workflow defect of mine, on its fourth occurrence](#a-workflow-defect-of-mine-on-its-fourth-occurrence) +* [The menu residual, decomposed — and half of 13.06 is tone](#the-menu-residual-decomposed--and-half-of-1306-is-tone) ## P0 — the exporter, 2026-08-28 @@ -15625,3 +15626,49 @@ an iteration of authored-data edits across `audio.json`, `flow.json`, `main_menu` 13.21, `extras` 13.38, `title` 14.16. **Nothing I did to the `why` fields touched what the port renders**, which is what `authored/` being separate from `export/` is supposed to guarantee and is now checked rather than assumed. + +## The menu residual, decomposed — and half of 13.06 is tone + +`verify-capture`'s header has said for weeks that *"RMSE is reported and is NOT a +target: the capture carries the game's own tone ramp, so it has a floor."* **The +floor has never been measured.** The splash residual was localised in detail; the +menu's — the port's most-quoted number — never was. + +| | luma RMSE | +|---|---| +| `main_menu` render vs capture, aligned | **10.60** | +| after fitting one monotone transfer curve | **4.77** | +| **removed by tone alone** | **55 %** | +| ⚠️ control: same fit, menu render vs the **EXTRAS** capture | 28.92 → 20.98, **27 %** | + +📌 **The control is what makes the 55 % mean anything.** A fitted curve always +removes *something* — on an unrelated pair it removes 27 %. Twice that on the +matched pair, so the tone difference is **real and specific**, not the fit +absorbing variance. + +**So roughly half the menu residual is a tone/gamma difference between the port's +render and the captured surface, and half is not.** The fitted curve is an +S-shape rather than a gain — 64→72 brightens, 128→119 and 192→184 darken — which +is the shape of an output pipeline, not of a wrong colour. + +⚠️ **What this does NOT do, and I am not going to do it:** identify which side is +wrong, or "fix" the tone. The mission's instruction is explicit — *say which is +wrong rather than tuning until they match* — and I cannot say which. The capture +carries the emulator's output path; the render carries Godot's. **Nothing in the +port changes on the strength of this.** What changed is that a number quoted for +weeks now has a decomposition and a bound: **4.77 of it is not tonal**. + +### 🔴 And my first attempt at it was misaligned in exactly the documented way + +Before this I ran a raw full-frame comparison and got *"75.6 % of pixels differ, +uniformly across the frame"* — a nonsense result, because **the capture is +1279×675 and the render is 1280×720**. `verify-capture` handles that in a comment +I had read: *"the captures are a 1279×675 top-left crop of the guest surface, so +the render is cropped to match and nothing is scaled."* + +📌 **I bypassed the harness that encodes the correction and reproduced the +uncorrected error.** Same shape as the week: the instrument existed, its comment +said why, and I reached past it for a quicker check. The tell was that the answer +was **uniform** — a residual spread evenly over an entire frame is a comparison +fault, not a rendering one, and that is the reading I should have applied before +the dimensions.