79 lines
2.8 KiB
Python
Executable File
79 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""CHECK-2026-09-28: the verdict for the Triage-2026-09-28 classification.
|
|
|
|
Exit 0 iff the committed manifest (Triage-2026-09-28-classify.json) matches a
|
|
fresh, independent re-derivation of the classification straight from the seed's
|
|
own fields (summary prefix), with counts and orderings identical. A tautology
|
|
or a mismatch both exit nonzero. Run from any directory:
|
|
python3 CHECK-2026-09-28
|
|
(The repo's ralph-loop convention invokes the committed CHECK and reads its rc.)
|
|
"""
|
|
import json
|
|
import sys
|
|
|
|
ROOT = "/root/troupe-standup"
|
|
SEED = f"{ROOT}/inbox/seed-2026-09-26.json"
|
|
MANIFEST = f"{ROOT}/wizard-work/sol/Triage-2026-09-28-classify.json"
|
|
|
|
# Independent re-implementation of the classifier (deliberately separate
|
|
# expression shape from the builder that produced the manifest).
|
|
CATS = ["archive_fix", "app_pr", "general", "other"]
|
|
|
|
def expected_category(summary):
|
|
s = (summary or "").strip()
|
|
if s.startswith("Archive fix:"):
|
|
return "archive_fix"
|
|
if s.startswith("Turd app:"):
|
|
return "app_pr"
|
|
if s.startswith("Trial by Timmy:") or s.startswith("Q9:"):
|
|
return "general"
|
|
return "other"
|
|
|
|
seed = json.load(open(SEED))
|
|
assert set(seed.keys()) == {"cutover", "decided", "exported_at", "pending", "source"}
|
|
|
|
expected_items = []
|
|
for it in sorted(seed["pending"], key=lambda x: int(x["id"])):
|
|
expected_items.append({
|
|
"id": int(it["id"]),
|
|
"category": expected_category(it["summary"]),
|
|
"status": "table",
|
|
})
|
|
|
|
expected_counts = {"archive_fix": 0, "app_pr": 0, "general": 0, "other": 0}
|
|
for it in expected_items:
|
|
expected_counts[it["category"]] += 1
|
|
|
|
manifest = json.load(open(MANIFEST))
|
|
|
|
errors = []
|
|
|
|
# Structural keys that any genuine manifest carries (not a flake).
|
|
for key in ("artifact", "seed", "generated_at", "lane", "summary", "decision_counts", "categories", "items"):
|
|
if key not in manifest:
|
|
errors.append(f"manifest missing key {key!r}")
|
|
|
|
if [i["id"] for i in manifest.get("items", [])] != [i["id"] for i in expected_items]:
|
|
errors.append("item id order differs from seed")
|
|
|
|
if manifest.get("decision_counts") != {"approve": 0, "reject": 0, "table": 12}:
|
|
errors.append(f"decision_counts {manifest.get('decision_counts')!r} != expected")
|
|
|
|
if manifest.get("categories") != expected_counts:
|
|
errors.append(f"categories {manifest.get('categories')!r} != expected {expected_counts}")
|
|
|
|
got = [(i["id"], i.get("category")) for i in manifest.get("items", [])]
|
|
exp = [(i["id"], i["category"]) for i in expected_items]
|
|
if got != exp:
|
|
errors.append(f"per-item categories differ: {got} != {exp}")
|
|
|
|
if errors:
|
|
print("CHECK-2026-09-28: VERDICT FALSE")
|
|
for e in errors:
|
|
print(" -", e)
|
|
sys.exit(1)
|
|
|
|
print("CHECK-2026-09-28: VERDICT TRUE "
|
|
f"(categories={manifest['categories']} table={manifest['decision_counts']['table']})")
|
|
sys.exit(0)
|