Banked: func_80136334 (126, all four levers), func_8016B234 (129), func_8015FBE0 (125), func_80143D28 (131),
func_8014D820 (126 of 128). 27,984 -> 26,714 sites.
lever_census --check: 26,714 pin/asm sites, 26,714 marked !FAKE, 0 UNMARKED — OK
THE MISSING CALL ARGUMENT CLASS IS NOW CONFIRMED SIX TIMES, independently, by six agents that never saw each other's
work: a7, a8, a11, a12, a13, a25. In every case the source declares a call with fewer arguments than the callee really
takes — m2c drops arguments at unprototyped and indirect call sites — and the register pin was hired to fake the
instruction the missing argument would have produced. Mechanisms differ and were each proven on bytes: combine.c:1458's
added_sets_2 gate; set_preference (global.c:1535/1589) applied ahead of first-fit at :997-1030, the argument copy
degenerating to a self-move deleted at toplev.c:3142 / jump.c:424-443 so it costs zero instructions; and reorg.c:3374's
liveness half, where restoring the argument adds a use to CALL_INSN_FUNCTION_USAGE (reorg.c:428) so a delay-slot steal
is refused. No generator can reach any of it: every family rewrites statements and declarations, none edits a call's
argument list.
Two concurrency defects, both found by agents rather than by me:
- the includers cache wrote through a FIXED temp name, so concurrent processes clobbered each other's os.replace and the
loser saw FileNotFoundError, which reads like a compiler crash on the candidate. Now a unique tempfile per process.
- the agent brief now mandates PACK/scratch/ for helper scripts and dumps, and says to retry once when a --try failure
names something that is not your own text. Three agents had scripts overwritten mid-run by another agent.
One valuable negative: func_80178970 does not close, and the agent proved why by construction rather than by exhaustion
— only a call or a return writes $v0 in plain C, and a return's hard write is always emitted after its guarding branch,
so combine deletes the call-result copy (combine.c:914-917, use_crosses_set_p at :10127-10130; the SMALL_REGISTER_CLASSES
arm at :944-957 is not defined for MIPS). Its early-return rewrite still improves the source from 6 to 2 and reads
better than the pinned original.
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.
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.
search: 285 of 800 exemplars matched lever-free in 2.32 h (285 of 800 bodies behind them; 94,627 compiles) — NO-MATCH 499 · MATCH 285 · UNSTRIPPABLE 9 · UNSCORED 7
- the first broad draw of non-head classes, at the cheap width, with the full generator set. By first move:
R7 105, R10 59, R12 42, R6 26, R9 20, R18 13, R8 9, R3 6, R15 4, R14 1 — and 242 of the 285 closed in ONE move.
These are not deep searches; they are bodies nobody had ever offered a single shape to. R18, one day old, is 13 of them.
- the contrast that steers the rest of T7: 36% of the tail closes mechanically, against 6 closes in ~128,000 compiles on
the head. The head's 57 classes are the agents' work; everything else is the engine's, at zero tokens. Sweep the whole
residue before spending another agent.
- check-all: 218 passed, 0 failed of 218
lever_census --check: 29,204 pin/asm sites, 29,204 marked !FAKE, 0 UNMARKED — OK
- snapshot row 15.
search: 1 of 80 exemplars matched lever-free in 0.89 h (6 of 486 bodies behind them; 28,042 compiles) — BUDGET 59 · NO-MATCH 18 · UNSTRIPPABLE 2 · MATCH 1
- func_801621CC by R6 inline lo + R7 do-while; delever --propagate: 5 of 5 sibling(s) banked, 0 refused.
- the figure that prices the draw is BUDGET 59 of 80: three quarters of the remaining bodies exhausted 400 compiles rather
than being refuted, so this family is sampled, not measured. s3 had already taken its cheap half (10 bodies).
- two UNSTRIPPABLE recorded by name: func_8017DC80 (a launder with 2 outputs), func_80181A4C (instruction lw has no C
spelling in the table).
- check-all: 218 passed, 0 failed of 218
lever_census --check: 29,527 pin/asm sites, 29,527 marked !FAKE, 0 UNMARKED — OK
- snapshot row 14. Loop economics two agents in (R41): 30,358 -> 29,527 sites, 9,747 -> 9,320 bodies; the agents' own two
bodies account for 255 of that and their toolified moves for the other 576, at zero drafting tokens.
- s2 (the head, with R16/R17 added): search: 0 of 140 exemplars matched lever-free in 0.24 h (0 of 7,085 bodies behind
them; 23,689 compiles). The two new generators closed nothing on the head; recorded as measured.
- agent a2's "284 constant-holder pins of 10,958" verified against the source rather than believed (R14), and my first
instrument was wrong (R40): asking R16 directly answered 33, because R16 only fires on a split declaration while most
pins carry their value as an initialiser. R3 converts one form to the other, so the reachable family is R3+R16.
Corrected, both figures derived: 537 constant-holder pin sites of 17,302, in 510 bodies (152 initialiser, 385 separate
assignment; by register $2 282, $20 136, $3 28).
- s3 drew exactly those 99 function names and closed 10 bodies before crashing with
AttributeError: 'Namespace' object has no attribute 'allow_residue'
in propagate — the a2 fix read the flag off the caller's namespace and the search engine builds its own Namespace for
that in-process call. Fixed with getattr(a, "allow_residue", False): a library must not assume its caller's namespace
shape (R43).
- the ten banks were real, proven by gating the tree the crash left:
check-all: 218 passed, 0 failed of 218
lever_census --check: 29,533 pin/asm sites, 29,533 marked !FAKE, 0 UNMARKED — OK
- by first move the ten are R15 x3, R6 x4, R7 x2, R9 x1 — the draw was right about the family even though R16 did not fire.
- snapshot row 13; s3 re-runs from the top with the fix.
- two moves: delete `register s32 c40 __asm__("$3")` and its `c40 = 0x40;`, writing the literal at its four uses (byte-neutral
on its own — the pin was never doing the work); then swap the adjacent `f1e = 0x40;` and `f1a = 0x10;` so the 0x10 store
splits the run of 0x40 stores.
- the residual reads like cse/sched and the decision is local-alloc's. Dumps of the real TU in both orderings differ on one
.lreg line — `Register 76 used 5 times across 10 insns` -> `across 14 insns`, `Register 76 in 2.` -> `in 3.` — which is
find_free_reg's live-range scan at local-alloc.c:2109-2110: unswapped the two constants' ranges are disjoint and share $v0,
swapped they overlap and the first takes $v1.
- the $4 pin STAYS, and not as a lever: src/shared/ov/func_801687CC.h declares extern void func_80168828(void), so the
target's `move s1,a0` has no C source. An uninitialised local, a pointer-typed one, a split declaration and deleting it
outright all give the identical score-25 residual; both parameter forms are hard cc1 errors against that header. This is
the first measured pin that only a declaration fix can remove — one of the 51 conflicts P35 ledgered for the types phase.
The engine's score-1 text is a coincidence (its andi truncates garbage in $s1 and never reads $a0); not proposed.
- instrument fixed in the same change: --propagate refused all 124 siblings because the reshape deliberately keeps a lever.
The allowance is now derived from the exemplar's own banked text (its surviving !FAKE markers), and a sibling whose remap
would carry more levers than the exemplar is refused by name.
delever --propagate: 124 of 124 sibling(s) banked, 0 refused
- check-all: 218 passed, 0 failed of 218
lever_census --check: 29,572 pin/asm sites, 29,572 marked !FAKE, 0 UNMARKED — OK
- snapshot row 12; delever --selftest OK. The toolify (R16, the constant-run split) follows.
The harvest half of agent a1 paying off. With R15 in the registry the engine was swept over the rest of the residue head
(--only the 56 other head functions, which draws every body of those names: 147 exemplars judged).
search: 6 of 147 exemplars matched lever-free in 0.28 h (267 of 7,477 bodies behind them; 23,892 compiles) — NO-MATCH 141 · MATCH 6
- all six closes are R15, each in FOUR compiles: func_8013EB7C (126 + 7 copies) and func_8016DF5C (127 + 4 + 2 + 1) across
their fleet copies. Every propagation 0 refused. R15 also moved func_80136824 from 21 to 2 as a first move.
- the loop's economics with denominators (R41): one agent's reading (~221k tokens) bought 130 bodies directly and 267 more
for zero tokens — 397 bodies, 30,358 -> 29,697 sites (-661).
- check-all: 218 passed, 0 failed of 218
lever_census --check: 29,697 pin/asm sites, 29,697 marked !FAKE, 0 UNMARKED — OK
- snapshot row 11 (9,617 -> 9,350 bodies); the checkpoint headline and loop state refreshed (R101).
The first agent of the one-at-a-time T7 loop, on the rank-1 head class (130 copies, two NEEDED pins $2/$3). Six mechanical
rung-G runs had been stuck at best 1 on this body; the agent closed it at 0.
- the move is not a dial: the iVar3/puVar2 pair that every arm of the if/else chain set is deleted, and each arm gets the
whole address expression (puVar4 = &D_80192454 + (((u32)param_2) & 0xffff) * 0x14). Two locals fewer than the levered
text — shorter AND byte-identical, which is what this phase is for.
- mechanism, read from gcc 2.7.2's own source and confirmed in the .lreg/.greg dumps: scoping the base into the arm makes
the block hold THREE local quantities instead of two, and block_alloc's unrolled case 3 (local-alloc.c:1491-1496) falls
through into case 2 and applies qty_compare(0,1) a second time, undoing its own exchange — so the $2/$3 assignment flips
(density formula local-alloc.c:1578-1596); deleting the cross-block variable also takes it out of global.c, where
set_preference (global.c:1535+) had given it a copy preference for $5 through puVar4's argument copy, merged by
expand_preferences (global.c:781-825) and overriding first-fit at global.c:1034-1067.
- why the engine could not find it: the u16-width move six runs found is a local optimum that IMITATES the fix by
manufacturing the third quantity while paying an andi. No generator in the registry deletes a variable, so the search
could not leave that basin. That is the toolify target and it follows in its own commit (R16).
- verified before banking (--try: score 0, mine 74 ins, target 74 — MATCH), then
delever --apply-body: ... IDENTICAL on 1 object(s) (0.11 s) — KEPT, ledgered (rung E, a1)
delever --propagate: 129 of 129 sibling(s) banked, 0 refused
check-all: 218 passed, 0 failed of 218
lever_census --check: 30,098 pin/asm sites, 30,098 marked !FAKE, 0 UNMARKED — OK
audit_public: OK — 0 offenders among 11445 tracked paths
- snapshot row 10; the agent's body.c and mechanism.md kept in the pack as the reading behind the generator.
- delever --propagate: 132 + 130 + 131 + 132 siblings banked, 0 refused; each sibling's body is the exemplar's reshaped
text with ITS OWN func_/D_ addresses (the class is "identical modulo addresses", so the two old bodies' tokens
correspond one for one), judged on its own objects before it is kept
- the class key comes from the FIRST bank in a body's chain, not the last: a body that was reshaped and then tidied has
two rows, and the later row's before-hash describes a text only that body ever had (func_80163EC8 found 0 siblings
until this was fixed, then 132)
- R22 clean fleet: `check-all: 218 passed, 0 failed of 218`
- lever_census --check: 33,427 pin/asm sites, 33,427 marked, 0 UNMARKED — 664 sites gone this session (34,091 at S99's
open); lever_progress snapshot "T6 p1"
- delever_permute --bank: 4 winners applied through delever --apply-body, each IDENTICAL on its own object; the winner is
now TIDIED first (pycparser reprints a body it parsed: two-space indent and a corpse `;` where a statement was inlined
away) and the tidy is judged like any other candidate, so the source keeps the tree's shape; parenthesisation and brace
style are deliberately left to the formatting phase, over the whole tree at once
- a slip, named: --bank re-applied a permuter body over the ONE-LINE version rung R had already banked for
func_80135D20; the clean text was restored through the oracle (label d1fix) and --bank now skips any body the ledger
already calls LEVER-FREE
- --recipes is killable now: the oracle writes the candidate into the tree to compile it, so the original goes into
inflight.json first (P35's rule: a tool restores from its own snapshot) — a killed run had left a candidate in src/
- rung R's R6 generalised from "assigned once, read once" to "dead after one read" (the lever rung D actually found:
uVar5 is assigned in two branches and only one was inlined); it still does not reproduce that class's win, which is
recorded as an open item rather than papered over
- lever_census: 33,953 sites (was 33,957), 0 UNMARKED; lever_progress snapshot "T6 d1"; R22 218 passed, 0 failed of 218
The pin/hint removal's COUNT OVER TIME is a deliverable in its own right: the post-100% chart, the story's spine, a wiki
page, and the day-one rule the decomp-architect kit should carry. It is only ever counted by the phase that removes it, so
it has to be captured while the work happens — a census is a moment.
- docs/levers.md: the taxonomy (A pins · B1-B4 barriers/launders/keep-alives/hand-placed instructions · B5 GTE, not a
lever · C volatile · D bare register · E asm-label aliases · F builtins · G attributes); a GENERATED §2; how the levers
got in phase by phase (P18's pin toolkit took the wave close-rate 33% -> 56% -> 90%; the family engine then copied every
lever across up to 134 overlays, which is why 1,758 distinct bodies are 12,578); the ladder with each rung's measured
yield; §5 the prevent-vs-defer argument; §6 what the wiki, the kit and the story each take.
- tools/lever_progress.py: --snapshot appends a milestone row (the census's totals by class + HEAD) to
docs/lever-progress.tsv and re-renders the document; the campaign table is derived from the de-lever ledger on every
render and scored as state TRANSITIONS, so the rung that FINISHES a body gets the credit (counting first-rows-only
reported rung R's 134-body batch as zero); --check refuses a series that is not this tree's.
- the numbers, generated: 21,061 sites removed or rewritten across 17,119 bodies against 33,957 still standing — 38% of
the class A/B population came off with no understanding at all, which is the evidence behind §5's rule:
BAN THE SILENCE, NOT THE LEVER (a lever is allowed and is a marked, ledgered, published debt from the first bank, with a
one-compile bank-time trial; never block the byte gate on it).
- Reference-index row (doc_links OK), SETUP row, tool dictionary row, CURRENT_PHASE entry for the story.