- docs/commit-map.tsv: 4,032 rows (ordinal of the ORIGINAL main -> rewritten hash, author/committer dates, subject);
1 pruned row of zeros (ordinal 1712, "session archive update"); 0 old hashes asserted; ordinal 1 unchanged by the
rewrite (byte-identical)
- resolve_tokens: 1,238 commit:NNNN tokens -> shortest-unique new hashes in 98 files (docs, phase-ends, logs, tool
docstrings, 2 C comments, the A5 evidence logs); residue left as tokens: commit:1712 x4 (the pruned commit),
commit:orphan-24 x2, commit:orphan-26, commit:orphan-35 (cited commits that exist in no lineage)
- the rewrite (C4): filter-repo 2.47.0 on a bare clone of the C2 tip, 311 s, exactly 1 pruned, main 4,032 -> 4,031;
the pre-rewrite history is mirrored in the private archive repo and in the local bundle
- the proof (C5): verify_rewrite 4,031 pairs / 0 failures; absent_scan 0 offenders; gate_scan 0 offenders on the clone
- adoption (C6): 100 text files differ at the tip, 0 purge paths, 0 added/deleted; leftover refs dropped; no gc yet
- resolver skips tools/public_rewrite/ (its self-test fixtures are the token grammar, not citations); repo-local
identity is the GitHub noreply address from here on; CURRENT_PHASE: C4–C7 logged, checkpoint -> NEXT = C8
1. MAIN LANE — the largest single block of unfinished work was drawing 32 cards a wave.
main_lane.draw() never passed --max-bins, so it inherited build_wave_atlas's default of
12 gate groups — a cap that exists because each group costs a whole-binary rebuild, and
main's own --only-bins docstring says the opposite applies to it: "main is gated ONCE per
SLATE, so main has no per-TU gate cost and --max-bins can be large". Nobody passed it.
Measured cost: main banked ~19 stubs/hour against 1,291 remaining while the overlay lane
ran 650-card waves beside it. Now --max-bins 400 (MAIN_MAX_BINS overrides), and the lane
shell draws 600 cards with 600 workers instead of 200/150.
2. TWO LANES GATE, SO READ BOTH LOGS — a defect I introduced this session. The in-flight
exclusion derived "this wave has been gated" from .run/gater.log only, but the main lane
gates its own waves into .run/main_lane.log. Every m## wave therefore looked permanently
in flight and main's draw lost 425 cards to an exclusion meant for work in progress.
3. TAIL_DONE_FRAC 0.80 -> 0.65. At 0.80 the fleet runs 2-3 overlapping waves at ~250
req/min; the residual troughs are the gap between one wave draining and the next ramping.
65% keeps 3-4 waves overlapping. Stragglers keep their full 700s grace in the finisher
thread — this changes when the NEXT wave starts, never what lands.
4. ATOMIC ATLAS WRITE. The lanes read .run/atlas.json at every draw and atlas.py dumped
straight onto it, leaving a truncated file readable for the length of the write. Now
written to .tmp and os.replace'd.
Context for 1-3: the atlas both lanes draw from is dated 08-23 01:13 — two days stale,
predating ~4,600 banks — and its regen chain is running now (its own R32 assertion caught a
stale family map first and named the fix).
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
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.
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.
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.