port: the loading screens are no longer black -- it was the paint order

verify-screen's header has said since P1 that build_12/build_15 render pure black
in both renderers, with an open question whether that was the port's bug or the
decoders' reading of rest. Measured today: max 214.5 on both sides, mean 1.949
port against 1.918 reference. Not blank, and they agree.

It was the paint order. My own earlier measurement had already answered it and I
had not connected them: removing the forced-backdrop pass makes the first element
pgloading_loop5 and the black screen returns. pgloading_eff00 carries layer: null,
layer_source: none -- the only elements in the export with neither a read nor an
implied key -- so its position rests entirely on the occlusion constraint.

The guard stays, with the stale paragraph kept as history. It was right when
written, and a guard that stops firing is the kind that rots out of a tool.

Refutation attempt on the Decoder's census scope: my six transient
ptlogo_back2eff* on title are also GP_TITLE, so if they 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, so the fallback never
runs. The two censuses differ in scope, not in fact.

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-30 12:14:43 +00:00
parent f486aac4b9
commit 779191daa4
2 changed files with 64 additions and 1 deletions

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 --> <!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
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) * [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) * [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) * [🔴 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) * [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) * [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)
<!-- /INDEX --> <!-- /INDEX -->
## P0 — the exporter, 2026-08-28 ## 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 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 agrees with every capture it has. The number bounds what would break the day
anything scored a `rest` frame against an oracle. 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.

View File

@@ -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 # 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. # 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 # 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 # 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 # pass either, and `status` is left alone so an unrelated screen's DIFFERS is