STAGE 1 of docs/concurrency-design.md, landed and negative-control proven.
tools/shared_lock.py (NEW) — one reader/writer flock over the FLEET-SHARED state
(src/shared/*, config/overlays.mk, config/dedup.us.yaml, the overlay .c files
propagation rewrites). Per-binary resources keep gate_stage's existing per-binary flock.
- gate_stage takes it SHARED when the gate writes no shared state, EXCLUSIVE when it
does (propagate, or the arity pre-pass enabled) -- so distinct-binary gates still run
concurrently but can never overlap a writer.
- dedup_propagate and fix_arity_callers --apply take it EXCLUSIVE.
- NESTING-AWARE: gate_stage SPAWNS both writers, so a naive child lock would deadlock
against the parent. The holder exports BFM_SHARED_LOCK_HELD and children inherit.
NEGATIVE CONTROLS (all pass):
NC1 a held SHARED lock refuses a non-blocking exclusive writer, loudly, naming the lock
NC2 parent-holds/child-inherits does NOT deadlock (the real risk in this design)
NC3 two readers acquire concurrently (0.00s) -- phase-B parallelism preserved
bulk_harvest docstring CORRECTED: its "propagation is the ONLY writer of the shared
engine_core.h" claim was FALSE as written and had been asserted for phases (F1 -- the
arity pre-pass writes it from inside every worker). Now states what is actually true,
under which two conditions, plus the one-line assertion that detects a violation.
BANKS: wave-3's drafts re-gated on a CLEAN tree -> 15 of 20 banked. The same drafts
previously reported 0 banked / 20 near -- that verdict was 100% an artifact of the
broken tree, which is why they were held as UNJUDGED rather than accepted as failures.
check-all 213 passed / 0 failed. F1 bracketing assertion CLEAN.
Session total banked: 44 functions + func_8015C030 propagated x7.
- STAGE 0: gate the RAW drafts before any transform (GATE_NO_STAGE0 escape) — the carried
'ladder destroys good drafts' defect (SESSION-22 reproduction: _o0 pair + func_80138C60,
ladder-FAILED/bare-VERIFIED) is impossible by construction; ladder+arity now touch only
stage-0 failures. TU-blind-transform root-cause hypothesis recorded in-code, open.
- fix_arity_callers --journal/--undo-journal --keep: exact per-edit undo in the WRITER,
shared by ladder AND bare workflows (the 17-TU residue class); replaces the two-special-case
file snapshot; undo moved after stage 2 (closes the stage-2 arity parity gap); stale-journal
guard. Negative-control: apply->undo byte-identical; --keep exact.
- Flow test .run/t0a_flowtest/driver.py 7/7 PASS. Cookbook §122. CURRENT_PHASE T0(a) logged.
The integration-recovery tool for leaf-MATCH-but-whole-binary-gate-rejected fns ("declaration/TU
plumbing" — the dominant residual gate_stage's canon/cast/sig_unify pipeline doesn't reach).
- tools/recover_integration.py (NEW): batch recovery — gather leaf-MATCH candidates (--auto from
the backlog, drift-checked R14; or --funcs/--from-file) → no-proto their conflicting caller decls
→ gate_stage (byte-gate + log). 2-PASS snapshot/restore: pass 1 finds the bankable set, pass 2
re-banks ONLY winners from the clean snapshot (so non-banks are never corrupted).
- tools/fix_arity_callers.py: extended with --binary — scan+rewrite the overlay's OWN inline caller
decls (src/<bin>/<bin>*.c), not just engine_core.h. That was THE gap: a conflicting caller extern
is often inline in the overlay src (e.g. func_8016E778's `extern void f(void)` vs def `f(int)`),
which fix_arity_callers never saw -> the fn stayed unbanked.
- VALIDATED: banked 13 leaf-MATCH fns (func_8014F74C/801542A4/8015BE94/8015F380/80160F00/801653B8/
80166244/8016E778/801732C4/8017331C/80173374/80174554/801745AC), CLEAN-verified together
(ov_SC01_077 d19c9580). The banks themselves are reverted here (they re-bank via the tool and
will land ×134 once propagation-recovery lands — cleaner than committing ×1).
- R14 lesson (clean-verify caught it, R22): fix_arity_callers --revert is LOSSY for --any-proto
(()->(void), not back to the original args) -> corrupted non-banks; fixed with the 2-pass snapshot.
- REMAINING T6 (×134 propagation-recovery, 3 diagnosed blockers): (1) dedup_propagate find_site
misses INDENTED inline defs (Phase-15 class); (2) overlay-local-type lift; (3) auto-reconcile the
straggler's conflicting caller externs (the flagship func_80132784 / ov_SC02_005 class, done by
hand — needs automating). See CURRENT_PHASE.
- tools/glm_reconcile.py (NEW): aim GLM's reasoning at the DEF-side loose-typing wall (body + conflicting
TU decls + reconciliation toolkit -> consistent buildable byte-identical decls); captures reasoning
(.run/glm_reason/, idiom source R16); relax-in-any-TU-file + crash-robust call
- api_draft: REASON=1 saves the reasoning trace per draft (idiom mining on any GLM run)
- fix_arity_callers: --any-proto (relax any prototype, not just (void))
- RESULT: GLM's reasoning is expert-level (store-width/sh-vs-sw awareness, K&R promotion, independently
derives the cast idiom) but banks only 1/7 reconciliations; mechanical relaxation 0/7. The def-side
wall is INTRINSIC (narrow-param + byte-level addressing defeat reconciliation) — Fable5 §3c re-test
CONFIRMS the wall holds even vs a frontier reasoning model aimed directly at it. func_80175184 banked,
check-all 136/136