re: primitive blend mode -- undecodable with reach, and no longer a risk

Looked in four places. The bundle has no field: a primitive has no RATC child at
all and the declaration words are constant across every element of three measured
screens -- the two grounds ui-prm-primitives.md already used to refute a
bundle-side LAYER key, and they apply identically to blend.

The colour census: every full-screen *eff00* primitive on the disc carries pure
black at its various alphas, and the only non-black primitive anywhere is
pbafc.prm, RGB 00e8e0 cyan.

The occlusion constraint cannot reach that one. pbafc.prm looked alarming at a
declared 844x600 and alpha ff; it is a small moving glint. It strobes between
alpha 255 and 124 every 2 units, travels from x=178 to x=291, and is scaled
2%x3%, so it draws about 17x18 pixels. At that size it occludes essentially
nothing.

The oracle is unavailable: GP_READY_ROOM is a recorded no-go and gameplay needs
the A press that faults the guest in this container.

But the consequence closes even though the question does not. For a BLACK quad
-- which is every primitive forced_backdrop touches -- the hypotheses differ only
in whether it hides what is beneath. Drawn first it is correct under both; drawn
last it is correct only under additive. So the rule's verdict is robust to the
open question, and the port's original "layerless sorts last" was wrong under
alpha-over and merely pointless under additive. This is explicitly NOT evidence
for alpha-over.

The investigation also found forced_backdrop judging coverage from the pivot
alone, ignoring scale -- pbafc.prm is the disc's own proof that a nominally
844x600 element can draw at 2%. Checked before changing anything: all 80 forced
instances are at scale 100% on every opaque instant, so no verdict moved. The
guard now requires scale >= 100 at the instants it counts as opaque. Defensive,
not a fix. 4 + 13 disc tests green either side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
sylph-decoder
2026-08-29 21:58:25 +00:00
parent 1f6e07598e
commit 29c99e1b3e
5 changed files with 186 additions and 1 deletions

View File

@@ -178,3 +178,4 @@ files, which is how the same ground got covered twice.
| [`structures/ui-clock-freezes-at-settle.md`](structures/ui-clock-freezes-at-settle.md) | The top-level clock stops at the settle point — observed in the running game | ✅ **measured**: `GP_TITLE` build 4 declares `t = 0…269`, about 120 presented frames at this run's pacing, and the dwell lasted **~1 100**. `ptcopyright` declares alpha≥1 for **106 units** (t=138…244) and is **drawn for 1 050 frames**; `ptlogo1` declares an exit at t=264 and is drawn for 1 095. Both vanish within three frames of the dwell ending. **The clock advances through the build-in, stops inside the settle window `[160,236]`, and holds; the exit ramp plays when the screen leaves, not on a timer** — [`ui-settle-time.md`](structures/ui-settle-time.md)'s decode observed from the other side. A nested record keeps looping on its own clock throughout. 🔴 **This closes the 114-vs-120 gap, and it was my arithmetic**: 2.231 units/frame was regressed over *build-in* events (the only stretch the top-level clock advances) and applied to a period measured during the freeze — two different clocks. The declared **120** was never in doubt from the calibration-free dark-fraction test. ✅ The 51.158-frame period is now confirmed by a **second independent estimator** (autocorrelation, lag 51 with harmonics at 102/154) — ⚠️ whose first version **failed its control**, returning 48, because it indexed by sample position where the log's frame numbers have gaps. ❔ The **sweeps'** period stays unmeasured: the same validated estimator disagrees between two dwells of one screen (515 vs 452 frames). 🔴 **Blocker: a single Ⓐ on the title faults the guest** — 3 attempts, 2 register dumps of 223 MB and 519 MB, against 3 no-input runs that all completed; bounds menu-side dynamic RE here, and any scripted button press needs a `canary.stdout` size guard |
| [`structures/boot-splash-dwells-are-declared.md`](structures/boot-splash-dwells-are-declared.md) | How long each boot splash is shown | ✅ **decoded**: the dwells are the bundles' own declared timelines — publisher **t=0…255 = 4.250 s**, developer **t=0…210 = 3.500 s** at 60 units/s. The corpus's independent screenshot timing over 3 cold boots gives 4.30/4.60/4.37 and **3.51/3.50/3.37** — the developer agreeing to **1.1 %**, two of its three runs to 0.3 %. 🔴 **Wall clock is the wrong unit to author**: a fresh no-input boot measured the same two dwells at **5.105.61 s** and 3.834.30 s, 1520 % longer than both the declared values and the corpus's runs, on the same disc — so a seconds figure is one run's emulator pacing. Boundaries from the draw stream: publisher wordmark frames 6119, **3 frames with no sprite drawn**, developer glows 123, wordmarks 140209, intro video 216. 🔴 **The frame→wall-clock instrument resolves to one BUFFER FLUSH, not one frame** — 69 of 125 samples showed no advance and the rest jumped 715 frames, making the apparent rate swing 0.01640.0316 s/frame; frames 119 and 123 fall in one burst, so the inter-splash gap is **not separable** by it. Quoted as brackets; sub-flush estimates withdrawn before reporting. ⚠️ `palogo_anima` never appears — almost certainly the 8-vertex cap (7 elements batched, 2 logged), the same trap as the `eff3` false negative, so it is named not reported. ❔ the publisher's 4.1 % error vs the developer's 1.1 % is unexplained |
| [`structures/ui-forced-backdrop.md`](structures/ui-forced-backdrop.md) *(colour census + self-refutation)* | What colour a keyless element is, and which forced verdicts the argument actually supports | ✅ **decoded, disc-wide**: every full-screen `*eff00*` **primitive** is **pure black** at its various alphas (`ff000000`, `7f000000`, `40000000`, `b2000000`, `cc000000`, `d4000000`, `00000000`) — exactly an alpha-over dim or fade, and an *additive* black quad would be a no-op nobody would author. The **only** non-black primitive on the disc is `pbafc.prm`, RGB `00e8e0` cyan at alphas to `ff`, and it is **844×600, not full-screen**, so outside the backdrop rule's geometry guard — ❔ it is now the sole additive candidate. 🔴 **Self-refutation: of the 80 forced-first instances only 42 are `.prm`; 38 are `.tbm` carrying fade `ffffffff`.** A *solid* white quad painted first would make the screen white and no screen is white, so a `.tbm` is a white **modulation on a texture** — and element alpha does not establish its coverage. That is the `.t32` error one extension further out: I had fixed the symptom (`el.sprite.is_some()`) not the cause, **an element's alpha is not its texture's opacity, and only an untextured primitive makes the two the same fact**. So 42 verdicts stay **decoded**, 38 drop to 🟡 (still almost certainly right — all named `*base*`, full-screen, and `pfbase.tbm`'s first position is *measured* — but on a name-and-role argument this page elsewhere calls the weaker kind). ⚠️ Code deliberately unchanged: restricting to `.prm` would send eleven screens' backgrounds back to last, the blank-screen bug the rule fixed. Split pinned by a test |
| [`structures/ui-prm-blend-mode.md`](structures/ui-prm-blend-mode.md) | Whether a primitive blends additively or alpha-over | ❔ **undecodable, with reach** — but the consequence is closed. Looked in **the bundle** (no field: the declaration words are constant and a primitive has no RATC child at all), **the colour census** (every full-screen `*eff00*` primitive is **pure black**; the only non-black primitive on the disc is `pbafc.prm`, cyan `00e8e0`), **the occlusion constraint** (inapplicable — `pbafc.prm` strobes 255/124 every 2 units, travels, and is scaled **2 %×3 %**, so it draws ~**17×18 px**, not its declared 844×600), and **the oracle** (`GP_READY_ROOM` is a recorded no-go and gameplay needs the Ⓐ that faults the guest). ✅ **Why it stopped mattering:** for a *black* quad the hypotheses differ only in whether it hides what is beneath — drawn **first** it is correct under **both**, drawn **last** only under additive. So `forced_backdrop`'s verdict is robust to the open question, and the port's original "layerless sorts last" was wrong under alpha-over and merely pointless under additive. ⚠️ This is not evidence *for* alpha-over. 🔴 The investigation found `forced_backdrop` judged coverage from the **pivot alone**, ignoring scale; checked first, **all 80 forced instances are at 100 %**, so no verdict moved and the added guard is defensive |

View File

@@ -0,0 +1,85 @@
# Primitive blend mode — narrowed to one element, and it does not matter
**Classification: undecodable, with reach.** Looked in the bundle, in the colour
census, in the occlusion constraint, and at the oracle. The question survives; its
*consequences* do not.
## The question
[`ui-prm-primitives.md`](ui-prm-primitives.md) leaves blend mode open: "a dim quad
at `0x7f000000` is presumably straight alpha over what is beneath, but the flash
(`0xf0ffffff`) and the coloured ones (`0x60ff0000`) may well be additive. Nothing
measured." [`ui-forced-backdrop.md`](ui-forced-backdrop.md) then assumed
alpha-over, so the assumption became load-bearing.
## Where I looked
**1. The bundle — nothing.** `ui-prm-primitives.md` already refuted a bundle-side
key for a primitive's *layer*, on two grounds that apply identically to blend: the
declaration entry's unread words are constant across every element of three
measured screens, and the bundle carries **no RATC child at all** for a primitive.
There is no field to read.
**2. The colour census — the population is overwhelmingly black.** Every
full-screen `*eff00*` primitive on the disc carries **pure black** at its various
alphas: `ff000000`, `7f000000`, `40000000`, `b2000000`, `cc000000`, `d4000000`,
`00000000`. The `*base*` elements are `ffffffff`. **The only non-black primitive on
the disc is `pbafc.prm`**, RGB `00e8e0` — cyan.
**3. The occlusion constraint — inapplicable to the one candidate.** `pbafc.prm`
looked alarming at a declared 844×600 and alpha `ff`. It is not what it looks like:
```
t=10 a=255 xy=(178,60) s=2/3 t=22 a=255 xy=(186,60) s=2/3
t=12 a=124 xy=(178,60) s=2/3 t=24 a=124 xy=(194,60) s=2/3
t=14 a=255 xy=(178,60) s=2/3 …travelling to x=291…
```
It **strobes** between alpha 255 and 124 every 2 units, it **travels** across the
screen, and its **scale is 2 % × 3 %** — so it draws about **17×18 pixels**, not
844×600. It is a small moving glint. At that size it occludes essentially nothing,
so the constraint that settles the backdrops cannot reach it.
**4. The oracle — not reachable.** `pbafc.prm` lives in `GP_READY_ROOM`, which
[`ready-room-probe.md`](../ready-room-probe.md) recorded as a no-go, and reaching
gameplay needs button input, which
[`ui-clock-freezes-at-settle.md`](ui-clock-freezes-at-settle.md) records as
faulting the guest in this container.
## ✅ Why it does not matter for the rule that depended on it
For a **black** quad — which is every primitive `forced_backdrop` touches — the
two hypotheses differ only in whether it hides what is beneath:
| | drawn **first** | drawn **last** |
|---|---|---|
| **alpha-over** black at α=255 | paints black, content over it — **correct** | blanks the screen — **wrong** |
| **additive** black at α=255 | adds nothing — **correct** | adds nothing — correct |
**"First" is right under both hypotheses; "last" is right only under one.** So the
forced-backdrop rule's *verdict* is robust to the blend question even though the
question is open — and the port's original "layerless sorts last", which produced
solid black on `build_12`/`build_15`, is wrong under alpha-over and merely
pointless under additive.
⚠️ **This is not evidence that the blend is alpha-over.** It is the reason the
open question stops being a risk. `pbafc.prm` remains genuinely unknown, and it is
the only element on the disc where the answer could change a pixel.
## 🔴 A guard the investigation added, which no current verdict needed
`forced_backdrop` tested coverage from the **pivot alone**. `pbafc.prm` is the
disc's own proof that scale can shrink a nominally full-screen element to 2 %.
Checked before changing anything: **all 80 forced instances are at scale 100 % on
every opaque instant**, so no verdict moved. The guard now requires
`scale_x >= 100 && scale_y >= 100` at the instants it counts as opaque — a guard
against data not yet met, not a fix. 4 + 13 disc tests green either side.
## Reach
⚠️ The colour census covers keyless elements. A **sprite**'s blend is a separate
question, and `T8aD +0x04` bit `0x02` was already refuted as an additive flag.
`pbafc.prm` is unsettled and would need either a `GP_READY_ROOM` capture or a
blend-state read from Canary, neither of which is available here.