87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Generator: re-derive the sol-lane triage for the frozen 8-item seed.
|
|
|
|
Reads wizard-work/sol/seed-2026-10-29.json and classifies each pending item
|
|
with an explicit keyword rubric (independent of any prior generator), then
|
|
writes wizard-work/sol/Triage-2026-10-30.json.
|
|
|
|
Rubric (keyword, priority-ordered):
|
|
* app_pr -> evidence mentions release notes / submit / pull-request / merge
|
|
* general -> evidence mentions standup / hand over / checksum / QC / digest
|
|
* archive_fix -> everything else (content/copy/caching/table/docs)
|
|
"""
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent.parent
|
|
SRC = REPO / "wizard-work" / "sol"
|
|
SEED = SRC / "seed-2026-10-29.json"
|
|
OUT = SRC / "Triage-2026-10-30.json"
|
|
|
|
APP_PR_KW = ("release notes", "submit", "pull-request", "merge", "pr,", "pr")
|
|
GENERAL_KW = ("standup", "hand over", "checksum", "qc", "digest", "record")
|
|
|
|
|
|
def classify(evidence: str) -> str:
|
|
e = evidence.lower()
|
|
if any(k in e for k in APP_PR_KW):
|
|
return "app_pr"
|
|
if any(k in e for k in GENERAL_KW):
|
|
return "general"
|
|
return "archive_fix"
|
|
|
|
|
|
def main() -> int:
|
|
seed = json.loads(SEED.read_text(encoding="utf-8"))
|
|
pending = seed["pending"]
|
|
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
sha = hashlib.sha256(SEED.read_bytes()).hexdigest()
|
|
|
|
items = []
|
|
for it in pending:
|
|
cat = classify(it["evidence"])
|
|
items.append({
|
|
"id": it["id"],
|
|
"summary": it["summary"],
|
|
"category": cat,
|
|
"decision": "approve" if cat != "general" else "table",
|
|
"rationale": f"Evidence-keyword classification: {cat}.",
|
|
"evidence": it["evidence"],
|
|
})
|
|
|
|
dec_counts = {}
|
|
cat_counts = {}
|
|
for it in items:
|
|
dec_counts[it["decision"]] = dec_counts.get(it["decision"], 0) + 1
|
|
cat_counts[it["category"]] = cat_counts.get(it["category"], 0) + 1
|
|
|
|
# Decision categories are always reported, so a sink always appears as 0.
|
|
for _key in ("approve", "table", "reject"):
|
|
dec_counts.setdefault(_key, 0)
|
|
|
|
artifact = {
|
|
"artifact": "Triage-2026-10-30.json",
|
|
"source": "wizard-work/sol/seed-2026-10-29.json (frozen inbox probe set)",
|
|
"generated_at": now,
|
|
"checked_at": now,
|
|
"lane": "Triage - everyday Q&A and classification",
|
|
"pending_in_seed": len(pending),
|
|
"seed_sha256": sha,
|
|
"summary": "Independent re-derivation of the 8-item frozen seed "
|
|
"classification using a documented keyword rubric.",
|
|
"decision_counts": dec_counts,
|
|
"categories": cat_counts,
|
|
"items": items,
|
|
}
|
|
OUT.write_text(json.dumps(artifact, indent=2) + "\n", encoding="utf-8")
|
|
print(f"Wrote {OUT} ({len(items)} items)")
|
|
print(json.dumps({"decision_counts": dec_counts, "categories": cat_counts}, indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|