101 lines
3.7 KiB
Python
101 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Deterministic classifier for the frozen 8-item probe seed.
|
|
|
|
Lane: sol / Triage (everyday Q&A and classification).
|
|
|
|
Rule (evidence-keyword driven, stdlib only):
|
|
Category:
|
|
- archive_fix -> evidence describes a defect / omission in deployed content:
|
|
hero mark, funding table, leaderboard restat, export rows,
|
|
readme env vars.
|
|
- app_pr -> evidence is a publish / submit action.
|
|
- general -> everything else (batch / handover / coordination).
|
|
Decision:
|
|
- approve -> proposed_action applies a single corrective change
|
|
(update / add / fix / publish) and names no second owner.
|
|
- table -> proposed_action batches a group or hands a file to a named
|
|
second owner (batch ... digest / hand ... to Timmy).
|
|
|
|
Input: wizard-work/sol/seed-2026-10-29.json (frozen, 8 pending items)
|
|
Output: wizard-work/sol/Triage-2026-11-01.json (manifest)
|
|
"""
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent.parent
|
|
SEED = REPO / "wizard-work" / "sol" / "seed-2026-10-29.json"
|
|
OUT = REPO / "wizard-work" / "sol" / "Triage-2026-11-01.json"
|
|
|
|
# Evidence keywords -> category. Checked in order; first match wins.
|
|
CATEGORY_RULES = [
|
|
("archive_fix", ["hero", "funding table", "restats", "export drops",
|
|
"readme omits", "readme", "funding table rows lack"]),
|
|
("app_pr", ["publish", "submit", "release-notes"]),
|
|
]
|
|
|
|
|
|
def classify_category(evidence: str) -> str:
|
|
low = evidence.lower()
|
|
for cat, kws in CATEGORY_RULES:
|
|
if any(k in low for k in kws):
|
|
return cat
|
|
return "general"
|
|
|
|
|
|
def classify_decision(proposed_action: str) -> str:
|
|
low = proposed_action.lower()
|
|
# Handover / batch items name a second owner or a group -> table.
|
|
if re.search(r"\b(batch|hand|record|send)\b", low):
|
|
return "table"
|
|
return "approve"
|
|
|
|
|
|
def main() -> None:
|
|
seed = json.loads(SEED.read_text(encoding="utf-8"))
|
|
pending = seed["pending"]
|
|
|
|
items = []
|
|
for s in pending:
|
|
evidence = s["evidence"]
|
|
summary = s["summary"]
|
|
proposed_action = s["proposed_action"]
|
|
items.append({
|
|
"id": s["id"],
|
|
"summary": summary,
|
|
"category": classify_category(evidence),
|
|
"decision": classify_decision(proposed_action),
|
|
"rationale": (
|
|
f"evidence='{evidence}' -> category rule matched '{classify_category(evidence)}';"
|
|
f" proposed_action='{proposed_action}' -> decision rule matched '{classify_decision(proposed_action)}'."
|
|
),
|
|
"evidence": evidence,
|
|
"source": "seed-2026-10-29.json (frozen)",
|
|
})
|
|
|
|
decision_counts = {}
|
|
categories = {}
|
|
for it in items:
|
|
decision_counts[it["decision"]] = decision_counts.get(it["decision"], 0) + 1
|
|
categories[it["category"]] = categories.get(it["category"], 0) + 1
|
|
|
|
manifest = {
|
|
"artifact": "Triage-2026-11-01.json",
|
|
"source": "wizard-work/sol/seed-2026-10-29.json (frozen 8-item probe set)",
|
|
"generated_at": "2026-11-01T00:00:00Z",
|
|
"lane": "Triage - everyday Q&A and classification",
|
|
"pending_in_seed": len(pending),
|
|
"summary": "Triage of 8 pending items in the frozen seed, classified by "
|
|
"evidence-keyword rules.",
|
|
"decision_counts": decision_counts,
|
|
"categories": categories,
|
|
"items": items,
|
|
}
|
|
OUT.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
|
print(f"Wrote {OUT}")
|
|
print(f"decision_counts={decision_counts} categories={categories}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|