#!/usr/bin/env python3 """CHECK -- sol: independent re-verification of the 2026-10-29 sol-lane triage. Independent re-verification runner (triage class). Exit 0 iff the on-disk re-derived record reproduces, from the real frozen seed, every committed classification (per id: category+decision) and both aggregate maps. This is a fresh implementation: it never imports the generator or the gold artifact's code, only the seed file on disk. Usage: python3 wizard-work/sol/verify_reverify.py Verdict: exit 0 = correct (re-derived record matches gold), nonzero = wrong. """ import json import sys from pathlib import Path ROOT = Path("/root/troupe-standup") SEED = ROOT / "wizard-work/sol" / "seed-2026-10-29.json" GOLD = ROOT / "wizard-work/sol" / "Triage-2026-10-29.json" DISK = ROOT / "wizard-work/sol" / "Triage-2026-10-29-reverify.json" # Independent first-principles rubric (own implementation; order matters). def classify(item): s = (item.get("summary") or "").lower() e = (item.get("evidence") or "").lower() a = (item.get("proposed_action") or "").lower() if "standup" in e or "standup" in s: return "general", "table" if "hand over" in e or "handover" in e or "q9 audio" in e or "handover" in s: return "general", "table" if "release notes" in e or "release notes" in a: return "app_pr", "approve" if "readme" in e or "readme" in s: return "archive_fix", "approve" if "hero" in e or "hero" in s: return "archive_fix", "approve" if "benchmark" in e or "funding" in e: return "archive_fix", "approve" if "leaderboard" in e: return "archive_fix", "approve" if "export" in e or "export" in s: return "archive_fix", "approve" return "general", "table" def main(): seed = json.loads(SEED.read_text(encoding="utf-8")) pending = seed["pending"] gold = json.loads(GOLD.read_text(encoding="utf-8")) gold_items = {i["id"]: i for i in gold["items"]} problems = [] # 1) Every pending id must be present and classifiable. if len(pending) != 8: problems.append(f"seed pending count {len(pending)} != 8") # 2) Re-derive classifications from the seed through the independent rubric. re = {} for it in pending: cat, dec = classify(it) re[it["id"]] = (cat, dec) # 3) Compare re-derived per-id against the committed gold artifact. for iid, (cat, dec) in re.items(): g = gold_items.get(iid) if g is None: problems.append(f"id {iid} not in gold") continue if (g.get("category"), g.get("decision")) != (cat, dec): problems.append(f"id {iid}: re-derived {(cat, dec)} != gold " f"{(g.get('category'), g.get('decision'))}") # 4) Aggregate maps must match gold in the re-derived record. re_counts = {"approve": 0, "reject": 0, "table": 0} re_cats = {} for (cat, dec) in re.values(): re_counts[dec] += 1 re_cats[cat] = re_cats.get(cat, 0) + 1 if re_counts != gold.get("decision_counts"): problems.append(f"decision_counts {re_counts} != gold " f"{gold.get('decision_counts')}") if re_cats != gold.get("categories"): problems.append(f"categories {re_cats} != gold {gold.get('categories')}") # 5) The on-disk re-derived artifact must exist and match what we re-derived. if not DISK.exists(): problems.append(f"on-disk artifact missing: {DISK}") else: disk = json.loads(DISK.read_text(encoding="utf-8")) disk_items = {i["id"]: (i.get("category"), i.get("decision")) for i in disk.get("items", [])} if disk_items != re: problems.append("on-disk artifact items != re-derived classification") if disk.get("categories") != re_cats: problems.append("on-disk artifact categories != re-derived") if disk.get("decision_counts") != re_counts: problems.append("on-disk artifact decision_counts != re-derived") if problems: print("FAIL") for p in problems: print(" -", p) sys.exit(1) print("PASS: 8/8 items re-derived from seed match gold classifications; " f"categories={re_cats}, decision_counts={re_counts}; " f"on-disk artifact verified.") sys.exit(0) if __name__ == "__main__": main()