Commit Graph

2725 Commits

Author SHA1 Message Date
Drew T bce7aee2d3 feat(decomp): main lane m05aaa — 3 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  func_800159E4
  func_800290BC
  func_8002A9B8
2026-08-24 20:06:15 -06:00
Drew T 536c420e59 feat(decomp): ox wave bs overlays — 10 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 19:42:03 -06:00
Drew T affe6728be feat(decomp): ox wave bx overlays — 14 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 19:32:41 -06:00
Drew T eae679684a feat(decomp): main lane m05abba — 2 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  func_80039C5C
  func_8005E13C
2026-08-24 19:28:29 -06:00
Drew T 65ece40852 feat(decomp): main lane m05aba — 3 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  func_8002D59C
  func_80036F98
  func_8005D138
2026-08-24 19:27:55 -06:00
Drew T 7e8c56df5f feat(decomp): main lane m05aa — 5 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  func_8001BFB0
  func_8001D150
  func_8002CCB4
  func_8005D6CC
  func_8005E480
2026-08-24 19:25:45 -06:00
Drew T e56355428a feat(decomp): free A-prop sibling lane (maintenance pass) — zero model tokens 2026-08-24 19:24:12 -06:00
Drew T e6bb079a2f docs(s59): the proof run — 40 drafts, 32 banked, one rebuild, SHA green (m05 = commit:2717) 2026-08-24 19:23:29 -06:00
Drew T 00ce6c6171 chore(decomp): commit in-tree banked work before the next gate
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
2026-08-24 19:22:18 -06:00
Drew T 2aea2261d4 feat(decomp): main lane m05 — 32 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  ResetRCnt
  SYS_OBJ_E34
  func_80015118
  func_800159C0
  func_80015A08
  func_80015A50
  func_80017168
  func_800178EC
  func_80017910
  func_80017E68
  func_8001CF30
  func_8001D050
  func_8001D70C
  func_800291A0
  func_800291B4
  func_800291C8
  func_800291DC
  func_800291F0
  func_80029204
  func_80029524
  func_80029A94
  func_80029EC0
  func_8002A520
  func_8002A9DC
  func_8002AEE4
  func_8002AF48
  func_8002D844
  func_8002F0D0
  func_8002F12C
  func_8003A0D0
  func_8005E374
  func_8005FB70
2026-08-24 19:22:18 -06:00
Drew T 210dba7afe feat(decomp): ox wave bw overlays — 47 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 19:15:01 -06:00
Drew T 1432dba125 docs(accelerators): 6 — the null-input control belongs in the failure path 2026-08-24 19:09:47 -06:00
Drew T 78a377f38b docs(ops): runbook carries the S59 main-lane baseline guard and the one-writer rule 2026-08-24 19:09:13 -06:00
Drew T e40fe9c116 fix(main-lane): the baseline was RED — guard every gate with a no-draft control (S59)
PROVEN: from 14:57:01 to 18:43:23 today HEAD built main to 307aa45d… against the
expected 143dbb89…, with NO draft substituted (measured under gate.main.lock, no
gate_main alive). Auto-commit commit:2693 had adopted a mid-flight gate_main
substitution — its carve-out reverted main's TUs, gate_main re-wrote them, and
`git add -A src/` swept the unverified bodies in (a TOCTOU race, 14 s after a
bisect chunk banked). Every main batch after it was doomed before its first
draft was judged: m00–m03 card cycles drafted ~737, slated 160, banked 0, and
burned ~50 clean rebuilds bisecting innocent slates. commit:2712 restored the
green content by accident (it swept this investigation's diagnostic checkout).

gate_main: on any batch failure, ONE try_batch([]) control runs first — if HEAD
itself is red it prints BASELINE RED, leaves the slate reusable, exits 3 (R40).
clean_build no longer reports a linked-but-mismatched build as "no binary" (the
build target embeds the SHA check), the compile-conflict shortcut fires only on
error-shaped lines naming a symbol some draft in the slate actually uses (the
baseline's own func_800143AC implicit-decl WARNING was matching — every m04
chunk died with "drafts declaring it: []"), reverts narrow to top-level src/*.c
(main_tus) so a main gate can never destroy overlay lanes' in-flight work, and
--assert-baseline is a first-class mode.

main_lane: every cycle opens with gate_main --assert-baseline and REFUSES to
draft or gate against a red baseline (R43) — BaselineRed parks nothing, burns
no tries, writes .run/main_lane.BASELINE_RED, re-checks every 30 min.

Adopters (ox_campaign ×3, maintenance.sh, gate_stage, gate_lane, idiom_serial):
main's TUs (top-level src/*.c) are never staged and never reverted by an
overlay/maintenance lane — one writer (gate_main), one committer (main_lane,
after the whole-EXE SHA re-checks green). Unstage-after-add is race-free where
the old revert-then-add was the losing half of the TOCTOU.

Diagnosis, evidence and the full timeline: docs/tool-designs/main-lane-fix-s59.md
2026-08-24 19:08:47 -06:00
Drew T 88673d3708 feat(decomp): ox wave bv overlays — 44 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 18:43:23 -06:00
Drew T 86ebc95a81 feat(ops): one status view for ALL lanes; straggler grace = one full turn; distill dedupe
STATUS BLINDNESS (Drew): status checks kept reporting the overlay drafter and the
gater — the lanes whose logs scroll — while the main, maintenance and distill lanes
went unmentioned for hours. A lane you do not report is a lane you do not notice
failing: the main lane spent an afternoon on an old config and bisected a whole batch
to zero banks without that ever reaching a status line. tools/campaign_status.py
prints every lane with ITS OWN metrics, read from artefacts rather than memory.

STRAGGLER GRACE 120 -> 700, tied to HTTP_TIMEOUT so they cannot drift. collect_drafts
queues a wave once 95% of shards finish, then waits this long for the rest — and 120s
is shorter than a single turn (~530s for a 16k generation at ~30 tok/s). So raising
the token budget converted truncated turns into agents guillotined mid-thought with NO
draft: overlay draft completion fell from 84-89% at 8k to 41% (bt) and 69% (bu).

DISTILL DEDUPE: each pass re-offers everything unmined, so the lane wrote a fresh
overlapping marker every five minutes — eight queued, each a superset of the last, and
a reviewer cannot tell which one is the work. One pending marker at a time.
2026-08-24 18:27:05 -06:00
Drew T 5be231d446 feat(decomp): ox wave bu overlays — 42 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 18:02:49 -06:00
Drew T e3f8241592 feat(decomp): free A-prop sibling lane (maintenance pass) — zero model tokens 2026-08-24 17:53:38 -06:00
Drew T 1cbe3004f8 feat(decomp): ox wave bt overlays — 44 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 17:31:22 -06:00
Drew T 6f5eb90844 docs(ops): correct the truncation numbers — the denominator was wrong
I reported 240 of 244 turn-finishes truncated in wave bk and called it ~100%. That
count came from grepping lines containing 'finish=', which api_agent only prints when
a turn ends WITHOUT a tool call — so the denominator was not all turns, it was all
anomalous turns. I compared a subset against itself.

Counting every turn:
  bk (8k / 420s):   240 truncated of 3,222 turns = 7.4%
  bt (16k / 700s):   16 truncated of 1,210 turns = 1.3%

Still a ~6x improvement and the change stands on its own evidence, but it is a tax
reduction, not the collapse I described. Recorded alongside: a truncated turn is one
turn of 24, not a lost agent — the logs show the agent emitting its tool call on the
very next turn.

Both docs keep the wrong figure explicitly, with why it was wrong, so the next reader
does not re-derive it from the same grep.
2026-08-24 17:11:46 -06:00
Drew T 1f7fdc7913 feat(decomp): ox wave br overlays — 8 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 16:50:56 -06:00
Drew T b6ba6ab7df docs(ops): SETUP + runbook carry the probed campaign constants
SETUP gains rows for recover_rejects.py (free recovery of the 45% of drafts that never
reach the gate, 13% of which are a deterministic symbol rebase),
restart_main_lane_when_idle.sh, and a campaign-constants row recording MAXTOK 16000 /
HTTP_TIMEOUT 700 with the measurements behind them: reasoning_tokens=0 so the output
cap was the reasoning cap, 240 of 244 turn-finishes truncated at 8k, an uncapped hard
prompt wanting 8,067 tokens, ~30 tok/s, and the 1M-context / 131,072-max-completion
model ceiling that makes 16k our choice rather than a limit.

The runbook gains the same table plus the ordering rule (generation < HTTP_TIMEOUT <
stallguard's 1200s kill), the evidence that turn caps are NOT binding on the default
lane, one-lane-one-band with the size table that retired the 120-2000 slot, the
maintenance lane's new recovery job, and the main-lane restart helper.
2026-08-24 16:44:36 -06:00
Drew T 6a19755969 feat(lanes): restart the main lane at its idle boundary, not mid-work
Same problem as the drafter: an env/arg change (MAXTOK, HTTP_TIMEOUT) only reaches a
fresh shell, and the main lane is usually either drafting or gating. This waits for
the one safe window — no main-lane agents alive and no gate_main running, i.e.
between the gate and the next draw — then restarts. Mid-draft would discard drafted
work; mid-gate would abort a batch (safe, since gate_main reverts its own
substitution, but wasteful).
2026-08-24 16:39:42 -06:00
Drew T db3fe3490b fix(lanes): raise HTTP_TIMEOUT with MAXTOK — they are one setting, not two
Probed ox-alpha directly on a real MIPS derivation:

  no reasoning cap      265.2s  finish=stop  completion=8,067  reasoning=0   30 tok/s
  reasoning cap 2000     22.3s  finish=stop  completion=  672  reasoning=0
  reasoning cap 6000     41.4s  finish=stop  completion=  618  reasoning=0

Three findings. (1) ox reports reasoning_tokens=0 — its thinking is IN the content
stream, so the output cap was capping the reasoning; that is exactly why turns ended
in 'no tool call (finish=length)'. (2) The uncapped hard prompt wanted 8,067 tokens —
it was finishing precisely where the old 8k cap cut it off. (3) It generates at ~30
tok/s, not the ~54 I estimated from turn gaps, so a full 16k generation needs ~530s
and the 420s socket would have killed the very turns the bigger budget exists to
allow. A timeout wastes the whole turn; truncation at least leaves a partial.

HTTP_TIMEOUT=700 on both drafting lanes. The ordering that must hold is generation <
HTTP_TIMEOUT (700) < stallguard's wedged-agent kill (1200s). 420 was itself deliberate
— 1800 once parked a hung agent for thirty minutes — and 700 keeps a hang under 12
minutes without strangling legitimate deep reasoning.

Also recorded: a reasoning cap DOES work on ox, but it shortens the ANSWER too (618-672
total tokens), so it is a quality knob, not a fix for truncation.
2026-08-24 16:36:47 -06:00
Drew T 99e71bfa83 perf(waves): MAXTOK 8000 -> 16000, and free recovery of pre-gate rejects
THE OUTPUT CAP WAS EATING THE TURN BUDGET. Wave bk's shard logs: 240 of 244
turn-finishes were 'no tool call (finish=length) — NUDGE n/6'. The model was
exhausting its 8,000-token output budget BEFORE emitting a tool call, so the turn did
no work; an agent gets six nudges before giving up. That is why MATCHes average 2.8
oracle calls against a 24-turn budget — the turns are going to truncation, not
iteration. ox is free, so a bigger output budget costs latency and nothing else.

Measured alongside it, and worth recording because it redirects the obvious fix: turn
caps are NOT binding on the default lane. Across 1,166 agent completions, non-MATCH
runs used a median of 4 oracle calls and a p90 of 12, and exactly 1 of 194 reached 20
of the 24 available. Agents are not running out of turns; they are giving up early
after truncated turns. (The tells lane WAS cap-bound — 98 of 270 — which is why it
already has 40 turns.)

Plus tools/recover_rejects.py, wired into the maintenance lane: rebase the pre-gate
rejects whose body already matches and only the symbols are wrong (§171), stage them
for the lane's existing free gate. Zero model tokens; it only stages, so a bad
recovery can waste a build but never a bank.
2026-08-24 16:23:37 -06:00
Drew T d510806fc7 feat(waves): index the pre-filter rejects — 45% of drafts were recorded nowhere
Everything that reaches the GATE and fails gets a backlog row with closeness, class
and best draft. A draft the reloc pre-filter drops never reaches the gate, so it was
recorded nowhere and just sat on disk: 569 of 1,261 drafts across the last eight waves
— 45%.

They are not all garbage. 13% of the MISMATCH? rejects have a body that ALREADY
MATCHES and only the symbol names wrong, which is the deterministic aprop_symfix
stale-symbol class that banked 4 of 4 earlier this session. Roughly 6 recoverable
drafts per wave were being thrown away because no index existed to find them.

Now appended to .run/reloc_rejects.jsonl with the verdict, the shape (MATCH here means
right body, wrong symbols) and the first mismatches, so a recovery pass can work them
without re-drafting. Wrapped so telemetry can never break a gate.
2026-08-24 16:18:16 -06:00
Drew T 801a32179e perf(lanes): one lane, one band — the rotation is obsolete and its large slot is the worst wave we run
The tells slot became redundant when build_wave_atlas started reserving 60 tell-lever
cards inside every ordinary wave: a dedicated tells wave draws 70-87 cards, a quarter
of a default wave, for a full 40-minute slot.

The 120-2000 slot is worse than redundant. Bank rate by size, measured: 57% under 50
instructions, 30% at 50-80, 22% at 80-120, 3% at 120-200, 6% above. Wave br drew 69
cards on that band — roughly 3 banks for a slot that a full-band wave turns into ~150.
Large functions are not abandoned: the full band contains them and the draw takes
mass-first within each gate group.

Takes effect at the next wave boundary via relaunch_drafter_shell.sh.
2026-08-24 16:08:34 -06:00
Drew T 0de85bc8d2 feat(decomp): ox wave bj overlays — 19 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 15:56:26 -06:00
Drew T fd47c86f4f docs: seed the portable decomp workflow — the part of this project that transfers
Drew's endgame deliverable is a workflow system another person can run solo on any
target, any compiler. We had three docs recording BFM's history (accelerators,
decision-log, automation-runbook) and none stating the SYSTEM. This is that document,
written to one rule: if it would still be true for a different console and a different
compiler, it belongs here.

Contents: the byte gate as the only arbiter and the oracle ladder around it (each
oracle must state its own blind spots); lanes and why the clock-limited one is never
stopped to ship a change; the CARD as fuel rather than a ticket, including the lever
lesson (a label a worker cannot look up is a dead end — 108 transcripts searched for a
word our knowledge base did not contain); draw-time refusal and the four measured
instances of the dominant defect class; free work before paid work; giving an excluded
population its own lane instead of an exclusion; model routing and per-lane budgets;
the flywheel with the one-wave lag and the inert-rider law (1 in 3 credited levers is
byte-inert, measured twice); the economics as measured; what transfers vs what does
not (the knowledge base is per-compiler, the machine that builds it is universal); and
a bootstrapping order for a new project.

Numbers are stated with their denominators so a new project calibrates rather than
copies.
2026-08-24 15:46:01 -06:00
Drew T be637a79d7 feat(decomp): ox wave be overlays — 11 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 15:25:26 -06:00
Drew T 69397ca1e1 fix(waves): a mid-gate binary is EXCLUDED from the draw, not a reason to refuse it
corpus.stubs() misreports for a binary while a gate has draft bodies substituted into
its sources (R35) — but only for THAT binary. The blanket refusal cost far more than
it saved: the gater runs almost continuously, so nearly every fresh draw was refused
and the drafter fell back to PRE-DRAWN waves. Measured at 15:20 — wave br refused,
wave bj (drawn hours earlier) drafted instead.

That is worse than idle time: a pre-drawn wave carries the OLD draw-time defaults, so
every feature landed today — the tells quota, the jtbl quota, the -O0 filter, the
oversize filter — was silently not reaching the fleet, while the logs showed healthy
410-shard waves.

Which binaries are mid-gate is not a guess: gate_stage and gate_main hold
.run/auto/gate.<bin>.lock for exactly that window, so a non-blocking test-lock answers
it per binary. Those are added to EXCLUDE for that draw; the refusal survives only for
--only-bins draws where every requested binary is busy.

Verified live against a running gate: the draw that would have been refused now
returns 40 cards.
2026-08-24 15:23:31 -06:00
Drew T 1ae1012a9e feat(decomp): ox wave bq overlays — 81 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 15:09:11 -06:00
Drew T 3e9ef768b4 feat(decomp): free A-prop sibling lane (maintenance pass) — zero model tokens 2026-08-24 14:57:23 -06:00
Drew T 24bd259931 chore(decomp): commit in-tree banked work before the next gate
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
2026-08-24 14:57:01 -06:00
Drew T 78db16c7ca feat(decomp): main lane m00baaa — 1 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  func_8001D1C4
2026-08-24 14:56:47 -06:00
Drew T 30a42f0ef4 feat(decomp): main lane m00a — 13 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  func_80014238
  func_80017DC4
  func_80029178
  func_8002A790
  func_8002AA00
  func_8002D80C
  func_8002D8A8
  func_8002D8D4
  func_8002E5BC
  func_800342E8
  func_800351E8
  func_80036D24
  func_8003A3D8
2026-08-24 14:56:02 -06:00
Drew T d0dca96faf fix(main-lane): commit each verified sub-batch immediately, not at cycle end (R42)
A bisect can run many levels; deferring the commit left byte-proven functions sitting
uncommitted in src/ for the whole descent — precisely the window in which any other
tool's blind revert destroys them (61 banked functions died that way once). The tree
is verified byte-identical on the line where the credit is granted; that is both when
it is safe to commit and when it must be.
2026-08-24 14:55:22 -06:00
Drew T df5c1a1b15 docs(ops): rewrite the automation runbook for the campaign as it actually runs
The runbook was dated 2026-06-22 and described the reach-1 grinder pivot — it named
no lane that exists today, two months and an entire toolchain later. Rewritten around
what is actually running: the six lanes and their restart rules, the OpenRouter
drafting toolchain (cards, LEVER_CRIB, per-lane budgets, the draw's admit/refuse
census, quotas as floor AND ceiling), the banking toolchain by binary class
(sweep_parallel vs gate_main vs the gate-time jtbl carve vs -O0 objects), the main
lane, the distill lane and the flywheel's measured yield, the rate/credit numbers with
their denominators, and recovery.

Two ops laws are stated where they will be read rather than rediscovered: bash parses
a while-loop up front (so code, args and draw-defaults each take effect differently),
and never pkill -f a lane by a bare name because it matches the harness's own wrapper.

SETUP.md gains rows for main_lane, the distill lane and the three restart helpers.
2026-08-24 14:50:09 -06:00
Drew T 394a0781a6 fix(main-lane): bisect compile conflicts, cap retries, and scope the draw guard
Three defects found by running it, all of the same family — a check that is true about
the wrong thing:

1. FALSE BANKS. The first accounting asked corpus.stubs('main') whether each name was
   still a stub; that returns {addr: Stub(symbol=...)} — a dict keyed by INT. Comparing
   a NAME against a set of ints is always True, so the lane reported '12 banked of 12'
   from a gate that banked nothing and committed nothing. Credit now requires BOTH the
   INCLUDE_ASM line gone from the working tree AND main re-checked byte-identical.
2. INNOCENT DRAFTS DYING WITH A DECL CLASH. gate_main deliberately refuses to bisect a
   COMPILE conflict (right for a human caller, wrong for an unattended lane): the first
   live batch hit a conflict on a symbol that was in the TU and in NO draft, so there
   was nothing to drop and 40 innocent drafts died with it. The lane now halves the
   slate — a main rebuild measures ~15 s, so bisecting is cheaper than discarding.
3. THE DRAW GUARD REFUSED EVERYTHING. build_wave_atlas refused to draw whenever any
   gate was in flight (R35: corpus.stubs misreports mid-gate) — but only for the
   binaries being gated. Main's sources are touched by gate_main alone, so a main-only
   draw now watches gate_main and every other draw keeps the blanket refusal.

Failed drafts are parked with a try count instead of discarded (a failed draft is
evidence), capped at 2 so an unbankable body cannot spin the lane.

Live: 13 main functions banked, main byte-identical at 143dbb89, stubs 1713 -> 1700.
2026-08-24 14:48:29 -06:00
Drew T 57255bc56c feat(decomp): ox wave bp overlays — 44 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 14:43:48 -06:00
Drew T 157c6dac3b feat(decomp): main lane m00 \u2014 11 banked\n\nOne clean whole-EXE rebuild verified the batch (gate_main). Functions:\n func_80014390\n func_800152F4\n func_80017738\n func_80017E8C\n func_8001D130\n func_8002955C\n func_8002F658\n func_800301A4\n func_80037D74\n func_8003834C\n func_8003A424 2026-08-24 14:39:46 -06:00
Drew T d6a06bc084 feat(main): a second drafting lane for the EXE, on its own gate cadence
main is excluded from every wave draw for a good reason — its gate is a clean
whole-EXE rebuild that bisects, and on the overlay critical path it cost three
measured stalls (39 min unfinished on 29 drafts, 25 on 8, 65+ on 8). The consequence
was that main sat outside the loop entirely: 1,713 open stubs, no lane, no cadence,
while the overlay lane ran at ~a quarter of the API ceiling because CARD SUPPLY, not
throughput, is its constraint. Two populations, one idle half of a rate limit.

draw (main only) -> draft -> reloc pre-filter -> ONE gate_main batch -> commit.
Never sweep_parallel or gate_stage (both build incrementally; main's extract rewrites
the linker script, so an incremental build yields a FALSE diff — that is what banked
0 of 105 main cards in wave ab). Batches because one clean rebuild verifies the whole
slate; the reloc pre-filter is what keeps a batch from bisecting. Commits the moment a
batch is green (R42) since gate_main deliberately does not.

Parked drafts first: 170 main drafts sit in .run/main_queue from before the exclusion —
already drafted, never gated, free.
2026-08-24 14:38:07 -06:00
Drew T 86b96b2125 perf(lanes): gate-jobs 12 -> 24, and tells become a quota inside default waves
TELLS QUOTA (Drew approved): a dedicated tells wave drew only 70-87 cards — a full
40-minute drafting slot at a quarter of a default wave — because the 5-80 size cap and
the tells pool cannot fill more. Tells now ride inside ordinary waves with a 60-card
quota, same as jtbl. The size cap moved into the draw itself: tell-lever members above
--tells-max-ins (80) are not drawn at all, because the measured bank rate is 27-40%
at 5-80, 10% at 81-120, 1% at 121-200 and 0% above — those 383 members / 51,941 ins
are idiom_serial's work, and the skip counter names it (R45).

A QUOTA IS A FLOOR UNLESS IT IS ALSO A CEILING. First test: putting the tell levers in
the default list let them win the ranked fill too, and a 300-card wave came back 122
tells (41%). The size cap held; the mix did not. Tells now enter through the quota or
not at all.

GATE JOBS 24. The quotas deliberately pull cards from binaries outside the ranked gate
groups, so a measured draw went from ~24 groups to 63 — 63 whole-binary rebuilds per
wave, five serial batches at 12 jobs. The box is 32 cores at ~6% (load 3.1) with 39 GB
free. Lands via restart_gater_when_idle.sh so no sweep is killed mid-flight.

Correction to the record: the live draw already passed --max-bins 24 (plus
--one-per-gid and --exclude-bins main). An earlier measurement of mine used the tool's
default of 12 without those flags and read as 'max-bins is the cap' — it is not;
--one-per-gid is, and deliberately: it defers same-skeleton siblings to the free
deterministic remap instead of paying an agent twice.
2026-08-24 14:34:09 -06:00
Drew T c4a7a45bf5 fix(lanes): drop the paid lane before the credit floor kills drafting
Balance $2.56 and falling ~$1.43/h over the last three waves ($4.56 at 11:54 ->
$2.56 at 13:18) — about 23 minutes from --credit-floor 2.0. That floor does NOT pause
the paid lane: it breaks the whole drafting loop, and the shell then restarts a python
that breaks again, so the clock-limited resource dies on a check about money.

ox-alpha is free for the rest of this window, so drafting continues on ox alone at zero
burn, and the floor drops to 0.25 because with a free model the balance stops being a
proxy for 'can we draft'. deepseek was 280 of 2,000 workers — its value was an
independent 429 ceiling, not throughput.

Takes effect at the next wave boundary via relaunch_drafter_shell.sh, so wave bp's
in-flight drafts are not lost. Restoring it after a top-up is two edits, named in the
script's header.
2026-08-24 14:17:52 -06:00
Drew T 2bf18f2a25 docs(cookbook): 268-269 from the ax/bm distill batch (82 candidates)
268 a register __asm__ pin on a call-clobbered register is honored EXACTLY when the
    pinned range crosses no call — turning 257-2's 'pins are silently ignored' into a
    rule with a precondition, and explaining both faces: a pin that does nothing
    (range crosses a jal, gcc silently falls back) and a pin that fixes a REGALLOC
    residual in a function that has calls (range sits between them). Three A/B'd cards.
269 ten addenda, plus the 266 solo-lever sweep table.

THE HEADLINE IS THE INERT-RIDER RATE. 19 strip-tests across 13 banked bodies: 6 of 19
credited levers are byte-inert (32%), against 4 of 8 last batch. One in three 'this is
what made it match' claims credits something that changes nothing — and one whole
proposed section dissolved under its own strip test. 67 of 82 candidates (81.7%) were
already covered, matching the previous batch's re-derivation rate.
2026-08-24 14:09:13 -06:00
Drew T d06e8e69b6 feat(decomp): ox wave bo overlays — 24 banked
Committed before the main batch: gate_main reverts on failure and would take these with it.
2026-08-24 14:06:03 -06:00
Drew T 6c580a28a0 docs(distill): name the review tier — Opus/Sonnet, not Fable
Drew, 2026-08-24: distillation is judgement over an existing corpus (read harvested
notes, decide covered / addendum / new against 760+ sections), not a new wall class.
Fable is for the walls — an unsolved tooling problem, an adversarial design review, a
residual no documented lever reaches. I routed a distill batch to Fable; recorded here
so the next session reads the tier off the lane rather than guessing it.
2026-08-24 13:57:31 -06:00
Drew T 333a169458 fix(distill): state is {tag: novel-count}, never a done-list — it nearly buried 82 candidates
A re-gated wave rewrites its candidate file with NEW rows under the SAME tag, so
"have I seen this tag" answers the wrong question. Two instances in one hour:

  * wave `at` was re-gated hours after its first harvest, so an mtime-keyed seed
    called it new and 52 mostly-re-derived rows went to a reviewer;
  * my own hand-edit of the state folded "queued for review" into "reviewed", which
    marked `ax` and `bm` — 82 candidates, gated minutes earlier — as mined by nobody.
    Caught only because their files were newer than the edit.

The scan now compares COUNTS: a tag re-opens the moment its file grows past what was
mined from it. Extracted to tools/distill_scan.py so the logic is testable rather than
living inside a heredoc inside a lane loop (the heredoc-in-heredoc edit is also what
produced a syntax-broken lane script a minute earlier).

Verified: the lane now raises exactly the true pending batch — ax + bm, 82 novel.
2026-08-24 13:38:52 -06:00
Drew T 99f096c591 fix(flywheel): the index is the entry point, and a cited number that fails to grep is a LINE
Two discovery-gap defects the distill review measured, both costing drafters real
compiles:

1. LINE NUMBERS CITED AS SECTIONS. Index rows end with a <sub>L1234</sub> anchor = the
   section's line in the cookbook. Drafters read it as a section id and cite it: this
   batch alone carries §1907, §12479, §2965, §11383, §8892, §5583, §1832, §2429,
   §1755, §2609 — line numbers, every one, and a grep for any of them returns nothing.
   The number is real and the reading is wrong, which is the worst kind of dead end
   because it looks like a citation. The index now publishes an L→§ table, and
    answers it directly (verified: §12479 → §3-The,
   §1907 → §21).

2. THE INDEX WAS NEVER NAMED AS THE ENTRY POINT. One drafter wrote 'no numbered
   section I could find by grep' about a lever whose section title literally contains
   the words it searched — it grepped the 25k-line cookbook, not the symptom-keyed
   index. api_agent's SYS now says to start at the index, and how to resolve a
   line-number citation.
2026-08-24 13:36:58 -06:00
Drew T 7740f14143 docs(cookbook): 265-267 from the at/bh/bk/bl distill batch (165 candidates)
265 the verbatim-asm bank lane — two in-tree precedents, the MASPSX decimal-immediate
    rule, and a REVIEW-ADDED accounting caveat: an __asm__ body is not an INCLUDE_ASM
    stub, so corpus.stubs() counts it as MATCHED. Bytes proven, function not
    decompiled. Fine for hand-written asm; for an -O0 C function the right answer is
    the -O0 object, and this lane is a temporary hold at best.
266 the inert-rider law — a lever is only citable when its solo removal breaks the
    match. Measured 4 of 8 credited levers on this batch were byte-inert: a $2 pin
    silently dropped, a volatile the scheduler already ordered, a named zero, and a
    statement split. The banked artifact CONTAINS the rider precisely because it is
    inert, which reads as proof. R40 applied to the flywheel itself.
267 eleven addenda to existing sections, six with fresh match_one A/Bs.

The batch's real headline: 145 of 165 candidates were ALREADY COVERED, and 8 claims
were refuted (4 by live A/B) — the harvest is mostly re-derivation, and an unchecked
wrong law is worse than no law.
2026-08-24 13:35:46 -06:00