From 2bc20ec31d5ec4ba7bffc76cb49b8447237556f3 Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Mon, 31 Aug 2026 03:46:52 +0000 Subject: [PATCH] tools: a layout control for structural claims -- and the obvious version does not work sylpheed-port named a gap in their own rule: the fourth aside of mine to reach their authored data was a STRUCTURE, not a decoration, and 'the unchecked things carry no weight' did not cover it because a wrong field order looks like a fact. It carried no weight only by luck. The fix belongs at my end, so this is the control that should have existed when I published the layout. The obvious form fails, and its failure is the useful part: checking that all records are type-plausible passes on the SHIFTED alignments too, 69 of 70 in both directions. A homogeneous repeated table has the same field types in sequence, so any window starting on a field boundary type-checks and the interior carries no information about phase. Only the BOUNDARIES do. A shifted reading must consume a word from outside the table at one end, and that word does not obey the field's type -- which is exactly how the original error surfaced, record 0's handler reading as 0x10000000. Two-sided: the published alignment survives at both edges and both shifts fail. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- tools/re-capture/struct_layout_control.py | 111 ++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 tools/re-capture/struct_layout_control.py diff --git a/tools/re-capture/struct_layout_control.py b/tools/re-capture/struct_layout_control.py new file mode 100644 index 00000000..4dfa39f6 --- /dev/null +++ b/tools/re-capture/struct_layout_control.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +"""Type-plausibility control for a published record layout. + +🔴 WHY THIS EXISTS. I published the dialog table as `{handler, id, name_ptr}`. +It is `{id, name_ptr, handler}` -- the same three fields shifted one word, so every +record was credited with the PREVIOUS record's handler. sylpheed-port had copied it +into their authored data before either of us noticed. + +Their rule -- "the claims that go unchecked are the ones that carry no weight" -- +did NOT protect them here, and they named the gap precisely: a wrong FIELD ORDER +looks like a fact rather than an aside, and a later reader builds on it. It carried +no weight only by luck. + +So a structural claim needs a control that FAILS when the alignment is wrong. Every +field has a type, and a wrong alignment breaks the types: an id stops being small, +a string pointer stops pointing at a string, a code pointer stops looking like code. + +⚠️ TWO-SIDED BY CONSTRUCTION: it checks the published layout passes AND that the +shifted alignments fail. A layout check that only confirms the current reading is +the same defect one level up. + + struct_layout_control.py +""" +import struct +import sys + +PE = open("/image/sylpheed.pe", "rb").read() +BASE = 0x82000000 +CODE_LO, CODE_HI = 0x82000000, 0x82600000 + + +def rd(va): + o = va - BASE + return struct.unpack_from(">I", PE, o)[0] if 0 <= o < len(PE) - 4 else None + + +def is_id(v): + return v is not None and v < 100_000 + + +def is_dlg_name(v): + if v is None or not (BASE <= v < BASE + len(PE)): + return False + o = v - BASE + e = PE.find(b"\x00", o) + return e > o and PE[o:e].startswith(b"DLG_") + + +def is_code(v): + """A code pointer whose target opens with a real PowerPC prologue.""" + if v is None or not (CODE_LO <= v < CODE_HI) or v % 4: + return False + w = rd(v) + return w is not None and (w == 0x7D8802A6 or (w >> 26) == 37) # mflr r12 / stwu + + +def check(first_field_va, order, n=70): + """order: sequence of predicates, one per 4-byte field.""" + ok = 0 + for k in range(n): + b = first_field_va + 12 * k + vals = [rd(b + 4 * i) for i in range(len(order))] + if all(p(v) for p, v in zip(order, vals)): + ok += 1 + return ok + + +ID_NAME_HANDLER = (is_id, is_dlg_name, is_code) +HANDLER_ID_NAME = (is_code, is_id, is_dlg_name) +NAME_HANDLER_ID = (is_dlg_name, is_code, is_id) + +TABLE = 0x820A0A30 # first record under the published layout +N = 70 + +# 🔴 THE OBVIOUS CONTROL DOES NOT WORK, AND THAT IS THE POINT. +# Checking "are all records type-plausible" passes on the SHIFTED alignments too: +# 69/70 in both directions. A homogeneous repeated table has the same field types +# in sequence -- id, name, handler, id, name, handler -- so ANY window starting on +# a field boundary type-checks. The interior carries no information about phase. +# +# ✅ ONLY THE BOUNDARIES DO. A shifted reading must consume a word from OUTSIDE the +# table at one end, and that word does not obey the field's type. That is exactly +# how the original error surfaced: under the shifted alignment record 0's "handler" +# was 0x10000000, the word sitting before the table. +print("── dialog table: alignment control (boundaries, not interior) ──") +print(" interior is UNINFORMATIVE, shown so nobody rebuilds it:") +for label, base, order in (("published ", TABLE, ID_NAME_HANDLER), + ("shifted -1", TABLE - 4, HANDLER_ID_NAME), + ("shifted +1", TABLE + 4, NAME_HANDLER_ID)): + print(f" {label} {check(base, order, N)}/{N} records type-plausible") + +def edges_ok(base, order): + """Both terminal records must type-check under this alignment.""" + for k in (0, N - 1): + b = base + 12 * k + if not all(p(rd(b + 4 * i)) for i, p in enumerate(order)): + return False + return True + +print("\n boundaries -- the discriminating test:") +res = [("PUBLISHED {id, name_ptr, handler}", edges_ok(TABLE, ID_NAME_HANDLER), True), + ("shifted -1 {handler, id, name_ptr}", edges_ok(TABLE - 4, HANDLER_ID_NAME), False), + ("shifted +1 {name_ptr, handler, id}", edges_ok(TABLE + 4, NAME_HANDLER_ID), False)] +bad = 0 +for label, got, want in res: + good = (got == want) + bad += not good + print(f" {'✅' if good else '🔴'} {label} edges type-check: {got} (want {want})") +if bad: + print("🔴 LAYOUT CONTROL FAILED"); sys.exit(2) +print("\n ✅ only the published alignment survives at both boundaries")