Files
BFM-decomp/tools/lanes
Drew T baabdd0478 fix(jtbl): end the stale-pad-spec RED class, and check the fleet every pass
THE CLASS. JTBL_PADS is a per-object spec written by jtbl_carve at CARVE time — one entry
per rodata `.align 3`, each 0 or 4 — describing how many jump tables the object emits. That
is a DERIVED property of the current source stored as static config, so any bank carrying a
`switch` (or any bank being reverted) invalidates it and nothing re-derives it. Three of the
five REDs on 08-25 were this one design choice: ov_SC02_005 and ov_SC07_006 from wave dd
banking switch-bearing functions, ov_SC04_018 from the identical symptom with the opposite
cause — a reverted bank taking its table with it.

WHY NOT DERIVE IT. The COUNT is derivable from the assembly stream; the VALUES are not — a
pad records where the ORIGINAL image has an inter-table pad, which lives in the retail
layout, not in our source. Guessing shifts every downstream data symbol: silent corruption,
the worst outcome available. So tools/jtbl_pads_fix.py does not derive. It ENUMERATES the
2^(N-1) candidate specs (first entry 0, rest in {0,4}) and accepts one ONLY if it is the
UNIQUE candidate that rebuilds the binary byte-identical to config/check.<bin>.sha; zero or
two matches restore the original and refuse. R39 negative control: on a healthy binary it
reports "no pad-count drift" and changes nothing.

TWO INSTRUMENT BUGS THIS TOOL FOUND IN ITSELF:
  * JTBL_PADS is a target-specific MAKE VARIABLE, so changing it does NOT make the .o out of
    date. The first run reported "no drift" against a spec I had deliberately broken. It now
    deletes the armed objects before every build — R22's incremental trap in config costume.
  * A failed object build leaves the PREVIOUS binary in build/<bin>/<bin>, so
    `make build; sha1sum build/<bin>/<bin>` reports the OLD artifact as if it were this
    build's — a FALSE GREEN over a build that never linked, which briefly convinced me two
    binaries were fixed. build_sha now deletes the output too and requires make to exit 0.
    Same family as R49: an error inside something shaped like success.

CADENCE: the fleet sweep runs EVERY maintenance pass, not every 4th. A RED fails at BUILD,
so every draft gated against it is rejected regardless of quality and the wave reads as a
drafting failure — detection latency is the whole cost. Gates now finish in ~35 min rather
than 60, so the sweep is affordable each pass. It still FIXES NOTHING by design, with this
single exception, admissible only because it proves itself against the byte gate first.
2026-08-25 12:04:14 -06:00
..

Autonomous lanes (P31 S58)

The unattended campaign architecture. These are the RUNNING copies' source of truth — the live lanes execute from .run/, which is gitignored, so a fresh clone would otherwise have none of it. Copy back with cp tools/lanes/*.sh .run/ before launching.

lane role rule
drafter.sh draw → shard → draft → queue a ready marker, forever NEVER stop it to ship a code change. Measured 2026-08-23: 139 of 162 idle minutes were exactly that
gater.sh reloc pre-filter → gate → commit → harvest → ledger safe to kill/restart at will
maintenance.sh the free A-prop sibling lane triggers on 150+ newly banked functions, not a timer
stallguard.sh 60s: revive dead lane shells, kill agents silent >20min, kill gates >90min the only thing that works at 3am

Start: setsid nohup .run/<lane>.sh >> .run/<lane>.log 2>&1 </dev/null & Stop everything: touch .run/ox_campaign.stop

Editing a lane requires replacing its SHELL, not just its python — bash has the loop body parsed, so killing the python restarts it with the old arguments. Verify from the startup banner, never from the file.