Commit Graph

3405 Commits

Author SHA1 Message Date
Drew T 61335ad18e feat(decomp): -O0 whale bank — ov_MAIN_012 func_80144B9C (770) + func_801457A4 (79), BINARY COMPLETE
Replaced the carve's generated _o0d.c wholesale with the minimal fleet-standard
whale TU. Keeping the generated §8b carried decl layer was NOT an option: it
conflicts with shared/func_80144B9C.h on 7 symbols (func_80015978 void*/s32,
func_800CF854 void/s32, func_801336E8, D_801274C8/CC/D0). Legitimate to drop it
here because the region holds ONLY these two functions (0xD44 = 0xC08 + 0x13C
exactly), so nothing in the TU needs the carried decls.

func_801457A4 remapped from ov_SC01_077_o0b.c: its 79 instructions differ across
overlays by exactly ONE data symbol (D_80186AD0 -> D_8017E338).

Byte-identical: d6b3e8b971cdd6c53aea8c4f265afb82b363283c == config/check.ov_MAIN_012.sha.
corpus.stubs(ov_MAIN_012) = 0 -- the binary has no open stubs left.

NOT via rollout_o0: its stub_file_of() skips any basename containing _o0, and the
carve moved BOTH stubs into _o0d.c, so the driver is structurally blind to them
and would have reported 'no-stub / already banked?' and banked nothing.
2026-08-31 16:21:13 -06:00
Drew T ff524cd07e feat(config): -O0 whale carve step 1 — split 0x80144B9C..0x801458E0 out of ov_MAIN_012_jr_8013F350
o0_subsplit: 2 unmatched stubs (func_80144B9C 770 ins + func_801457A4 79 ins), 0
already-matched islands interleaved, so K=0 and one -O0 region is correct. carve
repoints (none); config/overlays.mk UNCHANGED (the whale object owns no .rodata
carve anywhere in the fleet: 0 of 213 splat yamls carve .rodata to an _o0b).

BYTE-NEUTRAL, which is the whole claim of a carve:
  build d6b3e8b971cdd6c53aea8c4f265afb82b363283c == config/check.ov_MAIN_012.sha
interleave_check ALIGNED. Derived AND carved under .run/auto/gate.ov_MAIN_012.lock
(the commit:2791 rule: a plan derived outside the lock can describe a tree state that
never existed).
2026-08-31 16:20:38 -06:00
Drew T dd608ce5fd feat(decomp): parallel gate — 5 fns across 5 binaries (6 workers)
md_SC04_027    func_801EB014
  ov_SC07_007    func_8013DD68
  md_MAIN_003    func_800D1E9C
  ov_SC03_105    func_801824CC
  ov_SC06_029    func_80181DF8
2026-08-31 16:19:19 -06:00
Drew T e57deb0a8b feat(wave): escalate_fable.js — a Fable tier that is warm-started, not restarted
An escalation that re-derives what the cheaper tier already closed pays twice for
the same instructions. This passes the prior draft, its measured closeness and its
full residual report into the prompt, tells the agent to reproduce that closeness
first (and to STOP and report if it cannot -- R40), and forbids re-trying the
levers the prior agent already ruled out.

Points the agent at the escalation path the project actually has for a
compiler-internal residual (R17): the pinned gcc-2.7.2 source in-repo,
docs/gcc-2.7.2-map, and pass-disabling as a DIAGNOSTIC only.

Requires a 'new_idiom' field in the verdict: a Fable run that closes a function
but names no reusable lever has bought one function; one that names the lever
buys the class.
2026-08-31 16:18:00 -06:00
Drew T 380308b954 feat(gater): tools/gater_lane.py — the continuous gater lane
Drains a drafting wave's finished drafts into parallel_gate, grouped by binary,
while drafting keeps streaming. Accumulates to --min-drafts because same-binary
drafts must share a build (S67 had ov_SC05_010 x3 in one batch). --r22 by
default: it re-verifies the whole fleet from make clean after the merge and
aborts instead of committing a red binary -- the guard that would have caught
S67's '13 of 213 red, every one a jtbl binary' at once, for ~2.5 min.

Ledger keyed 'binary:fn' (R48 -- func_8017BEBC is a different function in
different overlays). A draft absent from its wave's targets.json is REFUSED
LOUDLY, never guessed at (R43); negative-controlled both directions: synthetic
unresolvable draft -> exit 1, clean tree -> exit 0, normal path unchanged.
Propagation, twin_sweep and harvest stay periodic and operator-driven: they need
aggregate, and cookbook 330 existed only because four instances landed in one wave.
2026-08-31 16:02:32 -06:00
Drew T ed53a68f18 feat(p31 s68): deferred propagation done honestly (2 banked) + seed_ref was offering DEAD TEXT
The S67 FINAL-3 OPEN item, plus the two defects found while doing it.

* fix(dedup_propagate): the tool could not run AT ALL. S67's -j patch wrote
  `os.environ` at module level in the one module that imports `os as _os`, so
  every invocation died with NameError before doing any work. Propagation was
  not deferred, it was impossible. Import-checked the other 7 -j-patched tools.

* propagation, honestly scoped: the real closable set is 11, not 32, derived two
  independent ways that agree (seed_ref exact+same_addr, and a direct corpus
  derivation). The 3,161-entry --auto-from plan over 53 overlays is dedup
  hygiene over already-matched code and closes almost no open stub.
  Applied: 2 banked byte-green (ov_SC04_018 func_80181270, func_80182AF8);
  3 gate-refused and cleanly reverted; 6 blocked with named blockers
  (3 CARRY-FIXABLE, 3 func_80144B9C not-inline-def -> needs the o0 whale carve).
  R22 clean fleet: extract 212/212, check 213 passed 0 failed of 213, rc 0/0/0.
  Frontier 453 -> 451.

* fix(seed_ref): REFUSE targets in LINKED subsegs. The playbook calls this tool
  "the fleet-wide answer" and it reported 82 open stubs with a banked twin --
  43 of them main stubs whose TUs the linker script never references. Any C
  written there compiles, links and leaves the SHA1 green WHETHER OR NOT IT IS
  CORRECT, so a mechanical twin lane fed from that list could have minted up to
  43 gate-green FALSE matches the byte gate cannot see. draw_waves has refused
  these since S66; this oracle did not. The refusal is counted and printed, not
  silent. NC: guarded 39 subset of raw 82, all 43 dropped are main, the non-main
  population is identical.

* wave drawn: .run/S68o1 (24 opus 187-770 ins) + .run/S68m1 (30 main), cards +
  packs + wave_args asserted, queue of 53. Drafting opened at concurrency 5.
2026-08-31 15:59:01 -06:00
Drew T 746a7cf656 docs(phase-31): S67 FINAL-3 — 77 closed (530 -> 453), fleet 213/213, jtbl parallelised (both halves), propagation deferred 2026-08-31 15:23:25 -06:00
Drew T 51abe2d174 feat(decomp): parallel gate — 19 fns across 14 binaries (8 workers)
ov_SC03_110    func_8018035C
  ov_SC04_000    func_8017F98C
  ov_SC04_015    func_8017E520
  ov_SC03_121    func_8017D8D4 func_80180E64
  ov_SC04_011    func_801827DC
  ov_SC03_007    func_801810E4 func_80184AFC
  ov_SC03_105    func_8017F55C func_801831E0
  ov_SC02_003    func_8017F62C
  ov_SC06_024    func_8017E1F0
  ov_SC05_001    func_80183C9C
  ov_SC06_030    func_8017F268 func_80181164
  ov_SC05_010    func_8018340C func_8018388C
  ov_SC04_016    func_8017D118
  ov_SC06_022    func_8017EBE8
2026-08-31 15:19:41 -06:00
Drew T 93ea53217e docs(playbook): a carve writes THREE outputs — merge all three, splice overlays.mk per block, gate jtbl with --r22 2026-08-31 15:17:27 -06:00
Drew T 101dec757a fix(pgate): merge carve STATE too — jtbl parallelizes for real now
The S67 first attempt banked jtbl bodies in worktrees and left their carve config behind, so 13 of
213 went red (reverted commit:3396). A carve writes THREE things and the merge must carry all or none:
  1. src/<bin>/*.c            per-binary, adopted like any bank
  2. config/splat.<bin>.yaml  per-binary, adopted whole, baseline-checked
  3. config/overlays.mk       SHARED — adopt ONLY this binary's BLOCK

ovl_block()/splice_ovl_block() cut on the  headers, so two workers carving
different binaries edit disjoint regions and cannot clobber each other. Same pinned-baseline refusal
as the per-file adopt, at block granularity — never a blanket file add
(the carve-state-files-never-blanket-add rule).

Verified: block round-trips byte-identically and leaves other binaries' blocks untouched.
2026-08-31 15:14:10 -06:00
Drew T a732097c37 Revert "feat(decomp): parallel gate — 19 fns across 14 binaries (8 workers)"
This reverts commit commit:3394.
2026-08-31 15:09:32 -06:00
Drew T 5bcb322283 docs: gating is fully parallel — no serial lane; jtbl unlocked via isolate_asm; launch detached with setsid 2026-08-31 14:55:39 -06:00
Drew T c26ddf136d feat(decomp): parallel gate — 19 fns across 14 binaries (8 workers)
ov_SC04_000    func_8017F98C
  ov_SC04_015    func_8017E520
  ov_SC03_121    func_8017D8D4 func_80180E64
  ov_SC03_110    func_8018035C
  ov_SC04_011    func_801827DC
  ov_SC03_007    func_801810E4 func_80184AFC
  ov_SC03_105    func_8017F55C func_801831E0
  ov_SC02_003    func_8017F62C
  ov_SC05_001    func_80183C9C
  ov_SC06_024    func_8017E1F0
  ov_SC06_030    func_8017F268 func_80181164
  ov_SC05_010    func_8018340C func_8018388C
  ov_SC04_016    func_8017D118
  ov_SC06_022    func_8017EBE8
2026-08-31 14:53:41 -06:00
Drew T 2b618caf6b perf(pgate): jtbl drafts now parallelize — isolate ONE binary's asm instead of symlinking all 448MB
Drew: "we need to parallel the jtbl stuff too. nothing should be serial."

THE BLOCKER: harvest_verify's jtbl carve runs `make extract`, and a worktree's asm/ is a SYMLINK to
the main tree (parallel_gate.py:77) — so a carving worker would rewrite the MAIN tree's asm while
other workers read it. That is the only reason jtbl drafts had a serial lane, and it cost ~1 hour to
gate 16 binaries in order to protect ONE jtbl draft this session.

THE FIX IS CHEAP, and the measurement is why: asm/ is 448 MB but ONE binary's subtree is 3.6-5.0 MB.
isolate_asm() replaces the blanket symlink with a real directory that SYMLINKS every other binary
(read-only, free) and holds a real COPY of just the binary being carved. `make extract BINARY=<b>`
then writes only inside the worktree. ~5 MB per worker on a box with 32 GB free.

Applied per JOB, not per worktree, because worker slots are reused across binaries — _drafts_carry_jtbl
uses the SAME predicate harvest_verify carves on (a jtbl_ reference in the target .s), so the router
and the gate cannot disagree (R33/R34).

NEGATIVE CONTROL: _drafts_carry_jtbl agrees with gate_wave.split()'s independent classification on
all 37 binaries of the S67 draft set, both directions.
2026-08-31 14:46:23 -06:00
Drew T dfc5d5b3c5 feat(decomp): parallel gate — 13 fns across 13 binaries (12 workers)
md_SC07_004    func_801A3180
  ov_SC01_080    func_801809E4
  ov_SC03_006    func_801823B8
  ov_SC01_001    func_801810A4
  ov_SC02_005    func_80190538
  ov_SC02_031    func_80183458
  ov_SC01_084    func_80181A7C
  ov_SC03_092    func_8017E780
  ov_SC04_008    func_8017D3F8
  ov_SC03_102    func_80180C38
  ov_SC03_107    func_8017CF48
  ov_SC07_006    func_8013DD68
  ov_SC07_002    func_80181394
2026-08-31 14:45:51 -06:00
Drew T 389d7d6197 feat(decomp): wave gate — +1 fns x0 propagated (fleet 99.2%) 2026-08-31 14:41:41 -06:00
Drew T 3a4eac272e docs(cookbook): §353 -fno-thread-jumps as a pass-identification oracle; launder the value to keep a dead re-test 2026-08-31 14:37:16 -06:00
Drew T 91a622b4c5 docs(cookbook): §352 CRITICAL — two identical zero-byte barriers merge with EACH OTHER, defeating their purpose 2026-08-31 14:34:16 -06:00
Drew T b39db34b56 docs(cookbook): §351 /s is a per-access dial; the base-split spelling; a pin-induced sched1 residual with the remaining door named 2026-08-31 14:33:55 -06:00
Drew T bbddb26e68 docs(cookbook): §350 the zero-byte re-tie also kills sched1's birthing_insn_p boost — attribute WHICH pass it moved 2026-08-31 14:32:30 -06:00
Drew T fcada63ada docs(cookbook): §349 n_times_set>1 on a base pointer defeats both the invariant hoist and the address giv 2026-08-31 14:27:27 -06:00
Drew T 932977cc5a docs(cookbook): §348 base spelling picks the addressing mode (3-insn lui/%lo vs 2-insn addu/lw); §137 refuted on constants 2026-08-31 14:27:10 -06:00
Drew T 6bd3d6ba42 perf: -j on the last three per-binary make build sites (family_sweep/twin_sweep, rollout_o0, restore_dropped_decls)
Completes the S67 audit: 0 remaining 'make build' call sites without -j. family_sweep is the one
that matters most of the three — twin_sweep delegates to it, so every sibling remap now gets the
6.1x build too.

NOT parallelizable, checked: 'make extract' is a single `splat split` process, so -j cannot help
it; its cost is splat's own runtime. The 4 extract calls in harvest_verify's jtbl carve path stay
as they are.
2026-08-31 14:24:03 -06:00
Drew T 6ad89305b8 docs(cookbook): §347/§343 addenda — one variable per purpose (3rd instance); sltiu proves an unsigned return 2026-08-31 14:21:45 -06:00
Drew T 096da8e4ff docs(cookbook): §347 loop regalloc is a declaration-order/live-range dial (no live-range splitting in gcc-2.7.2) 2026-08-31 14:21:25 -06:00
Drew T 675b4702b3 perf(gate): pass -j to the per-binary build — 6.1x on the inner loop of every gate
MEASURED on ov_SC03_010 (35 objects), clean each time, byte-verified against the locked SHA:
    make build            7.18 s real / 6.84 s user   <- SERIAL, one core, on a 32-thread box
    make -j16 build       1.18 s real / 11.3 s user   <- 6.1x, IDENTICAL bytes
Negative control at -j32 over ov_SC03_010 + ov_SC01_004 + md_MAIN_031: all rc=0, all byte-identical
to config/check.<bin>.sha.

WHY IT WAS MISSED: the Makefile's `JOBS ?= 16` is parallelism ACROSS binaries (`xargs -P`), which
parallel_gate already uses for extract-all/check-all. Parallelism WITHIN one binary's ~35 objects was
never passed by any tool, though docs/SETUP.md:416 documents `make -j$(nproc) build` as the form.

PATCHED the two hot sites:
* harvest_verify.py — the gate's build, run ONCE PER DRAFT (--chunk 1). Every gate in the project.
* dedup_propagate.py byte_gate — run once per propagation candidate, which is why a wide
  propagation dominated a 33-minute gate this session.
Both honour BFM_BUILD_JOBS, else os.cpu_count().

SAFE BY CONSTRUCTION: these builds feed a locked-SHA comparison, so a bad parallel build FAILS the
gate rather than banking wrong bytes. The error direction is a false NEGATIVE, never a false bank;
G3/P9 remains the sole arbiter.

Correction recorded: I earlier extrapolated "9 serial binaries x 30 min" from ONE 33-minute
measurement. That was unfounded — propagation time scales with how many sites a body reaches, and
other gates today propagated x19/x8/x7 quickly. One slow binary is not a rate (R41).
2026-08-31 14:18:05 -06:00
Drew T bd9b9f827d docs(cookbook): §346 COND_EXPR singleton path — c?X:-X negates in place, if/else does not 2026-08-31 14:14:53 -06:00
Drew T 34da91b45e docs(p31 s67): harvest §339-§345 from the 30-workflow streaming burst
Seven sections from 30 single-function opus workflows on 187-297 instruction targets (30/30 MATCH):
 §339 a 2-case switch OMITS gcc's low-bound range test (stmt.c emit_case_nodes) — so slti/bnez
      between two beqs is a COUNT TELL that a case node is missing from your draft
 §340 §194-K corollary: a 'scheduler' residual can be sched.c's ALIAS ORACLE inventing a false
      true-dependence; source order picks the edge's DIRECTION, so reverse it into an anti-dep
      rather than fighting it (10->0, zero bytes; 3 alternatives refuted with reasons)
 §341 an HImode store temp reweights a sched2 tie no statement order can reach
 §342 NEW LAW: a twin's  param cast in a local is NOT byte-neutral when a later param also
      needs a callee-saved reg — and the §333 converse does NOT hold (gcc may already pad the gap)
 §343 decl_prior's fleet MAJORITY can be wrong about the true signature — read the RIVALS.
      Measured: void(s32) x1374 vs the truth s32(s32) x163. The tool is honest, the corpus is wrong.
 §344 raise a biv's global_alloc priority with a zero-byte REFERENCE; a register pin kills LSR
 §345 volatile STORE evicts the MEM from cse and keeps sh; volatile LOAD blocks combine and
      degrades lh into lhu+sll+sra — the qualifier is not symmetric

Also: seed_ref validated on a live A/B. The same 187-ins body cost 102,193 tokens / 476 s in
ov_SC03_107 when the card said 'no banked twin', and 72,077 tokens / 135 s in ov_SC07_006 once the
card carried the twin — 30% fewer tokens, 3.5x faster. A second instance (func_8017F62C) went
63,595 vs 118,485 tokens. others_open=137 on that one exemplar, so it compounds.
2026-08-31 14:14:26 -06:00
Drew T 022d50325a docs(playbook): the pgrep bracket is NOT enough when launch and wait share a shell
Measured a SECOND time in S67, and the first fix was incomplete. A waiter using the bracketed
pattern still matched itself and spun 1h35m, because the same shell command had LAUNCHED the job —
so its own command line carried the unbracketed 'gate_stage.py --binary ov_SC07_007' from the nohup
half. The regex gate_[s]tage.py does not match the literal bracketed text, but it happily matches
the plain text sitting earlier on the same line.

Rule is now: launch and wait in SEPARATE shell invocations, or better, wait on a completion MARKER
the job writes to its own log rather than on process liveness.
2026-08-31 13:51:48 -06:00
Drew T 00812fc62f docs(p31 s67): wave-playbook (the CURRENT pipeline) + seed_ref fix + harvest §333-§338
THE DOC GAP, and it cost tokens this session. `docs/automation-runbook.md` was titled "the
autonomous campaign, as it actually runs" while documenting the RETIRED OpenRouter/ox-alpha system
whose lanes are all deliberately DEAD. The current Claude-wave pipeline existed only as two dense
tooling-inventory rows in SETUP.md — reference, not procedure. Three of this session's costliest
mistakes were procedural and a playbook prevents each:
  * hand-typed a refill target -> invented func_80184F60 (2nd instruction of a matched function), 58k
  * hand-rolled a serial gate loop when parallel_gate existed -> ~1h for what took 103s
  * re-derived a function banked verbatim in ~20 overlays -> 102k

NEW docs/wave-playbook.md — start to finish, each guard paired with the MEASUREMENT that produced it
(that pairing is the part a generic decomp guide cannot have, and the seed of the future template).
automation-runbook.md retitled HISTORICAL with a pointer; SETUP.md §6.9 links the playbook.

NEW tools/seed_ref.py — the cross-TU banked twin, joined on corpus signature hashes (no atlas knn,
~2s fleet-wide), wired into t5_cards.py. FLEET: 87 open stubs have a banked twin; 41 of them sit in
twin_sweep's refusal ledger, invisible to BOTH tools at once. Documents twin_sweep's two holes:
load_sigs covers 141/213 binaries (main, resident, all md_MAIN_* absent), and one curated symbol
name silently disables an entire binary via a bare `except Exception: pass`.
Schema note: seed_ref's binary/fn are the EXEMPLAR's, because api_agent greps src/{binary} for {fn};
naming them after the target would send every agent grepping for itself — caught pre-ship.

HARVEST §333-§338 from the s67o2_1/pool_1 waves:
 §333 frame size is set by DECLARED aggregates, not used ones — an unreferenced trailing local is a
      dial (3 instances; one worth 30 of 32 residual rows)
 §334 a reload spill slot rounds to BIGGEST_ALIGNMENT for align AND size: one 4-byte pseudo grew a
      frame by 16 (82->53)
 §335 `extern u16 A[]` at a variable subscript allocates ~8B/access of dead stack temps that inflate
      the frame with ZERO extra instructions — invisible in a body diff (141->20)
 §336 the §5a barrier goes at the BOTTOM of the twin; find_cross_jump walks BACKWARD
 §337 the CC1-ONLY blocker class: blocker_probe's static oracle says "none" and cc1 still fails
 §338 _sltiu_bounds misreads a non-switch sltiu as a bounds check, over-spanning the table

gate_wave.py now STREAMS both lanes (R55) — it captured output and printed at the end, leaving a
zero-byte log indistinguishable from a hang.
2026-08-31 13:48:56 -06:00
Drew T d989ed08ae feat(decomp): parallel gate — 14 fns across 11 binaries (6 workers)
md_SC07_003    func_801A38E4
  md_MAIN_027    func_800CB4A4
  ov_SC02_037    func_8013DD68
  ov_SC02_003    func_8018046C
  ov_SC01_084    func_8017EA98 func_80181F80 func_80184138
  ov_SC03_107    func_8013DD68
  ov_SC05_003    func_8017E380
  ov_SC05_008    func_8017DF68 func_8017EBB8
  ov_SC05_010    func_8017FAF4
  ov_SC06_032    func_80190D70
  ov_SC06_025    func_8017EA74
2026-08-31 13:43:44 -06:00
Drew T 21a2212ae3 feat(decomp): S67 main r2 — 1 banked (main 89 -> 88) + §332/§332a toolchain-wall findings
Wave s67m2_1: 7 sonnet agents, 1 MATCH banked, 6 NEAR — but 4 of the 7 are NOT drafting failures:
* func_8005FA94 / func_8005D244 — oracle_reorder.py bypass gives 0/55 and 0/62 diffs: the C is
  byte-correct, the pinned as -O1 cannot emit the §188 epilogue. func_8005D244 is additionally
  libpad pdent3.o, an SDK object owned by psyq_integrate.py — it should never have been drawn.
* func_80062144 / func_8005DBD8 — §332, traced to the compiler sources: gcc-2.7.2 emits a symbolic
  la as ONE atomic length-2 insn (no HIGH/LO_SUM split in this backend), eligible_for_delay requires
  length==1, so it can never fill a jump delay slot; the retail split is ASPSX macro-hopping that
  maspsx does not replicate. Byte-verified by running maspsx over cc1's raw -dS output.
  6 such functions fleet-wide, NONE banked.

§332a records the draw-policy consequence: main's cheap population is spent and the residual is
ENRICHED in toolchain walls, so main's apparent match rate is contamination, not a model signal.
Wall ledger at .run/S67_walls.txt for the --exclude mechanism.
2026-08-31 13:21:01 -06:00
Drew T b8a4eae41a docs(phase-31): S67 FINAL-2 — 29 closed (530 -> 501), fleet 213/213, wave 20/20 MATCH, gate_wave.py replaces the serial loop 2026-08-31 12:48:46 -06:00
Drew T 6bb3d240fa feat(p31 s67): harvest §325-§331 + gate_wave.py (split jtbl/parallel, both lanes concurrent)
HARVEST — the s67o1/s67m1 wave banked 7 cookbook sections:
* §325 a shared small constant stored twice in the pre-loop block is a LOCAL-ALLOC $s-occupant that
  steals the argument allocno's register — pin the ARGUMENT-derived local, not the constant
  (pinning the constant reached only closeness 15). byte-proven func_80184F18.
* §326 spelling two reads of the same halfword differently (sym[i] vs *(s16*)(base+i*4+2)) yields
  different address rtx and DEFEATS address-CSE, restoring separate %hi/%lo groups. func_8017FAAC.
* §327 a range test must be HImode: with s32 + a (u16) cast gcc PROVES the mask redundant and drops
  the andi — a real -1 length drift that reads as a schedule. +3 levers. func_8017EC34.
* §328 NEW LAW: the volatile alias must be an aliased OBJECT; `*(volatile s32*)&sym` unfolds %lo
  into a separate addiu (+1 ins). func_80181B8C.
* §329 fold-const narrows `(int)s16 & 0xFFF` onto the RAW HImode pseudo, breaking the
  sign-extend/mask register tie; a zero-byte `s32 e = t;` widening temp restores it (30 rows -> 0).
* §330 the NEIGHBOUR-SHAPE lever, four independent instances in one wave — copy an already-banked
  in-TU function's SPELLING before any codegen reasoning (one dissolved 18 REGALLOC-PERM rows in a
  single compile). Corollary: a warm start from another binary is often worth LESS than the
  neighbour 20 lines away.
* §331 OPEN GAP, recorded as unsolved: no lever eliminates an UNWANTED DUPLICATE copy at a
  branch-target block head (main/func_80013154, closeness 12, ~16 iterations, 5 approaches refuted).

TOOLIFY — tools/gate_wave.py: split the batch on the per-draft jtbl predicate, run parallel_gate
and the serial jtbl lane CONCURRENTLY. Measured this session: 4 binaries in 103s wall through
parallel_gate (87/87/88/102s each) vs ~6 min serially; I had gated all 16 serially to protect ONE
jtbl draft, ~1 hour. The split precedes the run because a jtbl worker does NOT fail cleanly — it
re-extracts through the worktree's asm/ symlink and writes the MAIN tree while other workers read it.

Its own negative control found two defects in it before first use:
  * listdir counted gate_stage's _xform output dirs (-cn/-cast/-rc/-sd, written as SIBLINGS inside
    the drafts root) as binaries: 20 "binaries" for a 16-binary wave. Now validated against
    progress.BINARIES and refused loudly (R32/R43).
  * a post-hoc control over BANKED functions cannot reproduce a split (has_jtbl has no stub to read);
    re-controlled against a live draft set, where it correctly routes the two functions the gate had
    independently reported CARVE-REFUSED.
2026-08-31 12:44:13 -06:00
Drew T b94af95740 feat(decomp): parallel gate — 1 fns across 1 binaries (2 workers)
ov_SC03_118    func_80184F18
2026-08-31 12:40:21 -06:00
Drew T 96f4e0ed5d feat(decomp): S67-wave-jtbl gate — +1 fns x2 propagated (fleet 99.2%) 2026-08-31 12:23:50 -06:00
Drew T 026bca9be8 feat(decomp): parallel gate — 4 fns across 4 binaries (4 workers)
ov_SC04_016    func_8017DA50
  ov_SC07_006    func_8018984C
  ov_SC03_119    func_80184F18
  ov_SC03_031    func_8017F428
2026-08-31 12:15:45 -06:00
Drew T 253f5c9d44 feat(decomp): S67-wave gate — +1 fns x0 propagated (fleet 99.2%) 2026-08-31 11:32:42 -06:00
Drew T 7e9bfa37f7 feat(decomp): S67-wave gate — +1 fns x0 propagated (fleet 99.2%) 2026-08-31 11:28:51 -06:00
Drew T 4ced908c08 feat(decomp): S67-wave gate — +1 fns x7 propagated (fleet 99.2%) 2026-08-31 11:25:39 -06:00
Drew T e23492e3bc feat(decomp): S67-wave gate — +1 fns x6 propagated (fleet 99.2%) 2026-08-31 11:22:50 -06:00
Drew T 098cb932ef feat(decomp): S67-wave gate — +2 fns x0 propagated (fleet 99.2%) 2026-08-31 11:20:02 -06:00
Drew T 274057d132 feat(decomp): S67-wave gate — +2 fns x8 propagated (fleet 99.2%) 2026-08-31 10:34:40 -06:00
Drew T 257b9d8a3b feat(decomp): S67-wave gate — +2 fns x1 propagated (fleet 99.2%) 2026-08-31 10:31:15 -06:00
Drew T 1a4d725a15 feat(decomp): S67-wave gate — +1 fns x0 propagated (fleet 99.2%) 2026-08-31 10:25:27 -06:00
Drew T 9dfc91ba6d feat(decomp): S67-wave gate — +1 fns x1 propagated (fleet 99.2%) 2026-08-31 10:22:41 -06:00
Drew T 89ede18c22 feat(decomp): S67-wave gate — +1 fns x0 propagated (fleet 99.2%) 2026-08-31 10:21:36 -06:00
Drew T 9673373d97 feat(decomp): S67 main wave — 5 of 7 banked (main 94 -> 89), byte-identical 143dbb89
Wave s67m1: 7 sonnet agents, 0 errors. 5 MATCH banked after bisection in 9 rebuilds;
the 2 NEAR drafts rejected exactly as their agents predicted (func_80013154 close=12,
func_8005ECC0 close=6).

One draft's declaration refused the whole batch first: func_8002A088 declared
`extern s32 func_8002A108(void);` while src/800.c DEFINES it as (s32) at line 15270.
Fixed with the no-proto half of cookbook §324 (`extern s32 func_8002A108();`) — a
no-prototype decl is compatible with a promotion-safe definition and leaves the 0-arg
call unchecked, byte-neutral for the emitted jal. Argues for wiring §324 into the ladder
rather than hand-applying it; it cost a full main gate cycle.

NOTE for the ledger: func_8005E8E8 and func_8005EC00 are verbatim file-scope __asm__
transcriptions, not decompiled C — both hit the §188 wall (2 callee-saved regs with
jr $ra + addiu $sp in the delay slot, unreachable from cc1 under the pinned as -O1),
and both follow established in-TU precedent (func_8005E79C, func_8005EB28).

WALL LEDGER candidates: func_8005ECC0's epilogue tail is proven unreachable via
oracle_reorder.py; only idx24-26 (a beq delay-slot steal) remains open there, and it has
now resisted 8 prior wave attempts plus 3 today.
2026-08-31 10:20:25 -06:00
Drew T b2256e3700 docs(phase-31): S67 FINAL checkpoint — 4 closed (530 -> 526), fleet 213/213, propagation found unverified 2026-08-31 09:45:55 -06:00
Drew T bac7537564 fix(p31 s67): repair ov_SC04_018 — dedup_propagate deleted a decl layer the surviving bodies needed
R22 caught it: 212/213 after the S67-cc1 gate run. `ov_SC04_018` was RED.

ROOT CAUSE (from the diff, not inferred). Commit commit:3354's propagation replaced three bodies in
`ov_SC04_018_jr_80135D20.c` with DEFINE_func_*() instantiations and deleted the 981 lines they
occupied — INCLUDING the TU's file-scope declaration layer, which the two surviving non-deduped
bodies still referenced. A duplicate copy of those decls survived at line 225, BELOW the function
that uses them at line 42, so C89 ordering made it fatal (`D_8018D7A4' undeclared).

THE STRUCTURAL GAP: gate_stage byte-gates the SOURCE binary, then propagation writes to N OTHER
binaries and nothing re-verifies them. "fleet 99.2%" in the commit subject is a metric, not a gate.
This is the blind spot R50 exists for, and only the periodic whole-fleet R22 could see it.

REPAIR: restored src/ov_SC04_018 to commit:3354^, re-extracted (banking had pruned the .s stubs the
restored INCLUDE_ASM lines need), rebuilt rc=0 at the locked SHA fe9b413f. dedup-check clean
(2193 validated, 0 failed, C1 255302/255302). Cost: the 2 banks in that binary.

NEW tools/restore_dropped_decls.py — compiler-driven recovery for this failure mode: build, read
which identifiers cc1 calls undeclared, look each one up in the pre-deletion git ref, insert it
above the leading #include block, repeat. Two defects found and fixed in it while using it:
  * anchoring after "the last extern in the first 400 lines" inserts BELOW the point of use, so the
    build fails identically and the loop re-inserts forever (measured: 25 rounds, 100 dead decls).
    The only safe anchor is the top of the file.
  * a no-progress guard now REFUSES when a round asks for what the last round already inserted.
It also correctly refused when the failure changed class (link-level undefined references), which
is how the wider damage was found rather than papered over.

NOT a defect of the S67 §8d rung: scope_demote_drafts only ever writes draft dirs under .run/.

FLEET: make clean + extract-all + check-all = 213 passed, 0 failed of 213.
FRONTIER: 530 -> 526 (4 functions closed this session, measured from corpus.stubs).
2026-08-31 09:44:50 -06:00