diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index b5be29b5..63c1286a 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -151 sections. Search this before re-deriving anything. +152 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) @@ -162,6 +162,7 @@ dies, which is what this file is for. * [🔴 CORRECTION: the port did not move away from the game — I scored the wrong frame](#correction-the-port-did-not-move-away-from-the-game--i-scored-the-wrong-frame) * [The `rest()` flash defect reaches four screens I ship — and the port already survives it](#the-rest-flash-defect-reaches-four-screens-i-ship--and-the-port-already-survives-it) * [Correction: those two are the *sound* path, which makes the rule stronger](#correction-those-two-are-the-sound-path-which-makes-the-rule-stronger) +* [The two loading screens are no longer black, and it was the paint order](#the-two-loading-screens-are-no-longer-black-and-it-was-the-paint-order) ## P0 — the exporter, 2026-08-28 @@ -8804,3 +8805,51 @@ eight — both titles, both splashes and their region twins, and both loading screens. ✅ None of it reaches shipped output: the port poses `pose_at(hold)` and agrees with every capture it has. The number bounds what would break the day anything scored a `rest` frame against an oracle. + +## The two loading screens are no longer black, and it was the paint order + +`verify-screen`'s header has carried, since P1, that `build_12` and `build_15` +*"render as pure black in BOTH renderers, mean 0 and max 0"*, with an open +question: *"whether that is the port's bug or the decoders' reading of `rest`"*. + +✅ **Both halves are now settled, and the answer is neither.** Measured today: + +| | max | mean | +|---|---|---| +| port | 214.5 | 1.949 | +| reference | 214.5 | 1.918 | + +Not blank, on either side, and the two agree — the rows read `OK` on a real +comparison rather than on nothing-against-nothing. + +🔴 **It was the paint order, not `rest`.** My own earlier measurement had already +answered it and I had not connected the two: removing the forced-backdrop pass +makes these screens' first element `pgloading_loop5`, *"and the black screen +returns"*. `pgloading_eff00` is the full-frame opaque untextured quad, and it +carries `layer: null`, `layer_source: none` — the only elements in the export with +neither a read nor an implied key. Its position rests entirely on the occlusion +constraint. The rule that fixed it is the one the Decoder supplied and I +implemented this session. + +⚠️ **The guard stays and the stale paragraph stays with it**, marked as history. +It was correct when written — two of sixteen rows were reporting this script's +strongest verdict for comparing nothing against nothing — and a guard that stops +firing is exactly the kind that rots out of a tool. A reader who hits a blank pair +tomorrow needs the reasoning, not just the verdict. + +### Refutation attempt: does the Decoder's census miss my title screens? + +Their `GP_TITLE` census is *"5 fires, 4 visible, all four on the splash screens"*. +My own census found six transient `ptlogo_back2eff*` elements on `title` and seven +on `title_jp` — also `GP_TITLE` builds. If those were fallback fires, their count +of four would be wrong. + +✅ **Their claim survives.** All six reach `rest` by the **plateau** path — alpha +255→255 with identical `pos` *and* `scale` across the pair — so `rest_plateau()` +handles them and the dwell fallback never runs. They are not fires. + +📌 Which is their own point back at them, now with my screens as evidence: my +census counts a **superset spanning both paths**, and the difference between the +two numbers is not disagreement but scope. A plateau that happens to sit on a +transient's peak is invisible to a fallback census and still produces a rest frame +the game never shows. diff --git a/tools/port/verify-screen b/tools/port/verify-screen index cc0a4fd9..df92f5f0 100755 --- a/tools/port/verify-screen +++ b/tools/port/verify-screen @@ -202,6 +202,20 @@ print(json.load(open("export/"+f))["source"]["build"])' "$name") # is the port's bug or the decoders' reading of `rest` is open; what is not # open is that a blank pair may not be scored. # + # ✅ RESOLVED 2026-08-30, AND THE PARAGRAPH ABOVE IS NOW HISTORY. It was the + # PAINT ORDER, not `rest`. `pgloading_eff00` carries `layer: null`, + # `layer_source: none` -- the only elements in the export with neither a read + # nor an implied key -- so without the forced-backdrop pass the first element + # becomes `pgloading_loop5` and the opaque quad paints over everything. With + # the pass, both screens render at max 214.5 in BOTH renderers (mean 1.949 + # port, 1.918 reference) and the rows read `OK` on a real comparison. + # + # ⚠️ The guard STAYS. It is not firing today, which is exactly when a guard + # quietly rots -- and it was right when it was written: two of sixteen rows + # were comparing nothing against nothing and reporting this script's + # strongest verdict. Leaving the reasoning above intact is deliberate; a + # reader who hits a blank pair tomorrow needs it. + # # So blankness is checked FIRST and reported as its own verdict. It is not a # failure -- the port may legitimately have nothing to draw -- but it is not a # pass either, and `status` is left alone so an unrelated screen's DIFFERS is