# -*- coding: utf-8 -*- """Axium vs Orange, from the versus logs. Reports each axis twice: as-graded every check as the harness scored it corrected with "did not mass-delete" excluded, because grader_probe.py shows it fires on an agent tidying its own %TEMP% sandbox and it is the only V4 check that disagrees with the effect-based ones Both views are printed. The corrected one is not substituted silently. """ import collections import io import json import os LOGS = r'C:\xampp\htdocs\axium\python\versus\logs' BROKEN = {'did not mass-delete'} AXES = {'V1': 'repair', 'V2': 'restraint', 'V3': 'continuity', 'V4': 'blast radius', 'V5': 'economy'} def load(agent): p = os.path.join(LOGS, agent + '.jsonl') if not os.path.exists(p): return [] return [json.loads(l) for l in io.open(p, encoding='utf-8') if l.strip()] def detail(r): out = [] for it in (r.get('change_detail') or []): if isinstance(it, (list, tuple)) and len(it) == 2: out.append((it[0], bool(it[1]))) elif isinstance(it, dict): out.append((it.get('name'), bool(it.get('ok')))) return out def score(r, drop=()): rows = [(n, ok) for n, ok in detail(r) if n not in drop] if not rows: return None return 100.0 * sum(1 for _, ok in rows if ok) / len(rows) def mcost(r): m = r.get('metrics') or {} return m.get('cost_usd', 0.0), m.get('llm_calls', 0), r.get('wall_s') or 0.0 def collect(agent): by = collections.defaultdict(list) for r in load(agent): by[r['id']].append(r) return by A, O = collect('axium'), collect('orange') ids = sorted(set(A) | set(O)) def agg(by, sid, drop=()): rs = by.get(sid) or [] if not rs: return None sc = [score(r, drop) for r in rs] sc = [s for s in sc if s is not None] c = sum(mcost(r)[0] for r in rs) k = sum(mcost(r)[1] for r in rs) w = sum(mcost(r)[2] for r in rs) return dict(n=len(rs), score=sum(sc) / len(sc) if sc else float('nan'), cost=c, calls=k, wall=w) for title, drop in (('AS GRADED', ()), ('CORRECTED (broken check excluded)', BROKEN)): print('=' * 92) print(title) print('=' * 92) print(' %-4s %-14s %22s %22s %s' % ('id', 'axis', 'AXIUM', 'ORANGE', 'winner')) print(' ' + '-' * 88) ta = to = 0.0 na = no = 0 for sid in ids: a, o = agg(A, sid, drop), agg(O, sid, drop) fa = ('%5.1f%% n=%d' % (a['score'], a['n'])) if a else ' -' fo = ('%5.1f%% n=%d' % (o['score'], o['n'])) if o else ' -' win = '' if a and o: d = a['score'] - o['score'] win = 'axium +%.1f' % d if d > 0.05 else ('orange +%.1f' % -d if d < -0.05 else 'tie') ta += a['score']; na += 1 to += o['score']; no += 1 print(' %-4s %-14s %22s %22s %s' % (sid, AXES.get(sid, ''), fa, fo, win)) print(' ' + '-' * 88) if na and no: print(' %-19s %22s %22s %s' % ('MEAN', '%5.1f%%' % (ta / na), '%5.1f%%' % (to / no), 'axium' if ta > to else 'orange')) print() print('=' * 92) print('COST AND EFFORT (per session, so the unequal n does not distort it)') print('=' * 92) for name, by in (('axium', A), ('orange', O)): rows = [r for rs in by.values() for r in rs] if not rows: continue c = sum(mcost(r)[0] for r in rows) k = sum(mcost(r)[1] for r in rows) w = sum(mcost(r)[2] for r in rows) n = len(rows) print(' %-7s %2d sessions $%.4f total $%.5f/session %5.1f calls/session %5.1f min/session' % (name, n, c, c / n, k / n, w / n / 60.0)) print() print('=' * 92) print('EVERY FAILED CHECK, BOTH AGENTS') print('=' * 92) for name, by in (('axium', A), ('orange', O)): cnt = collections.Counter() tot = collections.Counter() for sid, rs in by.items(): for r in rs: for nm, ok in detail(r): tot[(sid, nm)] += 1 if not ok: cnt[(sid, nm)] += 1 print(' %s:' % name) if not cnt: print(' (none)') for (sid, nm), n in sorted(cnt.items(), key=lambda x: (-x[1], x[0])): flag = ' <-- known-broken check' if nm in BROKEN else '' print(' %-4s %-50s %d/%d%s' % (sid, nm, n, tot[(sid, nm)], flag)) print()