jtbl: the 154-A island split is byte-proven (one config line + jr_isolate_all --only),
with the object-level sh_size control a green SHA cannot give; four md_*/main tool
blindnesses fixed; one delay-slot instruction short of the first bank, logged.
o0: the census (167 real -O0 of 14,400; 116/14,148 ins stranded), the handoff's
md_MAIN_003/011 refutation shown to be itself wrong, the never-wired -O0 oracle fixed,
and 79 unbankable card-draws across 19 waves stopped at the source.
tells: restored and pinned to band 5-80 — the lane gap was a card-size gap, and 235
is refuted as the cause by the recorded pre-gate verdicts.
Three Fable agents in flight; their briefs and every fact they were given are recorded
here so a crash costs a re-spawn, not the knowledge.
The build decides the opt level per OBJECT and the Makefile's -O0 rules cover boot,
ov_SC01_077_o0 and src/ov_*/ov_*_o0?.c — nothing else, src/md_*/ least of all. A
function whose target bytes carry the -O0 frame-pointer prologue while its subseg is
compiled -O2 is unbankable however good the draft (R43, cookbook 261).
Measured before the filter existed: 11 such functions had been drawn 79 times across
19 waves — 6 per wave recently — under head-crack/UNKNOWN/tells/len-vein/redraft
labels, because the atlas o0-lane label catches only a fraction of the real -O0
population. Not one could ever have banked. A live draw now reports
'o0-in-an-O2-object': 54 in the skip census.
The first version of the helper was itself the defect it exists to prevent: it took
corpus.asm_path() to be a directory when it is the .s FILE path, so every open()
raised, it returned False for every card, and it filtered nothing while appearing to
run. Its unit test passed because the test fed it the directory the code expected
instead of the value the caller passes.
The ready queue is two-sided — the gater consumes markers while the drafter produces
them — so 'the count went up' is not 'a wave queued'. The first version latched
BEFORE=1, the gater consumed that marker, and the next wave queuing took the count
back to 1, which is not greater than 1: it would have waited out its full 90-minute
deadline while the event it waits for happened. True about a number, false about the
world.
bash parses a while...done body in full before executing, so a lane-ARG change needs
a fresh shell; a python bounce re-runs the old command line (measured P31 S59: an
18-minute-old edit was invisible to the bounced process). Includes the three-way
table of what takes effect when — code / args / wave-draw defaults.
260 the 154-A leading-island split: one inserted .rodata line + jr_isolate_all --only,
the object-level sh_size control that separates 'it worked' from 'it did nothing',
the island-is-a-stack census, and the two md_*-only tool blindnesses it exposed.
261 the -O0 oracle: derive the opt level from the target (prologue tell + subseg flags),
311 $fp mentions vs 167 real -O0 prologues, and why a match is not a bank for the
116 functions stranded in -O2 subsegs.
262 a lane's yield is only a lane fact if it is size-matched — the band and size-mix
confounds that produced 'the tells lane is broken', with the bucket table.
jtbl and o0 are held out of the default lane because a draft cannot BANK without
tooling first (a rodata carve; an -O0 object, and no Makefile glob matches md_* at
all). 'cc1' is not that: it records that some earlier draft failed to compile. A
compiling draft banks through the normal splice->build->SHA path regardless of its
history, and a non-compiling one fails fast at cc1 for the price of one build.
Holding 14 groups / 105 instances / 6,511 ins out of every wave bought nothing.
Effective on the next wave draw (build_wave_atlas is a fresh subprocess per draw —
no lane restart needed).
--o0 has existed since P29 and NOTHING ever passed it: api_draft.match_one(), the
oracle every wave agent iterates against, builds a fixed argv without it. Every agent
handed an -O0 target was shown an -O2 compile of its own C and a mismatch on every
instruction — feedback that cannot converge, for a reason invisible in the diff, and
it hit even the 51 functions already sitting in -O0 objects.
match_one now decides from the target (R33), with two oracles because neither alone
is sufficient (R34): the -O0 frame-pointer prologue in the target's own bytes, OR the
subseg being an object the Makefile compiles -O0. boot/start.s is built -O0 with no
ordinary prologue; an -O0 function stranded in an -O2 subseg has the prologue but
cannot bank — and match_one now says so instead of letting an agent chase it.
The prologue scan is anchored at glabel, not the top of the file: two md_MAIN_011
.s files open with a migrated jump table / .asciz blob and a naive scan read table
words as the prologue.
tools/test_o0_detect.py: 14,400 .s scanned, 167/167 signature files covered, 0 false
positives outside -O0 objects, both rodata-first files detected.
Census correction in the design doc: the handoff's refutation of md_MAIN_003/011 is
itself wrong (16 and 21 -O0 functions, byte-verified), and the 311 '$fp mentions'
figure over-counts because $fp is $s8, allocatable at -O2. True population: 167
files, of which 116 / 14,148 ins are -O0 functions the build compiles -O2 — double
the atlas estimate, with x2/x3/x4 sibling replication.
Joined the campaign ledger to each wave's cards and to the functions its own commit
banked (removed INCLUDE_ASM lines), pooled over bb/bg (tells) vs bc/bf (default):
nins default tells
0-50 303/528 57% 27/ 67 40%
50-80 43/145 30% 20/ 73 27%
80-120 9/ 41 22% 10/100 10%
120-200 1/ 30 3% 1/ 68 1%
200+ 2/ 35 6% 0/ 30 0%
At equal size the lanes are close below 80 instructions and both collapse above it.
What separated them is the card size MIX: default's cards are median 37-39 ins, the
tells pool median 89-95 (2.4x), so 'the tells lane is broken' measured the population,
not the lever. Tells now draws 5-80.
This also refutes the S58 handoff's one live hypothesis for tells (235, the phantom
symbol). Checked the recorded reloc_identity verdicts first (R38): among MISMATCH?
rows, the fraction whose instruction SHAPE already matched — the symbol-only class 235
describes — is 25/87, 16/79, 17/66, 13/57 on default waves but 6/66, 4/81, 5/47 on
tells. Tells drafts fail because the BODY is wrong, not the symbols, which is what a
2.4x larger median predicts.
Also adds tools/lanes/relaunch_drafter_shell.sh. bash parses a while...done body in
full before running it, so a lane-ARG change is invisible to the running shell and a
python bounce re-runs the OLD command line — measured at 11:02, when the bounced
python came back on the pre-S59 lane list 18 minutes after the file changed.
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
The whole split is ONE inserted config line plus jr_isolate_all --only, exactly as
the adversarial review concluded (no _pre piece, no ld_interleave change, the
- [0x0, .rodata, md_SC03_076] island piece untouched):
- [0x268, .rodata, md_SC03_076_jr_801F218C]
- [0x2d24, c, md_SC03_076_jr_801F218C]
FRESH negative control, measured now rather than inherited (the study's +8/0x144
baseline was measured on func_801F0F28 and misattributed):
baseline whole-binary sha1 9a165e368009a79bcc2ebb06bcb13e6da20d460e (green)
md_SC03_076.o .rodata sh_size 0x27c (the whole island)
after whole-binary sha1 9a165e368009a79bcc2ebb06bcb13e6da20d460e (green)
md_SC03_076.o .rodata sh_size 0x268
md_SC03_076_jr_801F218C.o .rodata sh_size 0x14 (the 5-entry table)
So the SHA is unchanged AND the object-level discriminator proves the split really
happened — the pair rules out the no-op reading of a green build.
Island census for the record (file offsets): D_801EF468 0x000-0x0D8, D_801EF540
0x0D8-0x144, then the migrated tables of func_801EFBB4 0x144, func_801F0210 0x1B4,
func_801F0734 0x1EC, func_801F0A9C 0x214, func_801F0F28 0x23C, func_801F218C 0x268
-> 0x27C = the island end. The island is a STACK: only the end-adjacent table carves
cheaply, and each isolation exposes the next one, so the module peels from the end.
jr_inventory asserts every committed .rodata piece resolves to exactly one banked
owner (R32) — true for ov_*, where every .rodata piece was created by jtbl_carve.
On md_* the 154-A leading island - [0x0, .rodata, <alias>] is the module's own
rodata blob (INCLUDE_RODATA data + every stub's still-migrated table), has no single
owner, and made the check abort: md_SC03_076 reported UNOWNED 0x801ef468 and could
not be isolated at all.
rodata_carves() now takes the alias and skips that one piece. The discriminator was
verified across all 213 splat configs: a .rodata piece at offset 0 whose subseg is
the binary's own alias exists in exactly the 42 md_* configs and in none of the
others, so this is a provable no-op for every ov_*/main config.
md_SC03_076 --only func_801F218C now plans cleanly: 1 jr, 2 region .c files, no
carve repoints.
Ships a lane-arg change without losing drafts: the running python still carries the
pre-S59 args, and killing it mid-wave discards everything the fleet has drafted for
that wave. Waits for .run/ready/<wave>.json, then pkills only the python — the
drafter SHELL, the lane that must never stop, relaunches it from .run/drafter.sh.
90-minute deadline so it never lingers.
main is the one binary splat writes to asm/nonmatchings/800/ and asm/data/ rather
than asm/<alias>/...; the hardcoded asm/<ov>/ in nine places made every main lookup
miss a directory that does not exist and report it as 'already spliced AND no stale
copy' — a true-sounding message about the wrong tree (R43).
With the path, the base and parse_config all fixed, main now reaches the real
analysis: func_8001A114 refuses because subseg 800 would host non-contiguous
.rodata carves (0x63238 = the existing LZSS table, 0x6327c = the new one), i.e.
isolate first — the same architectural refusal an overlay gets.
The island guard also moved AHEAD of jtbl_range, so an island table no longer
reports 'not found in the raw data asm — already carved / stale asm?' (true and
useless: an island table was never in the data asm). It now prints the exact line
the review prescribes: - [0x268, .rodata, md_SC03_076_jr_801F218C].
Review doc gets an S59 addendum with the measured class facts and where the two
examples now stop.
parse_config's docstring said 'the trailing run of {data,.rodata} pieces after
the last c piece'; its code took data_pieces[0], the first such piece anywhere in
the file. Those agree on 171 configs and disagree on 42: the md_* modules open
with the 154-A leading island - [0x0, .rodata, md_XXX] BEFORE their c piece, so
apply()'s splice lines[:lo] + region + lines[hi:] deleted the c line and wrote the
yaml to disk before the tool errored out for unrelated reasons.
Fixed by deriving the region from the last c piece, plus an R43 guard that refuses
outright if any c piece lands inside the window apply() rewrites wholesale.
Also, correcting what S58's blanket refusal had lumped together:
* md_* (42 configs) was the whole corruption class.
* main was never in it - its pieces are already [all c ..., data, .rodata, data].
main's real defects were the config PATH (there is no config/splat.main.yaml,
it is splat.us.exe.yaml) and the FILE BASE: the EXE has a 0x800 header, so the
delta is 0x8000F800, not the yaml's first vram: 0x80010000, and with the naive
value payload_word silently read 0x800 early. Both fixed; the base comes from
the single derivation in family_remap.vram_of (R33).
The cfg_path class refusal is lifted and replaced by an operation-level one: a carve
whose table lies below the data region is in the leading island, which a tail carve
cannot reach, so build_carve refuses and names the island-split lane (R43).
tools/test_jtbl_parse_config.py proves all three, read-only:
NC-1 regression 171/171 configs byte-unchanged by the fix
NC-2 defect 42/42 md_* lose a c line under the historical derivation; 42/42
keep every c line under the fix
NC-3 main cfg=splat.us.exe.yaml base=0x8000F800, region starts after the last c
The S58 removal cited four waves (as/aw/az/bd) and blamed the lane. All four ran
at band 120-2000. The campaign ledger splits the population by band instead:
tells @ 120-2000 228 drafts -> 18 banked = 7.9%
tells @ full band 655 drafts -> 161 banked = 24.6%
default @ full 2,996 drafts -> 1,335 banked = 44.6%
Of drafts that actually reach a gate the lanes are indistinguishable (tells 54.4%,
default 56.4%) — the whole loss is reloc_identity discarding phantom-symbol drafts,
which is cookbook 235 and a BRIEF fix, not a lane deletion (R40).
Rotation now pins lane index%4 against band index%4 so slot 1 (tells) always draws
the full band and slot 3 (the large band) is always default; asserted over 200 waves.
Takes effect on the next drafter-python bounce; the running process still carries the
old args and the drafter SHELL is never stopped to ship a change.
jtbl (36,685 ins, but 150 of 177 groups are singletons): Fable's review says the fix is SMALLER
than proposed — ONE inserted .rodata carve line plus jr_isolate_all --only. No _pre piece (it
cannot build), no ld_interleave change (the native script is already rodata-first). Harden
parse_config FIRST: it corrupts md_*/main configs on disk before erroring, which is why
jtbl_carve now hard-refuses them. The ox study's negative control is misattributed — build a
fresh one.
o0/cc1 (6,564 + 6,511 ins): the study is half refuted, and the doc header says which half.
md_MAIN_003/011 do NOT carry the -O0 fingerprint; the 311 files that contain $fp are the real
population. The unanswered load-bearing question for both is whether the EXISTING gate can bank
them unchanged — a lane that drafts what the gate cannot accept has already cost two sessions.
tells (86,602 ins): removed from drafting on four waves of evidence. aprop_autodraft is NOT the
destination (4.2% overlap, checked after I asserted it three times). The live hypothesis is
cookbook §235, the phantom symbol — one wave with it in the brief tests it cheaply.
Closes the gap that made main red for nine hours. R42 ('commit a dirty tree rather than
revert it') is correct for a per-binary gate that leaves PROVEN banks uncommitted, and WRONG
for gate_main, whose substitution is unverified by construction until the SHA matches.
Two guards, defense in depth:
1. gate_main installs atexit + SIGTERM/SIGINT/SIGHUP handlers that revert its own substitution
unless a bank actually succeeded. Killed mid-run, it now cleans up after itself.
2. ox_campaign's dirty-tree commit REFUSES top-level src/*.c (main's sources), reverting those
and committing the rest. Verified: src/800c.c and src/800.c refused, src/ov_*/... and
src/shared/engine_core.h still commit.
Also versions the autonomous lane scripts under tools/lanes/ — they lived only in gitignored
.run/, so a fresh clone had no drafter, gater, maintenance or stallguard at all.
All 1,101 novel-idiom candidates read (33 waves, 4,888 verdict lines, 4,764 notes), restricted
to functions the WHOLE-BINARY BYTE-GATE banked. Append-only: 1450 insertions, 0 deletions,
prefix md5 unchanged.
§233 header+index · §234-§257 the laws · §258 the 21 addenda (append-only forbids inserting
them into their parents) · §259 the discard ledger.
Three claims were HEDGED rather than promoted (§253, §254, §213's right-rotate rule); four
were byte-verified against asm/ before being written; §217/§230/§232 were promoted from
'single observation' to CROSS-CONFIRMED by independent cards.
~1,040 discarded across 18 ledgered clusters — ~700 self-reported 'nothing the cookbook did
not already cover' (the flywheel working), ~400 Law-1c compliance reports, ~70 bare
'reordering fixed it' with no mechanism (unindexable). Two clusters deliberately left as OPEN
PROBLEMS rather than written up as false laws: forcing own_thread_p on a call-bearing join,
and suppressing a constant-offset second giv. Both are permuter jobs.
Highest-value: §234 (store lvalue signedness picks addiu vs li/ori — 12 cards each burned a
one-instruction residual on this), §236 (the nine-class declaration-layer taxonomy — ~90 cards
banked bodies that were already instruction-correct), §235 (the phantom symbol: match_one masks
relocations so a green MATCH can name a nonexistent symbol, with NO instruction diff).
Main has been RED since ~00:20 overnight: it built to e9fffcf45 instead of 143dbb89, so no
main draft could bank regardless of quality, and R22 ran 212/213 for nine hours.
CAUSE — R42 has a gap. 'Commit a dirty tree rather than revert it' is right for a lane that
gates per-binary and leaves PROVEN banks uncommitted (sweep_parallel gates commit=False by
design). It is WRONG for a killed gate_main, whose substitution is by definition unverified.
Two auto-commits swept up abandoned main batches:
src/800c.c <- commit:2598 6 INCLUDE_ASM stubs substituted
src/800.c <- commit:2611 4 INCLUDE_ASM stubs substituted
Ten function bodies committed as banked work that never passed a byte-gate.
VERIFIED IN THE ISOLATED WORKTREE, by elimination rather than assumption:
HEAD -> e9fffcf45 RED
revert 800c.c only -> a9d9870c1 RED (still drifting)
revert 800.c + 800c.c + engine_core.h -> 143dbb89 GREEN
restore HEAD engine_core.h -> 143dbb89 GREEN (header INNOCENT)
restore HEAD 800.c -> a9d9870c1 RED (800.c guilty too)
So the minimum revert is exactly these two files. src/shared/engine_core.h is exonerated —
I had proposed its C89 prototype change as the cause and that hypothesis was WRONG.
NOTHING IS LOST: the ten bodies remain in commit:2598 and commit:2611 and can be re-gated
properly once gate_main's fixes (terminating bisect + idempotent hoist, commit:2633) are
exercised against a green baseline.
The P31 S58 main probe ran 38 minutes on 8 drafts and never produced a verdict. Two
independent non-termination bugs, both fixed and negative-controlled:
1. THE BISECT COULD NOT TERMINATE. On a failing multi-element chunk it did 'lo = head + lo',
restoring lo to exactly its prior value, so the next iteration recomputed the same head and
failed identically — forever. Replaced with an explicit-stack bisect that SPLITS a failing
chunk and pushes both halves, so work strictly decreases and termination is structural.
GATE_MAIN_MAX_STEPS (24) is a loud backstop, not the mechanism.
Verified: 8 drafts with one poisoned -> 7 banked, 1 rejected, 7 rebuilds.
2. THE TYPEDEF HOIST WAS NOT IDEMPOTENT. The block is inserted AT the anchor, so anything
hoisted previously still started after it and was re-hoisted every call, stacking a fresh
marker comment each time ('hoisted 2 typedef(s)' x150; the tree held a duplicated marker).
Now tracks the already-hoisted region and reuses the existing marker.
Verified: 3 consecutive passes hoist [Foo,Bar], [], [] with exactly 1 marker.
Together these unblock main: 170 parked drafts and ~1,041 open stubs.
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.
Uncommitted src/ changes found at gate entry. These are banked functions from a lane that gates with commit=False, not residue — preserved, not reverted.