diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index b0363cd2..3db95892 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -1946,11 +1946,9 @@ The flashes occupy a six-frame window and are absent from all 155 other sampled frames. Units-per-frame came from the **glow's period alone** — a different element — so the timings are not circular. -🔴 **One thing for you to act on: do not draw all five flashes every time.** A -flash's peak is 2 keyframe units, which at this run's pacing is **0.85 of a -presented frame**. `ptlogo_back2eff3` was **never drawn** — not a miss, a phase -effect. The console shows a *subset* of these on any given play; a port that draws -all five will show more of the sweep than the real thing. +🔴 ~~**Do not draw all five flashes every time.**~~ **WITHDRAWN the same day — see +the correction at the end of this file. Your sequential drawing is correct; ignore +this.** ✅ **And your 120 is confirmed from the guest's own vertex data.** The glow quad's per-vertex colour alpha *is* the element's fade alpha: observed range **0…80** @@ -1975,3 +1973,56 @@ is 1280×720. Both wrong, neither loud. Detail, controls and reach: [`docs/re/structures/ui-title-buildin-measured.md`](../re/structures/ui-title-buildin-measured.md). +## 2026-08-29 — retraction: the flash advice was wrong + +🔴 **I told you not to draw all five title flashes. That was wrong and you should +ignore it.** You checked it against your renderer instead of reasoning about it, +and you were right to. + +Two claims of mine, both withdrawn: + +* **"`eff3` was never drawn because a 2-unit peak is sub-frame."** `eff3` is + non-zero for t ∈ (58, 64), and the capture's frames 133 and 134 sit at t = 60.0 + and 62.2 — squarely inside that window, with `eff2` and `eff4` both drawn in the + same frames. It should have been submitted and was not. **The absence is real + and unexplained**; it is not sampling phase, and it is not evidence that the + element is inert. Your sweep drawing it at t=60–62 is what the disc says. +* **"A port drawing all five shows more sweep than the console."** No evidence. + The pile-up worth warning about was the `rest()` bug, which is fixed. + +⚠️ **What does hold is your own point, and it is now on my page.** The game's +timeline is 60 units/s against a 30 Hz present — 2 units per submitted frame — and +this capture ran at **2.231 units per presented frame**. So a frame-by-frame +comparison of the build-in against this capture **will** disagree about which +flash lands in which frame, and neither side is wrong. The settled comparison is +unaffected: at t=198 none of the five is drawn. + +✅ **And a better confirmation of 120 than the one I sent, needing no calibration +at all.** The glow's draw is omitted when its alpha hits zero, and the smallest +alpha actually submitted across 807 drawn frames is **1** — so the culling +threshold is 1, read off the data. Then: + +| | dark-frame fraction | +|---|---| +| **measured** (173 of 980 settled frames) | **17.7 %** | +| a **120**-unit cycle (15-unit dark hold) predicts | **14.4 %** | +| a **105**-unit cycle (no dark hold) predicts | **2.2 %** | + +🔴 105 is out by a factor of eight, and would need a culling threshold of alpha 11 +out of a peak of 80 — while the capture contains submitted draws at alpha 1, 2, 3, +4, 5, 6, 7, 8, 9, 11 and 12. **The declared 15-unit dark hold is directly visible +as the frames where the game submits no draw.** No frame rate, no pacing factor, +no wall clock. + +⚠️ **One honest gap, since I am correcting myself anyway.** With units/frame from +a regression over five build-in events (residuals ≤ 0.9 frames, and it recovers +t=0 at frame 106.1 against a composite spike at 107 that was not in the fit), the +glow's 51.158-frame period implies a **114**-unit cycle, not 120. The +dark-fraction test settles 120 against 105; the 5 % gap in the period does not +have an explanation yet. + +⚠️ And a limit on the vertex-alpha trick: it holds for the **glow** and does not +generalise. Read the same way, `eff4` gives 255 / 127 / 254 on frames 133 / 134 / +135 — non-monotonic. The glow's exact agreement is evidence about the glow, not a +decoded rule about vertex colour. + diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index 19725d96..727f58f3 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -171,4 +171,4 @@ files, which is how the same ground got covered twice. | [`structures/ui-tie-break-cost-at-settle.md`](structures/ui-tie-break-cost-at-settle.md) | What the unknown paint-order tie-break costs, in pixels | ✅ **decoded**, closing the open half of Q3: at the settled instant the tie-break costs **at most 1 px at Δ1**, on the **Japanese title only** (`ptlogo2`×`ptlogo_tm`, 5 px shared ink); **exactly 0 px on all five port screens**. The earlier 24-pair bound was a `rest()` count — and 10 of the title's 11 tied pairs are between `ptlogo_back2eff1`…`eff5`, five transient flashes that are **transparent** on the settled screen ([`ui-settle-time.md`](structures/ui-settle-time.md)). Live pairs at settle: entry 4 → **1**, entry 7 → **2**, the four loading bundles → **0**. ✅ Not a knife-edge — sweeping every keyframe time and midpoint, the count is **flat across the whole settle window**, and the loading bundles' tie is live only at t17–t33. ✅ Controls: an overlapping *different*-key swap moves 25 310 / 268 698 / ~765 000 px on the entries reporting zero; zeros are explained by shared-ink counts (the `ptframe` pairs share **0 px** of ink). ⚠️ Entries 0/1/12/15 have **no live control** — their zeros rest on keyframe data, not a render. 🟡 Refutation attempt on the corpus's "24 pairs": **survives** as a rest-pose bound, 16/16 on entry 7. ❔ *Why* ties order as they do is still unknown — and now worth one pixel | | [`structures/ui-record-loop-length.md`](structures/ui-record-loop-length.md) | Where a looping record's cycle restarts — and the `PRESS Ⓐ` plate's real period | ✅ **decoded**: a nested record is itself a RATC bundle and its header **`+0x08` is the loop length**; its keyframes need not fill it, and the slack is a hold at the final pose. Disc-wide over **1 781** timed nested records: 92.3 % declare exactly their last keyframe time, **7.7 % declare more**, and **0 declare less** — the falsifier (a cycle cannot restart before its own last pose) never fires. 🔴 **The plate's `ptbtn00f` is 105 units of ramp inside a 120-unit cycle, so it holds dark for 15 units** — the port was shipping **105**, and the answer is **120**. ✅ Falsification test against the running game, using a pacing factor measured *independently* on the focus ring (declared 120 → **2.177 s**, factor **1.0885**): to reach the corpus's measured 2.12–2.34 s, 105 units needs a factor of **1.211–1.337** (🔴 excludes the ring's) while 120 needs **1.060–1.170** (✅ contains it). Different elements, different bundles, separate runs — tied only by both declaring 120. ⚠️ Says where a cycle *ends*, not which records cycle. ❔ the **top-level** `+0x08` (300 on every `GP_TITLE` entry, elements ending at 244–269) is a different question, untouched | | [`structures/ui-focus-record-pulse-census.md`](structures/ui-focus-record-pulse-census.md) | Every focus record whose glow pulses, and where `rest()` puts it | ✅ **decoded**, disc-wide: **1 130** focus records, **2 664** timed elements, **210 with a varying alpha** — of which **202** have `rest()` == the **peak** (burns bright forever) and **8** land **mid-ramp**. By pak: `PILOTLOG` 116, `MOVIE_THEATER` 54, `HANGAR_ARSENAL` 30, `LEADERBOARD` 8, **`GP_TITLE` 2**. 🟡 Bounds rather than refutes the port's "34 in the export, 2 varying, nothing to fix" — correct, and correct *because* `GP_TITLE` has 2; the pathology sits in the screens a wider port needs next. 🔴 The 8 mid-ramp ones are the worse mode: `py_ranking_btn01f` swings 255→127→255 and `rest()` returns **244**, neither extreme, which looks entirely plausible and nothing reports it. ✅ Control: `ptbtn01f` is genuinely constant (255 throughout) and is **not** flagged; two hits verified keyframe by keyframe. ⚠️ A pulsing element has no resting pose — the question is malformed, not mis-answered; `pose_at(t)` inside the record's declared cycle ([`ui-record-loop-length.md`](structures/ui-record-loop-length.md)) is the only well-formed query. ⚠️ 210 is a **floor**: focus records are matched by the `Xf.rat` name rule, and varying scale/rotation/position is not counted | -| [`structures/ui-title-buildin-measured.md`](structures/ui-title-buildin-measured.md) | The title's build-in and the plate glow, read out of the guest's own draw stream | ✅ **measured** (Canary, `ARM=early` draw capture): the decoded *mechanism* is observed, not just its end state. **The five flashes fire in a six-frame window and are absent from all 155 other sampled frames**; `ptlogo_back2eff1` is drawn in exactly 2 frames at **t = 54.0** against a decoded peak of **t54–56**, and `ptlogo1` first appears at **t = 42.2** against a decoded **t42** — with units/frame taken from the **glow's period alone**, a different element. The two holders (`ptlogo_back2eff`, `ptlogo_back2`) are continuous from frame 134. ✅ The glow's per-vertex colour alpha IS its fade alpha: **observed range 0…80 against a decoded peak of 80**, exact and unfitted; **period 51.158 presented frames** over 20 cycle starts; fitting the decoded ramp gives RMS **13.16** against **38.18 reversed** (2.9×), so the asymmetry is real and correctly directed. Structure: frame **107** is a **27-draw composite**, the settled title is 10–11 draws naming no sprite — which is why arming at the title sees nothing. ⚠️ **`eff3` was never drawn and that is expected**: a 2-unit flash peak is **0.85 of a presented frame**, so catching one is a matter of phase — 🔴 a port drawing all five every time shows more sweep than the console does. 🔴 **Trap:** matching a bound texture's dimensions to a sprite fails both ways — it missed every flash *and* read the intro movie's 640×360 YUV planes as `ptbase2`. ❔ Run's frame rate not recorded, so nothing is stated in seconds; `eff5` vs `ptlogo_back2eff` not separated | +| [`structures/ui-title-buildin-measured.md`](structures/ui-title-buildin-measured.md) | The title's build-in and the plate glow, read out of the guest's own draw stream | ✅ **measured** (Canary, `ARM=early` draw capture): the decoded *mechanism* is observed, not just its end state. **The five flashes fire in a six-frame window and are absent from all 155 other sampled frames**; `ptlogo_back2eff1` is drawn in exactly 2 frames at **t = 54.0** against a decoded peak of **t54–56**, and `ptlogo1` first appears at **t = 42.2** against a decoded **t42** — with units/frame taken from the **glow's period alone**, a different element. The two holders (`ptlogo_back2eff`, `ptlogo_back2`) are continuous from frame 134. ✅ The glow's per-vertex colour alpha IS its fade alpha: **observed range 0…80 against a decoded peak of 80**, exact and unfitted; **period 51.158 presented frames** over 20 cycle starts; fitting the decoded ramp gives RMS **13.16** against **38.18 reversed** (2.9×), so the asymmetry is real and correctly directed. Structure: frame **107** is a **27-draw composite**, the settled title is 10–11 draws naming no sprite — which is why arming at the title sees nothing. 🔴 **Two claims here were WITHDRAWN the same day**: `eff3`'s absence is **unexplained**, not a sub-frame phase effect (frames 133/134 sit at t=60.0/62.2, inside its t(58,64) window, with `eff2` and `eff4` drawn alongside); and the advice that a port drawing all five "shows more sweep than the console" had no evidence behind it. ⚠️ What a frame-by-frame build-in comparison *will* show is disagreement about which flash lands in which frame — 2 units/submitted frame against this run's 2.231 units/presented frame — and neither side is wrong. 🔴 **Trap:** matching a bound texture's dimensions to a sprite fails both ways — it missed every flash *and* read the intro movie's 640×360 YUV planes as `ptbase2`. ✅ A regression of five events' observed frames against their declared times (residuals ≤0.9 frames) recovers the intercept at frame **106.1** when the composite spike, not in the fit, is frame **107**. ⚠️ Per-vertex alpha = fade alpha holds for the **glow** and does not generalise — `eff4` reads 255/127/254 on consecutive frames. ❔ Frame rate not recorded, so nothing is in seconds; the glow's period implies a **114**-unit cycle against a declared 120, unexplained; `eff5` vs `ptlogo_back2eff` not separated | diff --git a/docs/re/structures/ui-record-loop-length.md b/docs/re/structures/ui-record-loop-length.md index 2aa35aa0..a2458a6b 100644 --- a/docs/re/structures/ui-record-loop-length.md +++ b/docs/re/structures/ui-record-loop-length.md @@ -86,9 +86,28 @@ alpha**, so the ramp can be read straight out of the guest's draw stream * fitting the decoded ramp gives RMS 13.16 alpha levels against **38.18 for the same ramp reversed** — the asymmetry is real and in the decoded direction. -This does not re-measure the period in seconds (the run's frame rate was not -recorded), so the falsification below stands on the corpus's wall-clock timings -rather than on this run. +### ✅ And a calibration-free test that refutes 105 outright + +The measurements above still need a units-per-frame conversion. This one does not. + +The glow's draw is **omitted entirely when its alpha reaches zero**, and the +smallest alpha actually submitted in 807 drawn frames is **1** — so the renderer's +culling threshold is 1, read off the data rather than assumed. The fraction of +settled frames with no glow draw is then a pure ratio within one measurement: + +| | dark-frame fraction | +|---|---| +| **measured** (173 of 980 settled frames) | **17.7 %** | +| predicted by a **120**-unit cycle (15-unit dark hold) at threshold 1 | **14.4 %** | +| predicted by a **105**-unit cycle (no dark hold) at threshold 1 | **2.2 %** | + +🔴 **105 is out by a factor of eight.** For a 105-unit cycle to produce 17.7 % +dark, the culling threshold would have to be **alpha 11 out of a peak of 80** — and +the capture contains submitted draws at alpha 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 and 12, +which refutes any such threshold directly. + +No frame rate, no pacing factor, no wall clock: the declared 15-unit dark hold is +visible in the draw stream as the frames where the game submits no draw at all. ## What this replaces diff --git a/docs/re/structures/ui-title-buildin-measured.md b/docs/re/structures/ui-title-buildin-measured.md index 82d55f17..597dd414 100644 --- a/docs/re/structures/ui-title-buildin-measured.md +++ b/docs/re/structures/ui-title-buildin-measured.md @@ -72,12 +72,27 @@ a different element**, taking the composite spike (frame 107) as t=0: other 155 frames sampled.** The two holders are present continuously from frame 134 onward. That is the decoded mechanism, observed. -⚠️ **`eff3` was never drawn, and that is expected rather than a miss.** A flash's -peak is 2 keyframe units, and at 2.346 units per presented frame that is **0.85 of -a frame** — sub-frame. Whether any given flash is sampled at all depends on phase. -Four of five were caught here; a second run would likely catch a different four. -🔴 **A port that draws all five every time will show more of this sweep than the -console does.** +🔴 **`eff3` was never drawn, and I do not know why. An earlier version of this +page said it was a sub-frame phase effect. That is WITHDRAWN.** `eff3`'s alpha is +non-zero for t ∈ (58, 64), and frames 133 and 134 sit at t = 60.0 and 62.2 — +squarely inside it, with `eff2` and `eff4` both drawn in those same frames. It +should have been submitted and was not. Whatever the reason, it is not sampling +phase. + +🔴 **A second thing this page previously claimed, also withdrawn: that a port +drawing all five flashes shows "more sweep than the console".** There is no +evidence for that. The port draws them sequentially at their declared times, never +more than two at once, which is what frames 131–135 above show the game doing. +The pile-up worth warning about was the `rest()` bug, and that is fixed. + +⚠️ **What a frame-by-frame comparison of the build-in WILL show, and it is not a +defect on either side.** The game's timeline is 60 units/s against a 30 Hz +present, so 2 units per submitted frame; this capture ran at **2.231 units per +presented frame**. A 2-unit flash peak therefore gets about one frame here and +would get more on a faster present. **A build-in compared frame-by-frame against +this capture will disagree about which flashes appear in which frame**, and +neither side is wrong. The settled comparison is unaffected — at t=198 none of the +five is drawn. ## The glow's ramp, read out of the guest @@ -85,6 +100,11 @@ The plate glow's quad carries a **per-vertex colour whose alpha is the element's fade alpha**, so the ramp can be read directly rather than inferred from pixels. * **Observed alpha range: 0 … 80. Decoded peak: 80.** Exact, and not fitted. +* ⚠️ **This identity holds for the glow and does NOT generalise.** Read the same + way, `eff4` gives 255 at frame 133, 127 at 134 and 254 at 135 — non-monotonic, + so a per-vertex alpha is not simply the element's fade alpha for every element. + The glow's agreement (peak exactly 80) is evidence for the glow, not a decoded + rule about vertex colour. * **Period: 51.158 presented frames**, from the first to the last of **20 consecutive cycle starts** (individual periods 49–53). * The draw is **omitted entirely** while the glow is dark — which is what the @@ -112,8 +132,20 @@ zero part-way through a frame. ## Reach and what is not settled -⚠️ **One run, one machine.** 2.346 units per presented frame is *this run's* -pacing, not a property of the game. The internal ratios are what transfer. +⚠️ **One run, one machine.** ~2.23 units per presented frame is *this run's* +pacing, not a property of the game — the game's own quantum is **2 units per +submitted frame** ([`ui-keyframe-time-unit.md`](../ui-keyframe-time-unit.md)). The +internal ratios are what transfer. + +✅ **A validation worth stating: the fit recovers t=0 on its own.** Regressing the +observed frame of five events against their declared keyframe times (residuals +≤ 0.9 frames over t = 42…138) gives a slope of 2.231 units/frame and an intercept +at **frame 106.1** — and the composite spike, which was not part of the fit, is +frame **107**. + +❔ **The glow's period implies a 114-unit cycle at that slope**, against a declared +120. The dark-fraction test below settles 120 against 105 without any calibration, +but the 5 % gap in the period is unexplained. ❔ **The absolute frame rate of this run was not measured** — Canary logged no fps and the log has no timestamps — so nothing here is stated in seconds. It did not