"""Minimal evidence viewer / status dashboard over the real state store (standard library HTTP server, read-only). Run: PYTHONPATH=src python -m pgar.evidence_viewer [--port 8765] [--db runs/state.sqlite] Pages: / run table (status, cost, success) with live counts /run/ run manifest, sessions, gate receipts, review, evaluation receipt, event stream /events/ raw-ish event list The HTML is a plain rendering of database rows; it is NOT an imitation of a terminal or of the Claude Code UI. """ from __future__ import annotations import argparse, html, json, os, sqlite3, datetime from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer DB = None STYLE = "" def q(sql, args=()): c = sqlite3.connect(f"file:{DB}?mode=ro", uri=True, timeout=30); c.row_factory = sqlite3.Row try: return [dict(r) for r in c.execute(sql, args).fetchall()] finally: c.close() def page(title, body): now = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds") return f"{html.escape(title)}{STYLE}

{html.escape(title)}

WP29 PGAR evidence viewer — read-only rendering of {html.escape(DB)} at {now} (dashboard, not a terminal){body}" def index(): runs = q("SELECT r.run_id, r.task_id, r.split, r.treatment, r.repeat_index, r.node, r.status, r.terminal_reason, r.manifest_json, e.scientific_success, e.n_violations, e.quality_json FROM runs r LEFT JOIN evaluations e ON e.run_id=r.run_id ORDER BY r.run_id") counts = {} for r in runs: counts[r["status"]] = counts.get(r["status"], 0) + 1 ev = q("SELECT COUNT(*) AS n FROM events")[0]["n"]; se = q("SELECT COUNT(*) AS n, COALESCE(SUM(session_cost_usd),0) AS c FROM sessions")[0] rows = [] for r in runs: m = json.loads(r["manifest_json"]); u = m.get("usage") or {} s = r["scientific_success"]; sc = "" if s is None else (f"success" if s else f"fail") rows.append(f"{r['run_id']}{r['task_id']}{r['split']}{r['treatment']}{r['repeat_index']}{r['node'] or ''}{r['status']}{html.escape(str(r['terminal_reason'] or ''))[:60]}{u.get('spent_usd', 0):.3f}{u.get('n_sessions', '')}{sc}{'' if r['n_violations'] is None else r['n_violations']}") body = (f"

Runs: {len(runs)} — " + ", ".join(f"{k}: {v}" for k, v in sorted(counts.items())) + f" — events: {ev} — sessions: {se['n']} — total inference cost (client estimate): {se['c']:.3f} USD

" "" + "".join(rows) + "
runtasksplitarmrepnodestatusreasonUSDsessionsscienceviol.
") return page("WP29 experiment status", body) def run_page(rid): r = q("SELECT * FROM runs WHERE run_id=?", (rid,)) if not r: return page("not found", "

no such run

") r = r[0]; m = json.loads(r["manifest_json"]) sess = q("SELECT session_id, role, kind, seq, started_utc, ended_utc, result_subtype, session_cost_usd, num_turns, duration_ms, first_turn_input_tokens, model_reported, exit_code, note FROM sessions WHERE run_id=? ORDER BY seq", (rid,)) gates = q("SELECT cycle, origin, utc, passed, n_failed, receipt_json FROM gate_receipts WHERE run_id=? ORDER BY id", (rid,)) revs = q("SELECT utc, verdict, n_issues, review_json FROM reviews WHERE run_id=?", (rid,)) ev = q("SELECT receipt_json FROM evaluations WHERE run_id=?", (rid,)) tr = q("SELECT from_status, to_status, utc, note FROM run_transitions WHERE run_id=? ORDER BY id", (rid,)) events = q("SELECT event_id, seq, received_utc, elapsed_s, event_type, tool_name, status, summary FROM events WHERE run_id=? ORDER BY seq", (rid,)) def tbl(rows, cols): if not rows: return "

none

" return "" + "".join(f"" for c in cols) + "" + "".join("" + "".join(f"" for c in cols) + "" for x in rows) + "
{c}
{html.escape(str(x.get(c, '')))[:300]}
" body = f"

← index

Manifest

{html.escape(json.dumps({k: v for k, v in m.items() if k != 'usage'}, indent=1, sort_keys=True))}
" body += "

Resource envelope

" + html.escape(json.dumps(m.get("usage"), indent=1)) + "
" body += "

State transitions

" + tbl(tr, ["from_status", "to_status", "utc", "note"]) body += "

Sessions

" + tbl(sess, ["seq", "session_id", "role", "kind", "started_utc", "ended_utc", "result_subtype", "session_cost_usd", "num_turns", "duration_ms", "first_turn_input_tokens", "model_reported", "exit_code", "note"]) g2 = [] for g in gates: rec = json.loads(g["receipt_json"]); fails = "; ".join(f"{c['id']}: {c['detail']}" for c in rec.get("checks", []) if not c["passed"]) g2.append({"cycle": g["cycle"], "origin": g["origin"], "utc": g["utc"], "passed": "PASS" if g["passed"] else "FAIL", "n_failed": g["n_failed"], "failed_checks": fails[:600]}) body += "

Gate receipts

" + tbl(g2, ["cycle", "origin", "utc", "passed", "n_failed", "failed_checks"]) body += "

Review

" + ("".join(f"
{html.escape(x['review_json'])[:4000]}
" for x in revs) or "

none

") body += "

Evaluation receipt (hidden-oracle evaluator, run on the evaluator host)

" + ("".join(f"
{html.escape(json.dumps(json.loads(x['receipt_json']), indent=1, sort_keys=True))[:12000]}
" for x in ev) or "

not evaluated

") body += f"

Event stream ({len(events)} events)

" + tbl(events, ["event_id", "received_utc", "elapsed_s", "event_type", "tool_name", "status", "summary"]) return page(f"Run {rid} — {m['task_id']} arm {m['treatment']}", body) class H(BaseHTTPRequestHandler): def do_GET(self): p = self.path.split("?")[0] if p == "/": out = index() elif p.startswith("/run/"): out = run_page(p[5:]) else: self.send_response(404); self.end_headers(); return b = out.encode(); self.send_response(200); self.send_header("Content-Type", "text/html; charset=utf-8"); self.send_header("Content-Length", str(len(b))); self.end_headers(); self.wfile.write(b) def log_message(self, *a): pass def main(): global DB ap = argparse.ArgumentParser(); ap.add_argument("--port", type=int, default=8765); ap.add_argument("--db", default=os.path.join(os.path.dirname(__file__), "..", "..", "runs", "state.sqlite")) a = ap.parse_args(); DB = os.path.abspath(a.db) print(f"evidence viewer on http://127.0.0.1:{a.port}/ over {DB}") ThreadingHTTPServer(("127.0.0.1", a.port), H).serve_forever() if __name__ == "__main__": main()