mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
d801b8f177
ROOT CAUSE of both wipes today. config/overlays.mk was rewritten in four places with
open(mk, "w").write(txt)
(jr_isolate_all.py:593, jtbl_carve.py:1077/1118/1165) — which TRUNCATES to zero first and only
then writes. Three ways that loses the registry: the process dies between truncate and write
(empty file); another process reads inside that window (sees an empty registry); two writers
interleave (a partial line lands after the last good one — this morning's file ended in a stray
`uto.txt` fragment, exactly that fingerprint). The jtbl carve automation runs AT THE GATE, which
is when all three wipes happened, and ONE_PER_GID=0 made it far likelier by putting many more
carve members in every wave.
BLAST RADIUS, measured twice: with no binaries registered, main's object glob sweeps every
overlay's nonmatchings/*.s into MAIN's OBJS and assembles them standalone, so main cannot build,
the main lane correctly refuses against a RED baseline, and every overlay gate rejects every
draft. Waves dn/do banked 0/224 and 0/236; waves ei..em banked 2 of ~1,100 with 675 backlog rows
reading "match_one MATCH but the whole-binary gate rejected" — the local oracle proving the
drafts were byte-correct while the tree could not build them.
tools/mk_write.py is now the only writer: atomic (tmp + fsync + os.replace, so no reader ever
sees a partial file and a crash leaves the original intact), collapse-refusing (a rewrite below
80% of the current line count raises), and flock-serialized.
TWO HONEST LIMITS, recorded rather than papered over:
* Callers still READ outside the lock, so two concurrent carves can each read-edit-write and
the second drops the first's line. That is a LOST UPDATE — a missing line, not a wiped file —
caught downstream by the fleet check and jtbl_pads_fix. Closing it means holding the lock
across read-modify-write in every caller.
* The guard now also refuses when the CURRENT file is under 100 lines. That case cost me
directly: my own verification control overwrote a registry a carve had truncated seconds
earlier, because the collapse check was skipped when the old file was empty. A control must
assert its precondition; mine did not, and now the tool enforces it instead.