Files
Sylpheed/docs/re/structures/ui-blend-mode-decoded.md
sylph-decoder 864ab45a1e 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

8.3 KiB
Raw Blame History

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 said the mode is not on the disc, and 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 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):

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, committed at bbd85e9, said of GP_OPTIONSa 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, capture): 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.