feat(phase-29): T1.1 func_80183814 round 1 — 99.3% structural, named lever; cookbook §83

- VERIFIED INDEPENDENTLY (R14): match_one reproduces DIFF 5127 vs 5122, LENGTH-DRIFT/+5. Agent did
  not over-claim; tree untouched. Difflib-aligned truth: 36/5122 structural (99.3%), 17/21 cases
  EXACT, args+locals BYTE-EXACT at 216B
- §83a: on a LENGTH-DRIFT class match_one's mismatch count is NOT a progress signal — 4,622 and 36
  describe the same draft (index-wise comparison smears every index after the delta)
- §83b THE LEVER: the handoff's '35x repeated template' (which I passed on flagged UNVERIFIED) is
  TRUE and was the whole game — 2,625 of 5,122 ins (51%) from ONE parameterised 72-ins body. Three
  sub-levers: pointer walk (no strength-reduction under -G0), rand()%(u32) for divu, cast barrier vs combine
- §83c TRAP: the inherited 'dead local' pad[32] is gcc's OWN SPILL AREA — removing it made the locals
  area byte-exact. §83e: two 'pure allocation' residuals were a copy-pointer walk -> zero (§80 again)
- §83d THE STALL, cited: cse.c:8340 sizes the quantity table by WHOLE-FUNCTION pseudo count, so no
  per-case edit can move a function-global CSE fork. Next move = close the +5 (buys length parity AND
  perturbs max_reg), then re-run the do-not-re-buy table on the new base
- no pins in the deliverable (diagnostic-only, table row 15) — agent self-reported unprompted
- DECISION: round 2 QUEUED, not spent now — T0.2 (224,410-ins pool) outranks a ~0.04pp lever
This commit is contained in:
Drew T
2026-07-26 13:02:58 -06:00
parent 57ee715f3c
commit 1fe4850136
2 changed files with 99 additions and 0 deletions
+60
View File
@@ -6387,3 +6387,63 @@ declared it `(MATRIX2 *, SVECTOR2 *, SVECTOR2 *)`, the TU and the fleet canon us
void *)` — **2,286 of 2,835 sites**. Conforming the draft's decl to the canon is byte-neutral
(pointer args pass identically) and banked first try. **On a jr function, expect BOTH gates to have
something to say: the carve chain answers the jump table, and §75a answers the declarations.**
## §83 — The parameterised-repeat law, the spill-area trap, and why a per-case edit cannot move a per-case symptom (Phase 29 SESSION-20, `func_80183814` 5,122 ins, cold-ish start → 36 structural / 99.3%)
The largest unmatched function in the project, a 21-case state machine. Round 1 reached **5,127 ins vs
5,122 target, 36 structurally-unmatched instructions under a register-blind mask (99.3% exact), 17 of
21 case bodies EXACT, args+locals byte-exact at 216 bytes** — not a match, and the residual is *one*
decision, not 36 problems.
### §83a — READ THE HEADLINE NUMBER CORRECTLY: a LENGTH drift makes `match_one`'s count meaningless
`match_one` compares **strictly index-wise**. A +5 instruction delta shifts every later index, so the
tool reported **4,622 mismatched** where difflib-aligned comparison shows **36**. Those two numbers
describe the same draft. **When the class is `LENGTH-DRIFT`, the mismatch count is not a progress
signal — align first (difflib) and re-read, or you will abandon a 99.3% draft as a 10% one.**
(Counterpart to §78: there, a length drift *was* a register grant in disguise; here it inflates the
score. Both say the same thing — never read a length-drifted diff literally.)
### §83b — THE LEVER: find the parameterised REPEAT before decoding case-by-case
Three callees (`func_8012EC04`/`func_8012F14C`/`func_8012C51C`) each appear **exactly 35 times** as
one **72-instruction body parameterised only by `(KIND, START, BOUND)`** — with the invariants
`member == KIND*4`, `array == &D_801F61C0[START]`, and `prev.BOUND == next.START`. **That is 2,625 of
5,122 instructions (51%) from a SINGLE definition.** Writing it once as a template and generating the
35 sites (harness: `.run/giants/s20_g14_*.py` — edit the template in one place, re-propagate to all
35) is the whole game on a function this size.
**Practice: on any large state machine, hunt for a parameterised repeated block BEFORE decoding case
bodies one at a time.** The tell is a repeated call triplet at a fixed stride with monotone constants.
*(A prior handoff asserted this repeat existed; it was carried forward flagged UNVERIFIED because it
appeared nowhere in the recon. It proved TRUE — but flagging it cost nothing and the discipline stands:
an unverified premise is a hypothesis to test first, not a foundation to build on.)*
**Three sub-levers made the template byte-exact:**
1. **A running POINTER walk, not array indexing** — under `-G0` array indexing does not strength-reduce.
2. **`rand() % (u32)x`** to force `divu` (the signed spelling emits `div` + the sign-fixup dance).
3. **`(s32)((u8 *)p + (X + 0xC))`** — the cast barrier stops `combine` reassociating the offset.
### §83c — TRAP: a "dead local" in a prior draft may be gcc's OWN spill area
The inherited recon modelled a 128-byte `s32 pad[32]` local and called it dead. **It is not a local at
all — it is gcc's spill area.** Declaring it explicitly *adds* 132 bytes and corrupts the layout;
**removing it made the 216-byte args+locals area byte-exact.** If a draft needs an unexplained dead
block to reach the target frame size, suspect the spill area before inventing a variable. (The frame
being 8 bytes over here is a *different* cause — two extra callee-saved registers, §83d.)
### §83d — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom
The stall: in cases 0 and 3, gcc CSEs three `&D_8018E27C`-class address constants (+0x30) across two
call groups that share a basic block, consuming **2 callee-saved registers the target spends on real
variables** — so `a0` lands in `$s7` instead of `$s2` and every register downstream renames.
**Why no rewrite of case 0 moved it:** `cse.c:8340` sizes the quantity table as
`max(nsets*2, 500) + max_reg` — **gated by the whole-function pseudo count.** A per-case edit does not
change `max_reg`, so it cannot change a CSE decision, even one whose *symptom* is local.
**⇒ The lever for a function-global CSE fork is a function-global quantity change** — here, closing the
+5 length delta is expected to move `max_reg` and the fork together. **Diagnose the SCOPE of a
compiler decision (function-global vs block-local) before choosing where to edit.**
A diagnostic `a0 → $s2` pin halves the residual and makes the prologue byte-exact — which *confirms*
the diagnosis — but it is a hand-placed dial, not plausible source, and it does not fix the frame. It
belongs in the do-not-re-buy table, **not** in the deliverable (§72/§74).
### §83e — §80 vindicated again, on the same day it was written
Two case residuals (6 and 11, 8 and 7 diffs) had been written off as "pure allocation". They were not:
the morph/lerp loop walks **copies** of its two input pointers (`pa = msa; pb = msb;`), not the
originals — and spelling that took both cases to **zero**. **A residual class you assigned on an
earlier base is a hypothesis, not a verdict** (§80). Re-run the negative list after the base moves.
+39
View File
@@ -4386,3 +4386,42 @@ resolves. T0.1/T0.3 only read sigs/configs and write `.run/` + `docs/` ⇒ safe
already PROVED -O0 members bank (9/9 on ov_SC07_010, R22-verified); the blocker is the *fleet-scale*
carve's splat `%lo` re-disassembly sensitivity, deferred on ROI. **That is a build-infra task with a
known shape, not a compiler wall** — worth re-pricing once the FREE subset is harvested.
- **◐ 2026-07-26 (SESSION-20) — T1.1 `func_80183814` (5,122 ins, ov_SC07_006) ROUND 1: 99.3%
structural, NOT banked. The predicted shape, with a precise named next move. → cookbook §83.**
**Verified independently (R14), agent did NOT over-claim:** my own `match_one` re-run reproduces
`DIFF mine=5127 target=5122, 4622 mismatched`, class **LENGTH-DRIFT/+5**. Tree untouched
(`git status config/ src/` clean — the agent respected the no-build-tree constraint).
**The honest state, difflib-aligned:** **36 / 5,122 structurally unmatched (99.3% exact)** under a
register-blind mask · 1,201 register-sensitive · **args+locals byte-exact at 216 B** · frame 8 B over
(2 extra callee-saved regs) · **17 of 21 case bodies structurally EXACT** (case 20, 525 ins, perfect).
**⚠️ THE 4,622 IS AN ARTEFACT OF INDEX-WISE COMPARISON** — a +5 length delta smears every later
index. 4,622 and 36 describe the SAME draft. **On a LENGTH-DRIFT class, the mismatch count is not a
progress signal** (§83a) — this is exactly how a 99.3% draft gets mistaken for a 10% one.
**THE LEVER (and the vindication of a flag I raised):** the handoff's *"35× repeated template"*
claim — which I passed to the agent **flagged UNVERIFIED because it appeared nowhere in the recon** —
**is TRUE and was the whole game.** Three callees each appear exactly 35× as ONE 72-ins body
parameterised by `(KIND, START, BOUND)` (`member==KIND*4`, `array==&D_801F61C0[START]`,
`prev.BOUND==next.START`) = **2,625 of 5,122 ins (51%) from a single definition**. Flagging it cost
nothing and the discipline stands: an unverified premise is a hypothesis to TEST, not a foundation.
**TWO INHERITED-RECON CORRECTIONS (both R14-class):** (1) the `pad[32]` "dead local" is **gcc's own
spill area** — declaring it corrupts the layout; removing it made the locals area byte-exact (§83c);
(2) the recon's case 12 was **incomplete** (it cross-jumps into case 14's tail).
**THE STALL, WITH A SOURCE CITATION:** one global regalloc fork — gcc CSEs three `&D_8018E27C`-class
address constants across two call groups sharing a basic block, eating 2 callee-saved regs the target
spends on real variables. **`cse.c:8340` sizes the quantity table `max(nsets*2,500)+max_reg` — gated
by WHOLE-FUNCTION pseudo count**, which is why no local rewrite of case 0 ever moved it (§83d).
**⇒ NAMED NEXT MOVE (round 2):** find the ~5 spurious instructions (5127→5122). That buys length
parity **and** perturbs `max_reg` — the same lever — then **re-run the 15-row do-not-re-buy table on
the new base** (§80). Round-2 economics are measured-cheaper than round 1 (§79/SESSION-19).
**§80 VINDICATED THE DAY AFTER IT WAS WRITTEN:** cases 6 and 11 (8 and 7 diffs) had been written off
as "pure allocation"; they were a copy-pointer walk (`pa = msa; pb = msb;`) and went to **zero**.
**NO PINS IN THE DELIVERABLE.** A diagnostic `a0→$s2` pin halves the residual and makes the prologue
byte-exact (confirming the diagnosis) but is a hand-placed dial and does not fix the frame — recorded
as row 15 of the do-not-re-buy table, not shipped (§72/§74). **Agent self-reported this unprompted.**
Artifacts: `.run/giants/s20_func_80183814_b1.c` · `s20_80183814_report.md` (15-row table with BASES)
· 6 × `s20_g14_*.py` (regenerate the draft identically; edit the template once → all 35 sites).
Cost: 367,677 agent tokens / 115 tool-uses / ~41 min.
**DECISION: do NOT spend round 2 now.** Per the approved order this is a ~0.04pp lever while **T0.2
is a measured probe on a 224,410-ins (12.5%) pool** — and T0.2 was blocked only by this agent holding
`asm/`. Round 2 is queued with its lever named; nothing is lost (§80 table + harness are on disk).