- 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.
Not banked, and the agent said so itself: it solved the whole tail — instructions 32 to 489 of 490 byte-identical in
plain C with the $4 pin gone — by hoisting one statement above two derived pointers, a COLOURING move rather than a
scheduling one (the scheduler's RTL order is identical in both candidates, so the tree's header note blaming it
describes the assembly, not the RTL). The head is a proven wall: find_best_addr (cse.c:2663-2665) folds the base to an
absolute address because its only set is a symbol_ref, and its known-true control keeps its base in plain C only because
both uses are at offset 0. It then labelled its two remaining improvements COMPENSATING ERRORS — a width change that
deletes the target's real andi to cancel an extra instruction — and wrote 'nothing here is bankable' instead of handing
back a 16 dressed as progress.
Two pack defects fixed from its report:
- neighbours.txt carried the @class/@stuck LINES but not the header comment they sit in, and that comment is an
eight-point English explanation of every lever in the body, including the tail crack stated outright. The pack now
ships the target's own header in full. A grep for tags is not a substitute for the paragraph it sits in.
- history.txt's line numbers are relative to the evolving text, so reconstructing a path by hand lands elsewhere (b9
reached 51 where the engine reproduces 16 in one round). The pack now ships the best candidate's text as best_body.c.
Not banked: 203/203 instructions with a two-instruction residual. Four byte-proven moves recorded, the notable one being
a while loop rewritten as a label plus goto so no loop notes are emitted and loop.c cannot hoist a call argument's shift
into a preheader — loop.c:595-596 forcing n_times_set = 1 for a hard register is exactly what its $21 pin was buying.
cookbook 176 documents only the opposite rewrite (goto-loop to for, to OBTAIN a hoist); the de-looping direction is new.
Its sharpest observation is about our own instrument: none of the seven NEEDED sites named what actually had to change,
and one shape move retired three of them. A site list says which levers the oracle could not remove ALONE, not which
source facts are load-bearing.
- 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.
- tools/argcheck.py: every call site whose in-scope declaration is narrower than the callee's real definition. 15,626
definitions read; 110,478 narrower declarations over 1,912 callees (86,701 K&R-empty, 23,777 positively narrow);
471 of them sit in a body that still holds a NEEDED $4-$7 pin — 323 bodies, the targeted draw, written to
.run/P36/engine/argcheck_draw.tsv.
Checked against the six agent cracks it was built from: it finds a7, a12 and a25, and it CANNOT find a13, whose
function is declared (void) in 131 of 138 sites AND defined (void) — a declaration comparison is blind to a definition
that is uniformly wrong. The census is a lower bound and the residual stays the oracle; the docstring says so.
Corrected before use: the scope column says which FIX is available, not whether the body can be banked — the cast route
is body-only at either scope (a7 closed a file-scope case that way).
- Drew challenged a10's 'needed by construction' verdict: nobody wrote the pin, so a plain-C spelling must exist. He is
right and the verdict is downgraded to its real scope — no spelling reaches the bytes in that TU's CURRENT declaration
environment. That environment is demonstrably wrong there: the file declares extern s32 func_801789AC(s32 arg0) while
the body calls it through a cast that drops the argument, the same class six agents cracked today. Restoring it was
tested at once and scores 3, not 0, so it is not the whole answer — but a verdict taken inside a distorted environment
is not a property of the function. func_80178970 moves to the structs/types phase list rather than being marked
permanent, with its reading attached.
- R14's documented premise corrected on bytes (agent a15): MIPS defines only PROMOTE_PROTOTYPES, not PROMOTE_MODE
(config/mips/mips.h:1153), so a narrowed parameter stays HImode and the extension still happens at the use. R14's
banked closes stand on their bytes, not on that rationale.
The scorer named its scratch object after the FILE (compile_obj tag="score"), so the nine burst agents sharing one
translation unit wrote and read one object. Two reported it independently without seeing the code: spurious
COMPILE-ERRORs naming an unrelated header, and one agent scoring four candidates against another agent's function. The
tag is now per function. Every landed body was re-verified after the fix and all still score 0; the banks were never at
risk, the agents' intermediate readings were.
- banked: func_801627E8 (132), func_8017A3D8 (118), func_80141874 (119 of 125), func_801345F8 (134). 28,887 -> 27,984.
lever_census --check: 27,984 pin/asm sites, 27,984 marked !FAKE, 0 UNMARKED — OK
- THE FINDING: the biggest lever class in this phase is a WRONG DECLARATION, not codegen. Four agents independently
reached score 0 by restoring a call's real arity, each in a different spelling — a function-pointer cast, a widened
block-scope prototype, a call given its argument, and a definition given its two parameters. The mechanisms differ
(combine.c:1458's added_sets_2 gate; set_preference global.c:1589 ahead of first-fit at :1001-1015, the argument copy
becoming a self-move deleted at toplev.c:3142 so it costs zero instructions; assign_parms' parameter home copies) but
the class is one: a truncated (void) declaration removes an instruction the pin was then hired to fake. No generator
can reach it — every generator rewrites statements that exist, and this changes a call's arity.
- func_80157D20 does not bank body-only (gcc rejects a block-scope redeclaration), so its Path A joins func_80136824 and
func_80168828 as the third measured case for the types phase.
- two more new classes, byte-proven: a store sinking past a load because true_dependence's exception (sched.c:837-839)
discards the edge, fixed by declaring the global an array and storing through [0] to set MEM_IN_STRUCT_P; and a
post-decrement queued by expand_increment until the next sequence point, fixed by splitting the statement plus a u16
destination cse refuses to join (cse.c:1017-1019).
- correction to record: an uninitialised register __asm__("$0") is an opaque operand, not a constant holder — R16 must
refuse it.
- snapshot row 20.
Drew: fix the build issue so agents' effort doesn't get wiped, this needs to be parallelizable.
- every score compares a candidate with the fleet run's object under build/, and the R22 gate starts with make clean,
which deletes exactly that. With agents scoring in parallel, a fleet gate would make every live --try compare against a
missing or half-written baseline and report nonsense in the agent's own voice.
- fixed at the single accessor: delever_oracle.baseline_path(obj) returns the snapshot under .run/P36/delever/baseline/
when it holds the object and falls back to build/ when it does not, so nothing silently scores against half a snapshot.
baseline_bytes and both direct readers in delever_search.py go through it. --snapshot-baseline refreshes it:
7,428 objects, 188 MB, taken at 9f5b22176. Valid until the fleet stops being green: the baseline is the original game's
bytes and a bank is byte-identical by construction.
- known-true test both ways: func_800123F0 in src/800.c scores 0 MATCH with build/src/800.o present; the object was moved
away and it scores 0 MATCH unchanged; restored.
- a4: func_8016C49C from a seed of 34 to score 0 by one move — do { param_1[1] = sVar1; } while (0); on the function's
LAST statement. The residual was a single qsort comparison in global_alloc lost by 142 units out of 6666 (global.c:546
sort, :587 priority, :904 first-fit). reg_n_refs is loop-weighted and computed before combine and sched, so the
reference inside the do-while is counted twice (flow.c:434, :440-443, :2067/:2501/:2711): refs 23->24, priority
6524->6808 > 6666, the order flips and all 34 words fall into place. A plain block at the same site still scores 34,
which proves it is the loop notes and not the scope.
delever --propagate: 125 of 125 sibling(s) banked, 0 refused
lever_census --check: 28,887 pin/asm sites, 28,887 marked !FAKE, 0 UNMARKED — OK
- two instrument findings to act on: the candidate ranking buried the winning move at 438 of 439 so --cap 48 discarded it
in six runs (~4,300 compiles), and history.txt's 'R15 sink @2777 -> 1' is not reproducible (the generator's own text
scores 40) — to be checked against the bytes before either is trusted.
- snapshot row 19.
A new class, and the cheapest one found so far. ov_SC04_011.c:197 declares extern void func_8013BC7C(void); while that
function's real byte-verified definition, src/shared/ov/func_8013BC7C__8042ae05.h:3, is void func_8013BC7C(void *arg0).
The $a0 instruction the pin was forcing is the argument the TU's own declaration denies.
- the move: a block-local s32 *p = &D_801F1640; tested and passed through a function-pointer cast,
((void (*)(void *))func_8013BC7C)(p); — the idiom this TU already uses for two other calls. Score 0 on the first
spelling tried, where seven mechanical runs and 4,000+ compiles had sat at 3, because every generator rewrites
statements already present and this move adds an argument.
- mechanism, both halves proven on bytes: update_equiv_regs (local-alloc.c:947, the referenced-exactly-twice test at
:1066, substitution at :1085-1112) — the second reference keeps the address in a register, which is what the volatile
was faking; and combine_regs (local-alloc.c:1722, hard-reg path :1797-1818) records $4 in qty_phys_copy_sugg so
find_free_reg (:2073, restricted at :2145-2150) colours the quantity $4, which is what the pin was faking.
Controls: reading the global directly scores 9; declaring the pointer at function top scores 4.
- unlike agent a2's case this truncation is a LOCAL extern, so the cast keeps the bank body-only.
delever --apply-body: ... IDENTICAL on 1 object(s) — KEPT, ledgered (rung E, a7)
delever --propagate: 126 of 126 sibling(s) banked, 0 refused
lever_census --check: 29,013 pin/asm sites, 29,013 marked !FAKE, 0 UNMARKED — OK
- the R22 fleet gate is deferred until the burst of 20 agents drains: make clean deletes the build/ baseline object that
every live --try scores against. Banking and propagation only read build/, so the writing lane runs beside the agents.
- snapshot row 18.
On a landing, in this order: --try the agent's body to prove the claim on bytes (seconds), launch the next agent
immediately, and only then bank, propagate, harvest the idiom into a generator, gate and commit — all of it while the new
agent runs. Still one agent at a time so the methodology is honed at each landing, but the slot is refilled in seconds
rather than after an hour of gating.
The one real hazard: the scorer's scratch object is keyed by the TU, so two processes scoring the same TU collide.
Banking beside an agent is safe (a bank is IDENTICAL on the whole object by construction and cannot move the agent's
function's bytes), but a --propagate that reaches the live agent's TU is deferred until that agent lands. Sweeps are not
part of this lane: they write candidates across many TUs for hours, which is what emptied the agent slot for six of the
eight hours of last night.
Drew, on waking: he expected dozens of agents overnight and got three. The cause is the cadence, not the agents — the loop
ran strictly serially (agent, gate, toolify, sweep) and the sweeps are hours long, so most of the night had no agent
running. His rule was one agent at a time so the methodology is honed each time one lands, not one agent per sweep.
- correction: agents run back-to-back, the next launched the moment the last lands; a sweep runs only when it does not
stand between two agents, and never on the TU a live agent is scoring in (the scratch object is keyed by the TU).
- stopping s7 cost a lesson worth keeping: the kill landed mid-write, inflight.json was empty, and --restore refused
loudly with instructions instead of guessing (R102). 8 dirty files: 5 the run's recorded banks, 3 with no bank; the
fleet named exactly those 3 binaries (ov_SC03_113, ov_SC04_004, ov_SC04_011), restored from HEAD.
check-all: 218 passed, 0 failed of 218
lever_census --check: 29,140 pin/asm sites, 29,140 marked !FAKE, 0 UNMARKED — OK
- snapshot row 17.
search: 25 of 337 exemplars matched lever-free in 1.39 h (25 of 337 bodies behind them; 57,838 compiles) — NO-MATCH 307 · MATCH 25 · UNSTRIPPABLE 4 · UNSCORED 1
- the draw asked for 1,200 and the ledger could offer 337: s5 had taken the easy half and the never-attempted pool is now
empty — every remaining residue class has been offered at least one shape. The yield falling from 36% to 7% on exactly
the bodies s5's ordering left for last is what an exhausted pool looks like, not a broken instrument.
- check-all: 218 passed, 0 failed of 218
lever_census --check: 29,148 pin/asm sites, 29,148 marked !FAKE, 0 UNMARKED — OK
- what is left and what it costs (R41): 9,010 bodies in ~1,300 classes, every one already refuted at beam 3 x depth 2 x
cap 48. The next zero-token lever is a wider re-draw over the NO-MATCH population (--include-done, beam 4 x depth 3-4),
the same move that took g1's 1-of-16 to g3's 13-of-64 in S101. The head's 57 classes remain the agents'.
- snapshot row 16.