Files

121 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""Deterministic triage classifier for the seed inbox (seed-2026-09-26.json).
Lane: Triage -- everyday Q&A and classification.
Reads the seed inbox, assigns each item a category and a decision using a
fixed rubric, and writes:
- wizard-work/sol/triage_results.json (machine-readable results)
- wizard-work/sol/triage_report.md (human-readable report)
Rubric (deterministic, no LLM):
CATEGORY
archive_fix - evidence mentions 'Flag', a 'Summary clause' in an
archive-fidelity/falsification pass, or 'magazine-' title.
app_pr - 'branch', 'push', 'submit', or 'PR' language (turd app items).
general - everything else (trial runs, handoffs, Q&A).
DECISION
decided items keep their seed decision (approved).
pending archive_fix -> approve (correction grounded in the article).
pending app_pr -> table (blocked: maintainer authorization required).
pending general -> table (blocked: machine-level resource gate).
"""
import json
import os
import sys
ROOT = "/root/troupe-standup"
INBOX = os.path.join(ROOT, "inbox", "seed-2026-09-26.json")
OUT = os.path.join(ROOT, "wizard-work", "sol")
os.makedirs(OUT, exist_ok=True)
CATEGORY_RULES = [
("archive_fix", lambda it: any(
k in (it.get("evidence") or "") for k in ("Flag", "Summary clause")
) or "magazine-" in (it.get("summary") or "")),
("app_pr", lambda it: any(
k in ((it.get("evidence") or "") + (it.get("summary") or "") + (it.get("proposed_action") or ""))
for k in ("branch", "push", "submit", "PR"))
or "turd" in ((it.get("summary") or "") + (it.get("evidence") or "")).lower()),
("general", lambda it: True),
]
def classify_category(item):
for cat, test in CATEGORY_RULES:
if test(item):
return cat
return "other"
def classify_decision(item, category):
if item.get("decided_at") is not None: # already resolved in the seed
return item.get("decision")
if category == "archive_fix":
return "approve"
return "table"
def main():
with open(INBOX) as f:
seed = json.load(f)
results = []
for kind in ("decided", "pending"):
for it in seed.get(kind, []):
cat = classify_category(it)
dec = classify_decision(it, cat)
results.append({
"id": it.get("id"),
"source": kind,
"summary": it.get("summary"),
"evidence": it.get("evidence"),
"category": cat,
"decision": dec,
"rule": {
"category": next(c for c, t in CATEGORY_RULES if t(it)),
"decision": {"approve": "article-grounded correction", "table": "wait for authorization"}.get(dec, dec),
},
})
results[-1]["rule"]["decision_detail"] = {
"approve": "article-grounded correction published to the live page",
"approved": "already resolved in the seed (approved)",
"table": "awaiting Alexander/maintainer authorization",
}[dec]
counts = {}
for r in results:
counts[r["category"]] = counts.get(r["category"], 0) + 1
payload = {
"classifier": "triage_classify.py",
"seed": "inbox/seed-2026-09-26.json",
"total": len(results),
"counts": counts,
"results": results,
}
with open(os.path.join(OUT, "triage_results.json"), "w") as f:
json.dump(payload, f, indent=2)
with open(os.path.join(OUT, "triage_report.md"), "w") as f:
f.write("# Triage report — seed-2026-09-26\n\n")
f.write(f"- total items: {len(results)}\n")
f.write(f"- counts by category: {json.dumps(counts)}\n\n")
for r in results:
f.write(f"## id {r['id']} [{r['source']}] {r['category']} -> {r['decision']}\n\n")
f.write(f"{r['summary']}\n\n")
f.write(f"- rule: {r['rule']['category']}\n")
f.write(f"- decision: {r['decision']} ({r['rule']['decision_detail']})\n\n")
f.write("## Evidence\n\n")
for r in results:
f.write(f"### id {r['id']}\n\n")
f.write(f"{r['summary']}\n\n")
f.write(f"**evidence:** {(r.get('evidence') or '')[:240]}\n\n")
print(json.dumps(payload, indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())