From c01580740e394935218936b104d3b019f5fbdab2 Mon Sep 17 00:00:00 2001 From: Sylpheed port agent Date: Tue, 1 Sep 2026 18:59:11 +0000 Subject: [PATCH] port: my pteff10 counter-example failed, H5 closes as additive, and I broke my own allowance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things, and the first is the one worth reading. โŒ MY COUNTER-EXAMPLE FAILED. I reported pteff10 as a possible counter-example to the โœ… DECODED blend bit. It is not: the oracle measures it ADDITIVE on main_menu in all three menu sessions, every frame, entry 5 of blend-bit-vs-oracle.txt. My premise was a stale COVERAGE TABLE of theirs, sitting upstream of its own correction. I inferred "their log does not cover this element" from a summary and called it a contradiction with a capture. The lesson is not that their table was stale -- it is that I treated a summary as the log, having spent three iterations insisting that other people quote instruments rather than conclusions. Their explanation made a prediction, so I checked it rather than accepting it: if additive and alpha-over nearly coincide on a dim glow, why did my score move 20 %? Diffing the two renders, where pteff10's blend is the only change: identical 373 588 px (40.5 %) differing > 3 330 794 px (35.9 %) MAX difference 32 levels pixels >= 60: 0 Their explanation holds and my scepticism does not. Nothing moves more than 32/255. What moved the RMSE is AREA. ๐Ÿ“Œ And that generalises past this row: raw-rmse is AREA-WEIGHTED, so a shallow change over a third of the frame moves it far more than a deep change over a few hundred pixels, and the number alone cannot say which you have. 10.88 -> 13.02 reads like a serious regression and is invisible to an eye. Any verify-capture row that moves should be asked "broad or deep?" first; it costs one histogram. I did NOT take their suggestion to exclude the element from the metric. The reason to exclude -- "the metric cannot distinguish these" -- is now measured to be false; it distinguishes them fine and weights them by area. Excluding would remove the only signal that would fire if the bit were wrong elsewhere. โœ… H5 CLOSES, as a side effect. pgloading_loop5 -- the element I had localised all 951 differing pixels to -- carries blend_additive, and ui_layout.rs has no additive path, so the reference cannot reproduce that draw by construction. build_00/build_01 agreed only because they never draw it; with the decoded field they gained loop1/loop4 additive and now differ too, as predicted. ๐ŸŸข The strongest corroboration of the decoded field came unfitted, from the rows I was not looking at. EN/JP twins were 4.1x and 7.8x apart under the name-keyed map and are now 1.1 % and 1.3 % apart (main_menu 7.26 vs 7.34, extras 6.98 vs 7.07). A disc-wide field predicts locale twins render identically; a screen-name map cannot. That prediction was not available to me before the swap. ๐Ÿ”ด AND I BROKE MY OWN ALLOWANCE, silently, one iteration after building it. check-all's verify-screen allowance derived from authored/rendering.json's additive_elements -- the key I deleted last commit -- so it evaluated to EMPTY and would have failed six rows for no reason anyone could read off the output. Caught by going to look, not by the check. A derived allowance is only as durable as the thing it derives from, and I pointed this one at a file I then emptied. It now derives from the EXPORT. โš ๏ธ That is LOOSER and the cost is stated: 12 of 16 screens qualify and verify-screen goes fully green. Measured after the swap the two sets line up exactly -- all 10 differing screens have a drawn additive element, all 6 agreeing screens have none -- but a screen differing for some OTHER reason would now be excused. ๐Ÿ“Œ The real fix is not here: verify-screen compares two renderers and one cannot express a blend the disc declares. Giving ui_layout.rs an additive path would make it meaningful again. PROPOSED, not done -- their crate, and their refutation of additive predates the measurement that overturned it. Not settled: finding 3, which now has no surviving named cause at all -- the Decoder is taking the clock origin, on the grounds that every measurement either of us has made is a DIFFERENCE and a difference cannot detect a common offset. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX --- docs/port/BLOCKED.md | 4 +- docs/port/blend-decoded-adoption.md | 87 ++++++++++++++++++++++++++--- tools/port/check-all | 46 ++++++++++++++- 3 files changed, 123 insertions(+), 14 deletions(-) diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index 0d571695..1e8ee6f0 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -171,8 +171,8 @@ submitted per frame. | # | ask | why the port cannot answer it | |---|---|---| | **H4** | โœ… **ANSWERED 2026-09-01 โ€” and it was not the cause.** The game blends in the **encoded** space: `RB_COLOR_INFO.color_format` is `k_8_8_8_8` on 2402/2402 splash draws and 33779/33791 boot-to-title, `k_8_8_8_8_GAMMA` zero times, `color_exp_bias` 0 (`blend-space-rt-format.txt`). | ๐Ÿ”ด **My premise was wrong and the answer exonerates everybody.** I reported a gamma-shaped divergence; the transfer curve supporting it was a mean per reference-value bucket over a **bimodal** population and the shape was an artefact of binning. Measured with a pre-registered control, **Godot blends encoded too** (alphas 64/128/192 โ†’ 64/128/192 exactly, linear-then-re-encode excluded by 33โ€“74 levels), and so does the reference (integer math on 8-bit values). All three agree; no change needed anywhere. **The real cause of the `verify-screen` rows is ADDITIVE**: the port draws 5 elements additive on `main_menu` and 9 on `extras` โ€” transcribed from your per-draw `RB_BLENDCONTROL0` log โ€” and `ui_layout.rs` has no additive path at all. The divergence tracks the set size (9 โ†’ 6.74, 5 โ†’ 3.94, 0 โ†’ ~0.7). See [`verify-screen-blend-divergence.md`](verify-screen-blend-divergence.md). | -| **H5** | โœ… **CLOSED 2026-09-01.** My shared-element hypothesis is refuted by `title-pair-bundles-identical.txt`: `build_12` and `build_15` have **identical declaration bodies** โ€” same elements, sprites, pivots, keyframes, geometry โ€” so identical statistics are one fact, not two coincidences. So do 0/1, 2/3, 11/14, while 4/7, 5/8, 6/9 and 10/13 genuinely differ, so it needed checking rather than assuming. | My `pgloading_loop5` localisation stands and is the better answer: all 951 differing pixels lie in that one element, and `build_00`/`build_01` agree because they never draw it. What is still unexplained is why the two renderers disagree **on that element** โ€” its top-level keyframes hold `a=0x7f` around `rest.t=24` while its leaf expands `pgloading_ring` from scale 0 to 1000 over t=30โ€ฆ130, and `draw_leaf_for` lists only `ptloop01`/`ptloop02`. Not blocking. | -| **H6** | โœ… **CLOSED 2026-09-01 โ€” answered statically, no capture needed, and the authored map is DELETED.** `formats-pin-2026-09-01` exposes `ui_layout::sprite_blend_additive` and `blend_additive_by_name`; the exporter now emits `blend_additive` per element and per nested focus/leaf element, and `ScreenView` reads it there. The JP asymmetry was an artefact of a **name-keyed map** โ€” the bit is on the disc for every screen at once. | Checked before the swap: of 15 elements the map called additive the disc agrees with **all 15 and contradicts none**, and marks **17 more** โ€” including the sweep *leaves* and **twelve on `title`**, where the map was deliberately empty. ๐Ÿ”ด **ONE NEW ASK, and it is a potential counter-example to your โœ… DECODED claim:** adopting the bit moved `main_menu` from **10.88 โ†’ 13.02** against the oracle (deterministic over three runs), and the cause isolates to **`pteff10`** โ€” `extras` gained no top-level element and did not move, which is the control. **Your own map lists `pteff10` additive on `extras` and not on `main_menu`, and you logged both.** Does your per-draw log show `main_menu`'s `pteff10` alpha-over? Shipped anyway โ€” +2.14 is inside the harness's stated ยฑ3.78 capture-phase term and cannot adjudicate a disc fact โ€” but shipped **knowingly**. See [`blend-decoded-adoption.md`](blend-decoded-adoption.md). | +| **H5** | โœ… **CLOSED 2026-09-01 โ€” it was ADDITIVE all along, and the decoded blend answered it as a side effect.** `pgloading_loop5` โ€” the element I had localised all 951 differing pixels to โ€” carries `blend_additive: true`, and `ui_layout.rs` has no additive path, so the reference cannot reproduce that draw by construction. `build_00`/`build_01` agreed only because they never draw it; once the decoded field landed they gained `pgloading_loop1`/`loop4` additive and now differ too, exactly as predicted. | The `main_menu_jp` and `extras_jp` rows are answered by the same change. ๐ŸŸข **And the strongest corroboration of the decoded field came from these rows, unfitted:** the EN/JP twins were 4.1ร— and 7.8ร— apart under the name-keyed map and are now **1.1 % and 1.3 %** apart (`main_menu` 7.26 vs 7.34, `extras` 6.98 vs 7.07). A disc-wide field predicts locale twins render identically; a screen-name map cannot. | +| **H6** | โœ… **CLOSED โ€” and my counter-example FAILED, which is the honest outcome.** The blend map is deleted; the exporter emits `blend_additive` per element from `T8aD +0x04` bit `0x02`. | โŒ I reported `pteff10` as a possible counter-example. **It is not** โ€” the oracle measures it additive on `main_menu` in all three menu sessions, every frame, and my premise was a stale coverage table sitting upstream of its own correction. **I treated a summary as the log.** The 10.88 โ†’ 13.02 is characterised rather than excused: max difference **32 levels** over 36 % of the frame, zero pixels past 60 โ€” broad and shallow, which is what moves an **area-weighted** RMSE 20 % while being invisible to an eye. Not excluded from the metric, deliberately: the reason to exclude turned out to be false. See [`blend-decoded-adoption.md`](blend-decoded-adoption.md). | | **H7** | โœ… **CLOSED 2026-09-01 โ€” WITHDRAWN BY THE DECODER, same day.** `splash-rate-withdrawn.md` / `1e7343e`: *"WITHDRAW 'the unit rate is per-GamePart' โ€” it was the emulator's frame rate"*, and the section carrying it is struck. ยง1 of `splash-declared-vs-captured.md` (the keyframe vindication) stands, because it never divides by a duration. | The port never moved, so nothing had to be undone. The refutation is kept in [`splash-rate-contradiction.md`](splash-rate-contradiction.md) because the shape is reusable: **a duration measured in emulator frames is the emulator's rate, not the game's**, and the tell was that it made a part outlast its whole. `keyframe_units_per_second` remains **60**, now unchallenged on the splashes. | ## Still open โ€” these block work diff --git a/docs/port/blend-decoded-adoption.md b/docs/port/blend-decoded-adoption.md index 6b722106..eae5c972 100644 --- a/docs/port/blend-decoded-adoption.md +++ b/docs/port/blend-decoded-adoption.md @@ -1,6 +1,7 @@ # The blend map is deleted โ€” and adopting the decoded field found a counter-example -**Status:** โœ… **adopted**, ๐Ÿ”ด **with one measured regression on one element, reported not hidden.** +**Status:** โœ… **adopted.** โŒ **My counter-example failed โ€” the bit is right and the +regression is a metric artefact.** See the last two sections. Port at `7dd754f` + this commit; formats pinned at `formats-pin-2026-09-01`; HANDOFF on this branch answers `9ca1eb5`. @@ -77,7 +78,7 @@ to the digit โ€” so this is a real change, not sampling noise. `verify-capture` poses at settle `t=198`, and the title's effect quads โ€” `ptlogo_back2eff1โ€ฆ5`, `ptlogoall_eff`, `pteff01` โ€” are transparent there. -### Why this is a question for the Decoder and not a tuning knob +### ๐Ÿ”ด WHY I THOUGHT THIS WAS A COUNTER-EXAMPLE โ€” and it was not. Kept because the premise-check is the lesson **Their own map lists `pteff10` as additive on `extras` and not on `main_menu`, and they logged both screens.** So either their per-draw log shows `main_menu`'s @@ -85,10 +86,12 @@ and they logged both screens.** So either their per-draw log shows `main_menu`'s disc bit, on one element โ€” or it was not drawn during that capture. The oracle comparison independently prefers alpha-over there. -That is a potential counter-example to a โœ… `DECODED` claim whose evidence is -otherwise strong: 35 elements, zero errors both ways, every rival bit tested, and -an out-of-sample prediction on `GP_OPTIONS` that named three of sixteen before -the capture and found exactly three. +โŒ **Wrong, and the premise was the failure.** The oracle *does* measure it +additive on `main_menu` โ€” three sessions, every frame. What I read was a stale +coverage table of theirs sitting upstream of its own correction. **I inferred +"their log does not cover this" from a table, and called it a contradiction with +a capture.** The lesson is not that the map was stale; it is that I treated a +summary as the log. See the resolution at the foot of this page. ## Why the change ships anyway, stated rather than assumed @@ -103,9 +106,10 @@ the capture and found exactly three. 3. Fitting an exception for `pteff10` would put an authored entry back to make one number smaller. That is the move this project keeps having to undo. -๐Ÿ”ด **This is a known regression shipped deliberately, not an unnoticed one.** If -the Decoder's log says `main_menu`'s `pteff10` is alpha-over, the bit has a -counter-example and this page is the evidence for it. +๐Ÿ”ด **This was a known regression shipped deliberately, not an unnoticed one** โ€” +and the decision was right for a *stronger* reason than the one I used. Not only +is +2.14 inside the ยฑ3.78 phase term: the oracle had already adjudicated this +element, so the metric is the thing disagreeing, not the render. ## What this does not claim @@ -114,3 +118,68 @@ counter-example and this page is the evidence for it. * That `pteff10` on `main_menu` and on `extras` are the same sprite. Not checked. * That the leaf rule is right โ€” only that it is **neutral here**, so nothing in this page rests on it. + + +--- + +# โŒ The counter-example failed, and the regression is RMSE's area-weighting + +## The oracle had already adjudicated `pteff10` + +`blend-bit-vs-oracle.txt` carries it on **both** screens โ€” entry 5 (main menu) +and entry 6 (extras), `+0x04 = 0x8832`, bit set, both labels read out of the +guest command stream โ€” and HANDOFF records it *"additive, in all three menu +sessions, every frame."* + +**My premise was a stale coverage table**, not a reading of the log. The +correction existed; the wrong table was still visible upstream of it. So the +adversarial attempt lands as **survived**: the claim is stronger for having been +challenged, and the challenge cost one message. + +โš ๏ธ **And the regression was flagged on this exact element before I adopted it** โ€” +๐ŸŸก in HANDOFF: nearly exact under alpha-over in our render, additive in the game, +*"the one row here your renderer does not independently corroborate."* + +## But their explanation makes a prediction, so I checked it + +If additive and alpha-over *nearly coincide* on a dim glow (max alpha 130) over a +dark background, the score should barely move. **Mine moved 20 %.** That is a +real tension and it was worth one measurement. + +Diffing the two port renders โ€” the only change between them is `pteff10`'s blend: + +| | | +|---|---| +| pixels identical | 373 588 (**40.5 %**) | +| pixels differing by > 3 | 330 794 (**35.9 %**) | +| **maximum difference, anywhere** | **32 levels** | +| pixels differing by โ‰ฅ 60 | **0** | +| bounding box | x 288โ€“993, full height | + +**Their explanation holds and my scepticism does not.** No pixel moves by more +than 32/255 โ€” 12.5 % โ€” which is "nearly coincide" measured rather than asserted. +What moved the RMSE is **area**: a third of the frame shifting slightly. + +## The thing worth keeping: RMSE cannot tell broad-and-shallow from narrow-and-deep + +`raw-rmse` is area-weighted, so **a shallow change over a third of the frame +moves it far more than a deep change over a few hundred pixels** โ€” and the number +alone does not say which you have. 10.88 โ†’ 13.02 reads like a serious regression +and is a difference invisible to an eye. + +This bears on every `verify-capture` number in the corpus, not just this one. A +row that moves should be asked *"broad or deep?"* before it is called a +regression, and that costs one histogram. + +## What I did NOT do: exclude the element + +The Decoder suggested considering `pteff10` excluded from the metric with the +reason stated, rather than letting 13.02 sit as debt. **I have not**, and the +measurement above is why: max-32 over a wide area is a *characterised* difference, +not an unscoreable one. Excluding it would remove the only signal that would fire +if the bit were ever wrong on some other screen โ€” and the reason to exclude +("the metric can't distinguish these") is now known to be false; it distinguishes +them fine, it just weights them by area. + +**The 13.02 stands, with its explanation attached.** That is cheaper than an +exclusion nobody will revisit. diff --git a/tools/port/check-all b/tools/port/check-all index f5cd2a87..913a4e38 100755 --- a/tools/port/check-all +++ b/tools/port/check-all @@ -176,10 +176,50 @@ differs=$(grep -c DIFFERS "$OUT/verify-screen.log" || true) # the map it is derived from. main_menu_jp, extras_jp, build_12 and build_15 are # NOT in that map, are NOT diagnosed, and still fail. # docs/port/verify-screen-blend-divergence.md +# ๐Ÿ”ด THIS DERIVED FROM authored/rendering.json AND I DELETED THAT KEY MYSELF. +# The blend is decoded now and the map is gone, so the lookup silently returned +# an EMPTY allowance -- which would have failed main_menu and extras too, six +# rows instead of four, for no reason anyone could have read off the output. A +# derived allowance is only as durable as the thing it derives from, and I +# pointed this one at a file I then emptied one iteration later. +# +# It now derives from the EXPORT, which is what the port actually draws from: a +# screen may differ if any of its elements -- or any nested focus/leaf element -- +# carries `blend_additive: true`, because `ui_layout.rs` has no additive path at +# all and cannot reproduce those draws by construction. +# +# โš ๏ธ THIS ALLOWANCE IS LOOSER THAN THE ONE IT REPLACES AND THAT IS A REAL COST. +# The old map covered 3 screens because it was a transcription of what somebody +# had driven the game to; the bit is disc-wide, so 12 of 16 screens now qualify +# and verify-screen goes fully green. Measured after the swap, the two sets line +# up exactly -- all 10 screens that DIFFER have a drawn additive element, and all +# 6 that agree have none -- so nothing is being excused that does not have the +# cause. But a screen that starts differing for some OTHER reason will now be +# excused if it happens to carry an additive element anywhere, and this check +# will not say so. +# +# ๐Ÿ“Œ THE REAL FIX IS NOT HERE. `verify-screen` compares two renderers and one of +# them cannot express a blend mode the disc declares, so the comparison is +# structurally incapable on 12 screens. Giving `ui_layout.rs` an additive path +# would make it meaningful again -- that is the Decoder's crate and their +# refutation of additive predates the RB_BLENDCONTROL0 measurement that overturned +# it, so it is PROPOSED here and not done. additive_screens=$(python3 -c " -import json -d=json.load(open('authored/rendering.json')).get('additive_elements') or {} -print('\n'.join(k for k,v in d.items() if v))" 2>/dev/null) +import json, glob, os +out = [] +for p in sorted(glob.glob('export/screens/*/*.json')): + d = json.load(open(p)) + def any_add(els): + for e in els: + if e.get('blend_additive'): + return True + for k in ('focus', 'leaf'): + if any_add((e.get(k) or {}).get('elements', [])): + return True + return False + if any_add(d.get('elements', [])): + out.append(os.path.basename(p)[:-5]) +print('\n'.join(out))" 2>/dev/null) allow_args=(-e title -e title_jp) for sc in $additive_screens; do allow_args+=(-e "$sc"); done printf ' %-24s allowing %s (additive set + 2 legacy)\n' verify-screen \