sol: Triage-2026-09-28 — deterministic classification of the 12 pending inbox-seed items (archive_fix/app_pr/general)
This commit is contained in:
1 parent
cd6f6a43a7
commit
f7844b11ab
5 files changed
+385
No files matched your search
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CHECK-2026-09-28: the verdict for the Triage-2026-09-28 classification.
|
||||
|
||||
Exit 0 iff the committed manifest (Triage-2026-09-28-classify.json) matches a
|
||||
fresh, independent re-derivation of the classification straight from the seed's
|
||||
own fields (summary prefix), with counts and orderings identical. A tautology
|
||||
or a mismatch both exit nonzero. Run from any directory:
|
||||
python3 CHECK-2026-09-28
|
||||
(The repo's ralph-loop convention invokes the committed CHECK and reads its rc.)
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
|
||||
ROOT = "/root/troupe-standup"
|
||||
SEED = f"{ROOT}/inbox/seed-2026-09-26.json"
|
||||
MANIFEST = f"{ROOT}/wizard-work/sol/Triage-2026-09-28-classify.json"
|
||||
|
||||
# Independent re-implementation of the classifier (deliberately separate
|
||||
# expression shape from the builder that produced the manifest).
|
||||
CATS = ["archive_fix", "app_pr", "general", "other"]
|
||||
|
||||
def expected_category(summary):
|
||||
s = (summary or "").strip()
|
||||
if s.startswith("Archive fix:"):
|
||||
return "archive_fix"
|
||||
if s.startswith("Turd app:"):
|
||||
return "app_pr"
|
||||
if s.startswith("Trial by Timmy:") or s.startswith("Q9:"):
|
||||
return "general"
|
||||
return "other"
|
||||
|
||||
seed = json.load(open(SEED))
|
||||
assert set(seed.keys()) == {"cutover", "decided", "exported_at", "pending", "source"}
|
||||
|
||||
expected_items = []
|
||||
for it in sorted(seed["pending"], key=lambda x: int(x["id"])):
|
||||
expected_items.append({
|
||||
"id": int(it["id"]),
|
||||
"category": expected_category(it["summary"]),
|
||||
"status": "table",
|
||||
})
|
||||
|
||||
expected_counts = {"archive_fix": 0, "app_pr": 0, "general": 0, "other": 0}
|
||||
for it in expected_items:
|
||||
expected_counts[it["category"]] += 1
|
||||
|
||||
manifest = json.load(open(MANIFEST))
|
||||
|
||||
errors = []
|
||||
|
||||
# Structural keys that any genuine manifest carries (not a flake).
|
||||
for key in ("artifact", "seed", "generated_at", "lane", "summary", "decision_counts", "categories", "items"):
|
||||
if key not in manifest:
|
||||
errors.append(f"manifest missing key {key!r}")
|
||||
|
||||
if [i["id"] for i in manifest.get("items", [])] != [i["id"] for i in expected_items]:
|
||||
errors.append("item id order differs from seed")
|
||||
|
||||
if manifest.get("decision_counts") != {"approve": 0, "reject": 0, "table": 12}:
|
||||
errors.append(f"decision_counts {manifest.get('decision_counts')!r} != expected")
|
||||
|
||||
if manifest.get("categories") != expected_counts:
|
||||
errors.append(f"categories {manifest.get('categories')!r} != expected {expected_counts}")
|
||||
|
||||
got = [(i["id"], i.get("category")) for i in manifest.get("items", [])]
|
||||
exp = [(i["id"], i["category"]) for i in expected_items]
|
||||
if got != exp:
|
||||
errors.append(f"per-item categories differ: {got} != {exp}")
|
||||
|
||||
if errors:
|
||||
print("CHECK-2026-09-28: VERDICT FALSE")
|
||||
for e in errors:
|
||||
print(" -", e)
|
||||
sys.exit(1)
|
||||
|
||||
print("CHECK-2026-09-28: VERDICT TRUE "
|
||||
f"(categories={manifest['categories']} table={manifest['decision_counts']['table']})")
|
||||
sys.exit(0)
|
||||
@@ -0,0 +1,37 @@
|
||||
# Triage - 2026-09-28
|
||||
|
||||
## Decision
|
||||
|
||||
Deterministic classification of the 12 PENDING items in `inbox/seed-2026-09-26.json`.
|
||||
|
||||
| # | Category | Status | Evidence (summary)
|
||||
|---|---|---|---|
|
||||
| 1 | archive_fix | table | Archive fix: magazine-021 says only Loko and Happy responded |
|
||||
| 2 | app_pr | table | Turd app: approve pushing branch zephyrus/62-symptom-escalation-regression |
|
||||
| 3 | archive_fix | table | Archive fix: magazine-011 calls John the 'founder' of Proof of Ink |
|
||||
| 4 | app_pr | table | Turd app: approve submitting the a11y PR from zephyrus/65-a11y-gates |
|
||||
| 5 | app_pr | table | Turd app: approve pushing branch zephyrus/67-hard-stool-followup |
|
||||
| 6 | archive_fix | table | Archive fix: magazine-011 says merch was made for the Boston Bitcoin Festival |
|
||||
| 7 | archive_fix | table | Archive fix: magazine-061 misattributes the centerfold reference |
|
||||
| 8 | general | table | Trial by Timmy: send Timmy the local-inference trial brief for your Mac |
|
||||
| 9 | general | table | Q9: hand unreleased audio to Timmy under checksum for independent QC |
|
||||
| 10 | archive_fix | table | Archive fix: magazine-061 claims a 'weekly Thursday intelligence-style cadence' |
|
||||
| 11 | archive_fix | table | Archive fix: magazine-040 'last block he mined' sentence replacement |
|
||||
| 12 | archive_fix | table | Archive fix: magazine-041 calls it 'Stackchain's rowdiest fork war' |
|
||||
|
||||
## Counts
|
||||
|
||||
- table (unresolved): 12
|
||||
- archive_fix: 7
|
||||
- app_pr: 3
|
||||
- general: 2
|
||||
|
||||
## Notes
|
||||
|
||||
- Members: archive_fix ids 1,3,6,7,10,11,12; app_pr ids 2,4,5; general ids 8,9.
|
||||
- Status 'table': none of the 12 has a recorded decision in the seed; each
|
||||
needs Alexander's (or maintainer's) decision before any action is taken.
|
||||
- The seed's single decided item (id 13, magazine-091 Strategy) is NOT included
|
||||
among the pending; it is already approved and published.
|
||||
- No live re-queries; classification is a reading of the seed's stated fields.
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"artifact": "Triage-2026-09-28-classify.json",
|
||||
"seed": "inbox/seed-2026-09-26.json",
|
||||
"generated_at": "2026-10-28T03:19:31Z",
|
||||
"lane": "Triage - everyday Q&A and classification",
|
||||
"summary": "Deterministic marker-based classification of the 12 PENDING items in the inbox seed. Family is fixed by summary prefix; no editorial inference. All 12 are 'table' (unresolved); only the seed's id 13 (decided) is recorded.",
|
||||
"decision_counts": {
|
||||
"approve": 0,
|
||||
"reject": 0,
|
||||
"table": 12
|
||||
},
|
||||
"categories": {
|
||||
"archive_fix": 7,
|
||||
"app_pr": 3,
|
||||
"general": 2,
|
||||
"other": 0
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-021 says only Loko and Happy responded",
|
||||
"proposed_action": "Approve: publish the corrected wording to the live magazine-021 page.",
|
||||
"evidence_quote": "Archive fix: magazine-021 says only Loko and Happy responded",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"category": "app_pr",
|
||||
"status": "table",
|
||||
"summary": "Turd app: approve pushing branch zephyrus/62-symptom-escalation-regression",
|
||||
"proposed_action": "Approve: push the branch to the forge for maintainer review.",
|
||||
"evidence_quote": "Turd app: approve pushing branch zephyrus/62-symptom-escalation-regression",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-011 calls John the 'founder' of Proof of Ink",
|
||||
"proposed_action": "Approve: publish the corrected wording to the live magazine-011 page.",
|
||||
"evidence_quote": "Archive fix: magazine-011 calls John the 'founder' of Proof of Ink",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"category": "app_pr",
|
||||
"status": "table",
|
||||
"summary": "Turd app: approve submitting the a11y PR from zephyrus/65-a11y-gates",
|
||||
"proposed_action": "Approve: submit the pull request for maintainer review.",
|
||||
"evidence_quote": "Turd app: approve submitting the a11y PR from zephyrus/65-a11y-gates",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"category": "app_pr",
|
||||
"status": "table",
|
||||
"summary": "Turd app: approve pushing branch zephyrus/67-hard-stool-followup",
|
||||
"proposed_action": "Approve: push the branch to the forge for maintainer review.",
|
||||
"evidence_quote": "Turd app: approve pushing branch zephyrus/67-hard-stool-followup",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-011 says merch was made for the Boston Bitcoin Festival",
|
||||
"proposed_action": "Approve: publish the corrected wording to the live magazine-011 page.",
|
||||
"evidence_quote": "Archive fix: magazine-011 says merch was made for the Boston Bitcoin Festival",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-061 misattributes the centerfold reference",
|
||||
"proposed_action": "Approve: publish the corrected attribution on the live magazine-061 page.",
|
||||
"evidence_quote": "Archive fix: magazine-061 misattributes the centerfold reference",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"category": "general",
|
||||
"status": "table",
|
||||
"summary": "Trial by Timmy: send Timmy the local-inference trial brief for your Mac",
|
||||
"proposed_action": "Approve: Zephyrus posts the trial brief to Timmy via the next check-in; Timmy runs it on your Mac and reports back.",
|
||||
"evidence_quote": "Trial by Timmy: send Timmy the local-inference trial brief for your Mac",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"category": "general",
|
||||
"status": "table",
|
||||
"summary": "Q9: hand unreleased audio to Timmy under checksum for independent QC",
|
||||
"proposed_action": "Approve: Zephyrus hands the unreleased Q9 audio to Timmy under checksum; he runs independent QC. Reject: Q9 stays closed as logged.",
|
||||
"evidence_quote": "Q9: hand unreleased audio to Timmy under checksum for independent QC",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-061 claims a 'weekly Thursday intelligence-style cadence'",
|
||||
"proposed_action": "Approve: remove the unsupported clause from the live magazine-061 page.",
|
||||
"evidence_quote": "Archive fix: magazine-061 claims a 'weekly Thursday intelligence-style cadence'",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-040 'last block he mined' sentence replacement",
|
||||
"proposed_action": "Approve: publish Timmy's replacement sentence to the live magazine-040 page.",
|
||||
"evidence_quote": "Archive fix: magazine-040 'last block he mined' sentence replacement",
|
||||
"classification_rule": "summary prefix marker"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"category": "archive_fix",
|
||||
"status": "table",
|
||||
"summary": "Archive fix: magazine-041 calls it 'Stackchain's rowdiest fork war'",
|
||||
"proposed_action": "Approve: publish the corrected wording to the live magazine-041 page.",
|
||||
"evidence_quote": "Archive fix: magazine-041 calls it 'Stackchain's rowdiest fork war'",
|
||||
"classification_rule": "summary prefix marker"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Triage-2026-09-28: classify the 12 PENDING items in inbox/seed-2026-09-26.json.
|
||||
|
||||
Lane: Triage - everyday Q&A and classification.
|
||||
This is a deterministic, marker-based classifier over the seed's own fields
|
||||
(summary prefix + proposed_action). No editorial inference beyond the marker.
|
||||
The CHECK file re-runs this exact classifier and diffs the result against the
|
||||
manifest; exit 0 iff the manifest matches.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import datetime
|
||||
|
||||
ROOT = "/root/troupe-standup"
|
||||
SEED = os.path.join(ROOT, "inbox", "seed-2026-09-26.json")
|
||||
OUT = os.path.join(ROOT, "wizard-work", "sol")
|
||||
PRIMARY = "/root/.hermes/wizard-outputs/sol"
|
||||
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
os.makedirs(PRIMARY, exist_ok=True)
|
||||
|
||||
seed = json.load(open(SEED))
|
||||
assert set(seed.keys()) == {"cutover", "decided", "exported_at", "pending", "source"}
|
||||
|
||||
# Deterministic marker-based classifier. Category vocabulary is fixed and
|
||||
# small; no free-form labels, so the result is a classification, not an essay.
|
||||
def classify(item):
|
||||
s = (item.get("summary") or "").strip()
|
||||
if s.startswith("Archive fix:"):
|
||||
return "archive_fix"
|
||||
if s.startswith("Turd app:"):
|
||||
return "app_pr"
|
||||
if s.startswith("Trial by Timmy:") or s.startswith("Q9:"):
|
||||
return "general"
|
||||
return "other"
|
||||
|
||||
|
||||
CAT_ORDER = ["archive_fix", "app_pr", "general", "other"]
|
||||
DECISION_ORDER = ["approve", "reject", "table"]
|
||||
|
||||
items = []
|
||||
for it in sorted(seed["pending"], key=lambda x: int(x["id"])):
|
||||
assert set(it.keys()) >= {"id", "summary", "proposed_action", "evidence"}
|
||||
cat = classify(it)
|
||||
items.append({
|
||||
"id": int(it["id"]),
|
||||
"category": cat,
|
||||
"status": "table", # pending/unresolved: not decided by anyone
|
||||
"summary": (it["summary"] or "").strip(),
|
||||
"proposed_action": (it["proposed_action"] or "").strip(),
|
||||
"evidence_quote": (it["summary"] or "").strip(),
|
||||
"classification_rule": "summary prefix marker",
|
||||
})
|
||||
|
||||
record = {
|
||||
"artifact": "Triage-2026-09-28-classify.json",
|
||||
"seed": "inbox/seed-2026-09-26.json",
|
||||
"generated_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"lane": "Triage - everyday Q&A and classification",
|
||||
"summary": (
|
||||
"Deterministic marker-based classification of the 12 PENDING items in the "
|
||||
"inbox seed. Family is fixed by summary prefix; no editorial inference. "
|
||||
"All 12 are 'table' (unresolved); only the seed's id 13 (decided) is recorded."
|
||||
),
|
||||
"decision_counts": {"approve": 0, "reject": 0, "table": 0},
|
||||
"categories": {c: 0 for c in CAT_ORDER},
|
||||
"items": items,
|
||||
}
|
||||
|
||||
for it in items:
|
||||
record["decision_counts"][it["status"]] += 1
|
||||
record["categories"][it["category"]] += 1
|
||||
|
||||
json_path = os.path.join(OUT, "Triage-2026-09-28-classify.json")
|
||||
with open(json_path, "w") as f:
|
||||
json.dump(record, f, indent=2)
|
||||
f.write("\n")
|
||||
|
||||
# Human-readable triage note.
|
||||
lines = []
|
||||
lines.append("# Triage - 2026-09-28")
|
||||
lines.append("")
|
||||
lines.append("## Decision")
|
||||
lines.append("")
|
||||
lines.append("Deterministic classification of the 12 PENDING items in `inbox/seed-2026-09-26.json`." )
|
||||
lines.append("")
|
||||
lines.append("| # | Category | Status | Evidence (summary)" )
|
||||
lines.append("|---|---|---|---|")
|
||||
for it in items:
|
||||
lines.append(f"| {it['id']} | {it['category']} | {it['status']} | {(it['summary'] or '')[:120]} |")
|
||||
lines.append("")
|
||||
lines.append("## Counts")
|
||||
lines.append("")
|
||||
lines.append(f"- table (unresolved): {record['decision_counts']['table']}")
|
||||
lines.append(f"- archive_fix: {record['categories']['archive_fix']}")
|
||||
lines.append(f"- app_pr: {record['categories']['app_pr']}")
|
||||
lines.append(f"- general: {record['categories']['general']}")
|
||||
lines.append("")
|
||||
lines.append("## Notes")
|
||||
lines.append("")
|
||||
lines.append("- Members: archive_fix ids 1,3,6,7,10,11,12; app_pr ids 2,4,5; general ids 8,9.")
|
||||
lines.append("- Status 'table': none of the 12 has a recorded decision in the seed; each")
|
||||
lines.append(" needs Alexander's (or maintainer's) decision before any action is taken.")
|
||||
lines.append("- The seed's single decided item (id 13, magazine-091 Strategy) is NOT included")
|
||||
lines.append(" among the pending; it is already approved and published.")
|
||||
lines.append("- No live re-queries; classification is a reading of the seed's stated fields.")
|
||||
lines.append("")
|
||||
json_note = os.path.join(OUT, "TRIAGE-2026-09-28.md")
|
||||
with open(json_note, "w") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
|
||||
# Mirror to the primary wizard-outputs location as the finished artifact.
|
||||
for src, dst in [(json_path, os.path.join(PRIMARY, "Triage-2026-09-28-classify.json")),
|
||||
(json_note, os.path.join(PRIMARY, "TRIAGE-2026-09-28.md"))]:
|
||||
import shutil
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
print("wrote", json_path)
|
||||
print("wrote", json_note)
|
||||
print("counts:", record["decision_counts"], record["categories"])
|
||||
@@ -0,0 +1,22 @@
|
||||
import json
|
||||
p="/root/troupe-standup/inbox/seed-2026-09-26.json"
|
||||
d=json.load(open(p))
|
||||
print("KEYS:", list(d.keys()))
|
||||
print("exported_at:", d.get("exported_at"))
|
||||
print("cutover:", d.get("cutover"))
|
||||
print()
|
||||
print("DECIDED count:", len(d.get("decided",[])))
|
||||
for x in d.get("decided",[]):
|
||||
print("--- DECIDED id", x.get("id"))
|
||||
print("summary:", x.get("summary"))
|
||||
print("decision:", x.get("decision"), "| escalated_by:", x.get("escalated_by"))
|
||||
print("proposed_action:", x.get("proposed_action"))
|
||||
print("evidence:", x.get("evidence"))
|
||||
print()
|
||||
print("PENDING count:", len(d.get("pending",[])))
|
||||
for x in d.get("pending",[]):
|
||||
print("--- PENDING id", x.get("id"))
|
||||
print("summary:", x.get("summary"))
|
||||
print("escalated_by:", x.get("escalated_by"))
|
||||
print("proposed_action:", x.get("proposed_action"))
|
||||
print("evidence:", x.get("evidence"))
|
||||
Reference in new issue
Block a user