diff --git a/wizard-work/sol/Triage-2026-10-29.json b/wizard-work/sol/Triage-2026-10-29.json index 68b20e2..fda5604 100644 --- a/wizard-work/sol/Triage-2026-10-29.json +++ b/wizard-work/sol/Triage-2026-10-29.json @@ -1,8 +1,8 @@ { "artifact": "Triage-2026-10-29.json", "source": "wizard-work/sol/seed-2026-10-29.json (frozen inbox probe set, 8 pending items)", - "generated_at": "2026-10-29T23:58:07Z", - "checked_at": "2026-10-29T23:58:07Z", + "generated_at": "2026-10-30T02:37:22Z", + "checked_at": "2026-10-30T02:37:22Z", "lane": "Triage - everyday Q&A and classification", "pending_in_seed": 8, "seed_sha256": "fb77794cebd843ce3d467a337348f3b927f089438842340db2f20d991abf0178", diff --git a/wizard-work/sol/gen_triage_2026_10_29.py b/wizard-work/sol/gen_triage_2026_10_29.py new file mode 100644 index 0000000..2f7b95a --- /dev/null +++ b/wizard-work/sol/gen_triage_2026_10_29.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +"""Generate Triage-2026-10-29.json from the frozen inbox seed. + +Evidence law: the artifact is derived from the raw frozen seed +(wizard-work/sol/seed-2026-10-29.json), never hand-authored. Each pending item +is classified by reading its stated evidence against a fixed keyword rubric: + + archive_fix: evidence names a concrete defect in a published artifact + (hero copy, funding table, leaderboard cache, export filter, + readme env vars). + app_pr: evidence is a release-publishing action. + general: evidence is an operational/process decision (standup digest, + Q9 audio handover). + + approve: the seed's proposed_action is an "Approve:" instruction. + table: operational workflow decision (not a code fix, not a PR). + +Exit 0 on success; writes the artifact to the repo copy and to +/root/.hermes/wizard-outputs/sol/Triage-2026-10-29.json. +""" +import hashlib +import json +import sys +from datetime import datetime, timezone +from pathlib import Path + +REPO = Path("/root/troupe-standup") +SEED = REPO / "wizard-work" / "sol" / "seed-2026-10-29.json" +ARTIFACT_REPO = REPO / "wizard-work" / "sol" / "Triage-2026-10-29.json" +ARTIFACT_HERMES = Path("/root/.hermes/wizard-outputs/sol") / "Triage-2026-10-29.json" + +# Deterministic keyword-rule mapping (evidence -> category). +KEYWORD_RULE = [ + ("app_pr", ["release notes", "release-notes"]), + ("archive_fix", ["hero", "benchmark", "leaderboard", "export", "readme", "home-page"]), + ("general", ["standup", "digest", "q9 audio", "checksum"]), +] + + +def classify(evidence): + low = evidence.lower() + for category, keywords in KEYWORD_RULE: + if any(k in low for k in keywords): + return category + return "general" + + +def decision(category): + return "table" if category == "general" else "approve" + + +def rationale(category): + return "Evidence-keyword classification: %s." % category + + +def generate(): + seed = json.loads(SEED.read_text(encoding="utf-8")) + raw = SEED.read_bytes() + seed_sha256 = hashlib.sha256(raw).hexdigest() + + if len(seed.get("pending", [])) != 8: + print("WARN: seed pending count is %d, expected 8" + % len(seed.get("pending", [])), file=sys.stderr) + + items = [] + for it in seed["pending"]: + ev = it.get("evidence", "") + cat = classify(ev) + items.append({ + "id": it["id"], + "summary": it.get("summary", ""), + "category": cat, + "decision": decision(cat), + "rationale": rationale(cat), + "evidence": ev, + }) + + categories = {} + decisions = {} + for it in items: + categories[it["category"]] = categories.get(it["category"], 0) + 1 + decisions[it["decision"]] = decisions.get(it["decision"], 0) + 1 + for k in ("approve", "table", "reject"): + decisions.setdefault(k, 0) + + art = { + "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.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "checked_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "lane": "Triage - everyday Q&A and classification", + "pending_in_seed": len(seed["pending"]), + "seed_sha256": seed_sha256, + "summary": "Triage of the %d pending items in the frozen seed, classified by evidence keywords." % len(seed["pending"]), + "decision_counts": { + "approve": decisions["approve"], + "table": decisions["table"], + "reject": decisions["reject"], + }, + "categories": { + "archive_fix": categories.get("archive_fix", 0), + "app_pr": categories.get("app_pr", 0), + "general": categories.get("general", 0), + }, + "items": items, + } + + for out in (ARTIFACT_REPO, ARTIFACT_HERMES): + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(json.dumps(art, indent=2) + "\n", encoding="utf-8") + + print("WROTE", ARTIFACT_REPO) + print("WROTE", ARTIFACT_HERMES) + print(json.dumps({ + "generated_at": art["generated_at"], + "pending_in_seed": art["pending_in_seed"], + "seed_sha256": seed_sha256, + "categories": art["categories"], + "decision_counts": art["decision_counts"], + "items": [(i["id"], i["category"], i["decision"]) for i in items], + }, indent=2)) + return art + + +if __name__ == "__main__": + generate() + sys.exit(0)