fix(symfix): key the slate by (binary, fn); §420 multi-cluster rebase banks 4 in 57s

aprop_symfix deduped its slate by BARE FUNCTION NAME, so a four-row slate for
func_8016AB6C across ov_SC03_107/ov_SC07_007/010/011 reported "1 drafts audited" - and
the three dropped rows each needed a DIFFERENT rebase, because each overlay has its own
target symbols. Same root as reloc_filter's binof and gate_lane's homonym staging: three
tools, one R48/§238 defect.

With all four visible, the structure is two uniform delta clusters of two, identical in
shape across all four overlays - one seed body's two data clusters each moving as a
block. STALE-DELTA only admits ONE cluster, so it refused all four as AMBIGUOUS. §420
records the safe generalisation (runs of constant delta, every run >= 2 members, D_
symbols only) and the verification step.

Rebased by hand under that rule, all four still MATCH at closeness 0, and the gate
banked 4/4 in 57 seconds with no drafting (commit:3629). Frontier 165, 45 banked.
This commit is contained in:
Drew T
2026-09-02 05:38:28 -06:00
parent 24d5017039
commit 2cedd19aaa
3 changed files with 51 additions and 4 deletions
+5 -2
View File
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
> `docs/matching-cookbook.md` is ~716 KB / 1087 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
> `docs/matching-cookbook.md` is ~716 KB / 1088 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -812,7 +812,7 @@
- **§362** — TWO TRAPS WHEN A CARVE MOVES A STUB INTO THE `-O0` TU (P31 S68; byte-proven, 6 fns / 2,547 ins across ov_MAIN_012 / ov_SC02_037 / ov_SC03_107) <sub>L31682</sub>
- **§388** — ★★★ — THE **-O0 COLOURING ORACLE**: simulate `stupid.c` instead of grinding spellings (P31 S69; main/func_80011380 proved a C-level WALL at 6) <sub>L32384</sub>
### family propagation & sweeps (120)
### family propagation & sweeps (121)
- **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) <sub>L502</sub>
- **§11** — Cross-binary dedup & code-sharing (Phase 11 — "one match unlocks many") <sub>L927</sub>
@@ -934,6 +934,7 @@
- **§398** — ★★★ — `family_remap` CARRIES THE **SOURCE** TU's DECL ENVIRONMENT INTO A DESTINATION THAT ALREADY OWNS THOSE NAMES (P31 S69; measured 3 banked of 22) <sub>L32835</sub>
- **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) <sub>L33108</sub>
- **§408** — ★★★ — §406 REFUTED AS A SWEEP: THE SHAPE IS THE FAMILY, THE DISAGREEMENT IS THE DEFECT (P31 S71; 0 MATCH / 14 applied, 0 / 210) <sub>L33209</sub>
- **§420** — ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT (P31 S71; 4 banked in 57 s) <sub>L33692</sub>
### integration / TU plumbing (76)
@@ -2762,6 +2763,7 @@
- **§417** — ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `cse` SKIP-BLOCKS MERGE (P31 S71; byte-proven `ov_SC03_013/func_8017E6F4`, 182 ins) <sub>L33605</sub>
- **§418** — ★★★ — TWO LOOP-STRUCTURE LEVERS: MAKE THE SECOND INDEX A GIV, AND KEEP A TABLE ADDRESS UNFOLDED (P31 S71; byte-proven `ov_SC04_016/func_8017DF8C`, 184 ins, 32 → 0 in seven compiles) <sub>L33632</sub>
- **§419** — ★★★ — WHEN A PIN IS IMPOSSIBLE, WIN THE local-alloc DENSITY CONTEST INSTEAD (P31 S71; byte-proven `ov_SC01_000/func_8017DD04`, 297 ins) <sub>L33658</sub>
- **§420** — ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT (P31 S71; 4 banked in 57 s) <sub>L33692</sub>
---
@@ -3861,3 +3863,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: `
| L33605 | §417 | ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `c |
| L33632 | §418 | ★★★ — TWO LOOP-STRUCTURE LEVERS: MAKE THE SECOND INDEX A GIV, AND KEEP A TABLE ADDRESS UNF |
| L33658 | §419 | ★★★ — WHEN A PIN IS IMPOSSIBLE, WIN THE local-alloc DENSITY CONTEST INSTEAD (P31 S71; byte |
| L33692 | §420 | ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT |
+37
View File
@@ -33688,3 +33688,40 @@ density ranking rather than the register.* Reference count is a dial (zero-byte
length is a dial (where you place the barrier); local-alloc's ordering is arithmetic on the two, so
compute it from the `-df`/`-dl` dumps and aim, instead of trying pins that a call-argument register
structurally forbids.
## §420 ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT (P31 S71; 4 banked in 57 s)
**The shape.** One shared body (`func_8016AB6C`) lives in four overlays — `ov_SC03_107`,
`ov_SC07_007`, `ov_SC07_010`, `ov_SC07_011`. Every copy scored `match_one` closeness 0 and every copy
failed the gate with `undefined reference to D_8018D538`: the classic §171 stale-seed-symbol class, the
draft carrying the symbols of the overlay it was written for.
**Defect 1 — `aprop_symfix` deduped the slate by BARE FUNCTION NAME (R48/§238).** A four-row slate
reported *"1 drafts audited"*. Three rows were silently dropped, and they were not redundant: **each
overlay needs a DIFFERENT rebase**, because each has its own target symbols. Keyed by `(binary, fn)`,
all four audit. This is the same defect class as `reloc_filter`'s `binof` (fixed earlier the same
session) and `gate_lane`'s homonym staging — three tools, one root.
**Defect 2 — the delta rule allowed exactly ONE uniform cluster.** `STALE-DELTA` requires the sorted
zip to have a single `target − draft` delta, so it refused all four as AMBIGUOUS. The real structure
is **two clusters of two**, and it is identical in shape across all four overlays:
| overlay | run 1 | run 2 |
|---|---|---|
| ov_SC03_107 | −0x7F64 ×2 | −0x5A650 ×2 |
| ov_SC07_007 | −0x74DC ×2 | −0x2E898 ×2 |
| ov_SC07_010 | −0x844C ×2 | −0x4E3A0 ×2 |
| ov_SC07_011 | −0xBD8C ×2 | −0x65D08 ×2 |
Two data clusters, each moving as a block — exactly what one seed body copied into four overlays
produces. The single-delta rule is the special case of one cluster.
**The safe generalisation.** Sort both symbol lists, zip positionally, split into runs of constant
delta, and **require every run to have ≥ 2 members** — a single-member run is a free guess, not a
cluster, and that is where a wrong symbol would come from. Filter to `D_8xxxxxxx` first: the draft's
`Ent_`/`Obj_`/`SVec_` typedef names and the target's `rand`/`jtbl_` carry the same vram-looking suffix
and are not data symbols.
**Result: 4 banked in 57 seconds of gate time, zero drafting** — and all four had been sitting at
closeness 0 behind a symbol rename. **Verify after rewriting** (`match_one` again, all four still
MATCH) before gating; a rebase that changes the body is a rebase you got wrong.
+9 -2
View File
@@ -188,12 +188,19 @@ def main():
recs = [r for r in json.load(open(a.slate)) if isinstance(r, dict) and (r.get('fn') or r.get('name'))]
skip = set(json.load(open(a.skip))) if a.skip else set()
# KEY BY (binary, fn), NEVER BY NAME (R48/§238). A slate legitimately carries the SAME function
# name for several binaries — one shared body copied into four overlays is the common case — and
# a name-keyed `seen` silently audited ONE of them. Measured S71: a 4-row slate for
# func_8016AB6C across ov_SC03_107/ov_SC07_007/010/011 reported "1 drafts audited", and the
# three unexamined rows each needed a DIFFERENT rebase because each overlay's target symbols
# differ.
seen, rows = set(), []
for r in recs:
fn = r.get('fn') or r['name']
if fn in skip or fn in seen:
key = (r['binary'], fn)
if fn in skip or key in seen:
continue
seen.add(fn)
seen.add(key)
draft = r.get('draft') or f".run/aprop1/{fn}/{fn}.c"
st, stale, asm_only = audit_one(fn, r['binary'], draft)
rows.append(dict(fn=fn, binary=r['binary'], draft=draft, status=st,