mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 23:00:29 -04:00
fix(gater): never gate a draft whose workflow has not returned a verdict
A draft file appears at <wave>/<arm>/<fn>.c long before its agent is finished -- agents iterate in place and the wave brief tells them to write the file, not to write it last. Gating one mid-flight spends a build on unfinished work, records an honest-looking rejection, and then LEDGERS it, so the FINISHED draft is skipped as 'already-gated' when it lands. That is a silent loss of the whole draft. Measured this session: ov_SC01_000:func_8017E594 was gated at 0 banked while its workflow was still running, and its ledger entry had to be cleared by hand. Completion is now an explicit signal -- .run/gate_lane/verdicts.jsonl, one object per RETURNED verdict, appended by the orchestrator. A quiet file mtime is deliberately NOT accepted as one: an agent thinking for four minutes between edits looks identical to a finished agent. --any-draft opts out, and says what it costs. [gater] skipped 1 (IN-FLIGHT (no verdict yet)): ov_SC01_000:func_8017E594
This commit is contained in:
+43
-3
@@ -51,9 +51,41 @@ sys.path.insert(0, os.path.join(REPO, "tools"))
|
||||
import corpus # noqa: E402
|
||||
|
||||
LEDGER = os.path.join(REPO, ".run/gate_lane/ledger.json")
|
||||
VERDICTS = os.path.join(REPO, ".run/gate_lane/verdicts.jsonl")
|
||||
STAGE = os.path.join(REPO, ".run/gate_lane")
|
||||
|
||||
|
||||
def completed():
|
||||
"""{(binary, fn)} whose drafting workflow has RETURNED A VERDICT.
|
||||
|
||||
A draft file appears in <wave>/<arm>/<fn>.c long before its agent is finished — agents iterate
|
||||
in place, and the wave brief tells them to write the file, not to write it last. Gating one
|
||||
mid-flight spends a build on an unfinished draft, records an honest-looking rejection, and then
|
||||
LEDGERS it, so the finished draft is skipped as "already-gated" when it lands. Measured S68 on
|
||||
ov_SC01_000:func_8017E594 — gated at 0 banked while its workflow was still running.
|
||||
|
||||
The orchestrator appends one JSON object per returned verdict; nothing else is a completion
|
||||
signal (a quiet file mtime is not one — an agent that thinks for four minutes between edits looks
|
||||
identical to a finished one).
|
||||
"""
|
||||
out = set()
|
||||
try:
|
||||
with open(VERDICTS) as fh:
|
||||
for ln in fh:
|
||||
ln = ln.strip()
|
||||
if not ln:
|
||||
continue
|
||||
try:
|
||||
r = json.loads(ln)
|
||||
except ValueError:
|
||||
continue
|
||||
if r.get("binary") and r.get("fn"):
|
||||
out.add((r["binary"], r["fn"]))
|
||||
except OSError:
|
||||
pass
|
||||
return out
|
||||
|
||||
|
||||
def load_ledger():
|
||||
try:
|
||||
with open(LEDGER) as fh:
|
||||
@@ -93,11 +125,13 @@ def open_stub(binary, fn, cache={}):
|
||||
return None if known is None else (fn in known)
|
||||
|
||||
|
||||
def collect(waves):
|
||||
def collect(waves, require_verdict=True):
|
||||
"""[(binary, fn, path)] for every draft file not yet gated. Refuses unresolvable drafts."""
|
||||
led = load_ledger()
|
||||
out, skipped = [], {"already-gated": [], "already-banked": [], "UNRESOLVED": [], "oracle": []}
|
||||
out, skipped = [], {"already-gated": [], "already-banked": [], "UNRESOLVED": [], "oracle": [],
|
||||
"IN-FLIGHT (no verdict yet)": []}
|
||||
best, seen_arms = {}, {}
|
||||
done = completed()
|
||||
for wave in waves:
|
||||
tgts = wave_targets(wave)
|
||||
wdir = os.path.join(REPO, wave)
|
||||
@@ -125,6 +159,9 @@ def collect(waves):
|
||||
skipped["already-banked"].append(key)
|
||||
led[key] = "banked-elsewhere"
|
||||
continue
|
||||
if require_verdict and (binary, fn) not in done:
|
||||
skipped["IN-FLIGHT (no verdict yet)"].append(key)
|
||||
continue
|
||||
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]:
|
||||
@@ -179,6 +216,9 @@ def main():
|
||||
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")
|
||||
ap.add_argument("--any-draft", action="store_true",
|
||||
help="gate drafts that have no recorded verdict yet (see completed(); this gates "
|
||||
"work an agent may still be iterating on and will ledger the result)")
|
||||
ap.add_argument("--workers", type=int, default=12)
|
||||
ap.add_argument("--no-r22", action="store_true", help="skip the post-merge clean-fleet verify (see docstring)")
|
||||
ap.add_argument("--dry", action="store_true", help="print the plan, stage nothing, gate nothing")
|
||||
@@ -187,7 +227,7 @@ def main():
|
||||
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, skipped = collect(waves, require_verdict=not a.any_draft)
|
||||
ready.extend(collect_extra(a.extra, skipped))
|
||||
for why, items in skipped.items():
|
||||
if items:
|
||||
|
||||
Reference in New Issue
Block a user