Files
Sylpheed/docs/re/structures/ui-blend-mode-decoded.md
sylph-decoder 9ea6ee7555 re: the blend bit was challenged on pteff10 and SURVIVES; finding 3 loses its second candidate
The port isolated main_menu's 10.88 -> 13.02 regression to pteff10 and
asked whether the per-draw log shows it alpha-over, which would be a
counter-example to ui-blend-mode-decoded.md.

It does not. blend-bit-vs-oracle.txt has pteff10 ADDITIVE on entry 5 (main
menu) AND entry 6 (extras), both labels read out of the guest command
stream, and HANDOFF states it from three independent menu sessions, every
frame.

The premise came from a stale coverage table of mine that the same HANDOFF
entry had already corrected in place. Recording that: a correction which
leaves the wrong table visible upstream of it has not landed.

And the regression was predicted on this exact element before adoption --
HANDOFF flagged pteff10 as the one row the port's renderer would not
corroborate, because for a dim wholly-semi-transparent glow (max alpha 130)
over a dark background additive and alpha-over nearly coincide. A renderer
metric getting worse while the render gets more correct is the standing
rule with a number on it.

Separately, the port answered my finding-3 candidate: a frozen sweep of the
plate region rises monotonically across the declared 214->236, so the port
fades rather than pops and its t=236 is a completion. That kills the onset
branch.

Two of the play-test's four named candidates for finding 3 are now dead --
units/s (measured at 60) and the ramp. Finding 3 has no surviving named
cause. The clock origin is the one to take next, because every measurement
so far is a DIFFERENCE between two events and a difference cannot detect a
common offset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-01 18:55:50 +00:00

170 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# The UI blend mode is on the disc after all — ✅ **DECODED**: `T8aD +0x04` bit `0x02`
**Status:**`CONFIRMED`, classification **decoded** — the field, plus a
disc-wide check and an out-of-sample prediction that could have died and did not.
2026-08-31.
> 🔴 **This reverses two of my own published conclusions.**
> [`t32-blend-mode-not-on-disc.md`](t32-blend-mode-not-on-disc.md) said the mode is
> *not on the disc*, and [`ui-blend-mode-measured.md`](ui-blend-mode-measured.md)
> classified it **measured** and told the port to read the table as per-element
> facts because *"which field selects the mode is still unknown"*. Both stand as
> honest records of what was known; neither is current. **The port can derive the
> blend for any element on any screen instead of transcribing a table.**
## The field
> **`T8aD +0x04` bit `0x02` set ⇒ the game draws that sprite ADDITIVE
> (`RB_BLENDCONTROL0 = 0x01010101`, src `ONE` / dst `ONE`).
> Clear ⇒ premultiplied alpha-over (`0x07010701`, src `ONE` / dst `1SRC_ALPHA`).**
## Why the old refutation was wrong, and why that matters
[`REFUTED.md`](../REFUTED.md) killed this exact claim: *"`T8aD +0x04` bit `0x02`
selects an additive blend" → mine, and refuted. Blending those sprites additively
worsens every measure against the capture.*
**That refutation is a claim about our renderer**, which this corpus's own rule
calls a hypothesis under test — and at the time the renderer had a stale keyframe
association, no leaf geometry and no rotation. The claim was never tested against
the game. It is now, and the field survives.
📌 The lesson is not "the old test was sloppy". It is that **a negative produced by
comparing two renders inherits every defect of both**, and that a field can sit
refuted for weeks because the instrument that killed it was the thing under
repair.
## The evidence
### 1. The fit — 35 elements, three screens, zero errors
Every label is an `RB_BLENDCONTROL0` value read out of the guest command stream
and attributed by quad size ([`data/blend-bit-vs-oracle.txt`](../data/blend-bit-vs-oracle.txt)):
| | count |
|---|---|
| bit set **and** drawn additive | **16** |
| bit clear **and** drawn alpha-over | **19** |
| bit set but alpha-over | **0** |
| bit clear but additive | **0** |
### 2. The control — no rival field
A perfect partition on 35 elements is worthless if half the header partitions
equally well; that is exactly the mistake `+0x08 = 0x8050` was. So every bit of
the first twelve header words was tested against the same 35 labels:
**Exactly one separates them without error, and it is `+0x04` bit `0x02`.**
Nothing ties with it.
### 3. The within-pair case that no confound survives
| element | `+0x04` | drawn |
|---|---|---|
| `ptbtn00.t32` | `0x0110` | alpha-over |
| `ptbtn00f.t32` | `0x0112` | **ADDITIVE** |
The `PRESS Ⓐ` plate and its own highlight variant. Same screen, same bundle,
adjacent in draw order, differing in exactly this bit — and the game blends them
differently. Screen, archive, element family and draw order are all held fixed.
⚠️ And the obvious rival reading dies here too: `ptbtn01f`, `ptbtn11f` — other
`f` highlight variants — are `0x8130`, bit clear, and are drawn **alpha-over**.
It is not "focused variants are additive".
### 4. The prediction, written and committed **before** the capture
[`data/blend-bit-prediction-gp-options.txt`](../data/blend-bit-prediction-gp-options.txt),
committed at `bbd85e9`, said of `GP_OPTIONS` — **a different archive, an entirely
different element set, never captured**:
> *FALSIFIED IF: `po_menu_eff01/02/03` draw alpha-over, or any other `GP_OPTIONS`
> element draws additive.*
The developer splash was considered first and **rejected as a test**: both its
elements predict alpha-over, so it can fail but cannot discriminate.
**Result** ([`data/blend-bit-prediction-result.txt`](../data/blend-bit-prediction-result.txt),
[capture](../captures/ui-draws/blend-options-2026-08-31.log)): the game was driven
to `OPTIONS` and captured — 39 draws over 3 frames. **Exactly three additive quads
per frame, and they are `po_menu_eff01`, `po_menu_eff02`, `po_menu_eff03`.** Entry
19 declares 16 sprites, 3 predicted additive and 13 not. Zero errors.
## Reach, and what is *not* claimed
⚠️ **The alpha-over side of the `OPTIONS` test is a count, not 13 identifications.**
Draw 1 is a 20-index batch of tiled 320×360 background quads, a size several
elements share. What is measured there is that **no draw on that screen carries
`0x01010101` except the three**. That asymmetry is the right way round: the
prediction would have died on a fourth additive draw, and there was none.
⚠️ **Two blend states, not a general mode field.** Every UI draw observed on four
screens is one of `0x01010101`, `0x07010701`, or `0x00010001` for the one
non-UI blit that opens the frame. The bit chooses between the first two. Nothing
here says what a third mode would look like or whether one exists.
⚠️ **`src = ONE` in both states.** The fixed-function stage multiplies the pixel
shader's output by 1, so whatever alpha weighting happens is the shader's. This
says nothing about whether `.t32` texels are stored premultiplied; the shader is
unread.
⚠️ **Untextured primitives (`.prm`) have no `T8aD` header**, so the bit cannot
speak for them. `pteff00.prm` and `pteff02.prm` are observed alpha-over; that is
a measurement, not a decode.
📊 **Disc-wide population:** the bit is set on **4 995 of 14 709** sprites (34 %),
so it is not degenerate in either direction. Prior work established separately
that it is **not** "the name contains `eff`" (`P(eff|set) = 0.468` against
`P(eff|clear) = 0.144`) and **not** premultiplied-alpha storage — both refuted
disc-wide, and both remain refuted. Those were readings of the bit's *meaning*;
this is its *effect*.
## Challenged 2026-09-01 as a possible counter-example — and it SURVIVES
The port reported that adopting the bit moved `main_menu` **10.88 → 13.02**
against its oracle capture, isolated the only newly-additive top-level element as
**`pteff10`**, and asked whether the per-draw log shows `main_menu`'s `pteff10`
drawn **alpha-over** — which would put a counter-example on one element.
**It does not. The oracle measures it ADDITIVE on that screen.**
```
data/blend-bit-vs-oracle.txt
5 pteff10.t32 +0x04 = 00008832 bit 0x02 = true ADDITIVE
6 pteff10.t32 +0x04 = 00008832 bit 0x02 = true ADDITIVE
```
Entry 5 is the main menu and entry 6 is `EXTRAS`; the element is additive on
**both**, and every label there is an `RB_BLENDCONTROL0` value read out of the
guest command stream. `HANDOFF.md` states it directly and from three sessions:
*"Is `pteff10` additive on the MAIN MENU too? — **YES.** … additive, **in all
three menu sessions, every frame**."*
⚠️ **The premise came from a stale table of mine.** The port's *"your own map
lists `pteff10` additive on `extras` and not on `main_menu`"* is reading a
coverage table that the same HANDOFF entry had already corrected in place —
*"My coverage table listing `pteff10` as uncovered on the menu is corrected."*
A correction that leaves the wrong table visible upstream of it is a correction
that has not landed.
### 📌 The regression was PREDICTED, on this exact element, before adoption
`HANDOFF.md`, flagged as 🟡 at the time the port was told to take the bit:
> *"One flag on `pteff10` before you adopt it. You measure it as nearly exact
> under alpha-over, and the game draws it additive. Both can be true for a dim
> wholly-semi-transparent glow (max alpha 130) over a dark background, where the
> two nearly coincide — but it is the one row here your renderer does **not**
> independently corroborate."*
So `main_menu` getting *worse* on a renderer metric while getting *more correct*
against the GPU is the flagged case arriving on schedule, not a new fact. It is
the corpus's standing rule with a number attached: **a claim resting on our
renderer is a claim about our renderer**, and here the renderer and the oracle
disagree on the one element where the two blends are known to nearly coincide.
The port shipped the decoded bit anyway and recorded the movement as a known
regression. That was the right call for a better reason than the one it used:
not merely that `+2.14` sits inside the screen's `±3.78` capture-phase term, but
that the oracle had already adjudicated this element, three sessions deep.