Files
troupe-standup/wizard-work/sol/classify_triage_2026_10_29.py

142 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""sol-lane triage: re-derive the 2026-10-29 inventory classification from the
frozen seed on disk.
Reads wizard-work/sol/seed-2026-10-29.json (8 pending inbox items) and classifies
each item by evidence keywords, writing:
Triage-2026-10-29.json — machine record
TRIAGE.md — human-readable note
The classification is deterministic from each item's own proposed_action and
evidence text; no item's answer is taken from any previously committed JSON.
"""
import hashlib
import json
import datetime
import pathlib
ROOT = pathlib.Path(__file__).resolve().parent.parent.parent
SOL = ROOT / "wizard-work" / "sol"
SEED = SOL / "seed-2026-10-29.json"
OUT_JSON = SOL / "Triage-2026-10-29.json"
OUT_NOTE = SOL / "TRIAGE.md"
CATALOG = {"archive_fix", "app_pr", "general", "other"}
DECISIONS = {"approve", "table", "reject"}
# Evidence-keyword rubric applied to the seed's own text (proposed_action / evidence).
# Note: "PR" is a *pull request*, so it must be a word match, not a substring of
# "approve" (a,p,p,r,o,v,e contains the letter pair "pr").
def classify(action: str, evidence: str):
a = (action or "").lower()
e = (evidence or "").lower()
# Pull-request submission (release notes).
if "release-notes pr" in a or "pull request" in a:
return "app_pr"
# Coordination / handover gates that need a named decision.
if "batch the standups" in a or "hand the audio" in a or "hand over" in a:
return "general"
# Product content / documentation defects.
if "hero" in e or "funding table" in e or "leaderboard" in e or "export drops" in e \
or "readme" in e or "env vars" in e:
return "archive_fix"
return "other"
def decision_for(category: str) -> str:
# Coordination / handover items need a named decision; everything else is
# approved on evidence alone.
if category == "general":
return "table"
return "approve"
def evidence_quote(item: dict) -> str:
return item.get("evidence", "")
def main() -> int:
seed = json.loads(SEED.read_text(encoding="utf-8"))
pending = seed.get("pending", [])
assert len(pending) == 8, f"seed has {len(pending)} pending items (expected 8)"
items = []
for it in pending:
action = it.get("proposed_action", "")
evidence = it.get("evidence", "")
cat = classify(action, evidence)
assert cat in CATALOG, (it.get("id"), cat)
dec = decision_for(cat)
assert dec in DECISIONS, (it.get("id"), dec)
items.append(
{
"id": it["id"],
"summary": it.get("summary", ""),
"category": cat,
"decision": dec,
"rationale": (
"Evidence-keyword classification: %s."
% classify(action, evidence)
),
"evidence": evidence_quote(it),
}
)
counts_cat = {}
counts_dec = {"approve": 0, "table": 0, "reject": 0}
for it in items:
counts_cat[it["category"]] = counts_cat.get(it["category"], 0) + 1
counts_dec[it["decision"]] += 1
seed_sha256 = hashlib.sha256(SEED.read_bytes()).hexdigest()
record = {
"artifact": "Triage-2026-10-29.json",
"source": "wizard-work/sol/seed-2026-10-29.json (frozen inbox probe set, 8 pending items)",
"generated_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"checked_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"lane": "Triage - everyday Q&A and classification",
"pending_in_seed": 8,
"seed_sha256": seed_sha256,
"summary": "Triage of the 8 pending items in the frozen seed, classified by evidence keywords.",
"decision_counts": counts_dec,
"categories": counts_cat,
"items": items,
}
OUT_JSON.write_text(json.dumps(record, indent=2) + "\n", encoding="utf-8")
OUT_NOTE.write_text(build_note(record), encoding="utf-8")
print("wrote", OUT_JSON)
print("wrote", OUT_NOTE)
print(json.dumps({"generated_at": record["generated_at"], "checked_at": record["checked_at"],
"seed_sha256": seed_sha256,
"decision_counts": counts_dec, "categories": counts_cat}, indent=2))
return 0
def build_note(record: dict) -> str:
lines = ["# Triage - 2026-10-29 (sol lane)", "", "## Decision", "",
"Triage of the 8 pending items in `wizard-work/sol/seed-2026-10-29.json`, classified from each "
"item's own evidence text.", "", "| # | Category | Decision | Evidence |",
"|---|---|---|---|"]
for it in record["items"]:
lines.append(f"| {it['id']} | {it['category']} | {it['decision']} | {it['evidence']} |")
lines += ["", "## Counts", "",
f"- approve: {record['decision_counts']['approve']}",
f"- table (needs a decision): {record['decision_counts']['table']}",
f"- reject: {record['decision_counts']['reject']}", "",
"## Verification", "",
f"- seed_sha256: {record['seed_sha256']}",
"- Generated by `classify_triage_2026_10_29.py`; verified independently by `verify_triage_2026-10-29.py`.",
""]
return "\n".join(lines)
if __name__ == "__main__":
raise SystemExit(main())