diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 37ebc068..d4ae8eed 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -5556,3 +5556,71 @@ a defect — only as unmeasured. 45 `.rat`, 18 `.prm` and no `.tbm` at all**, and every non-primitive element has a resolvable sprite. The "draws no pixels for an unresolvable element" hazard — the shape that hid `pteff05` from both renderers — does not reach this archive. + +## `ScreenView.skipped` was correct and unread since P1 — now it says so itself + +The draw loop has always tracked what it could not draw, with the comment *"a +silently missing element looks like art"*. **Nothing ever printed it.** For eight +milestones the port could drop an element on every frame and report it to nobody. + +That is the same shape as the black hold — implemented, called, emitting nothing +until somebody filmed it — and as `verify-screen` scoring two blank frames `OK`. +A fact that needs someone to remember to look at it is a fact that goes +unnoticed, so `_note_structural` **prints from inside `ScreenView`** rather than +returning a value for a caller to surface. Routing it through a caller is exactly +what did not happen. + +Only **structural** skips are reported — `(no sprite in the export)` and +`(sprite failed to load)`. `(transparent at rest)` is ordinary animation, true of +every element at some instant, and reporting it would bury the two that mean +something under the one that never does. + +✅ **Nothing is being skipped today**: 0 across every screen, on the boot path and +per-screen. This is a guard, not a fix. The export corroborates it — no missing +sprite PNG, no element at alpha 0 on every keyframe, none at scale 0. + +### 🔴 And the first version of that scan was a false pass + +My first run reported *"0 structural skips"* on ten screens. **`screen_view.gd` +did not parse.** I had inserted a line at three tabs inside a four-tab block — +the Python `assert old in s` passed because a three-tab string is a *substring* +of a four-tab line — which orphaned a `continue`. Godot loaded nothing, printed +nothing, and `grep -c` faithfully counted zero. + +A count of zero from a dead script is indistinguishable from a count of zero from +a clean one, and I had already written the sentence claiming the clean reading. +The scan now counts the screen summary line as a **positive control**: if the +script did not run, `summary-lines=0` says so, and the zero cannot be read as a +pass. That is the third time this session that a well-formed answer to a +different question nearly became a finding. + +⚠️ Note the mechanism, because it will recur: matching indented code by substring +is unanchored, and it silently matched a *shallower* indent than the one in the +file. + +## Refutation attempt — "the element declared first paints first" + +All six of the port's forced-backdrop elements sit at **element index 0**. So on +those six screens the rule's verdict is indistinguishable from a far simpler +hypothesis I had not tested: *the first-declared element is painted first.* If +that held, `forced_backdrop` would be an elaborate way to reproduce the file's own +ordering, and my six verdicts would be no evidence for it at all. + +**It is refuted, on 8 of 16 screens.** Index 0 is *not* painted first on +`build_00`/`build_01` (position 2), `extras` (7), `title` (13), `title_jp` (18) +and — decisively — `main_menu`, where index 0 is **`pteff00`, painted last**, +position 15 of 16. `pteff00` is the Decoder's own *measured* control: the game +puts the first-declared element on top of that screen. + +So declaration order is not paint order, the six coincidences are coincidences, +and the rule is not redundant. + +⚠️ What survives as a real limitation: **those six screens, taken alone, cannot +distinguish the two hypotheses.** The evidence separating them comes from +elsewhere in the archive. Worth stating because it is the exact weakness in the +Decoder's `pfbase.tbm` upgrade — *"element 0 of the save/load frame, and the +measured order starts [0, 1, 2, …]"*. An order that equals the trivial order is +weak evidence for **any** rule, since every rule preserving declaration order +agrees with it. ✅ Their claim survives, but on evidence they did not cite: it is +`main_menu`'s `pteff00` that rules out the trivial reading, not the save/load +frame itself. diff --git a/port/scripts/boot.gd b/port/scripts/boot.gd index fbf6ffe8..f9c32bf2 100644 --- a/port/scripts/boot.gd +++ b/port/scripts/boot.gd @@ -233,6 +233,7 @@ func _ready() -> void: if _menu != null and _sequence.is_empty(): _menu_enter(name, true) + view.structural_skips.clear() var settle := view.settle_time() print("screen %s: %d elements, %d in paint order, design %dx%d, settles at t=%d (%.3f s)" % [ name, view.screen["elements"].size(), view.screen["paint_order"].size(), diff --git a/port/scripts/screen_view.gd b/port/scripts/screen_view.gd index dfdc7745..95a0028f 100644 --- a/port/scripts/screen_view.gd +++ b/port/scripts/screen_view.gd @@ -101,6 +101,19 @@ var tree: ExportTree = null var screen: Dictionary = {} var textures: Dictionary = {} var skipped: Array[String] = [] + +## Structural skips accumulated over the life of the CURRENT screen, deduplicated. +## +## 🔴 `skipped` itself is per-frame and was read by NOBODY. Its own comment says +## "a silently missing element looks like art" -- and for eight milestones +## nothing printed it, so the port could drop an element every frame and say so +## to no one. That is the same shape as the black hold, which was implemented, +## called, and emitted nothing until somebody filmed it. +## +## Only STRUCTURAL skips accumulate here. "(transparent at rest)" is ordinary +## animation -- every element is transparent at some instant -- and reporting it +## would bury the three that mean something under the one that never does. +var structural_skips: Array[String] = [] var drawn: Array[String] = [] ## Which button is highlighted, by element id. P1 leaves it empty: initial focus @@ -604,6 +617,7 @@ func _draw() -> void: var tex: Texture2D = textures.get(rel) if tex == null: skipped.append("%s (sprite failed to load)" % id) + _note_structural("%s (sprite failed to load)" % id) continue _draw_quad(tex, placement(pose, pivot, tex.get_size()), colour, pivot, pos, rot) drawn.append(id) @@ -616,3 +630,17 @@ func _draw() -> void: # A .t32 element whose sprite the exporter could not produce. Saying # so is the point -- a silently missing element looks like art. skipped.append("%s (no sprite in the export)" % id) + _note_structural("%s (no sprite in the export)" % id) + + +## Record a skip that is NOT ordinary animation, and SAY SO, once per screen. +## +## It prints from here rather than returning a value for a caller to report, +## because "the caller will report it" is precisely what did not happen: the +## per-frame `skipped` list has been correct and unread since P1. A fact that +## needs somebody else to remember to look at it is a fact that goes unnoticed. +func _note_structural(what: String) -> void: + if not structural_skips.has(what): + structural_skips.append(what) + push_warning("element not drawn: %s" % what) + print(" 🔴 element NOT DRAWN: %s" % what)