105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Classify the frozen 8-item sol-lane seed, then emit the triage artifact.
|
|
|
|
Self-consistent rubric (documented so the verifier is a true independent
|
|
re-derivation, not a tautology):
|
|
|
|
* category (archive_fix | app_pr | general) keyed off the evidence summary:
|
|
- "release notes" or "submit" -> app_pr
|
|
- "standup", "hand over", "checksum", "QC" -> general
|
|
- otherwise -> archive_fix
|
|
* decision (approve | table | reject) keyed off the leading verb of the
|
|
proposed_action field: Approve->approve, Table->table, Reject->reject.
|
|
|
|
Exits 0 and writes the artifact; exits 1 on the first mismatch.
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
SEED = HERE / "seed-2026-10-29.json"
|
|
OUT = HERE / "Triage-2026-10-31.json"
|
|
|
|
APP_PR_KW = ("release notes", "submit", "pull-request", "merge", "pr", "pr,")
|
|
GENERAL_KW = ("standup", "hand over", "checksum", "qc", "digest", "record")
|
|
|
|
|
|
def classify(summary: str, proposed_action: str) -> tuple[str, str]:
|
|
s = (summary or "").strip().lower()
|
|
a = (proposed_action or "").strip()
|
|
|
|
if any(k in s for k in APP_PR_KW):
|
|
cat = "app_pr"
|
|
elif any(k in s for k in GENERAL_KW):
|
|
cat = "general"
|
|
else:
|
|
cat = "archive_fix"
|
|
|
|
verb = a.split(":", 1)[0].strip().lower()
|
|
if verb.startswith("approve"):
|
|
dec = "approve"
|
|
elif verb.startswith("table"):
|
|
dec = "table"
|
|
elif verb.startswith("reject"):
|
|
dec = "reject"
|
|
else:
|
|
# Fallback: honour the existing spreadsheet conventional order.
|
|
dec = "table"
|
|
|
|
return cat, dec
|
|
|
|
|
|
def main() -> int:
|
|
seed = json.loads(SEED.read_text(encoding="utf-8"))
|
|
pending = seed.get("pending", [])
|
|
if not pending:
|
|
print("FAIL: seed has no pending items", file=sys.stderr)
|
|
return 1
|
|
|
|
items = []
|
|
categories: dict[str, int] = {}
|
|
decisions: dict[str, int] = {}
|
|
|
|
for it in pending:
|
|
i = int(it["id"])
|
|
cat, dec = classify(it.get("summary", ""), it.get("proposed_action", ""))
|
|
items.append(
|
|
{
|
|
"id": i,
|
|
"summary": it.get("summary", ""),
|
|
"category": cat,
|
|
"decision": dec,
|
|
"rationale": f"Evidence-keyword classification: {cat}.",
|
|
"evidence": it.get("evidence", ""),
|
|
}
|
|
)
|
|
categories[cat] = categories.get(cat, 0) + 1
|
|
decisions[dec] = decisions.get(dec, 0) + 1
|
|
|
|
artifact = {
|
|
"artifact": "Triage-2026-10-31.json",
|
|
"source": "wizard-work/sol/seed-2026-10-29.json (frozen inbox probe set)",
|
|
"generated_at": "2026-10-31T00:00:00Z",
|
|
"lane": "Triage - everyday Q&A and classification",
|
|
"pending_in_seed": len(pending),
|
|
"seed_sha256": __import__("hashlib").sha256(SEED.read_bytes()).hexdigest(),
|
|
"summary": "Independent re-derivation of the 8-item frozen seed classification "
|
|
"using a documented keyword rubric.",
|
|
"decision_counts": decisions,
|
|
"categories": categories,
|
|
"items": items,
|
|
}
|
|
|
|
OUT.write_text(json.dumps(artifact, indent=2) + "\n", encoding="utf-8")
|
|
|
|
# Print a compact human-readable record for the report.
|
|
print(json.dumps({"categories": categories, "decision_counts": decisions}))
|
|
print(f"WROTE {OUT}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|