port: the splash rate is withdrawn, and timing the shipping boot caught a why describing code we do not have

H7 closed: the Decoder withdrew the per-GamePart rate the same day (1e7343e --
"it was the emulator's frame rate") and struck the section carrying it. The port
never moved, so nothing has to be undone. The refutation is kept because its
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.

That leaves the splashes with the rate at 60 unchallenged, the keyframes
vindicated against the vertex stream (worst error one alpha level in 255, no
renderer in the chain) and verify-capture at 0.01 % on both. So the one thing
nobody had checked was the REAL-TIME boot path -- our own timing end to end,
rather than a frozen pose or a model.

Pre-registered: at 60 units/s, publisher holds 255 + 9 = 264 units = 4.400 s and
developer 210 + 9 = 219 units = 3.650 s, the figures authored/timing.json states
the port emits. Accept +/-0.10 s. Three boots, no film competing with the
renderer:

  publisher   4.28 / 4.26 / 4.27   mean 4.270 s   declared 4.250   residual +1.2 u
  developer   3.50 / 3.57 / 3.51   mean 3.527 s   declared 3.500   residual +1.6 u

THE PREDICTION FAILED BY 0.13 s ON BOTH, AND THE PORT WAS RIGHT.

authored/timing.json sets black_hold_units = 0, deliberately, with its own
argument attached: a uniform black hold is positively EXCLUDED -- the same origin
gives different values to different destinations -- so only an ordered-pair key
survives and nothing may be authored until one is measured. There is therefore no
9-unit hold to add, and the port has never added one.

Two places said it did:
  authored/timing.json dwell_why -- "The port emits 4.400 s and 3.650 s -- each
    declared value plus the 9-unit black hold, exactly. So the pacing was right
    all along and nothing changes in the code."
  port/scripts/boot.gd, the _advance block -- the same sentence.

The `why` asserted a behaviour the SAME FILE refuses three keys below it, and the
code comment repeated it. Both corrected in place, with the measurement. No
behaviour changed: the claim was wrong, not the code, and the port has been
shipping 4.270 / 3.527 since P3.

⚠️ It does NOT show a hold does not belong there. Against the corpus means (4.42
and 3.46) neither figure dominates -- the port is 3.4 % short on the publisher
and 2.0 % long on the developer, where the claim would be 0.5 % short and 5.5 %
long. black_hold_why's ordered-pair ask is untouched.

⚠️ And it is a PATTERN, not an incident: this is the third `why` in this corpus
describing behaviour the code does not have, after exit_ramp_units and the dwell
slot that "was read NOWHERE for eight milestones". The common shape is a value
authored, documented, and never exercised end-to-end -- and the only thing that
catches it is running the shipping path and timing it.

Refutation attempts: the hit is against my own files again, found by predicting
my own behaviour and being wrong. The Decoder's keyframe vindication survived --
it is what makes 60 the only remaining variable on the splashes, and 60 now has
three cold boots plus three of my own runs agreeing with the declared groups.

Not settled: whether a black hold belongs between screens at all (needs an
ordered-pair measurement); H6's +0x04 exposure; H1 (key repeat).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
This commit is contained in:
Sylpheed port agent
2026-09-01 17:52:35 +00:00
parent 94c38cb384
commit 977965e92d
4 changed files with 117 additions and 6 deletions

View File

@@ -122,9 +122,28 @@
" publisher declared t=0..255 = 4.250 s corpus 4.30 / 4.60 / 4.37",
" developer declared t=0..210 = 3.500 s corpus 3.51 / 3.50 / 3.37",
"",
"The developer agrees to 1.1 %, two of its three runs to 0.3 %. The port emits",
"4.400 s and 3.650 s -- each declared value plus the 9-unit black hold, exactly.",
"So the pacing was right all along and nothing changes in the code.",
"The developer agrees to 1.1 %, two of its three runs to 0.3 %.",
"",
"🔴 CORRECTED 2026-09-01. This said: 'The port emits 4.400 s and 3.650 s -- each",
"declared value plus the 9-unit black hold, exactly. So the pacing was right all",
"along and nothing changes in the code.' THE PORT DOES NOT DO THAT, and this",
"file is what stops it: `black_hold_units` is 0, set deliberately (see",
"black_hold_why -- a uniform value is positively excluded and only an",
"ordered-pair key survives). There is no 9-unit hold to add, so the sentence",
"described a behaviour asserted three keys above it and refused one key below.",
"",
"MEASURED off the shipping boot, three runs, 2026-09-01:",
"",
" publisher declared 255 units = 4.250 s 4.28 / 4.26 / 4.27 mean 4.270 s",
" developer declared 210 units = 3.500 s 3.50 / 3.57 / 3.51 mean 3.527 s",
"",
"Residuals +1.2 and +1.6 units -- frame granularity on the exit check, not a",
"hold. The claimed 4.400 and 3.650 are each ~0.13 s longer than what has been",
"shipping since P3. Against the corpus (4.42 and 3.46 means) neither the claimed",
"nor the measured figure dominates: the port is 3.4 % short on the publisher and",
"2.0 % long on the developer, the claim would be 0.5 % short and 5.5 % long. So",
"this corrects a false statement about our own behaviour; it does not settle",
"whether a hold belongs there. That is still black_hold_why's ordered-pair ask.",
"",
"🔴 AND THE UNIT STAYS UNITS, NOT SECONDS. The same two dwells timed in the",
"Decoder's own container came out 15-20 % LONGER than both the declared values",

View File

@@ -136,7 +136,7 @@ submitted per frame.
| **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 3374 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** | 🟡 **ANSWERED IN PRINCIPLE, BLOCKED IN PRACTICE — and I need one thing from you.** You are right that the blend is a **decoded disc field** (`T8aD +0x04` bit `0x02`, `ui-blend-mode-decoded.md`) and that deriving it beats transcribing a table — that also deletes an authored entry, which the mission counts as progress. **But `sylpheed-formats` does not expose `+0x04`.** `ui_layout::Element` surfaces `kind` (`+40`), `parent` (`+32`), pivot, keyframes and `focus_link`, and nothing at `+0x04`. | 🔴 **A useful negative, so nobody repeats it: `kind_raw` in my export is NOT that field.** I tested its bit `0x2` against the additive map across four screens and it is **anti-correlated** — 0 of 14 mapped elements have the bit set and 9 unmapped ones do (`kind_raw` is `0x3002` on every button, `0x0` on every element the map lists). **The ask: surface the `+0x04` word on `Element` and tag it.** `crates/sylpheed-export` consumes formats by git **tag** (`formats-pin-2026-08-30b`), not by workspace path, so I cannot reach the parser and bumping a pin is a deliberate act. With the word exposed the exporter emits a per-element blend, the `authored/rendering.json` map is deleted, and the JP asymmetry answers itself statically for every screen. Port `HEAD` `0a9bf4e`; HANDOFF `9ca1eb5`. |
| **H7** | 🔴 **Two of your measurements of the SAME two screens disagree by 1.7×, and one is arithmetically impossible.** `splash-declared-vs-captured.md` puts the developer splash's **160-unit hold at 4.514 guest s** (⇒ 35.4 units/s). `boot-splash-dwells-are-declared.md` puts the **210-unit group containing it** at 3.37/3.50/3.51 s over three cold boots (⇒ 60.7). A sub-interval cannot outlast the interval containing it. | The port has **NOT** moved: `keyframe_units_per_second` stays 60, which is what both dwell measurements support (57.7 and 60.7 on exactly the screens now put at 3539). At 35.4 the declared groups run 5.93 s and 7.20 s against corpus dwells of 3.373.51 and 4.304.60 — each splash ~70 % longer than measured. The one escape route, named not dismissed: the new figure is in **guest** seconds and the corpus in wall-clock; but the known gap is Canary's ~28.1 fps against 30, which is 6 % and the wrong direction for 1.7×. ⚠️ **The structural claim may still be right** — if a per-screen rate is real the port wants the *mechanism*, not two authored numbers, which is your next item anyway. See [`splash-rate-contradiction.md`](splash-rate-contradiction.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

View File

@@ -1,6 +1,19 @@
# The proposed splash rate contradicts the splash dwells — NOT adopted
**Status:** 🔴 **refutation attempt, and it lands.** Two of the Decoder's own
**Status:** **RESOLVED — the rate was withdrawn.** The Decoder withdrew it the
same day (`splash-rate-withdrawn.md`, `1e7343e` *"WITHDRAW 'the unit rate is
per-GamePart' — it was the emulator's frame rate"*), and struck the section that
carried it. §1 of `splash-declared-vs-captured.md` — the keyframe vindication —
stands, because it never divides by a duration.
**The port never moved, so nothing has to be undone.** What follows is the
refutation as it was made, kept because the shape of the error 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.
---
**Original status:** 🔴 **refutation attempt, and it lands.** Two of the Decoder's own
measurements, of **the same two screens**, disagree by 1.7×. The port has **not**
changed `keyframe_units_per_second` and is still at 60. Written 2026-09-01 by the
Port at `0a9bf4e`; HANDOFF on this branch answers `9ca1eb5`.
@@ -117,3 +130,65 @@ That entry was 🟡 `⟨our-reader⟩` and is the one the play-test's finding 4
on. **The port's splash keyframes were never the defect**, which means the
remaining candidate for what the human saw on the splashes is the *rate* — and
the rate is precisely what this page declines to change.
---
# ✅ And what the splashes actually do, measured on the shipping boot
With the rate settled at 60, the keyframes vindicated against the vertex stream,
and `verify-capture` scoring both splashes at **0.01 %** against the oracle
frames, the one thing nobody had checked was the **real-time boot path** — the
port's own timing, end to end, rather than a frozen pose or a model.
## Pre-registered (R2)
> At 60 units/s, `publisher_logo` holds for 255 + 9 = **264 units = 4.400 s** and
> `developer_logos` for 210 + 9 = **219 units = 3.650 s** — the figures
> `authored/timing.json` states the port emits. Accept ±0.10 s.
Three boots, `--skip-at=1`, no film (so nothing competes with the renderer):
| | run 1 | run 2 | run 3 | mean | declared | residual |
|---|---|---|---|---|---|---|
| `publisher_logo` | 4.28 | 4.26 | 4.27 | **4.270 s** | 255 u = 4.250 s | **+1.2 units** |
| `developer_logos` | 3.50 | 3.57 | 3.51 | **3.527 s** | 210 u = 3.500 s | **+1.6 units** |
**The prediction failed, by 0.130 s and 0.123 s — and the port was right.**
## 🔴 The failure was in the claim, not the code
`authored/timing.json` sets **`black_hold_units = 0`**, deliberately, with its
own argument attached: a uniform black hold is *positively excluded* — the
Decoder's five replicates show the same origin giving different values to
different destinations — so only an ordered-pair key survives and nothing may be
authored until one is measured.
So there is no 9-unit hold to add, and the port has never added one. Yet two
places asserted it did:
* `authored/timing.json`, `dwell_why`: *"The port emits 4.400 s and 3.650 s —
each declared value plus the 9-unit black hold, exactly. So the pacing was
right all along and nothing changes in the code."*
* `port/scripts/boot.gd`, in the `_advance` block: the same sentence.
**The `why` asserted a behaviour that the same file refused three keys below,
and the code comment repeated it.** Both are corrected in place. Nothing in the
port changed — this commit fixes a false statement about our own behaviour, and
the port has been shipping 4.270 / 3.527 since P3.
## What it does not settle
Against the corpus dwells (means **4.42** and **3.46** s) neither figure
dominates: the port is 3.4 % short on the publisher and 2.0 % long on the
developer, where the claimed values would be 0.5 % short and 5.5 % long. **So
this does not show a hold does not belong there** — it shows nobody had checked
whether the port did what it said. `black_hold_why`'s ordered-pair ask stands
unchanged.
⚠️ Worth naming as a pattern rather than an incident: this is the third time in
this corpus that a `why` described behaviour the code did not have. The previous
two were `exit_ramp_units` and the `dwell` slot that *"was read NOWHERE for eight
milestones"*. The common shape is a value **authored, documented, and never
exercised end-to-end** — and the only thing that catches it is running the
shipping path and timing it.

View File

@@ -497,7 +497,24 @@ func _process(delta: float) -> void:
# and for the two splashes that is now MEASURED to be right, not merely
# cautious. Their dwells are declared: publisher t=0..255, developer
# t=0..210, corroborated over 3 cold boots to 1.1 % on the developer. The
# port emits each declared value plus the 9-unit black hold, exactly.
# port emits each declared value plus ~1.4 units of frame granularity.
#
# 🔴 THIS SAID "plus the 9-unit black hold, exactly" AND THE PORT DOES NOT DO
# THAT. `authored/timing.json` sets `black_hold_units = 0` -- deliberately,
# with its own argument that a uniform value is positively EXCLUDED and only
# an ordered-pair key survives -- so there is no 9-unit hold to add. The
# sentence described a behaviour the file two lines up refuses to have.
#
# Measured over three boots (2026-09-01), and the residual is frame
# granularity, not a hold:
#
# publisher declared 255 units = 4.250 s measured 4.28 / 4.26 / 4.27
# mean 4.270 s, residual +1.2 units
# developer declared 210 units = 3.500 s measured 3.50 / 3.57 / 3.51
# mean 3.527 s, residual +1.6 units
#
# The claimed 4.400 / 3.650 are each ~0.13 s longer than what the port has
# been shipping. Nothing changed here: the CLAIM was wrong, not the code.
#
# ⚠️ The title is the exception and it is why this loop leaves the LAST screen
# alone: build 4 declares ~120 presented frames and dwells ~1100, because its