From c1200003aca4b9d9d45b14e83067c19de5a1782a Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:26:23 -0600 Subject: [PATCH] =?UTF-8?q?fix(gater):=20escalation=20supersedes=20?= =?UTF-8?q?=E2=80=94=20highest-tier=20arm=20wins=20a=20(binary,fn)=20colli?= =?UTF-8?q?sion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arm dirs are walked alphabetically, so 'fable' < 'opus' < 'sonnet' and the staging copy silently OVERWROTE: a sonnet NEAR would have replaced the fable MATCH that was escalated to rescue it. Measured live on main/func_800241C0 (sonnet closeness 19, fable MATCH) -- the escalation's entire product would have been lost to a directory listing order, and the gate would have reported an honest failure on the wrong draft. Now ranked fable > opus > sonnet > v3 > haiku, and a collision is REPORTED, never resolved silently: [gater] main:func_800241C0 drafted by fable/sonnet — staging the fable draft --- tools/gater_lane.py | 58 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/tools/gater_lane.py b/tools/gater_lane.py index 68367df4b..7890148ea 100644 --- a/tools/gater_lane.py +++ b/tools/gater_lane.py @@ -68,6 +68,14 @@ def save_ledger(d): json.dump(d, fh, indent=1, sort_keys=True) +# Escalation supersedes: a function drafted by several arms is staged from the HIGHEST tier that +# produced a draft. Without this the arm dirs are walked alphabetically ("fable" < "opus" < +# "sonnet") and the staging copy silently OVERWRITES, so a sonnet NEAR would replace the fable MATCH +# that was escalated to rescue it — the escalation's whole product, lost to a directory listing +# order. Measured live in S68 on main/func_800241C0 (sonnet closeness 19, fable MATCH). +ARM_RANK = {"fable": 40, "opus": 30, "sonnet": 20, "v3": 15, "haiku": 10} + + def wave_targets(wave): """{fn: binary} for one wave, from the file wave_args.py already asserted.""" with open(os.path.join(REPO, wave, "targets.json")) as fh: @@ -89,6 +97,7 @@ def collect(waves): """[(binary, fn, path)] for every draft file not yet gated. Refuses unresolvable drafts.""" led = load_ledger() out, skipped = [], {"already-gated": [], "already-banked": [], "UNRESOLVED": [], "oracle": []} + best, seen_arms = {}, {} for wave in waves: tgts = wave_targets(wave) wdir = os.path.join(REPO, wave) @@ -116,15 +125,57 @@ def collect(waves): skipped["already-banked"].append(key) led[key] = "banked-elsewhere" continue - out.append((binary, fn, os.path.join(adir, name))) + cand = (ARM_RANK.get(arm, 0), arm, binary, fn, os.path.join(adir, name)) + cur = best.get(key) + if cur is None or cand[0] > cur[0]: + best[key] = cand + seen_arms.setdefault(key, []).append(arm) + for key, (_, arm, binary, fn, path) in sorted(best.items()): + arms = seen_arms.get(key, []) + if len(arms) > 1: # never resolve a collision silently (R43) + print("[gater] %s drafted by %s — staging the %s draft (highest tier wins)" + % (key, "/".join(sorted(arms)), arm)) + out.append((binary, fn, path)) save_ledger(led) return out, skipped +def collect_extra(pairs, skipped): + """[(binary, fn, path)] for drafts that do not come from a wave (twin remaps, recovery output). + + The binary must be stated, never inferred: a draft file is named `func_XXXXXXXX.c` and that name + is ambiguous across the fleet (R48), so there is nothing in the path to infer it from safely. + """ + led = load_ledger() + out = [] + for spec in pairs: + if ":" not in spec: + sys.exit("[gater] --extra wants BINARY:PATH, got %r" % spec) + binary, path = spec.split(":", 1) + if not os.path.exists(path): + sys.exit("[gater] --extra path does not exist: %s" % path) + fn = os.path.basename(path)[:-2] if path.endswith(".c") else os.path.basename(path) + key = "%s:%s" % (binary, fn) + if key in led: + skipped["already-gated"].append(key); continue + st = open_stub(binary, fn) + if st is None: + skipped["oracle"].append(key); continue + if not st: + skipped["already-banked"].append(key); led[key] = "banked-elsewhere"; continue + out.append((binary, fn, path)) + save_ledger(led) + return out + + def main(): ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - ap.add_argument("--waves", required=True, help="comma-separated wave dirs (repo-relative)") + ap.add_argument("--waves", default="", help="comma-separated wave dirs (repo-relative)") + ap.add_argument("--extra", action="append", default=[], metavar="BINARY:PATH", + help="a draft from OUTSIDE a wave: 'ov_SC06_032:.run/S68_twin/drafts/ov_SC06_032/func_X.c'. " + "Repeatable. The binary is given EXPLICITLY because there is no targets.json to " + "assert it against, and a guessed binary gates the wrong TU (R43/R48).") ap.add_argument("--min-drafts", type=int, default=3, help="do nothing unless at least this many ungated drafts exist (default 3)") ap.add_argument("--drain", action="store_true", help="gate whatever is there, ignoring --min-drafts") @@ -134,7 +185,10 @@ def main(): a = ap.parse_args() waves = [w.strip() for w in a.waves.split(",") if w.strip()] + if not waves and not a.extra: + sys.exit("[gater] nothing to do — give --waves and/or --extra") ready, skipped = collect(waves) + ready.extend(collect_extra(a.extra, skipped)) for why, items in skipped.items(): if items: print("[gater] skipped %d (%s): %s" % (len(items), why, " ".join(items[:6])))