port: run the peer's shift-vs-blur discriminator -- the menu is not misregistered

They proposed the test and said they had not run it. It needs the port's render
beside the capture, so it was mine: a shift makes the signed residual track the
gradient (and the fitted slope is the shift in pixels), a blur makes it track the
laplacian. New tool, tools/port/edge-residual-kind.

Controls first, and they are not optional: a known +1 px shift reads back as
+0.938 px (r +0.789), a known blur as r -0.896 on the laplacian, neither leaking
into the other's channel.

Result: -0.010 px, -0.009 px, laplacian r +0.103. Flat. Any whole-frame
translation is under a hundredth of a pixel, and the weak blur term has the
opposite sign to the blur control. Misregistration is excluded.

Reach: whole-frame fit. One misplaced element is a small share of 38 752 edge
pixels and would not move these numbers -- this excludes a GLOBAL translation,
not a local one. A misplaced soft element remains untouched.

Exit codes 0 or 2, no 1 -- it classifies, it does not judge. The control-failure
branch verified by raising the thresholds: report suppressed, exit 2.

Also: GP_DIALOG 2/3 restored to authored/flow.json. I declined to re-add it on a
relay; they have now taken the ja capture (HANDOFF at 5a7f34d) -- 1.82 % of pixels
in four bands, EASY/NORMAL/HARD not among them because JP keeps Latin script. My
objection stands as an objection: adjacency never implied a language pair, and 26
of 65 adjacent pairs differ in button count. The claim now rests on a capture
instead of on that inference.
This commit is contained in:
Sylpheed port agent
2026-08-31 04:56:58 +00:00
parent 5738b8328f
commit f4351b0b8c
3 changed files with 229 additions and 1 deletions

View File

@@ -327,6 +327,25 @@
"zero rivals disc-wide, plus the oracle capture. The pairing was decoration on a",
"conclusion that stands without it, which is exactly why it travelled unchecked.",
"",
"✅ RESTORED 2026-08-31, ON A MEASUREMENT RATHER THAN A RELAY. The Decoder took",
"the `ja` capture of DIFFICULTY that was missing and 2/3 ARE English/Japanese:",
"EN vs JP differ in 1.82 % of pixels in FOUR BANDS AND NOWHERE ELSE -- the",
"heading (DIFFICULTY -> the JP heading), the ring by 2 px, the BACK label, and",
"the footer. EASY/NORMAL/HARD are NOT in the differing set: the Japanese release",
"leaves the three difficulty names in Latin script, which is why the disc figure",
"is only 2.77 % of bytes against 1.82 % of pixels.",
"",
"📌 MY OBJECTION WAS NOT WRONG AND IS NOT WITHDRAWN. It was that IDENTICAL",
"ELEMENT SETS DO NOT IMPLY A LANGUAGE PAIR -- 26 of 65 adjacent pairs differ in",
"button count, so adjacency proves nothing. That argument still holds; what has",
"changed is that the conclusion now rests on a direct locale capture instead of",
"on that inference. A bad argument for a true claim is still a bad argument, and",
"the claim was correctly out of this file until somebody went and looked.",
"",
"⚠️ REACH, THEIRS: one JP boot, one screen, does not generalise. GP_TITLE 4/7 is",
"known to differ by MORE than text -- entry 7 carries nine sprites entry 4 lacks.",
"Nothing in the port keys off locale today; this is recorded, not consumed.",
"",
"🔴 RECORD LAYOUT CORRECTED 2026-09-01, and I had copied the wrong one. I wrote",
"\"(handler, id, name pointer)\"; it is {id, name_ptr, handler} -- the same three",
"fields shifted one word, so every record was being credited with the PREVIOUS",

View File

@@ -9,7 +9,7 @@ dies, which is what this file is for.
<!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
323 sections. Search this before re-deriving anything.
325 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)
@@ -334,6 +334,8 @@ dies, which is what this file is for.
* [A workflow defect of mine, on its fourth occurrence](#a-workflow-defect-of-mine-on-its-fourth-occurrence)
* [The menu residual, decomposed — and half of 13.06 is tone](#the-menu-residual-decomposed--and-half-of-1306-is-tone)
* [Refutation: the peer's tone/geometry positive control rests on a number of mine that cannot carry it](#refutation-the-peers-tonegeometry-positive-control-rests-on-a-number-of-mine-that-cannot-carry-it)
* [The menu's edge residual is **not** a misregistration — the Decoder's discriminator, run](#the-menus-edge-residual-is-not-a-misregistration--the-decoders-discriminator-run)
* [`GP_DIALOG` 2/3 restored to `authored/flow.json` — on a measurement this time](#gp_dialog-23-restored-to-authoredflowjson--on-a-measurement-this-time)
<!-- /INDEX -->
## P0 — the exporter, 2026-08-28
@@ -15727,3 +15729,72 @@ edge concentration is spatial. The menu's is 3.2×.
concentration is the signature of sub-pixel misregistration, of antialiasing, or
of a genuinely misplaced soft element, and this measurement does not separate
those three. I am not guessing between them.
## The menu's edge residual is **not** a misregistration — the Decoder's discriminator, run
They proposed the test and said plainly they had not run it: *"the discriminator
would be whether the edge excess is signed — a misplaced element gives a residual
with a consistent direction along the edge, antialiasing does not. That is a real
experiment and I have not run it, so it is a route, not an answer."*
📌 **It needed my render beside the capture, so it was mine to run.** Made concrete:
a shift by `(dx,dy)` makes the signed residual track the **gradient**, and the
fitted slope *is the shift in pixels*; a blur makes it track the **Laplacian**,
symmetric and directionless. New tool: `tools/port/edge-residual-kind`.
### The controls come first, and they are not a flag
| render vs a deliberately damaged copy of itself | d/dx | d/dy | laplacian |
|---|---|---|---|
| known **+1 px horizontal shift** | **r +0.789, slope +0.938 px** | 0.008 px | 0.306 |
| known **blur, no shift** | +0.003 px | +0.004 px | **r 0.896** |
✅ **A 1-px shift reads back as +0.938 px.** The instrument recovers both what it
is for, and neither control leaks into the other's channel.
### The result
| `main_menu` render vs oracle capture | value |
|---|---|
| horizontal shift | r 0.027, **slope 0.010 px** |
| vertical shift | r 0.027, **slope 0.009 px** |
| blur / sharpness | r +0.103 |
🔴 **Flat on all three. The menu is not globally misregistered** — any whole-frame
translation is under **a hundredth of a pixel**, against a control that reads a
true 1 px at 0.938. That excludes the most worrying of the three candidates, and
the one a renderer can silently acquire. The blur channel at +0.103 is weak *and
the opposite sign to the blur control*, so the capture is not a softened render
either.
⚠️ **Reach, and it is the whole reach:** this is a **whole-frame** fit. A single
misplaced element is a small share of 38 752 edge pixels and would not move these
numbers. **This excludes a global translation, not a local one.** Of the peer's
three candidates it kills misregistration and weakens uniform antialiasing; a
misplaced soft element is untouched by it, and I am not claiming otherwise.
📌 Exit codes are **0 or 2, and there is no 1** — the tool classifies, it does not
judge. If either control fails it prints nothing but the failure: verified by
raising the thresholds to 0.99, which suppresses the report and exits 2. A guard
nobody has watched fail is decoration.
## `GP_DIALOG` 2/3 restored to `authored/flow.json` — on a measurement this time
I withdrew *"an EN/JP pair"* as an unchecked relay and **declined to re-add it**
because nothing depended on it. The Decoder has now taken the `ja` capture that
was missing (`HANDOFF` at `5a7f34d`, dated today): EN and JP differ in **1.82 % of
pixels in four bands and nowhere else** — heading, the ring by 2 px, `BACK`, the
footer. `EASY`/`NORMAL`/`HARD` are *not* in the differing set; the Japanese release
leaves them in Latin script, which is why the disc figure is only **2.77 % of
bytes**.
📌 **My objection was not wrong and is not withdrawn.** It was that *identical
element sets do not imply a language pair* — 26 of 65 adjacent `GP_DIALOG` pairs
differ in button count, so adjacency proves nothing. That still holds. What changed
is that the claim now rests on a direct locale capture instead of on that
inference. **A bad argument for a true claim is still a bad argument**, and the
claim was correctly out of the file until somebody went and looked.
⚠️ Their reach, carried across: one JP boot, one screen, does not generalise —
`GP_TITLE` 4/7 differs by more than text. Nothing in the port keys off locale
today, so this is recorded, not consumed.

138
tools/port/edge-residual-kind Executable file
View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python3
"""What KIND of error is left at the edges after tone is accounted for?
tools/port/edge-residual-kind [screen] # default main_menu
`verify-capture`'s `diff` column thresholds at 25 % and so only sees GROSS
displacement. Fitting a per-level LUT removes everything a tone effect can
explain. What is left on the main menu is concentrated 3.2x on edge pixels
(DECISIONS.md, 2026-08-31) -- and three things produce that: a misregistration,
an antialiasing difference, or a genuinely misplaced element.
THE DISCRIMINATOR IS THE SIGN, and it is the Decoder's, from their reply on
2026-08-31: a shift gives a residual with a CONSISTENT DIRECTION along the edge,
an antialiasing difference does not. Made concrete:
* shifted by (dx,dy): residual ~ dx*d/dx + dy*d/dy -- and the fitted SLOPE
IS THE SHIFT IN PIXELS
* blurred/sharpened : residual ~ -k * laplacian -- symmetric, no direction
EXIT CODES. 0 the report is trustworthy, 2 A CONTROL FAILED so the numbers below
it mean nothing. There is no 1: this tool classifies, it does not judge. A
correlation this tool reports is worthless without the two controls above it,
which is why they are not optional and not a flag.
"""
import math, os, subprocess, sys, tempfile
CAPS = "docs/re/captures/title-builds"
SCREEN = sys.argv[1] if len(sys.argv) > 1 else "main_menu"
# The captures are a 1279x675 top-left crop of the 1280x720 guest surface, so the
# render is cropped to match and NOTHING IS SCALED -- resampling would manufacture
# exactly the edge signal this tool measures. See verify-capture, same reason.
W, H = 1279, 675
EDGE = 12 # |grad| above which a pixel is an edge
PASS_SHIFT, PASS_BLUR = 0.70, -0.70
def gray(png, out):
subprocess.run(["convert", png, "-colorspace", "Gray", "-depth", "8",
"gray:" + out], check=True)
return open(out, "rb").read()
def lutfit(a, b):
tot = [0] * 256; cnt = [0] * 256
for i in range(len(a)):
tot[a[i]] += b[i]; cnt[a[i]] += 1
return [(tot[v] // cnt[v]) if cnt[v] else v for v in range(256)]
def analyse(a, b):
lut = lutfit(a, b)
gx = []; gy = []; lp = []; rs = []
for y in range(1, H - 1):
o = y * W
for x in range(1, W - 1):
i = o + x
ax = (a[i + 1] - a[i - 1]) * 0.5
ay = (a[i + W] - a[i - W]) * 0.5
if abs(ax) + abs(ay) < EDGE:
continue
gx.append(ax); gy.append(ay)
lp.append(float(a[i + 1] + a[i - 1] + a[i + W] + a[i - W] - 4 * a[i]))
rs.append(float(lut[a[i]] - b[i]))
n = len(rs)
if n < 1000:
print(f" 🔴 only {n} edge pixels -- nothing to classify"); sys.exit(2)
mr = sum(rs) / n
def fit(u):
mu = sum(u) / n
suu = sum((v - mu) ** 2 for v in u)
srr = sum((v - mr) ** 2 for v in rs)
sur = sum((u[k] - mu) * (rs[k] - mr) for k in range(n))
return (0.0, 0.0) if suu <= 0 or srr <= 0 else (sur / suu, sur / math.sqrt(suu * srr))
return n, fit(gx), fit(gy), fit(lp)
def row(label, res):
n, (sx, rx), (sy, ry), (sl, rl) = res
print(f" {label} (n={n})")
print(f" horizontal shift : r={rx:+.3f} slope={sx:+.3f} px")
print(f" vertical shift : r={ry:+.3f} slope={sy:+.3f} px")
print(f" blur / sharpness : r={rl:+.3f} coef ={sl:+.3f}")
return rx, ry, rl
def shifted(a, dx):
out = bytearray(a)
for y in range(H):
for x in range(W):
out[y * W + x] = a[y * W + min(W - 1, max(0, x - dx))]
return bytes(out)
def blurred(a):
out = bytearray(a)
for y in range(1, H - 1):
o = y * W
for x in range(1, W - 1):
i = o + x
out[i] = (a[i] * 4 + a[i + 1] + a[i - 1] + a[i + W] + a[i - W]) // 8
return bytes(out)
tmp = tempfile.mkdtemp()
cap_png = f"{CAPS}/live-{SCREEN.replace('_', '-')}.png"
if not os.path.exists(cap_png):
print(f" 🔴 no capture: {cap_png}"); sys.exit(2)
render = os.environ.get("RENDER") or f"{tmp}/render.png"
if not os.path.exists(render):
print(f" 🔴 no render at {render} -- set RENDER=<png>"); sys.exit(2)
subprocess.run(["convert", render, "-crop", f"{W}x{H}+0+0", "+repage",
f"{tmp}/crop.png"], check=True)
r = gray(f"{tmp}/crop.png", f"{tmp}/r.gray")
c = gray(cap_png, f"{tmp}/c.gray")
print("CONTROLS -- the render against a deliberately damaged copy of itself.")
print("A correlation below is meaningless unless these two recover what was done.\n")
ra = analyse(r, shifted(r, 1))
rxa, _, rla = row("known +1 px HORIZONTAL shift", ra)
rb = analyse(r, blurred(r))
_, _, rlb = row("known BLUR, no shift", rb)
bad = []
if rxa < PASS_SHIFT: bad.append(f"shift control r={rxa:+.3f} < {PASS_SHIFT}")
if rlb > PASS_BLUR: bad.append(f"blur control r={rlb:+.3f} > {PASS_BLUR}")
if bad:
print("\n 🔴 CONTROL FAILED: " + "; ".join(bad))
print(" The discriminator cannot see what it is for. Report suppressed.")
sys.exit(2)
print(f"\n ✅ controls pass -- a 1 px shift reads as {ra[1][0]:+.3f} px\n")
print(f"THE REAL PAIR -- {SCREEN}\n")
rx, ry, rl = row(f"{SCREEN} render vs oracle capture", analyse(r, c))
print()
if max(abs(rx), abs(ry)) < 0.15 and abs(rl) < 0.3:
print(" => NEITHER a global shift NOR a uniform blur.")
print(" ⚠️ REACH: this is a WHOLE-FRAME fit. One misplaced element is a small")
print(" share of the edge pixels and would not move these numbers. This")
print(" excludes a global translation; it does not exclude a local one.")