121 lines
4.3 KiB
Python
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())
|