From 374c8a0e97114b76296672fbce5d4f76fb013c18 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:54:31 -0600 Subject: [PATCH] phase-36: apply the R14 premise correction that the previous commit's message claimed but did not contain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The edit in 161d36cf3 failed its match assertion while the commit went through, so that message over-claimed: it said R14's documented premise was corrected and the file was unchanged. Naming it here rather than quietly fixing it (R66 — write 'done' only from the tool's own success line; the assertion had printed a traceback and I committed anyway). The correction itself, byte-proven by agent a15 on func_80166F58: MIPS in gcc 2.7.2 defines only PROMOTE_PROTOTYPES and not PROMOTE_MODE (config/mips/mips.h:1153), so a narrowed parameter stays a HImode pseudo and the extension still happens at the use — the prototyped narrow form, the wide form and the K&R form all give the same 67-instruction merged output. R14's banked closes stand on their bytes rather than on that rationale. --- docs/SETUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SETUP.md b/docs/SETUP.md index 62601887e..0566a7152 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -791,7 +791,7 @@ Every script under `tools/` (plus the two report make-targets), grouped by purpo | | `tools/verbatim_target_s.py --gas` (S99 amendment) | The gas listing is now VERIFIED before it is emitted: it is assembled, disassembled and compared word by word with the ROM image, every instruction that does not reproduce its word is replaced by `.word 0x…` with the mnemonic kept in the comment, and a listing that still disagrees is REFUSED. The class this catches: objdump prints the pseudo-instruction `move` for `addu rX,rY,$zero` and gas assembles `move` as `or` — 24 wrong words in one 234-instruction function, silently. Words carrying a relocation (jal/j, HI16/LO16) are excluded, since the linker fills those. NOTE for any consumer: the listing's %hi/%lo pairs are RESOLVED (no relocation), so an object assembled from it cannot be compared reloc-for-reloc against a compiled candidate — that is why the permuter's target is now the compiled body, not this file (see `tools/delever_permute.py`). | | | `tools/lever_progress.py` | **(P36, the record)** The lever series behind `docs/levers.md`: `--snapshot ""` appends one milestone row (the census's totals by class + the tree's HEAD) to `docs/lever-progress.tsv` and re-renders the document's generated block; `--render` rebuilds that block (the campaign half is derived from the de-lever ledger every time, scored as state TRANSITIONS so the rung that finishes a body gets the credit, not only the rung that first judged it); `--check` refuses a series whose last row is not this tree (a stale series is a wrong chart). Run it at the close of every task that changes the count, next to `lever_census --check`. | | | `tools/delever_permute.py` | **(P36 T6, rung D)** The permuter on the residue: `--plan` lists one exemplar per RESIDUE text class of the delever ledger (copies desc, then fewest NEEDED sites — a match banks every copy); `--prepare TU FN` builds that exemplar's scratch `.run/P36/permuter/__/` (R48: a function NAME repeats across overlapping overlays) — `tu.c` the lever-free TU (delever's own rung-A rewrite of every REMOVABLE site; a REFUSED site makes the exemplar UNSTRIPPABLE), `iso.c` the same with every OTHER definition reduced to a prototype, shared-header includes replaced by the prototypes they define, `INCLUDE_ASM`/`INCLUDE_RODATA` and file-scope asm statements dropped, `draft.c` that through `cpp -P` with the Makefile's own CPPFLAGS + `-I` + `-D__attribute__(x)=` (pycparser rejects `__attribute__` and decomp-permuter then REFUSES base.c and permutes nothing), `levered.c` the same pipeline with the levers KEPT, and the target in both forms — `gas/.s` (`verbatim_target_s --gas`, the only assemblable one: `mipsel-as` refuses the splat listing's bare `addiu sp,sp,-152` exactly as decomp.me did, R98) for `p16_permute.setup`, `splat/.s` for `match_one`. `--positive-control TU FN` perturbs a MATCHING body by one commutative swap and requires the permuter to find its way back to score 0 — the control that tells a hard population from a broken scorer (S99: two campaigns returned 0 of 16 against a target assembled from a listing, whose base score for the tree's own body was 28, not 0). `--calibrate [--limit N]` and every `--run` attempt: the LEVERED body must be `match_one` MATCH against the regenerated target (R39/R56 — the harness must agree with the tree before it may judge a candidate; 12 of 12 at S99), then the lever-free body's distance is recorded as the search's starting point (min 8 / median 78 / max 276 over those 12; a removed hand-placed `instruction` changes the instruction COUNT and shifts everything after it — `--max-start N` triages those as FAR with their number). `--run [--limit K] [--workers W] [--secs S] [--cycles C] [-j J]` runs `permuter_ils.py` per exemplar (profile from the NEEDED kinds: pins → regalloc, barriers/launders/keep-alives → schedule), `--winners`/`--pd` pointed at the scratch; every attempt appended to `.run/P36/permuter/outcomes.jsonl` (also the skip list; `--include-done` redraws). `--bank [--label dN]` puts each winner's definition back through `delever --apply-body … --rung D` (which refuses a body still carrying a class A/B lever and judges the real object through every recipe) and then `gte_consolidate --apply --rejudge` to re-fold the cpp-expanded GTE asm; serial, because each step runs `make`. Verdicts distinguish MATCH / NO-MATCH / FAR / UNSTRIPPABLE / UNCALIBRATED / SETUP-FAILED / ABORTED / NOT-JUDGED (R61: a run that never iterated is not a no-match). Run the campaign DETACHED (`setsid nohup … &` + a `Monitor`), never as a harness background task. | -| | `tools/delever_search.py` | **(P36 S101, rung G — the guided search)** Rung R tests ~57 one-move candidates per body for IDENTICAL and learns nothing from a miss (0 of 300 where no shape was known, §454a); rung D discovers but reprints the source. This engine keeps rung R's generators (`delever.recipe_candidates`, now with a `families` filter and two new moves: R8 a temp introduced/hoisted — R6's inverse — and R9 two adjacent statements swapped; R7 gained its own inverse, the unwrap) and the per-TU oracle, and SCORES every candidate: the function's instructions are read from the scratch object (`objdump -drz`, 35 ms on the largest object) and compared with the same function in the fleet run's baseline object under `build/` — the tree's own bytes, carrying the candidates' relocations by construction, so no listing is assembled and nothing is isolated (the two instrument classes of §454). The score is an EDIT DISTANCE over the reloc-masked words (a positional count read one inlined temp as 43 shifted words; difflib reads the real delta), the residual is classified from the diff blocks (REG on the caller- or callee-saved bank from the register pairs, COUNT, ORDER, MIXED) and the class picks the move families, ranked round-robin (a strict family order starved the inverse of a one-move perturbation behind 64 block wraps). The search is a beam (`--beam 3 --depth 3 --cap 48 --budget 400`): a child worse than its parent is dropped, the first score-0 is verified on every recipe of the file and banked through `delever --apply-body --rung G`, siblings by `--propagate` serially after the parallel phase. `--plan [--score]` lists the residue's exemplars (largest class first) with their starting distance and class; `--run [--limit K] [-j W] [--label gN]`; `--positive-control TU FN [--moves 1\|2]` perturbs a matching body by generator moves and requires the search to return to 0 without writing the tree (S101: one move back in 23 compiles; inline+wrap back in 74 by hoist+unwrap; an inlined pointer temp under a dereference has no inverse generator yet and stalls at 10 — the measurable stall mode); `--explain TU FN [--path "m1|m2"]` reads one body's residual as mnemonic blocks (mine vs the target) after any move path — the instrument that turns a stall into a generator (S101: the two 6-distance bodies are one surviving copy; a 7 is an association order plus a negation named once; a 40 is a duplicated call tail); `--selftest` (the classifier on synthetic streams, the beam on a stub needing three composed moves, the generators on fixtures). The registry's later moves, each from lane B's map of the compiler source and each with its selftest: R10 a parameter routed through a body-local copy and the reverse (map 1a-9), R12 a local's scalar width (1c-1 — verified NOT to reach a copy whose value's known bits fit the narrow mode), R13 two terms of a `+`/`-` chain exchanged, R8's third form a repeated RHS named once; a constant-operand R5 swap is never generated (fold moves it right — verified on bytes, `.run/P36/engine/micro/`), and the `do { } while (0)` lever works through the ref weight (`.run/P36/engine/micro/dowhile/`: `.lreg` `used 5` → `used 6 times`, `$18` → `$17`). Second round (S101, from `--explain` on the thirteen small residuals g3 left unmoved): R12 now covers `u8` and the `short`/`int`/`char` spellings; **R14** a PARAMETER's declared width in the header (a `short` parameter is sign-extended in place, `sra a1,a1,16; move s4,a1`, where a cast at the use extends into the destination); R8's fourth form one address local shared by every dereference of one base, stores included (lane B 2-6 and 2-12: a store through a bare pointer flushes cse's memory table and a global is re-loaded); R10's alias form through casts (`src = (u8 *)((u32)param_2)`). The bank and the propagation run IN PROCESS (`delever.apply_body_core`, `delever.propagate` returning `(banked, n, refused)`): run g3's 1,503 siblings had cost ≈40 min as a subprocess each, and a `delever.py` edit during a run could break a bank mid-run — now the running process holds its own copy. Measured runs: g1 1/16 (0.12 h), g2 1/16 (0.32 h, the wider beam), **g3 13/64 (1.02 h, 1,516 bodies; by first family R12 ×5, R7 ×3, R9 ×3, R10 ×2 — lane B's width and parameter moves half the closes)**. Fourth round: R14 rewrites the TU's prototypes with the header (else every candidate is a conflicting-types error); R8's named-once form also names a repeated depth-0 operand or parenthesised group; R12 splits a multi-declarator line to widen one name (`MULTI_DECL` also ends neither the declaration run nor is offered as a statement). Draw rules: a body whose NEEDED sites are all class C/D (a byte-needed `volatile` cast, a bare `register`) is DONE by decision 3 and is not drawn, and the seed keeps such sites; the scorer's scratch object is keyed by the TU (a per-tag name let two workers share one file — a byte-identical body read as 14,871 mismatches). g4s 3/38 (the thirteen explained names across the fleet, 133 bodies). Every attempt in `.run/P36/engine/outcomes.jsonl`, every scored candidate in `.run/P36/engine/trace/__.jsonl` — the byte record lane B's compiler-source hypotheses are checked against. A worker owns a TU; headers serial; `--dirty-ok` for a run that banks several bodies before one commit; run a campaign DETACHED with `nice`. `delever.py --repair-nhash` filled the 301 rung-R RESIDUE rows that carried no text hash (S99/S100 sweeps) from their bodies' earlier rows — the cause fixed in `recipes()`. **R15, the sink (P36 S102, the first T7 agent's crack toolified):** the statement AFTER an if/else chain pushed into every arm and the variables it consumed deleted — `if (c) { v = e1; } else { v = e2; } w = f(v);` becomes `if (c) { w = f(e1); } else { w = f(e2); }`. It is a REGISTER move, not a scheduling one: a value set in every arm and read after the merge is a CROSS-BLOCK pseudo local-alloc never gives a quantity to (`local-alloc.c:472`, `next_qty` reset per block at `:517`), so each arm holds two quantities and takes `block_alloc`'s unrolled `case 2` (`:1499-1502`, one `qty_compare` `:1578-1596`, higher density first); sinking makes it a third block-local quantity and `case 3` (`:1491-1496`) FALLS THROUGH into `case 2`, applying that comparison a second time and undoing its own exchange, so the two caller-saved colours swap — and while it is a global allocno it can inherit a copy preference from whatever the merge result is passed to (`set_preference` `global.c:1535+`, merged by `expand_preferences` `global.c:781-825`, overriding first-fit at `:1034-1067`), which sinking removes with it. Applicability is CHECKED: every consumed variable must be assigned exactly once in every arm by a simple statement, appear in the merge statement, and occur nowhere else in the function. `if_chains()` walks the arms counting a line's CLOSING braces before its opening ones — on a `} else if (…) {` line the two net to zero and a naive depth counter never closes the arm (the defect the generator's first run had). Ranked third in REG-caller and REG-mixed, third in COUNT; three selftest controls (a variable read after the merge, a variable one arm does not set, the brace walk's three arms). Its known-true check: run on `func_80156044`'s own pre-bank text it reproduces the agent's crack and scores 0. **R16 the constant holder and R17 the constant-run split (P36 S102, the second T7 agent's crack toolified):** R16 writes a local whose ONLY assignment is one integer literal at every use and deletes it — R6 stops at a temp read exactly ONCE, so a holder read four times was invisible to the search and the whole family with it; deleting it is byte-neutral by itself but removes a quantity from the block, which is what lets the next move reach the allocator. R17 splits a run of consecutive statements assigning the same integer literal by moving the nearest differently-valued literal assignment into it, at each interior split point: the decision is `find_free_reg`'s live-range scan (`local-alloc.c:2109-2110`) — while the two constants' ranges are disjoint they share one caller-saved register, and splitting the run makes the first live across the second so it takes another colour; the discriminator in the dumps is the `.lreg` line `Register N used K times across M insns`, whose M grows when the split lands. R17 is the DIRECTED form of a move R9 contains but reaches by luck (agent a2 measured 2,271 compiles for R9 in `func_80168828`; **R16 + R17 reproduce that close in ten**, the known-true check, on the seed that keeps the body's semantically-forced `$4` pin). Ranked: R16 second in REG-caller/REG-mixed and second in COUNT, R17 FIRST in ORDER. The engine selftest's caller-saved assertion is now the ORDERING INVARIANT — every targeted lever (R5, R15, R16) before every blind family (R9, R2, R4) — instead of a fixed window widened once per generator. `--propagate` inherits the exemplar's lever allowance, derived from the count of surviving `// !FAKE:` markers in its own banked text, and refuses by name any sibling whose remap would carry more (agent a2's reshape keeps one pin: 124 of 124 siblings banked once this existed). **R18 the bystander move (P36 S102, from the third T7 agent — the one that did NOT close its body):** one simple statement moved to each other position inside its own brace block, up to six statements away; R9's adjacent swap is its special case and the DISTANCE is the point. MIPS declares no `REG_ALLOC_ORDER`, so `find_free_reg` (`local-alloc.c:2158`) hands out the lowest free regno and the winner is whichever quantity `qty_compare` (`:1579`) reaches first, with `combine_regs` (`:1722`) welding an index chain into one quantity that competes with a short-lived value; moving a statement that depends on NEITHER contender into or out of the interval between the chain's birth and its first consumer changes `reg_live_length` and flips that race at ZERO instruction cost — unlike `R7 do-while`, whose LOOP notes are a full `sched1` barrier (`sched.c:2058-2074`) and always cost one displaced insn (the agent enumerated all 60 wrap ranges in its body and every one paid exactly that), which is why R18 is ranked ahead of R7 in every class. Two spellings were wrong before the known-true check passed: identifier-disjointness as a REQUIREMENT offered three candidates and none of them the agent's (it is now only an ordering preference — byte-identical output is the same program, so the oracle is the whole correctness proof, the footing R9 has always stood on), and a BLANK line counted as an obstacle, so the generator never offered the very move it was written from. It now reproduces that body exactly (`bystander @21->17`). `delever_pack.py` writes each trace candidate's residual CLASS beside its score, because a bare number hid from that agent that a move had already turned its body's residual from REG into ORDER. | +| | `tools/delever_search.py` | **(P36 S101, rung G — the guided search)** Rung R tests ~57 one-move candidates per body for IDENTICAL and learns nothing from a miss (0 of 300 where no shape was known, §454a); rung D discovers but reprints the source. This engine keeps rung R's generators (`delever.recipe_candidates`, now with a `families` filter and two new moves: R8 a temp introduced/hoisted — R6's inverse — and R9 two adjacent statements swapped; R7 gained its own inverse, the unwrap) and the per-TU oracle, and SCORES every candidate: the function's instructions are read from the scratch object (`objdump -drz`, 35 ms on the largest object) and compared with the same function in the fleet run's baseline object under `build/` — the tree's own bytes, carrying the candidates' relocations by construction, so no listing is assembled and nothing is isolated (the two instrument classes of §454). The score is an EDIT DISTANCE over the reloc-masked words (a positional count read one inlined temp as 43 shifted words; difflib reads the real delta), the residual is classified from the diff blocks (REG on the caller- or callee-saved bank from the register pairs, COUNT, ORDER, MIXED) and the class picks the move families, ranked round-robin (a strict family order starved the inverse of a one-move perturbation behind 64 block wraps). The search is a beam (`--beam 3 --depth 3 --cap 48 --budget 400`): a child worse than its parent is dropped, the first score-0 is verified on every recipe of the file and banked through `delever --apply-body --rung G`, siblings by `--propagate` serially after the parallel phase. `--plan [--score]` lists the residue's exemplars (largest class first) with their starting distance and class; `--run [--limit K] [-j W] [--label gN]`; `--positive-control TU FN [--moves 1\|2]` perturbs a matching body by generator moves and requires the search to return to 0 without writing the tree (S101: one move back in 23 compiles; inline+wrap back in 74 by hoist+unwrap; an inlined pointer temp under a dereference has no inverse generator yet and stalls at 10 — the measurable stall mode); `--explain TU FN [--path "m1|m2"]` reads one body's residual as mnemonic blocks (mine vs the target) after any move path — the instrument that turns a stall into a generator (S101: the two 6-distance bodies are one surviving copy; a 7 is an association order plus a negation named once; a 40 is a duplicated call tail); `--selftest` (the classifier on synthetic streams, the beam on a stub needing three composed moves, the generators on fixtures). The registry's later moves, each from lane B's map of the compiler source and each with its selftest: R10 a parameter routed through a body-local copy and the reverse (map 1a-9), R12 a local's scalar width (1c-1 — verified NOT to reach a copy whose value's known bits fit the narrow mode), R13 two terms of a `+`/`-` chain exchanged, R8's third form a repeated RHS named once; a constant-operand R5 swap is never generated (fold moves it right — verified on bytes, `.run/P36/engine/micro/`), and the `do { } while (0)` lever works through the ref weight (`.run/P36/engine/micro/dowhile/`: `.lreg` `used 5` → `used 6 times`, `$18` → `$17`). Second round (S101, from `--explain` on the thirteen small residuals g3 left unmoved): R12 now covers `u8` and the `short`/`int`/`char` spellings; **R14** a PARAMETER's declared width in the header (**the original rationale — "a `short` parameter is sign-extended in place, `sra a1,a1,16; move s4,a1`, where a cast at the use extends into the destination" — was CORRECTED ON BYTES at P36 S102 by agent a15: MIPS in gcc 2.7.2 defines only `PROMOTE_PROTOTYPES`, NOT `PROMOTE_MODE` (`config/mips/mips.h:1153`), so a narrowed parameter stays a HImode pseudo and the extension still happens at the USE — the agent compiled `func_80166F58` both ways and the K&R form too, and all three give the same 67-instruction merged form. R14's banked closes elsewhere stand on their bytes, not on this rationale; and since S102 the generator refuses any function the TU declares outside its definition, because the bank is body-only**); R8's fourth form one address local shared by every dereference of one base, stores included (lane B 2-6 and 2-12: a store through a bare pointer flushes cse's memory table and a global is re-loaded); R10's alias form through casts (`src = (u8 *)((u32)param_2)`). The bank and the propagation run IN PROCESS (`delever.apply_body_core`, `delever.propagate` returning `(banked, n, refused)`): run g3's 1,503 siblings had cost ≈40 min as a subprocess each, and a `delever.py` edit during a run could break a bank mid-run — now the running process holds its own copy. Measured runs: g1 1/16 (0.12 h), g2 1/16 (0.32 h, the wider beam), **g3 13/64 (1.02 h, 1,516 bodies; by first family R12 ×5, R7 ×3, R9 ×3, R10 ×2 — lane B's width and parameter moves half the closes)**. Fourth round: R14 rewrites the TU's prototypes with the header (else every candidate is a conflicting-types error); R8's named-once form also names a repeated depth-0 operand or parenthesised group; R12 splits a multi-declarator line to widen one name (`MULTI_DECL` also ends neither the declaration run nor is offered as a statement). Draw rules: a body whose NEEDED sites are all class C/D (a byte-needed `volatile` cast, a bare `register`) is DONE by decision 3 and is not drawn, and the seed keeps such sites; the scorer's scratch object is keyed by the TU (a per-tag name let two workers share one file — a byte-identical body read as 14,871 mismatches). g4s 3/38 (the thirteen explained names across the fleet, 133 bodies). Every attempt in `.run/P36/engine/outcomes.jsonl`, every scored candidate in `.run/P36/engine/trace/__.jsonl` — the byte record lane B's compiler-source hypotheses are checked against. A worker owns a TU; headers serial; `--dirty-ok` for a run that banks several bodies before one commit; run a campaign DETACHED with `nice`. `delever.py --repair-nhash` filled the 301 rung-R RESIDUE rows that carried no text hash (S99/S100 sweeps) from their bodies' earlier rows — the cause fixed in `recipes()`. **R15, the sink (P36 S102, the first T7 agent's crack toolified):** the statement AFTER an if/else chain pushed into every arm and the variables it consumed deleted — `if (c) { v = e1; } else { v = e2; } w = f(v);` becomes `if (c) { w = f(e1); } else { w = f(e2); }`. It is a REGISTER move, not a scheduling one: a value set in every arm and read after the merge is a CROSS-BLOCK pseudo local-alloc never gives a quantity to (`local-alloc.c:472`, `next_qty` reset per block at `:517`), so each arm holds two quantities and takes `block_alloc`'s unrolled `case 2` (`:1499-1502`, one `qty_compare` `:1578-1596`, higher density first); sinking makes it a third block-local quantity and `case 3` (`:1491-1496`) FALLS THROUGH into `case 2`, applying that comparison a second time and undoing its own exchange, so the two caller-saved colours swap — and while it is a global allocno it can inherit a copy preference from whatever the merge result is passed to (`set_preference` `global.c:1535+`, merged by `expand_preferences` `global.c:781-825`, overriding first-fit at `:1034-1067`), which sinking removes with it. Applicability is CHECKED: every consumed variable must be assigned exactly once in every arm by a simple statement, appear in the merge statement, and occur nowhere else in the function. `if_chains()` walks the arms counting a line's CLOSING braces before its opening ones — on a `} else if (…) {` line the two net to zero and a naive depth counter never closes the arm (the defect the generator's first run had). Ranked third in REG-caller and REG-mixed, third in COUNT; three selftest controls (a variable read after the merge, a variable one arm does not set, the brace walk's three arms). Its known-true check: run on `func_80156044`'s own pre-bank text it reproduces the agent's crack and scores 0. **R16 the constant holder and R17 the constant-run split (P36 S102, the second T7 agent's crack toolified):** R16 writes a local whose ONLY assignment is one integer literal at every use and deletes it — R6 stops at a temp read exactly ONCE, so a holder read four times was invisible to the search and the whole family with it; deleting it is byte-neutral by itself but removes a quantity from the block, which is what lets the next move reach the allocator. R17 splits a run of consecutive statements assigning the same integer literal by moving the nearest differently-valued literal assignment into it, at each interior split point: the decision is `find_free_reg`'s live-range scan (`local-alloc.c:2109-2110`) — while the two constants' ranges are disjoint they share one caller-saved register, and splitting the run makes the first live across the second so it takes another colour; the discriminator in the dumps is the `.lreg` line `Register N used K times across M insns`, whose M grows when the split lands. R17 is the DIRECTED form of a move R9 contains but reaches by luck (agent a2 measured 2,271 compiles for R9 in `func_80168828`; **R16 + R17 reproduce that close in ten**, the known-true check, on the seed that keeps the body's semantically-forced `$4` pin). Ranked: R16 second in REG-caller/REG-mixed and second in COUNT, R17 FIRST in ORDER. The engine selftest's caller-saved assertion is now the ORDERING INVARIANT — every targeted lever (R5, R15, R16) before every blind family (R9, R2, R4) — instead of a fixed window widened once per generator. `--propagate` inherits the exemplar's lever allowance, derived from the count of surviving `// !FAKE:` markers in its own banked text, and refuses by name any sibling whose remap would carry more (agent a2's reshape keeps one pin: 124 of 124 siblings banked once this existed). **R18 the bystander move (P36 S102, from the third T7 agent — the one that did NOT close its body):** one simple statement moved to each other position inside its own brace block, up to six statements away; R9's adjacent swap is its special case and the DISTANCE is the point. MIPS declares no `REG_ALLOC_ORDER`, so `find_free_reg` (`local-alloc.c:2158`) hands out the lowest free regno and the winner is whichever quantity `qty_compare` (`:1579`) reaches first, with `combine_regs` (`:1722`) welding an index chain into one quantity that competes with a short-lived value; moving a statement that depends on NEITHER contender into or out of the interval between the chain's birth and its first consumer changes `reg_live_length` and flips that race at ZERO instruction cost — unlike `R7 do-while`, whose LOOP notes are a full `sched1` barrier (`sched.c:2058-2074`) and always cost one displaced insn (the agent enumerated all 60 wrap ranges in its body and every one paid exactly that), which is why R18 is ranked ahead of R7 in every class. Two spellings were wrong before the known-true check passed: identifier-disjointness as a REQUIREMENT offered three candidates and none of them the agent's (it is now only an ordering preference — byte-identical output is the same program, so the oracle is the whole correctness proof, the footing R9 has always stood on), and a BLANK line counted as an obstacle, so the generator never offered the very move it was written from. It now reproduces that body exactly (`bystander @21->17`). `delever_pack.py` writes each trace candidate's residual CLASS beside its score, because a bare number hid from that agent that a move had already turned its body's residual from REG into ORDER. | | | `tools/delever_search.py --try TU FN FILE [--body]` + `tools/delever_pack.py` | **(P36 S101, T7 one agent at a time — Drew: efficiency, not wall-clock; hone the method after each lands.)** `--try` scores a candidate translation-unit text (or, with `--body`, a function body spliced into the tree's TU) WITHOUT writing the tree: the TU's own recipe is run on a scratch copy (`-I` so its relative includes resolve; a header candidate through a shadowing include dir) and the function's instructions are compared with the fleet run's baseline object — the same score, class and mnemonic diff as `--explain`. Proven on a known-true case (the tree's text 0; one pin removed the known residual). It is the loop an agent runs on its own candidate, so any number may run beside a campaign; the bank stays the coordinator's (`delever.apply_body_core` on the real recipe, then `--propagate`). `delever_pack.py --build [--min-copies 100] [--limit N]` writes one pack per residue exemplar under `.run/P36/agents/__/` (tu.txt, body_tree.c, body_free.c = the seed, residual.txt from `--try`, sites.txt, history.txt = every engine attempt and the best-scoring moves of the last trace) and `ORDER.tsv` (best distance reached ascending, then copies); `PROMPT.md` beside them is the brief (read the residual → name the pass from `tools/reference/gcc-2.7.2/` + the map → test on bytes with `--try` → deliverables early: `body.c` + `mechanism.md` with a GENERATOR PROPOSAL). `delever --restore` now refuses loudly on an empty or torn inflight.json (a kill mid-write) and says how to reconcile (the oracle: a bank is IDENTICAL, a leftover candidate DIFFERS). | | | `tools/kit_coverage.py` | **(P33.5 task 14.5)** The kit's DISTILLATION coverage: derives the rule population (every `- **R` of DIGEST §3, asserted contiguous) and the hindsight population (every `## ` heading of `docs/accelerators.md` at numbered-item granularity — 58 at S92) and asserts each is cited by a `provenance:` line of the registry seed / the kernels OR dispositioned in `config/kit_coverage_map.tsv` (`G` / `DK-` / `FOLDED:G` / `ENV` / `PA` / `SEED:` / `KIT:` / `RECORD` / `COOKBOOK` / `NOT-PORTABLE`; unknown ids refused, R43); counts with denominators (R41); rc 1 on any gap. In `tools-health` after `tool_census --check`. Its first run found 26 uncited rules and 21 uncited entries → three new kernels (DK-66–DK-68) and 41 authored dispositions. | | | `decomp-architect/` (the day-one decomp kit) | **(P33.5 tasks 9–14)** The package a new matching-decomp project installs as Phase 0.5 on ProjectArchitect 2.0: `README.md` (the three steps), `intake.decomp.md` (ProjectArchitect's twelve items pre-answered + the phase ladder + the six readability inversions), `SETUP.md` (the installer, Step 0 contract … Step 10 verify + hard stop; `answers: ` for unattended runs), `decomp-architect.md` (the methodology), `templates/` (the firewall pack — `gitignore.decomp`, `firewall.txt`, `audit_public.template.py`, the planted fixture, `no-rom.template.yml` —, the READMEs, `pa-overlays.md`, `registry-E.decomp.md` G1–G67, the skeletons, `PLACEHOLDERS.md`, `layout-contract.md`), `corpus/decomp-kernels.md` (DK-1 … DK-80), the three dictionaries `corpus/tools//` + `corpus/cookbook/` + `corpus/record/` (generated by `make kit-corpus`), `memory-seed/` (18), `tools/MANIFEST.md` (generated). **How it is checked:** `tools/kit_lint.py` (de-specialisation, placeholders, syntax, the gitignore-template diff) + `tools/tool_census.py --check` (the corpora equal their sources) + `tools/gitignore_template_check.py`, all in `tools-health`; the dry-run harness under `.run/P33.5/kit-dryrun/` (`answers.md`, `expected-manifest.txt`, `judge.py`, the install logs and verdicts of runs 1–5 — a kit change is re-verified by a resume on the last throwaway `repo/`, a fresh full run only when SETUP's steps change; the judge compares the real tree's dirty PATH SETS before/after). Wiki page: `docs/wiki/Start-a-new-decomp-project.md`. Split into its own repository after the flip. |