From 6fac2e0f3573ed8a6a40a97f9487950d3322951e Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Wed, 2 Sep 2026 01:59:46 -0600 Subject: [PATCH] feat(waves): refuse to launch an agent at an ALREADY-BANKED target (R43/R45) wave_args asserts a target is open AT DRAW TIME, then the payload sits on disk while gates run. S71 launched ov_SC01_006/func_8017F9F8 from a payload built before the gate that banked it; the agent spent a full run to report "STALE CARD - already banked today", with no .s left to score against. Filtering the wave-2 payload found 3 such targets of 27. launch_check.py re-asks the same oracle everything else uses (a bank REMOVES the INCLUDE_ASM stub, so corpus.stubs not containing the symbol IS the bank), either for one target or by filtering a {wave,targets} payload in place. An unreadable binary is treated as OPEN - a tool fault is not a verdict about the subject (R40). --- tools/launch_check.py | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tools/launch_check.py diff --git a/tools/launch_check.py b/tools/launch_check.py new file mode 100644 index 000000000..cd5730c53 --- /dev/null +++ b/tools/launch_check.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Refuse to launch a drafting agent at a target that is ALREADY BANKED (P31 S71, R43/R45). + +`wave_args.py` asserts a target is open AT DRAW TIME. A wave's payload then sits on disk while gates +run, so by launch time some of its targets are banked — and an agent handed one burns a full run to +report "STALE CARD — already banked today", with no `.s` left to even score against. Measured S71: +`ov_SC01_006/func_8017F9F8` was banked by gate `commit:3604` and drafted afterwards from a payload +built before it. + +The open oracle is the same one everything else uses: a bank REMOVES the INCLUDE_ASM stub, so +`corpus.stubs(binary)` not containing the symbol IS the bank. + + python3 tools/launch_check.py # exit 0 = still open, 2 = already banked + python3 tools/launch_check.py --payload p.json # filter a {wave,targets} payload in place +""" +import argparse, json, os, sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import corpus + + +def is_open(binary, fn): + try: + return fn in {s.symbol for s in corpus.stubs(binary).values()} + except Exception as e: # an unreadable binary is not a verdict (R40) + print('launch_check: corpus refused %s (%s) — treating as OPEN' % (binary, e), + file=sys.stderr) + return True + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument('binary', nargs='?'); ap.add_argument('fn', nargs='?') + ap.add_argument('--payload') + a = ap.parse_args() + if a.payload: + d = json.load(open(a.payload)) + keep, drop = [], [] + for t in d.get('targets', []): + (keep if is_open(t['binary'], t.get('name') or t.get('fn')) else drop).append(t) + d['targets'] = keep + json.dump(d, open(a.payload, 'w'), indent=1) + print('launch_check: %d open, %d ALREADY BANKED and dropped%s' + % (len(keep), len(drop), + (': ' + ' '.join('%s:%s' % (t['binary'], t['name']) for t in drop)) if drop else '')) + return 0 if keep else 2 + if not (a.binary and a.fn): + ap.error('give or --payload') + ok = is_open(a.binary, a.fn) + print('%s:%s %s' % (a.binary, a.fn, 'OPEN' if ok else 'ALREADY BANKED — do not launch')) + return 0 if ok else 2 + + +if __name__ == '__main__': + sys.exit(main())