From 04c5c9b47f73689cf25211583f989b2dd73b9ccc Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:32:05 -0600 Subject: [PATCH] fix(phase-21): dedup_propagate skips -O0 overlay-local fns + gate_stage surfaces prop failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cont.4 root-cause fixes so future _a waves auto-realize ×134: - dedup_propagate --auto-from now excludes *_o0.c (-O0) defs: -O0 codegen embeds per-overlay %lo data, so masked h_exact falsely reports reach-134 (§18/§20). One such straggler (func_8013C360) reverted 10 clean ×134 matches under the all-or-nothing batch gate (cont.4). Detected via find_site on the -O0 split file; --addr still forces them. (6 fns excluded.) - gate_stage: capture dedup_propagate's exit; on a real byte-gate revert (not the benign 'nothing to propagate' no-op) write .run/auto/last_propagate_error.log + add prop_error to the summary + warn. A swallowed revert previously hid the gain silently. --- tools/dedup_propagate.py | 16 +++++++++++++++- tools/gate_stage.py | 19 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/tools/dedup_propagate.py b/tools/dedup_propagate.py index 3f1889708..e07eb9d33 100644 --- a/tools/dedup_propagate.py +++ b/tools/dedup_propagate.py @@ -293,8 +293,22 @@ def main(): ssig = load_sig(src) ctext = source_text(src) # scan main + split files for matched defs reg = registered_addrs() # skip functions already shared (additive + resumable) + # -O0 split-file functions are OVERLAY-LOCAL (§18/§20, cont.4): -O0 codegen embeds per-overlay + # %lo data addresses, so their bytes diverge per overlay even though the relocation-MASKED + # h_exact falsely reports reach-134. Cross-overlay-propagating one fails the byte-gate and, + # under the all-or-nothing batch revert, poisons every CLEAN match in the batch (cont.4: + # func_8013C360 reverted 10 good ×134 matches). Never auto-propagate them — detect by def-site + # in the -O0 split file (*_o0.c). (--addr still forces them, for an explicit override.) + o0_skip = set() + for _p, _tag in overlay_files(src): + if _p.name.endswith("_o0.c"): + _o0txt = _p.read_text() + for _ad in ssig: + _s = find_site(_o0txt, src, _ad) + if _s and _s[0] == "def": + o0_skip.add(_ad) for addr in sorted(ssig): - if addr in reg: + if addr in reg or addr in o0_skip: continue site = find_site(ctext, src, addr) if not site or site[0] != "def": # only functions matched (inline def) in the source diff --git a/tools/gate_stage.py b/tools/gate_stage.py index b8b11ee5f..2c01a8599 100644 --- a/tools/gate_stage.py +++ b/tools/gate_stage.py @@ -120,10 +120,24 @@ def _run_gate_locked(drafts, binary, src, asm, out, good_sha, propagate, source_ # 5 propagate the banked matches fleet-wide propagated = 0 + prop_error = None if verified and propagate: before = _dedup_group_count() - sh([PY, "tools/dedup_propagate.py", "--auto-from", binary, "--min-reach", "2"], timeout=3600) + pr = sh([PY, "tools/dedup_propagate.py", "--auto-from", binary, "--min-reach", "2"], timeout=3600) propagated = max(0, _dedup_group_count() - before) + # Surface a REAL failure: dedup_propagate exits non-zero on a byte-gate revert (a false-reach + # straggler poisoned the all-or-nothing batch) — distinct from the benign "nothing to propagate" + # empty-plan no-op. A swallowed revert previously hid a real ×134 gain (cont.4); never again. + out = (pr.stdout or "") + (pr.stderr or "") + if pr.returncode != 0 and "nothing to propagate" not in out: + errlog = os.path.join(REPO, ".run/auto/last_propagate_error.log") + try: + open(errlog, "w").write(out) + except OSError: + pass + prop_error = [l for l in out.strip().splitlines() if l.strip()][-3:] or [f"exit {pr.returncode}"] + print(f"[gate] WARNING: dedup_propagate exited {pr.returncode} ({propagated} groups added); " + f"see {errlog}", file=sys.stderr) # 6 log every non-match to the backlog (closeness + RESIDUAL class + best draft for the human). # The drafter stamps `// @class: ` and `// @stuck: ` into the draft (so the @@ -171,7 +185,8 @@ def _run_gate_locked(drafts, binary, src, asm, out, good_sha, propagate, source_ commit_sha = sh(["git", "rev-parse", "--short", "HEAD"]).stdout.strip() return {"drafts": len(draft_fns), "banked": len(verified), "propagated": propagated, - "near": near, "failed": failed, "fleet_pct": fp, "verified": verified, "commit": commit_sha} + "near": near, "failed": failed, "fleet_pct": fp, "verified": verified, + "prop_error": prop_error, "commit": commit_sha} def main():