#!/usr/bin/env python # weapons_sweep checker -- ONE comprehensive per-family PASS/FAIL adjudicator # for scratchpad/night16/weapons_sweep.sh (2-node mad2-vs-madcat fight). # # Families / assertions (env on both nodes: BT_DMG_LOG BT_PROJ_LOG BT_DEATH_LOG # BT_AMMO_LOG): # A1 ENERGY : named [emitter] FIRED lines present AND laser/PPC [dmghit] # (type 3/4) land on the victim. # A2 AC : type=1 [dmghit] present, ALL of them burst=1 (single panel, # trigger-time hitscan); ZERO damage-carrying ballistic rounds in # the pool ([projectile] PUSH guided=0 must all be dmg=0 -- the # #171 restoration: the visible round is the cosmetic 0xBCD # tracer); every damage-carrying DET is reconciled to a guided # (missile) push. # A3 MISSILE: [ammo] LRM/SRM FIRED receipts, [projectile] IMPACT dmg>0 # deliveries with burst>1 salvo bursts, type=2 [dmghit]s landing # (burst>1 present) -- contact through the 4.0u fuze at # drag-governed speeds; plus >=1 death or zone cascade (vitality). # A4 NO-REGR: no zone cascades twice within one life per log (the #174 # guard); every [projectile] BYSTANDER receipt in the 2-mech # fight is a TRUE positive of the lane-12 sweep. # CALIBRATION NOTE (2026-08-13 run): the original "zero receipts # in a 2-mech fight" operationalization assumed a lock is always # the enemy mech. The run disproved the ASSUMPTION, not the # code: the production aim ray designates SCENERY constantly # (the ac_bench lesson), and rounds locked onto a structure DO # fly past the other mech -- the binary's world sweep detonates # on ANY solid in the path (FUN_0042291c via @004bef78 [T1]), so # a receipt there is the sweep WORKING. Forensics on all 11 # receipts of the calibration run (bys_forensics.py): struck == # the other live mech every time, aim point 146-1016u away from # the strike (the round was flying elsewhere), one paired IMPACT # delivery each. The check now asserts the actual false-positive # conditions per receipt: # - struck id == the shooter's OWN mech -> self-strike bug # - struck id not a known player mech -> phantom strike # - no DET/IMPACT pairing -> lost/duplicated delivery # - strike within 30u of the round's aim -> the sweep raced the # authentic 4.0u fuze at the lock itself (exclusion suspect) # and flags a hit receipt-print cap (24) as unmeasurable. # A5 FLOORS : rig-sanity minimums so a quiet rig cannot PASS. # # --selftest: prove the detector CAN fail (the week's hard rule) by feeding it # synthetic pre-fix log shapes (pre-#171 damage-carrying ballistic round, # pre-#174 double cascade, a bystander receipt, and an empty/quiet rig) and # requiring each to FAIL the matching assertion. import io import math import re import sys RX_DMGHIT = re.compile(r"\[dmghit\] mech=(\S+) zone=(-?\d+) vital=(\d+) " r"type=(\d+) amt=([\d.eE+\-]+) burst=(\d+)") RX_PUSH = re.compile(r"\[projectile\] PUSH target=(\S+) len=(\S+) speed=(\S+) " r"dmg=([\d.eE+\-]+) guided=(\d+)") RX_DET = re.compile(r"\[projectile\] DET .*?dmg=([\d.eE+\-]+) lead=(\d+)") RX_IMPACT = re.compile(r"\[projectile\] IMPACT damage=([\d.eE+\-]+) .*?burst=(\d+)") RX_EMIT = re.compile(r"\[emitter\] FIRED '([^']+)'") RX_AMMO = re.compile(r"\[ammo\] (\S+) FIRED, rounds left=") RX_CASC = re.compile(r"\[cascade\] zone (\d+) DESTROYED") RX_BYS = re.compile(r"\[projectile\] BYSTANDER id=(\d+) t=(\S+) at\(([^)]*)\) " r"dmg=([\d.eE+\-]+) lockedTgt=(\S+)") RX_DETAIM = re.compile(r"\[projectile\] DET at\(([^)]*)\).*?aim\(([^)]*)\)") RX_RESET = re.compile(r"Mech::Reset (\d+):(\d+)") RX_DEATH = re.compile(r"\[death\] VehicleDead") # rig-sanity floors (A5) -- calibrated against the proven kd_bench/cascade_bench # engagement levels (worker's 180s single-shooter evidence run: 200 dmghits). FLOOR_DMGHITS_TOTAL = 40 FLOOR_ENERGY_HITS = 5 # type 3+4 dmghits FLOOR_AC_HITS = 3 # type=1 dmghits FLOOR_MISSILE_HITS = 3 # type=2 dmghits FLOOR_MISSILE_BURSTS = 2 # IMPACT dmg>0 burst>1 deliveries FLOOR_EMITTER_FIRED = 10 FLOOR_VITALITY = 1 # deaths + cascades def _p3(s): try: v = [float(x) for x in s.split(",")] return v if len(v) == 3 else None except ValueError: return None def _dist(a, b): return math.sqrt(sum((a[i] - b[i]) ** 2 for i in range(3))) def parse(lines): lines = list(lines) d = { "dmghit": [], # (mech, zone, vital, type, amt, burst) "push": [], # (dmg, guided) "det": [], # (dmg, lead) "impact": [], # (dmg, burst) "emitter": {}, # name -> count "ammo": {}, # name -> count "bystander": 0, "bys_recs": [], # (line, struckid, at, dmg, lockptr, aim|None, paired) "bys_capped": 0, # the 24-receipt print cap was reached "own": None, # this node's own mech entity id (first Reset h:ID) "mechids": set(), # every player-mech entity id seen in Reset lines "deaths": 0, "resets": 0, "casc_total": 0, "casc_worst": {}, # zone -> worst per-life repeat count } life = {} for i, l in enumerate(lines): m = RX_DMGHIT.search(l) if m: d["dmghit"].append((m.group(1), int(m.group(2)), int(m.group(3)), int(m.group(4)), float(m.group(5)), int(m.group(6)))) continue m = RX_PUSH.search(l) if m: d["push"].append((float(m.group(4)), int(m.group(5)))) continue m = RX_BYS.search(l) if m: struck = int(m.group(1)) at = _p3(m.group(3)) if "receipt cap reached" in l: d["bys_capped"] = 1 # the receipt's own detonation follows within a few lines: DET # (carries the round's aim) then the mech delivery IMPACT aim = None paired = False for j in range(i + 1, min(i + 5, len(lines))): dm = RX_DETAIM.search(lines[j]) if dm and aim is None: aim = _p3(dm.group(2)) if "[projectile] IMPACT damage=" in lines[j]: paired = True break d["bys_recs"].append((i + 1, struck, at, float(m.group(4)), m.group(5), aim, paired)) d["bystander"] += 1 continue m = RX_DET.search(l) if m: d["det"].append((float(m.group(1)), int(m.group(2)))) continue m = RX_IMPACT.search(l) if m: d["impact"].append((float(m.group(1)), int(m.group(2)))) continue m = RX_EMIT.search(l) if m: d["emitter"][m.group(1)] = d["emitter"].get(m.group(1), 0) + 1 continue m = RX_AMMO.search(l) if m: d["ammo"][m.group(1)] = d["ammo"].get(m.group(1), 0) + 1 continue m = RX_CASC.search(l) if m: z = int(m.group(1)) life[z] = life.get(z, 0) + 1 if life[z] > d["casc_worst"].get(z, 0): d["casc_worst"][z] = life[z] d["casc_total"] += 1 continue if "Mech::Reset" in l: life = {} d["resets"] += 1 m = RX_RESET.search(l) if m: mid = int(m.group(2)) d["mechids"].add(mid) if d["own"] is None: d["own"] = mid continue if RX_DEATH.search(l): d["deaths"] += 1 return d def adjudicate(logs, verbose=True): """logs: {name: parsed-dict}. Returns (fails, table_rows).""" fails = [] def agg(key): out = [] for nm in logs: out.extend(logs[nm][key]) return out hits = agg("dmghit") push = agg("push") det = agg("det") impact = agg("impact") emitter = {} ammo = {} for nm in logs: for k, v in logs[nm]["emitter"].items(): emitter[k] = emitter.get(k, 0) + v for k, v in logs[nm]["ammo"].items(): ammo[k] = ammo.get(k, 0) + v bystander = sum(logs[nm]["bystander"] for nm in logs) deaths = sum(logs[nm]["deaths"] for nm in logs) resets = sum(logs[nm]["resets"] for nm in logs) cascades = sum(logs[nm]["casc_total"] for nm in logs) h_energy = [h for h in hits if h[3] in (3, 4)] h_laser = [h for h in hits if h[3] == 3] h_ppc = [h for h in hits if h[3] == 4] h_ball = [h for h in hits if h[3] == 1] h_missile = [h for h in hits if h[3] == 2] h_mis_multi = [h for h in h_missile if h[5] > 1] ball_multi = [h for h in h_ball if h[5] != 1] push_ballistic = [p for p in push if p[1] == 0] push_ballistic_dmg = [p for p in push_ballistic if p[0] != 0.0] push_guided_dmg = [p for p in push if p[1] == 1 and p[0] > 0.0] det_dmg = [x for x in det if x[0] != 0.0] imp_dmg = [x for x in impact if x[0] > 0.0] imp_multi = [x for x in imp_dmg if x[1] > 1] ammo_ac = {k: v for k, v in ammo.items() if k.upper().startswith("AFC")} ammo_mis = {k: v for k, v in ammo.items() if k.upper().startswith(("LRM", "SRM", "STRK", "STREAK", "NARC", "NRK"))} # ---- A1 ENERGY ---- a1 = [] if not emitter: a1.append("no named [emitter] FIRED lines") if len(h_energy) < FLOOR_ENERGY_HITS: a1.append("laser/PPC dmghits %d < floor %d" % (len(h_energy), FLOOR_ENERGY_HITS)) if not h_laser: a1.append("no type=3 laser dmghit landed") if sum(emitter.values()) < FLOOR_EMITTER_FIRED: a1.append("emitter FIRED total %d < floor %d" % (sum(emitter.values()), FLOOR_EMITTER_FIRED)) # ---- A2 AC HITSCAN (#171) ---- a2 = [] if len(h_ball) < FLOOR_AC_HITS: a2.append("type=1 dmghits %d < floor %d" % (len(h_ball), FLOOR_AC_HITS)) if ball_multi: a2.append("%d type=1 dmghit(s) with burst!=1 (multi-panel ballistic -- " "not the single-panel hitscan)" % len(ball_multi)) if push_ballistic_dmg: a2.append("%d ballistic PUSH(es) with dmg!=0 -- a damage-carrying " "ballistic round entered the pool (pre-#171 shape)" % len(push_ballistic_dmg)) if not push_ballistic: a2.append("no ballistic (guided=0) PUSH at all -- AC never cycled") if not ammo_ac: a2.append("no [ammo] AFC* FIRED receipt -- no autocannon cycled a round") # every damage-carrying DET must be attributable to a guided (missile) push, # per log (pool is node-local) for nm in logs: nd = len([x for x in logs[nm]["det"] if x[0] != 0.0]) ng = len([p for p in logs[nm]["push"] if p[1] == 1 and p[0] > 0.0]) if nd > ng: a2.append("%s: %d damage DETs > %d guided damage PUSHes -- an " "unguided round detonated carrying damage" % (nm, nd, ng)) # ---- A3 MISSILES ---- a3 = [] if not ammo_mis: a3.append("no [ammo] LRM/SRM FIRED receipt") if len(imp_dmg) < FLOOR_MISSILE_HITS: a3.append("missile IMPACT deliveries %d < floor %d" % (len(imp_dmg), FLOOR_MISSILE_HITS)) if len(imp_multi) < FLOOR_MISSILE_BURSTS: a3.append("salvo bursts (IMPACT dmg>0 burst>1) %d < floor %d" % (len(imp_multi), FLOOR_MISSILE_BURSTS)) if len(h_missile) < FLOOR_MISSILE_HITS: a3.append("type=2 dmghits %d < floor %d" % (len(h_missile), FLOOR_MISSILE_HITS)) if not h_mis_multi: a3.append("no type=2 dmghit with burst>1 (no salvo cluster landed)") if deaths + resets + cascades < FLOOR_VITALITY: a3.append("rig vitality: deaths+resets+cascades = %d < %d" % (deaths + resets + cascades, FLOOR_VITALITY)) # ---- A4 NO REGRESSION ---- a4 = [] for nm in logs: dup = {z: c for z, c in logs[nm]["casc_worst"].items() if c > 1} if dup: a4.append("%s re-descended zones %s within one life (#174 ALIVE)" % (nm, dup)) # BYSTANDER receipts: every receipt must be a TRUE positive (see the # calibration note in the header -- rounds locked onto scenery legitimately # detonate on the other mech crossing the flight path; the binary's world # sweep fires on ANY solid [T1]). False-positive conditions per receipt: all_mechids = set() for nm in logs: all_mechids |= logs[nm]["mechids"] bys_true = 0 for nm in logs: own = logs[nm]["own"] if logs[nm]["bys_capped"]: a4.append("%s: BYSTANDER print cap (24) reached -- receipt count " "unmeasurable, rerun a shorter window" % nm) for (ln, struck, at, bdmg, lockptr, aim, paired) in logs[nm]["bys_recs"]: bad = [] if own is not None and struck == own: bad.append("SELF-STRIKE (sweep hit the shooter's own mech)") if all_mechids and struck not in all_mechids: bad.append("phantom strike: id %d is no known player mech" % struck) if aim is None or not paired: bad.append("no paired DET/IMPACT delivery (lost or duplicated " "round)") elif at is not None and _dist(at, aim) < 30.0: bad.append("strike within %.0fu of the round's own aim -- the " "sweep raced the 4.0u fuze at the lock itself " "(target-exclusion suspect)" % _dist(at, aim)) if bad: a4.append("%s:%d BYSTANDER FALSE POSITIVE: %s" % (nm, ln, "; ".join(bad))) else: bys_true += 1 # ---- A5 FLOORS ---- a5 = [] if len(hits) < FLOOR_DMGHITS_TOTAL: a5.append("total dmghits %d < floor %d (quiet rig proves nothing)" % (len(hits), FLOOR_DMGHITS_TOTAL)) rows = [ ("ENERGY", a1, "emitterFIRED=%d(names=%d) hits t3=%d t4=%d" % (sum(emitter.values()), len(emitter), len(h_laser), len(h_ppc))), ("AC", a2, "acFIRED=%d hits t1=%d (burst!=1: %d) ballPUSH=%d " "(dmg!=0: %d)" % (sum(ammo_ac.values()), len(h_ball), len(ball_multi), len(push_ballistic), len(push_ballistic_dmg))), ("MISSILE", a3, "misFIRED=%d IMPACTdmg=%d(burst>1:%d) hits t2=%d" "(burst>1:%d) FIZZ n/a" % (sum(ammo_mis.values()), len(imp_dmg), len(imp_multi), len(h_missile), len(h_mis_multi))), ("NO-REGR", a4, "cascades=%d worstRepeat=%d bystander=%d " "(true-positive crossfire=%d, false=%d)" % (cascades, max([c for nm in logs for c in logs[nm]["casc_worst"].values()] or [0]), bystander, bys_true, bystander - bys_true)), ("RIG", a5, "dmghits=%d deaths=%d resets=%d DETdmg>0=%d " "guidedDmgPUSH=%d" % (len(hits), deaths, resets, len(det_dmg), len(push_guided_dmg))), ] for fam, fl, _ in rows: fails.extend("%s: %s" % (fam, f) for f in fl) if verbose: print("=== WEAPONS SWEEP -- per-family verdict ===") for fam, fl, info in rows: print("%-8s %-4s %s" % (fam, "PASS" if not fl else "FAIL", info)) for f in fl: print(" - %s" % f) print("weapon receipts (named, both logs):") for k in sorted(set(list(emitter) + list(ammo))): n = emitter.get(k, 0) + ammo.get(k, 0) src = "emitter" if k in emitter else "ammo" print(" %-16s %4d (%s)" % (k, n, src)) for nm in logs: print("%s: dmghits=%d pushes=%d dets=%d impacts=%d casc=%d " "resets=%d deaths=%d bys=%d" % (nm, len(logs[nm]["dmghit"]), len(logs[nm]["push"]), len(logs[nm]["det"]), len(logs[nm]["impact"]), logs[nm]["casc_total"], logs[nm]["resets"], logs[nm]["deaths"], logs[nm]["bystander"])) print("RESULT:", "PASS" if not fails else "FAIL") if fails: for f in fails: print(" FAIL:", f) return fails def load(fn): return parse(io.open(fn, encoding="latin-1", errors="replace").read().splitlines()) # --------------------------------------------------------------------------- # --selftest: the detector must FAIL on pre-fix log shapes (negative controls) # --------------------------------------------------------------------------- HEALTHY = [ # energy: named emitters + laser/PPC hits ] + [ "[emitter] FIRED 'ERMLaser_1' damage=8 heat=2" for _ in range(6) ] + [ "[emitter] FIRED 'ERPPC' damage=15 heat=6" for _ in range(6) ] + [ "[dmghit] mech=42 zone=%d vital=0 type=3 amt=8 burst=1 lvl 0->0.1" % (i % 5) for i in range(8) ] + [ "[dmghit] mech=42 zone=2 vital=0 type=4 amt=15 burst=1 lvl 0->0.2", ] + [ # AC: named ammo fire, cosmetic tracer pushes, hitscan type=1 burst=1 hits "[ammo] AFC50 FIRED, rounds left=93" for _ in range(4) ] + [ "[projectile] PUSH target=0x0 len=400 speed=250 dmg=0 guided=0 ttl=5 " "mz=(1,12,1) relY=12 lv=(fallback)" for _ in range(4) ] + [ "[projectile] DET at(9,2,3) dmg=0 lead=1 tgt=0x0 aim(9,2,3)" for _ in range(4) ] + [ "[dmghit] mech=42 zone=%d vital=0 type=1 amt=12.5 burst=1 lvl 0->0.1" % (i % 4) for i in range(6) ] + [ # missiles: guided pushes (1 lead + visuals), IMPACT bursts, type=2 hits "[ammo] LRM15 FIRED, rounds left=110" for _ in range(4) ] + [ "[projectile] PUSH target=0x5a len=300 speed=180 dmg=52.5 guided=1 ttl=13 " "mz=(1,14,1) relY=14 lv=(auth)" for _ in range(6) ] + [ "[projectile] DET at(4,5,6) dmg=52.5 lead=1 tgt=0x5a aim(4,5,6)" for _ in range(6) ] + [ "[projectile] IMPACT damage=52.5 subsys=21 v=540 burnLeft=0 burst=9 " "(direct dispatch) (zone cyl-resolved)" for _ in range(6) ] + [ "[dmghit] mech=42 zone=%d vital=0 type=2 amt=3.5 burst=%d lvl 0->0.3" % (i % 6, 4 + (i % 8)) for i in range(24) ] + [ "[cascade] zone 17 DESTROYED -> descend=1 destroySibs=0 crits=3", "[respawn] Mech::Reset 3:42 healed+moved to (0,0,0) alive=1 zones=22 subsys=34", "[cascade] zone 17 DESTROYED -> descend=1 destroySibs=0 crits=3", "[death] VehicleDead(-1) dispatched to the owning player", # the peer's mech id (a second life witness so 43 is a known player mech) "[respawn] Mech::Reset 2:43 healed+moved to (9,0,9) alive=1 zones=22 subsys=32", ] # a TRUE-positive bystander receipt: struck the OTHER mech (43 != own 42), # far from the round's own aim, one paired delivery -- must NOT fail A4. BYS_TRUE = [ "[projectile] BYSTANDER id=43 t=0.7 at(100,10,100) dmg=5 lockedTgt=0BADF00D", "[projectile] DET at(100,10,100) dmg=5 lead=1 tgt=0BADF00D aim(500,7,900)", "[projectile] IMPACT damage=5 subsys=29 v=300 burnLeft=2 burst=3 " "(direct dispatch) (zone cyl-resolved)", ] def selftest(): ok = True def expect(name, lines_a, want_frag): nonlocal ok logs = {"fx_a.log": parse(lines_a), "fx_b.log": parse(HEALTHY)} fails = adjudicate(logs, verbose=False) hit = any(want_frag in f for f in fails) print(" selftest %-28s %s" % (name, "DETECTED" if hit else "** MISSED **")) if not hit: ok = False for f in fails: print(" got:", f) print("=== DETECTOR SELF-TEST (negative controls; each MUST fail) ===") # 1. pre-#171: a damage-carrying ballistic round + multi-panel ballistic hit fx = list(HEALTHY) + [ "[projectile] PUSH target=0x5a len=400 speed=250 dmg=12 guided=0 ttl=5 " "mz=(1,12,1) relY=12 lv=(fallback)", "[projectile] DET at(9,2,3) dmg=12 lead=1 tgt=0x5a aim(9,2,3)", "[dmghit] mech=42 zone=3 vital=0 type=1 amt=12 burst=3 lvl 0->0.2", ] expect("pre-#171 ballistic round", fx, "damage-carrying ballistic") expect("pre-#171 multi-panel t1", fx, "burst!=1") # 2. pre-#174: same zone cascades twice inside one life fx = list(HEALTHY) + [ "[cascade] zone 18 DESTROYED -> descend=1 destroySibs=0 crits=4", "[cascade] zone 18 DESTROYED -> descend=1 destroySibs=0 crits=4", ] expect("pre-#174 double cascade", fx, "#174 ALIVE") # 3. bystander FALSE positives (each must be flagged) ... fx = list(HEALTHY) + [ "[projectile] BYSTANDER id=42 t=0.5 at(50,10,50) dmg=5 lockedTgt=0BADF00D", "[projectile] DET at(50,10,50) dmg=5 lead=1 tgt=0BADF00D aim(500,7,900)", "[projectile] IMPACT damage=5 subsys=29 v=300 burnLeft=2 burst=3 " "(direct dispatch) (zone cyl-resolved)", ] expect("bystander SELF-strike", fx, "SELF-STRIKE") fx = list(HEALTHY) + [ "[projectile] BYSTANDER id=7 t=0.31 at(4,5,6) dmg=8 lockedTgt=0x5a", ] expect("bystander phantom strike", fx, "phantom strike") fx = list(HEALTHY) + [ "[projectile] BYSTANDER id=43 t=1 at(499,7,899) dmg=5 lockedTgt=0BADF00D", "[projectile] DET at(499,7,899) dmg=5 lead=1 tgt=0BADF00D aim(500,7,900)", "[projectile] IMPACT damage=5 subsys=29 v=300 burnLeft=2 burst=3 " "(direct dispatch) (zone cyl-resolved)", ] expect("bystander fuze-race at lock", fx, "raced the 4.0u fuze") fx = list(HEALTHY) + BYS_TRUE + [ "[projectile] BYSTANDER id=43 t=0.9 at(200,10,200) dmg=5 " "lockedTgt=0BADF00D (receipt cap reached)", "[projectile] DET at(200,10,200) dmg=5 lead=1 tgt=0BADF00D aim(500,7,900)", "[projectile] IMPACT damage=5 subsys=29 v=300 burnLeft=2 burst=3 " "(direct dispatch) (zone cyl-resolved)", ] expect("bystander print-cap reached", fx, "cap (24) reached") # ... and the TRUE positive must NOT be flagged (no false alarm) logs = {"fx_a.log": parse(HEALTHY + BYS_TRUE), "fx_b.log": parse(HEALTHY)} fails = adjudicate(logs, verbose=False) bysf = [f for f in fails if "BYSTANDER" in f or "SELF" in f] print(" selftest %-28s %s" % ("bystander TRUE pos accepted", "CLEAN" if not bysf else "** FALSE ALARM **")) if bysf: ok = False for f in bysf: print(" got:", f) # 4. quiet rig: both logs empty must FAIL floors logs = {"fx_a.log": parse([]), "fx_b.log": parse([])} fails = adjudicate(logs, verbose=False) quiet = any("quiet rig" in f for f in fails) and any("floor" in f for f in fails) print(" selftest %-28s %s" % ("quiet rig floors", "DETECTED" if quiet else "** MISSED **")) ok = ok and quiet # 5. the healthy fixture itself must PASS (no false alarms in the detector) logs = {"fx_a.log": parse(HEALTHY), "fx_b.log": parse(HEALTHY)} fails = adjudicate(logs, verbose=False) print(" selftest %-28s %s" % ("healthy fixture passes", "CLEAN" if not fails else "** FALSE ALARM **")) if fails: ok = False for f in fails: print(" got:", f) print("DETECTOR:", "OK -- all negative controls detected" if ok else "BROKEN") return ok if __name__ == "__main__": if len(sys.argv) >= 2 and sys.argv[1] == "--selftest": sys.exit(0 if selftest() else 1) if len(sys.argv) < 3: print("usage: weapons_check.py | --selftest") sys.exit(2) logs = {fn: load(fn) for fn in sys.argv[1:]} fails = adjudicate(logs, verbose=True) sys.exit(0 if not fails else 1)