- c12: c3's reading held on both twins — the angle as the handler's first argument + tmp reused as the later operand;
the stale 'jalr with no args' comment corrected in the 135 files whose body now passes it
- c10: jump2 cross-jump merged two walk tails (exits now fall to the single final return), the s16 SUBREG gate, and
func_80135480 called at its real arity; its answer was func_80135888 in another file
- delever_pack related.txt: lever-free bodies in the overlay sharing a func_/D_ symbol, ranked (known-true: top hit for
func_80135A4C is func_80135888); METHOD_S103 +6 emitter entries; SETUP rows
- apply-body IDENTICAL x3, propagate 131/131 x2 + 133/133; check-all 218 passed 0 failed; lever_census 19,276 marked 0 UNMARKED
- closes, each --try 0 then apply-body IDENTICAL + propagate N/N 0 refused: func_80133AB0 (u16 width moves), func_80130D48
(one call per goto-tail site), func_80135168 (reused temps split + H16 member store), func_80134A74 (widths + join
statement in both arms), func_80148AFC (implicit handler argument + later operand), func_8015D738 (jump threading:
re-read + a do-while on precedent, the class raised with Drew), func_80135004 (temp split + argument from its global)
- func_8017EEC0: the uninitialised a0v T4 tus10 left is the parameter (8/8, IDENTICAL)
- CI red since cb2fb5e6d: verbatim_check --strict saw the DECOMPILE-NOW row func_8017EEC0 converted; row removed (one
row), --update keeps order + UTF-8 (proven equal to the hand fix), verbatim_check --strict now in make tools-health
- delever.split_reused_locals = family R23 (selftest + two refusals; known-true: joint split = the agents' measured 12/26)
- check-all 218 passed 0 failed (twice); lever_census 20,206 marked 0 UNMARKED; Drew: at most five concurrent agents
- agent c2 (Opus): a second pointer q = p + 5 stepped in lockstep with p kept a second biv alive (loop.c strength
reduction, -dL 'Cannot eliminate biv'); one pointer lets combine_givs fold every field read onto one base
- bank: apply-body IDENTICAL, propagate 130/130, check-all 218 passed 0 failed, lever_census 23,988 marked 0 UNMARKED
- delever.merge_walked_pointers = family R22 (selftest + two refusal controls; known-true: the agent's start text's
candidate is its closing body, --try score 0); leads the COUNT class after R19 in delever_search; SETUP row
- S103 opening: the method addendum .run/P36/agents/METHOD_S103.md; wave c launched (six agents); Fable out of credits,
c5/c6 relaunched on Opus
30,358 -> 24,119 lever sites (-6,239) in 6,317 bodies; 22 agents across two waves (14 closed, 8 read without closing);
generators R15-R21 added, each with a selftest and a known-true check against the body it was harvested from; 16,759
lying call declarations repaired free across 3,439 units; check-all: 218 passed, 0 failed of 218 at every step.
- docs/SETUP.md gains section P36 S102: the generator table R15-R21 naming the body each came from, the call-signature
tools, the baseline snapshot that makes the fleet gate and the agents independent, the repaired dump tools, and the
packs. Every tool has a tool_dictionary row; tool_census --check and doc_links --strict are green.
- the checkpoint carries the operating procedure (the agent lane is the main lane and is never empty; only one writer;
reconciliation after a killed run), the method that closed 14 of 22 bodies in order, the exact invocations, the
gotchas that cost something, and the open items by name.
- the three JOINT generators are called out as such: R20, R21 and b7's four-way retype all win only as a single edit
whose every intermediate step scores WORSE than the start, so a beam that composes one move at a time walks away from
them. Generate the joint candidate; do not trust the search.
- two refusals recorded as standing practice: an invented identically-zero term is not banked (R20 closed that body
honestly hours later), and a body whose improvements are compensating errors is reported rather than banked.
check-all: 218 passed, 0 failed of 218
lever_census --check: 24,119 pin/asm sites, 24,119 marked !FAKE, 0 UNMARKED — OK
Three moves, each predicted from a dump before it was compiled:
- while -> a guarded do-while (29 to 22). Cross-jump (jump.c:1969 -> find_cross_jump :2371, from toplev.c:3142) had
matched the load in front of the jump against the one in front of the bottom test and deleted three instructions; the
guarded form makes the two tails differ.
- the duplicated pre-loop call block -> goto (22 to 6). This is an allocno_compare rank move (global.c:585-611): the
priority is floor_log2(refs)*refs/live, reg_n_refs is loop-weighted (flow.c:2067), the in-loop copy of that call is
worth two references, and deleting the out-of-loop copy takes exactly one off — 8 to 7 crosses a floor_log2 step and
drops the pointer's priority from 3157.9 to 1891.9. The predicted allocation order matched the dump exactly. The
rewrite is byte-neutral on its own: reorg steals the target's first insn into the delay slot and retargets.
- the two-arm mask temp inlined (6 to 0): set in two arms it has two deaths, fails local-alloc.c:472, and combine_regs
bails at :1774, so it went to global allocation and took its copy preference.
Harvested as R21 second_consumer, from agents b2 and b6 together: give a computed value a second consumer before its
copy, either by chaining (v = slot = E) or by hoisting the store above it. cse deletes such a copy only when the
producer sits immediately before it (cse.c:7440-7501, guard :7454-7460), and flow links only the FIRST following use
(flow.c:2076-2091), so a store in between defeats both. R9 can never produce it — the two statements share the
identifier, so its independence guard refuses the swap. Known-true: the joint form scores 0 on b6's pre-bank text, and
the single-site forms do not, which is the third measured case this session of a joint edit no hill-climb can reach.
Also recorded from b8, worth a pre-check later: declaration-order moves are PROVABLY DEAD on a register residual whose
allocnos have distinct priorities, because global.c:604-610 compares priority first and only ties by allocno number —
4,811 compiles of those candidates sat flat because of it.
- the moves: retype four accumulators int -> short in ONE edit, delete the five hand temps that were spelling the
truncation, and type the colour temp to its destination field's own width (u8). Measured A/B/C on bytes: unsigned int
34, short 1, unsigned short 1, u8 0.
- mechanism: all four missing instructions were the same one — a move after an addiu whose result is re-read through a
16-bit shift. A narrowing assignment expands to a mode-changing copy, and combine_regs ties source into destination
only when the source DIES there (local-alloc.c:1855, return 0 at :1881); the wide temp is still live in the following
sign-extended test, so the copy survives. At int the copy is same-mode, the source dies, the tie happens, and combine
then re-selects the whole counter into the pre-shifted domain. The last instruction is cse's mode gate in insert_regs
(cse.c:1019-1021, :1029-1032).
- it confirms R20's shape and refines it: the group retype must be keyed on the residual's missing-move SET, since R12
is per-declarator and its single moves topped out at 24 here — a hill-climb cannot reach a four-way retype.
- delever_pack.py was missing an import for the neighbours block added an hour ago, so two packs shipped without
neighbours.txt and both agents said so. Fixed; all 34 packs now carry it.
- method note from the agent, now in the briefs: dump the target function WHOLE off the tree's own object rather than
reading the residual's hunks — the hunk view had scrambled two moves into branch delay slots and hid that four
differences were one repeated shape.
check-all: 218 passed, 0 failed of 218
lever_census --check: 24,915 pin/asm sites, 24,915 marked !FAKE, 0 UNMARKED — OK
- b2 func_80162438 (127 bodies): hoist the store above the assignment and store the EXPRESSION, so the temp falls out.
cse's 'REG0 is the cheapest' rewrite (cse.c:7440-7501, guarded :7454-7460) deletes a copy only when the insn
immediately before it set the source; putting a USE between compute and copy defeats that and flow's LOG_LINK, which
goes only to the first following use (flow.c:2076-2091), so combine is never offered the pair.
- b6 func_80161E08 (127 bodies): the same three blocks written as a CHAINED assignment, p = slot = base + K. The value
gains a second consumer, flow's only link goes to the store, and the copy survives — the instruction the pin faked.
- b5 func_80145934 + its sibling func_80145A2C (126 + 126 bodies): a body-local symbol ALIAS. Cross-jump's equality test
compares symbol names by POINTER (jump.c:2440), so two arms referencing one extern merge; an asm-label alias makes the
identifier distinct, the blocks survive, and assemble_name strips the star so the bytes and relocations are unchanged.
The barrier it replaces was standing in for symbol identity, not for ordering or liveness.
- the engine banked two of its own while the agents worked: R20 closed func_80139BE0 (129 bodies) by chain-narrowing —
the body agent a14 could only reach with an INVENTED identically-zero term, which I refused. The refusal was right and
the honest close arrived hours later from the generator.
- R19 closed func_8017A3D8's ov_SC07_006 copy (16 bodies) by restoring a dropped argument.
Two things to act on, both reported by agents:
- 'a @stuck: note claiming a lever is required should be re-tested, not trusted' — two such notes were refuted on bytes
today ('natural C ALWAYS coalesces that copy', 'no pure-C spelling survives that fold').
- one pack lacked neighbours.txt because the packs predate that change; the next --build carries it.
- the move: narrow every local in the counter's def-use chain together — the counter, its +/-1 temp and the copy-back —
and do it for BOTH chains at once. Four instructions were MISSING, not miscoloured, three of them the moves the $0 pin
was faking. insert_regs (cse.c:1029-1032, early bail :1018-1020) puts two pseudos in one equivalence class only when
their MODES match, so an all-int copy-back is collapsed and swept, while the narrowed one is a truncation: no
equivalence, the wide temp stays live and reaches reload as the move the target has. The fourth instruction is
strength_reduce minting a shift giv from a wide counter whose every use is a cast; a HImode pseudo cannot be that giv.
delever --propagate: 127 of 127 sibling(s) banked, 0 refused. 26,202 -> the census below.
- R20 narrow_chains: the agent PROVED the joint form is necessary, and the generator reproduces it. Single declarations
scored 45/72/51/24, each chain alone 43, both chains together 0 — every intermediate worse than the search's own best
of 11, so a beam over R12's one-declaration width moves cannot reach the answer from either side. Seven runs and 4,811
compiles stalled at 11; R20 offers six candidates and the right one is a single compile.
- known-true check: run on b3's pre-bank text, R20's joint signed candidate scores 0 (MATCH) and its single-chain
candidates score 43 and 51 — the agent's own hand-measured numbers, reproduced by the tool.
- chains are built conservatively from the body's text (two locals linked when one is assigned from the other, through a
cast or a +/- constant), and only whole components are offered, so the partial narrowings the measurement showed are
always worse are never generated. Selftest: the chain is found whole, an unlinked local is not pulled in, and a body
with no linked pair offers nothing.
- the move: delete the hand-walked pointer's self-increment and recompute p = &tbl[i] from the loop counter each
iteration. The lever-free body had TWO induction variables — the loop dump says 'Cannot eliminate biv 73: biv used in
insn 50' (loop.c:5976) because the pointer is itself a call argument — and combine_givs (loop.c:5494/:5527) then
merged the three +12 field addresses into one giv whose benefit clears the not-worth-while gate at loop.c:3822-3828,
reducing it to a THIRD walking register and forcing a fourth callee-saved one: the +4 instructions and the whole
recolouring. Indexing instead leaves one biv, the +12 rides as an immediate, and the body is byte-identical.
delever --propagate: 126 of 126 sibling(s) banked, 0 refused. 26,456 -> 26,202 sites.
- THE HEADLINE IS THE METHOD, not the crack: the answer was written in English thirty lines above, in the // @class:
header of an already-matched sibling in the same file, which spells out 'recompute p = &D[i] each iteration (NOT p++)
so gcc reduces base+i*0x10 into a SINGLE pointer IV'. The pack sent agents to the cookbook and to the compiler source
and never to the target's own neighbours. This project has been leaving itself notes for months and nobody was reading
them.
- delever_pack.py now writes PACK/neighbours.txt — the comment headers of the three matched functions either side of the
target, plus every @class/@stuck/@crack note in the translation unit — and the brief makes reading it step 0.
tool_census's two enumerations disagreed on one file: the new tool was written but never added, so the dictionary row
existed for a path git did not carry. That is exactly the disagreement the second oracle is there to find.
Drew: we do want C correctness on all funcs, and log it for the story and the chart.
- decl_repair --apply rewrote 3,439 units and repaired 16,759 declarations. check-all: 218 passed, 0 failed of 218.
lever_census --check: 26,456 pin/asm sites, 0 UNMARKED — unchanged, as expected: this pass fixed TRUTH, not levers.
- only the free set was touched: a declaration is repaired when every call to that function in the unit already passes
the arguments, so the code was right and only the promise was wrong. Calls that pass too few remain R19's population,
where the argument must be chosen and the bytes decide.
- tools/readability_progress.py: the Gen3 series beside docs/levers.md, because levers are only one way the source is
untrue. It counts lying call declarations (split by the K&R-empty and (void) forms, and how many sit in a body still
holding an argument-register pin) and raw cast dereferences against struct member reads — the struct debt. Each row
carries its date and commit so the chart is generated, never typed (R75). docs/readability.md renders it.
First row after the repair: 94,001 lying declarations over 1,564 callees (86,701 (), 7,300 (void)), 461 in 314 pinned
bodies; 414,148 raw cast dereferences against 173,286 struct member reads.
- dictionary rows for decl_repair and readability_progress; kit corpus regenerated; tool_census --check OK.
search: 3 of 55 exemplars matched lever-free in 0.33 h (3 of 730 bodies behind them; 12,034 compiles) — NO-MATCH 51 · MATCH 3 · UNSCORED 1
check-all: 218 passed, 0 failed of 218
lever_census --check: 26,456 pin/asm sites, 26,456 marked !FAKE, 0 UNMARKED — OK
Every one of the three closes is R19 restoring a dropped call argument, each at depth 1 in two compiles — the class that
seven earlier runs and thousands of compiles could not touch.
THE DECLARATION SCAN, AND THE INSTRUMENT FAILURE IT TOOK TWO TRIES TO SEE (R39/R40):
- first framing: widen every lying declaration and leave the call sites alone. That is not a repair — a prototype
demanding an argument the call does not pass is a hard error — so 1,766 of the first 3,250 units failed to compile BY
CONSTRUCTION and none was identical. A measurement that cannot come out any other way is not a measurement. The tool
now only repairs a declaration when every call to it in that unit ALREADY passes the arguments; calls that pass too
few are R19's population, where the argument must be chosen and the bytes decide.
- second failure, worse because it looked like a finding: the corrected scan still returned 0 free of 3,634 units. The
negative control I had not run — compile the UNCHANGED text through the same path — came back DIFFERENT by 9,176
bytes, because the candidate is built from a scratch copy and the object records its own source filename. Comparing
only .text/.rodata/.data removes the path, and the control then matches exactly. The control is now part of every
unit's judgement rather than something I remember to run.
- the corrected result: 3,414 units / 16,732 declarations are FREE to repair (byte-identical with the declarations made
honest), only 2 units / 3 declarations actually depend on the false declaration, 117 compile errors and 101 units
whose control failed and are therefore reported as harness failures, not results.
- scope limit stated: declarations inside src/shared headers are not units with recipes and were not tested here.
Six T7 agents independently reached score 0 by restoring an argument the decompiled source had dropped, and no generator
could reach the class because every other family rewrites statements that exist while this changes a call's ARITY. R19
closes that gap without cracking anything: it finds every call whose in-scope declaration is narrower than the callee's
real definition, then offers one candidate per value already in scope (each parameter, each local declared before the
call) and lets the byte oracle pick. The missing argument is never inferred.
- known-true check: run on the pre-bank text of func_8017A3D8, which agent a12 solved by hand, R19 emits that agent's
exact fix and --try scores it 0 (OTHER; mine 53 ins, target 53) — MATCH.
- two spellings were wrong before that passed. It took the return type from the DEFINITION and produced
((void (*)(s32))f)(a) != 0, which cannot compile because the defining TU says void where this one says int — it now
repairs the arity only and keeps the TU's declared return type. And it required a simple statement, so it found
nothing on the very body it was written from: these calls live in and far more often
than in a plain statement.
- it also sees the cast-wrapped form ((s32 (*)(void))f)(), which is how m2c usually spells a dropped argument, and
replaces the whole wrapper rather than nesting a second cast.
- ranked FIRST in every residual class: it emits candidates only for calls whose declaration provably disagrees with the
definition, so it costs nothing when it does not apply. The engine selftest's ordering invariant is updated to say so
rather than being widened again.
- argcheck now carries each definition's return type, which the cast route needs.
- selftest: two positive assertions and two controls (the declared return type is kept; the definition's is refused; a
call inside a return statement is seen; a matching declaration offers nothing).
- a22: func_8017B238 closed by giving the if-arm's pointer and the else arm's first table address one function-scope
local. Three decisions turn on that edit, all dump-proven: make_regs_eqv's head rule (cse.c:840-857), set_preference
stripping one RTX level so an arithmetic set inherits its operand's register (global.c:1535), and combine_regs with
birthing_insn_p's reg_n_sets == 1 (local-alloc.c:1765-1788, sched.c:2469) — which is why the merge must be with the
else arm's non-call-crossing temp. 26,714 -> 26,462 sites.
- a14 reaches score 0 on func_80139BE0 but only by an INVENTED identically-zero term whose sole purpose is to keep a
value live. NOT BANKED: an invented no-op expression is a compiler-forcing construct in C clothing, and worse than the
marked launder it replaces because the launder is counted and this would be silent. The phase's own rule is ban the
silence, not the lever. Parked for the structs/types phase with its reading; the tree comment above it ('no pure-C
spelling survives that fold') is refuted.
- a6 corrects cookbook 455: cse1 (cse.c:7439-7502) rewrites the producer's destination to the copy's whenever the
producer is the immediately preceding insn; combine only finishes the job once that adjacency is broken. It enumerated
the three lever-free blockers can_combine_p admits and showed the body can pay for none, then scanned all 4,284 built
objects for the shape — 101 hits, every lever-free precedent paying with a genuine second use, a narrow local with two
consumers, or a join label.
- a24's residual was one absent load: cse forwards a just-stored halfword so no lh is emitted, and seven branch
displacement mismatches were downstream of it. Its method gap is the instrument to fix next — three agents have now
asked for local-alloc's quantity table in the pack, and alloc_table.py prints an empty or one-row table because it
keys on dump lines that are often absent.
- Drew's struct question answered on the record: structs are not in the binary (types are erased; no metadata in a
retail build), what is there is base + offset + width + stride, so a struct is an inference across every function
touching a base — which makes per-function struct invention the wrong unit and is the failure P35 already recorded.
Recommendation: keep pins as the main lane, build a zero-token struct evidence census beside it, park stuck pins with
their evidence, and fix call signatures first because they are the bigger and cheaper blocker (471 narrow call sites
in 323 pinned bodies). Measured: 372,224 raw cast dereferences against 92,624 struct member accesses.
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.