diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index 4449be53..666a502b 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -128,7 +128,7 @@ HANDOFF. | ~~P6 โ€” runtime headroom~~ | ~~the Master bus clips~~ | โ€” | ๐ŸŸข **withdrawn by the port, 2026-08-29 โ€” it was my own overstatement.** Filed ๐Ÿ”ด twice on a peak reading of 0.0 dBFS. Measured properly: **43 samples at full scale in 5.9 s and 24 in 98.5 s, longest clamped run 0.25 ms** โ€” the disc's own `confirm` cue touching the ceiling on a transient, possibly only in the recording's 16-bit conversion since Godot mixes in float. Not a defect, and nothing is changed: attenuating to buy headroom would be an unmeasured level decision of exactly the kind this port refused for the BGM loop point. **A peak reading is not a clipping measurement** โ€” one sample at 0 dBFS and two seconds of square wave give the same number. | | Modding โ€” rule 4 | ~~base-and-overrides is unimplemented~~ | โ€” | โœ… **implemented 2026-08-29, and it was not blocked on anybody.** `MODDING.md` calls it a constraint on the exporter *today*; nothing read `data/mods/` for eight milestones. `ExportTree.resolve` now shadows by path for every asset kind, each replacement is logged as it is read, and `.gitignore` excludes the directory's contents โ€” a mod is usually an edited game asset, and that directory was the one place git would have taken one. โš ๏ธ The `export/` vs `data/base/` naming split between `PORT-MISSION.md` ยง3 and `MODDING.md` is **raised, not resolved**: only the human changes a mission. | -| P1โ€“P7 โ€” the keyframe record layout | **every pose is timed, and `exit_ramp_units` becomes decodable** | โ€” | ๐Ÿ”ด **large blast radius, NOT taken, and it cannot be taken yet.** The RE agent reports (branch `auto/no-disc-and-menu-captures`, sha `b28dfed`, tag `formats-pin-2026-08-29c`, `docs/re/ui-keyframe-record-layout.md`) that a pose's time is the word **before** it and pose 0's time is the group's lead-in, so **every** pose is timed including the last โ€” and that *both* readings the corpus was arguing between were wrong. It touches `pose_at`, `settle_units`, `spin_period_units`, `exit_ramp_units` and the plate. `sylpheed-formats` is a **path** dependency, so this reaches the port only when that branch lands on `main`; merging another agent's topic branch is not mine to do. โœ… Two things that limit the risk, both from the same message: **`ramp: "linear"` stays** โ€” do not add easing โ€” and **static composites are byte-identical across the change on all 12 `GP_TITLE` builds**, which `docs/port/DECISIONS.md`'s new `verify-screen` baseline is exactly the control for. Re-run `tools/port/verify-screen` the day the pin lands: if a still frame moves, it is the port's bug and not the decoder's change. | +| P1โ€“P7 โ€” the keyframe record layout | **adopt the corrected pose/time pairing** | โ€” | ๐ŸŸก **AVAILABLE TODAY โ€” this row's "cannot be taken yet" was WRONG.** It said the change reaches the port only when the Decoder's branch lands on `main`. It does not: `ui_layout.rs` in this checkout carries the corrected association behind **`SYLPHEED_KF_TIME_SHIFT=1`**, and has all along. I read that file twice in one session without noticing the switch. **Measured** by re-exporting under it and asking the oracle: `publisher_logo` 1.00 % โ†’ **0.75 %**, `developer_logos` 0.39 % โ†’ **0.33 %**, `title` RMSE 21.07 โ†’ **20.41** โ€” but `main_menu` 0.06 % โ†’ 0.10 % and `extras` 0.20 % โ†’ 0.24 % **worse**. โš ๏ธ **Not decisive, and the reason matters**: under the shift the untimed keyframe moves from **last to first**, while `pose_at` is written around *"the final keyframe carries no `t`"*. So the numbers measure a renderer/association mismatch, not the association. Adopting it means re-deriving `exit_ramp_units`, `settle_units`, `spin_period_units` and the plate against a layout where the untimed frame is first โ€” real work, not a flag flip. Export left on the default. | | ~~P7 / naming โ€” the four unnamed builds~~ | ~~which locale and variant is each of entries 0, 1, 12, 15?~~ | โ€” | โœ… **answered 2026-08-29** (`docs/re/ui-title-build-map.md`): all four are the loading screen, two variants โ€” plain (7 elements) and dressed (10) โ€” decoded from their own `pgloading_*` element names. โš ๏ธ **Not adopted as names yet, for two reasons the RE agent gave and one the port found.** Theirs: the executable names exactly two, and *which* bundle takes which name is ๐ŸŸก undecided, so `LOADING`/`LOADING2` must not go in an asset path; and locale is ๐ŸŸก โ€” the English member of a pair is the one in the first half of `GP_TITLE.p00`, 8/8 structurally but only 3/3 where a capture can check, and the three pairs that matter are the three no capture can check. Mine: **the message gives the bundles as "0/1 and 10/11", which is the `is_build` ordinal, and `authored/screen_names.json` is keyed by PAK ENTRY** โ€” in entry space 10 and 11 are `palogo_sqex` and `palogo_gamearts`, the splashes. See the refutation section in `DECISIONS.md`. | ## Answered since this file was last written โ€” no longer blocking diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 4d41cc7f..02c926b5 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -4054,3 +4054,72 @@ decode covers โ€” while the exporter keeps flagging all 15. Its `max` went 155 โ†’ 232 when they were drawn, and **that number is not evidence in either direction.** Recognising it as uninformative is the reason it did not become a justification. + +## The โˆ’324 was the old keyframe association, and the corrected one is available **today** + +The Decoder found it and it is not geometry: my leaf path pairs each pose with +the *next* pose's time. Fed my pairing into its own interpolation, it reproduces +**โˆ’324 to the digit**. Corrected, t=355 gives top-left **781** and centre +**980.5** against **992.0** measured โ€” so there was never a 1 300 px pivot +mystery to look for, and I am glad I said the two numbers instead of hunting one. + +### ๐Ÿ”ด Correcting BLOCKED: this was never gated on a branch landing + +`docs/port/BLOCKED.md` has carried the keyframe-record-layout row as *"NOT taken, +and it cannot be taken yet โ€ฆ `sylpheed-formats` is a path dependency, so this +reaches the port only when that branch lands on `main`."* + +**That is wrong.** The corrected association is in this checkout, behind an +environment variable: + +```rust +// Set `SYLPHEED_KF_TIME_SHIFT=1` to read `W[k-1]` as block `k`'s time +// ("the word is the time the NEXT pose is reached") instead of `W[k]`. +``` + +It has been switchable the whole time. **I read that file twice this session โ€” +once for `rotation_deg`, once for the leaf note โ€” and did not notice the switch.** + +### The experiment, run: mixed, and not decisive for the reason that matters + +Re-exported with `SYLPHEED_KF_TIME_SHIFT=1` and asked the oracle: + +| screen | default | shifted | +|---|---|---| +| `main_menu` | 13.21 / 0.06 % | 13.81 / **0.10 %** โ€” worse | +| `extras` | 13.38 / 0.20 % | 13.95 / **0.24 %** โ€” worse | +| `title` | 21.07 / 1.82 % | **20.41** / 1.86 % โ€” RMSE better, area worse | +| `publisher_logo` | 10.77 / 1.00 % | **9.05 / 0.75 %** โ€” better | +| `developer_logos` | 9.37 / 0.39 % | **8.86 / 0.33 %** โ€” better | + +โš ๏ธ **And it does not adjudicate the association, because the port's renderer is +built for the other one.** Under the shift the **untimed keyframe moves from last +to first** โ€” the leaf reads `t=None` at x=โˆ’639, then t=150, t=540 โ€” while +`pose_at` is written around *"the final keyframe carries no `t`, so it is given a +synthetic time `exit_ramp_units` after the last timed frame."* So this measures a +**renderer/association mismatch**, not the association. BLOCKED said as much: +the change touches `pose_at`, `settle_units`, `spin_period_units`, +`exit_ramp_units` and the plate. + +**Export reverted to the default.** Adopting the shift is a real piece of work โ€” +re-deriving the exit ramp, the settle, the spin period and the plate against a +layout where the untimed frame is the *first* โ€” and doing it hastily at the end of +an iteration is how a 1.8 % gap becomes five wrong ones. + +### โš ๏ธ The methodological point, which is the Decoder's and is the best thing here + +Its rule matched because **alpha at t=355 sits inside a long segment where a +one-keyframe shift barely moves it, while x sweeps 1 560 px over the same span.** +It confirmed on the insensitive quantity; I was wrong on the sensitive one; and +neither of us saw it until the two were compared. + +> **Check a new interpretation against the fastest-moving field you have, not the +> one that happens to agree.** + +That is a different failure from the ones this session has collected โ€” not an +uncontrolled instrument, but a control chosen where it could not fail. + +โ” A residual **11.5 px** (980.5 against 992.0) is left over and is **not** to be +fitted. A rotation about a declared pivot rather than the centre would displace by +roughly that; if it still matters once the association is adopted, it gets +measured rather than derived.