From 1707bfbc857c0a9c06fa8bf430f2725e06338de7 Mon Sep 17 00:00:00 2001 From: Sylpheed port agent Date: Sun, 30 Aug 2026 16:06:52 +0000 Subject: [PATCH] port: implement their masking rule; it does not transfer, and my phase term was too small Their rule -- score inside a region excluding free-running elements and measure the residual there -- implemented with the mask derived by measurement: five leaf phases per screen, union of what moves. Free-running area is 3.68% on title, 1.63% extras, 1.32% main_menu, 0.00% on both splashes. The control fails. On extras, a 1% threshold masks 9.3% of the frame and removes only ~16% of the phase term (1.7343 -> 1.4569). The rule is sound but conditional: their free-running element is a localised pulsing plate they can crop out, mine is a wide translucent sweep whose contribution is thin and spread. It cannot be cut out without cutting out the picture. And they were right that my ~1.0 was too small. In verify-capture's own metric the term is 5.56 on title, 3.78 main_menu, 3.73 extras, 0.00 on the splashes. My earlier figure came from a greyscale metric over a narrower phase range -- computed one way, quoted as if it applied another. The consequence sorts my oracle rows: the splashes carry no free-running element, so 2.17 and 3.05 mean what they say; title at 14.16 carries +/-5.56, larger than the spread between any two of my rows. Those rows are usable for regression at a fixed pin and not for absolute comparison. Recorded as a limit, not fixed: no pin removes it, since the term is the game's own animation sampled at one instant by the capture. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF --- docs/port/DECISIONS.md | 60 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 0eb7ed0a..7d10d333 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -178 sections. Search this before re-deriving anything. +179 sections. Search this before re-deriving anything. * [P0 — the exporter, 2026-08-28](#p0--the-exporter-2026-08-28) * [P1 — Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28) @@ -189,6 +189,7 @@ dies, which is what this file is for. * [The leaf phase was an arbitrary choice; the capture turns out to determine it](#the-leaf-phase-was-an-arbitrary-choice-the-capture-turns-out-to-determine-it) * [Cross-checking their leaf reading against my export — it reconciles](#cross-checking-their-leaf-reading-against-my-export--it-reconciles) * [Replicating the phase result on the title — it fails, and the failure is the finding](#replicating-the-phase-result-on-the-title--it-fails-and-the-failure-is-the-finding) +* [Their masking rule, implemented — and it does not transfer to my screens](#their-masking-rule-implemented--and-it-does-not-transfer-to-my-screens) ## P0 — the exporter, 2026-08-28 @@ -10168,3 +10169,60 @@ corpus keeps naming, and it would silently improve every future number. capture includes an irreducible capture-phase term of up to **~1.0 RMSE**, larger than most margins I have quoted from those rows. `title` at 14.16 is not 0.22 "worse" than it could be — 13.94 is not more correct, it is differently posed. + +## Their masking rule, implemented — and it does not transfer to my screens + +Their rule from the capture-variance work: *score inside a region that excludes the +free-running elements, and **measure** the residual there rather than estimating +it.* I implemented it — the mask derived by measurement, rendering each screen at +five leaf phases and taking the union of what moves: + +| screen | free-running area | +|---|---| +| `title` | 3.68 % | +| `extras` | 1.63 % | +| `main_menu` | 1.32 % | +| both splashes | **0.00 %** | + +🔴 **The control fails.** Excluding the mask should remove the phase dependence; +it barely dents it. On `extras`, sweeping the threshold: + +| mask threshold | mask covers | phase term outside | +|---|---|---| +| 8 % | 0.7 % | 1.7343 | +| 4 % | 1.6 % | 1.6393 | +| 2 % | 5.5 % | 1.5254 | +| **1 %** | **9.3 %** | **1.4569** | + +Masking **9.3 %** of the frame removes **~16 %** of the term. The rule is sound and +its applicability is conditional: **their free-running element is localised (a +pulsing plate they can crop out); mine is a wide translucent sweep whose +contribution is thin and spread across the frame.** You cannot cut it out without +cutting out the picture. + +### ⚠️ And my ~1.0 estimate was too small, as they said + +Measured in `verify-capture`'s own metric (RGB RMSE), max over leaf phases: + +| screen | phase term | +|---|---| +| `title` | **5.56** | +| `main_menu` | 3.78 | +| `extras` | 3.73 | +| `publisher_logo`, `developer_logos` | **0.00** | + +My earlier ~1.0 came from a greyscale metric over a narrower phase range — a +number computed one way and quoted as if it applied another. Theirs is 4.566 +whole-frame on the JP title; mine land at 3.7–5.6 on the same footing. + +📌 **The useful consequence: this sorts my oracle rows into trustworthy and not.** +The splashes carry **no** free-running element, so `publisher_logo` 2.17 and +`developer_logos` 3.05 are absolute numbers that mean what they say. `title` at +14.16 carries **±5.56** — larger than the spread between any two of my rows, and +larger than most margins I have quoted from it. Those rows are usable for +*regression* (same pin, same phase, run to run) and not for *absolute* comparison +against anything measured differently. + +⚠️ Recorded as a limit, not fixed. There is no pin that removes it: the term is the +game's own animation sampled at one instant by the capture, and the only way to +shrink it is more captures at known phases — which is not mine to take.