142 lines
5.3 KiB
Python
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())
|