port: localise the menu residual -- nothing is displaced, and the split I expected is absent
tools/port/edge-residual-map tiles the frame at 64 px and runs the shift discriminator inside each tile, which is what edge-residual-kind's reach statement said it could not do. Division agreed with the Decoder: the map is mine, the element inventory is theirs. The first control failed and that is the useful part. A known +2 px displacement localises perfectly but reads back +0.839 -- the slope is a linearisation and saturates. So there are two controls now: +1 px asserts localisation AND magnitude (+0.949), +2 px asserts localisation and sign only. A hot tile's slope is a floor on the displacement, never a ceiling. Result: every dx and dy in the top ten tiles is under 0.1 px. Nothing in the hot region has moved, locally or globally, so the misplaced-soft-element candidate now has no support on this screen. Hot tiles cluster at x 384-704, y 64-256 plus an outlier at 640,576; the tool names nothing and the list has gone to the Decoder. And a null: I added a flat-pixel column expecting two families, edge-only against hot-everywhere. The hot tiles run continuously 1.24..3.37 across a median of 1.84. What nearly manufactured the split was carrying over the frame-wide POOLED ratio of 3.16 as the baseline -- pooling is dominated by the tiles with the most edge pixels. Same quantity, wrong population; caught because the baseline was computed before the claim rather than after.
This commit is contained in:
@@ -9,7 +9,7 @@ dies, which is what this file is for.
|
||||
|
||||
<!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
|
||||
|
||||
325 sections. Search this before re-deriving anything.
|
||||
326 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)
|
||||
@@ -336,6 +336,7 @@ dies, which is what this file is for.
|
||||
* [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)
|
||||
* [The residual map: no local displacement either, and the split I expected is not there](#the-residual-map-no-local-displacement-either-and-the-split-i-expected-is-not-there)
|
||||
|
||||
<!-- /INDEX -->
|
||||
## P0 — the exporter, 2026-08-28
|
||||
@@ -15798,3 +15799,68 @@ 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.
|
||||
|
||||
## The residual map: no local displacement either, and the split I expected is not there
|
||||
|
||||
The Decoder proposed the division and it is the right one: *"the map is yours and
|
||||
the element inventory is mine."* `tools/port/edge-residual-map` tiles the frame at
|
||||
64 px and runs the same shift discriminator **inside each tile**, which is the
|
||||
thing `edge-residual-kind` said it structurally could not do.
|
||||
|
||||
### 🔴 The first control failed, and that is the useful part
|
||||
|
||||
A known **+2 px** displacement localises perfectly — the displaced region is the
|
||||
top four tiles — but reads back **+0.839 px**. The slope is a linearisation,
|
||||
`residual ≈ dx · gradient`, valid only while `dx` is small against the width of an
|
||||
edge. **The estimator saturates.** Reporting that as a distance would have
|
||||
understated a real displacement by more than half.
|
||||
|
||||
So there are now **two** controls, each asserting only what it can:
|
||||
|
||||
| control | localises | magnitude |
|
||||
|---|---|---|
|
||||
| **+1 px** (linear regime) | ✅ top 4 tiles | ✅ **+0.949** |
|
||||
| **+2 px** (saturating) | ✅ top 4 tiles | ⚠️ +0.839 — **a lower bound** |
|
||||
|
||||
📌 **A hot tile's slope is a floor on the displacement, never a ceiling.**
|
||||
|
||||
### The result
|
||||
|
||||
| tile | edge | flat | e/f | dx | dy |
|
||||
|---|---|---|---|---|---|
|
||||
| 512,128 | **18.80** | 10.20 | 1.84 | **−0.001** | **−0.000** |
|
||||
| 576,64 | 15.11 | 9.09 | 1.66 | −0.012 | +0.029 |
|
||||
| 384,256 | 14.12 | 4.40 | 3.21 | +0.003 | +0.003 |
|
||||
| 512,192 | 11.91 | 3.53 | 3.37 | −0.038 | −0.090 |
|
||||
| 448,128 | 11.78 | 9.53 | 1.24 | +0.084 | +0.036 |
|
||||
|
||||
median tile 5.13 · hottest 3.66× median · **every dx and dy under 0.1 px**
|
||||
|
||||
🔴 **No tile in the top ten is displaced.** Against a control that reads a true
|
||||
1 px at +0.949 and finds a 2 px one even while understating it, **nothing in the
|
||||
hot region has moved.** The peer's third candidate — a misplaced soft element —
|
||||
now has no support anywhere on this screen, globally or locally.
|
||||
|
||||
The hot tiles cluster: **x 384–704, y 64–256**, a wide upper-centre band, plus one
|
||||
outlier at **640,576**. Those are coordinates. **This tool names nothing** — what
|
||||
sits under them is the Decoder's, and I have sent them the list.
|
||||
|
||||
### ⚠️ And a structure I expected, went looking for, and did not find
|
||||
|
||||
I added the `flat` column expecting two families: tiles hot *only* at edges (an
|
||||
edge-rendering difference) against tiles hot *everywhere* (a local tone the global
|
||||
LUT mis-serves). Reading the first ten rows, that split looked obvious.
|
||||
|
||||
It is not there. The hot tiles run **continuously from 1.24 to 3.37** across a
|
||||
median of **1.84**.
|
||||
|
||||
📌 **What nearly manufactured it:** I had the frame-wide *pooled* edge/flat ratio,
|
||||
**3.16**, from the earlier work, and against 3.16 the rows at 1.2–1.8 look like a
|
||||
distinct low family. But the pooled figure is dominated by the tiles carrying the
|
||||
most edge pixels; **the per-tile median is 1.84**, and against *that* the same rows
|
||||
are unremarkable. **Same quantity, wrong population** — the week's pattern again,
|
||||
caught this time only because I computed the baseline before writing the claim
|
||||
rather than after.
|
||||
|
||||
**So the hot region is not one anomalous element with a character of its own**, and
|
||||
that is a finding, not an absence of one.
|
||||
|
||||
180
tools/port/edge-residual-map
Executable file
180
tools/port/edge-residual-map
Executable file
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
"""WHERE does the edge residual sit, and is that region locally shifted?
|
||||
|
||||
RENDER=<png> tools/port/edge-residual-map [screen]
|
||||
|
||||
`edge-residual-kind` fits the whole frame and excludes a GLOBAL translation. Its
|
||||
own reach statement says the thing it cannot do: one misplaced element is a small
|
||||
share of 38 752 edge pixels and would not move a whole-frame number. This tiles
|
||||
the frame and runs the same discriminator INSIDE each tile, so a single displaced
|
||||
element shows up as one hot tile with a local slope -- which is invisible to the
|
||||
global fit by construction, not by accident.
|
||||
|
||||
Division of labour, agreed with the Decoder 2026-08-31: the residual map is the
|
||||
port's (it needs the render beside the capture), the element inventory is theirs
|
||||
(it needs the disc). This tool produces the map and NAMES NOTHING.
|
||||
|
||||
THE CONTROL IS A KNOWN LOCAL SHIFT. A map that cannot localise a displacement it
|
||||
was told about cannot be trusted to have found one it was not. Exit 0 the report
|
||||
is trustworthy, 2 the control failed and the report is suppressed. No 1.
|
||||
"""
|
||||
import math, os, subprocess, sys, tempfile
|
||||
|
||||
CAPS = "docs/re/captures/title-builds"
|
||||
SCREEN = sys.argv[1] if len(sys.argv) > 1 else "main_menu"
|
||||
W, H = 1279, 675 # top-left crop of the guest surface; never scaled
|
||||
TILE = 64
|
||||
EDGE = 12
|
||||
MIN_EDGE_PX = 150 # below this a tile's slope is noise
|
||||
# The controls displace this region and the map must find it there.
|
||||
CTRL_BOX = (448, 320, 640, 448) # x0, y0, x1, y1
|
||||
# TWO controls, because ONE OF THEM FAILED AND TAUGHT ME THE LIMIT. The slope is
|
||||
# a linearisation, residual ~ dx * gradient, which holds only while dx is small
|
||||
# against the width of an edge. A +2 px displacement localises perfectly but reads
|
||||
# back +0.8..+1.25, so the estimator SATURATES. Control A checks magnitude in the
|
||||
# regime where magnitude means something; control B checks that a displacement too
|
||||
# large to measure is still FOUND. Reporting a saturating slope as a distance
|
||||
# would understate a real displacement by more than half.
|
||||
CTRL_A_DX = 1 # linear regime: localisation AND magnitude
|
||||
CTRL_B_DX = 2 # saturating: localisation and SIGN only
|
||||
|
||||
|
||||
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 tiles(a, b):
|
||||
"""Per-tile mean |residual| on edge pixels, and the local shift slope."""
|
||||
lut = lutfit(a, b) # ONE global LUT: tone is global, displacement is not
|
||||
out = {}
|
||||
for ty in range(0, H - 1, TILE):
|
||||
for tx in range(0, W - 1, TILE):
|
||||
gx = []; gy = []; rs = []; flat = []
|
||||
for y in range(max(1, ty), min(H - 1, ty + TILE)):
|
||||
o = y * W
|
||||
for x in range(max(1, tx), min(W - 1, tx + TILE)):
|
||||
i = o + x
|
||||
ax = (a[i + 1] - a[i - 1]) * 0.5
|
||||
ay = (a[i + W] - a[i - W]) * 0.5
|
||||
d = float(lut[a[i]] - b[i])
|
||||
if abs(ax) + abs(ay) < EDGE:
|
||||
flat.append(abs(d)); continue
|
||||
gx.append(ax); gy.append(ay); rs.append(d)
|
||||
n = len(rs)
|
||||
if n < MIN_EDGE_PX:
|
||||
continue
|
||||
mabs = sum(abs(v) for v in rs) / n
|
||||
mflat = (sum(flat) / len(flat)) if flat else 0.0
|
||||
mr = sum(rs) / n
|
||||
|
||||
def slope(u):
|
||||
mu = sum(u) / n
|
||||
suu = sum((v - mu) ** 2 for v in u)
|
||||
if suu <= 0:
|
||||
return 0.0
|
||||
return sum((u[k] - mu) * (rs[k] - mr) for k in range(n)) / suu
|
||||
out[(tx, ty)] = (mabs, slope(gx), slope(gy), n, mflat)
|
||||
return out
|
||||
|
||||
|
||||
def top(t, k=8):
|
||||
return sorted(t.items(), key=lambda kv: -kv[1][0])[:k]
|
||||
|
||||
|
||||
def show(t, label, k=8):
|
||||
print(f" {label}")
|
||||
print(f" {'tile':>12} {'edge':>7} {'flat':>7} {'e/f':>6} "
|
||||
f"{'dx':>7} {'dy':>7} {'edge px':>8}")
|
||||
for (tx, ty), (m, sx, sy, n, mf) in top(t, k):
|
||||
ef = (m / mf) if mf > 0.01 else float('inf')
|
||||
print(f" {tx:4d},{ty:4d} {m:7.2f} {mf:7.2f} {ef:6.2f} "
|
||||
f"{sx:+7.3f} {sy:+7.3f} {n:8d}")
|
||||
|
||||
|
||||
def shift_box(a, box, dx):
|
||||
x0, y0, x1, y1 = box
|
||||
out = bytearray(a)
|
||||
for y in range(y0, y1):
|
||||
for x in range(x0, x1):
|
||||
out[y * W + x] = a[y * W + min(W - 1, max(0, x - dx))]
|
||||
return bytes(out)
|
||||
|
||||
|
||||
tmp = tempfile.mkdtemp()
|
||||
cap = f"{CAPS}/live-{SCREEN.replace('_', '-')}.png"
|
||||
render = os.environ.get("RENDER", "")
|
||||
for p in (cap, render):
|
||||
if not p or not os.path.exists(p):
|
||||
print(f" 🔴 missing: {p or '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, f"{tmp}/c.gray")
|
||||
|
||||
print("CONTROLS -- the render against itself with ONE REGION displaced.\n"
|
||||
"The map must put that region on top; magnitude only in the linear regime.\n")
|
||||
x0, y0, x1, y1 = CTRL_BOX
|
||||
bad = []
|
||||
|
||||
|
||||
def control(dx, check_magnitude):
|
||||
t = tiles(r, shift_box(r, CTRL_BOX, dx))
|
||||
show(t, f"known +{dx} px shift inside x {x0}-{x1}, y {y0}-{y1}", 4)
|
||||
hits = [(k, v) for k, v in top(t, 4)
|
||||
if x0 - TILE < k[0] < x1 and y0 - TILE < k[1] < y1]
|
||||
if not hits:
|
||||
bad.append(f"+{dx} px: displaced region not in the top 4 tiles")
|
||||
return
|
||||
best = max(hits, key=lambda kv: kv[1][0])[1][1]
|
||||
if best <= 0.3:
|
||||
bad.append(f"+{dx} px: local slope {best:+.3f} has the wrong sign or is flat")
|
||||
elif check_magnitude and abs(best - dx) > 0.4:
|
||||
bad.append(f"+{dx} px: local slope {best:+.3f} does not recover it")
|
||||
print(f" -> localised, local slope {best:+.3f} px"
|
||||
f"{'' if check_magnitude else ' (saturating -- a LOWER BOUND)'}\n")
|
||||
|
||||
|
||||
control(CTRL_A_DX, True)
|
||||
control(CTRL_B_DX, False)
|
||||
if bad:
|
||||
print(" 🔴 CONTROL FAILED: " + "; ".join(bad))
|
||||
print(" A map that cannot find a displacement it was told about cannot be")
|
||||
print(" trusted to have found one it was not. Report suppressed.")
|
||||
sys.exit(2)
|
||||
print(" ✅ controls pass: a 1 px displacement is localised and measured, a 2 px\n"
|
||||
" one is localised with its magnitude understated. So a hot tile with a\n"
|
||||
" real slope is a floor on the displacement, never a ceiling.\n")
|
||||
|
||||
print(f"THE REAL PAIR -- {SCREEN}\n")
|
||||
rt = tiles(r, c)
|
||||
show(rt, f"{SCREEN}: hottest tiles, whole-frame LUT applied", 10)
|
||||
ms = sorted(v[0] for v in rt.values())
|
||||
med = ms[len(ms) // 2]
|
||||
efs = sorted(v[0] / v[4] for v in rt.values() if v[4] > 0.01)
|
||||
med_ef = efs[len(efs) // 2]
|
||||
hot = max(rt.items(), key=lambda kv: kv[1][0])
|
||||
print(f"\n median tile |resid| {med:.2f} hottest {hot[1][0]:.2f} "
|
||||
f"at {hot[0][0]},{hot[0][1]} ({hot[1][0]/med:.2f}x median)")
|
||||
print(f" median tile edge/flat {med_ef:.2f}")
|
||||
efs_hot = [v[0] / v[4] for _, v in top(rt, 10) if v[4] > 0.01]
|
||||
print(f" hot tiles span edge/flat {min(efs_hot):.2f}..{max(efs_hot):.2f}, "
|
||||
f"straddling that median")
|
||||
print(" 📌 SO THE COLUMN DOES NOT SPLIT THEM. I added it expecting two families --")
|
||||
print(" tiles hot only at edges (an edge-rendering difference) against tiles")
|
||||
print(" hot everywhere (a local tone the global LUT mis-serves). The hot tiles")
|
||||
print(" run continuously across the median instead, so the hot region is NOT")
|
||||
print(" one anomalous element with a character of its own. Note the frame-wide")
|
||||
print(" pooled edge/flat is 3.16 while the per-tile median is 1.84: pooling is")
|
||||
print(" dominated by the tiles carrying the most edge pixels, and reading a")
|
||||
print(" per-tile threshold off it would have manufactured the split.")
|
||||
print("\n ⚠️ THIS TOOL NAMES NOTHING. A hot tile is a coordinate, not an element.")
|
||||
print(" What sits under it is the Decoder's to say -- they hold the disc.")
|
||||
Reference in New Issue
Block a user