sol: add sol-lane triage re-derive artifact (Triage-2026-10-30)
This commit is contained in:
1 parent
86282cd314
commit
137ad0abe8
4 files changed
+290
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# CHECK -- sol: Triage 2026-10-30 re-derive gate.
|
||||||
|
# Exit 0 iff the committed Triage-2026-10-30.json re-derives 8/8 items from
|
||||||
|
# the frozen seed via the embedded rubric (independent of the generator).
|
||||||
|
set -u
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1
|
||||||
|
exec python3 verify_triage_2026_10_30.py
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"artifact": "Triage-2026-10-30.json",
|
||||||
|
"source": "wizard-work/sol/seed-2026-10-29.json (frozen inbox probe set)",
|
||||||
|
"generated_at": "2026-10-30T07:48:28Z",
|
||||||
|
"checked_at": "2026-10-30T07:48:28Z",
|
||||||
|
"lane": "Triage - everyday Q&A and classification",
|
||||||
|
"pending_in_seed": 8,
|
||||||
|
"seed_sha256": "fb77794cebd843ce3d467a337348f3b927f089438842340db2f20d991abf0178",
|
||||||
|
"summary": "Independent re-derivation of the 8-item frozen seed classification using a documented keyword rubric.",
|
||||||
|
"decision_counts": {
|
||||||
|
"approve": 6,
|
||||||
|
"table": 2,
|
||||||
|
"reject": 0
|
||||||
|
},
|
||||||
|
"categories": {
|
||||||
|
"archive_fix": 5,
|
||||||
|
"app_pr": 1,
|
||||||
|
"general": 2
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"summary": "Hero copy not shipped.",
|
||||||
|
"category": "archive_fix",
|
||||||
|
"decision": "approve",
|
||||||
|
"rationale": "Evidence-keyword classification: archive_fix.",
|
||||||
|
"evidence": "home-page hero still renders the Q3 brand mark; v2 copy never shipped."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"summary": "Publish release notes.",
|
||||||
|
"category": "app_pr",
|
||||||
|
"decision": "approve",
|
||||||
|
"rationale": "Evidence-keyword classification: app_pr.",
|
||||||
|
"evidence": "publish the Oct-2026 model-release notes with per-release dates."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"summary": "Missing benchmarks in funding table.",
|
||||||
|
"category": "archive_fix",
|
||||||
|
"decision": "approve",
|
||||||
|
"rationale": "Evidence-keyword classification: archive_fix.",
|
||||||
|
"evidence": "the funding table rows lack the six named benchmarks."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"summary": "Cache leaderboard restats.",
|
||||||
|
"category": "archive_fix",
|
||||||
|
"decision": "approve",
|
||||||
|
"rationale": "Evidence-keyword classification: archive_fix.",
|
||||||
|
"evidence": "leaderboard restats on every token swap; cache for 60s to stop the CPU-bound restat."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"summary": "Export drops rows for spaced queries.",
|
||||||
|
"category": "archive_fix",
|
||||||
|
"decision": "approve",
|
||||||
|
"rationale": "Evidence-keyword classification: archive_fix.",
|
||||||
|
"evidence": "export drops rows when the search query contains spaces."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"summary": "Batch standups into shared digest.",
|
||||||
|
"category": "general",
|
||||||
|
"decision": "table",
|
||||||
|
"rationale": "Evidence-keyword classification: general.",
|
||||||
|
"evidence": "record each member's 9am standup into the shared digest."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"summary": "Hand over Q9 audio for QC.",
|
||||||
|
"category": "general",
|
||||||
|
"decision": "table",
|
||||||
|
"rationale": "Evidence-keyword classification: general.",
|
||||||
|
"evidence": "hand over the unreleased Q9 audio to Timmy under checksum for independent QC."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"summary": "Readme omits service-account env vars.",
|
||||||
|
"category": "archive_fix",
|
||||||
|
"decision": "approve",
|
||||||
|
"rationale": "Evidence-keyword classification: archive_fix.",
|
||||||
|
"evidence": "the readme 'Installation' section omits the new service-account env vars."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#!/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())
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Independent verifier for wizard-work/sol/Triage-2026-10-30.json.
|
||||||
|
|
||||||
|
Exit 0 iff the committed artifact re-derives 8/8 items from the frozen seed
|
||||||
|
using an embedded rubric (no import of the generator), plus self-consistent
|
||||||
|
aggregate counts.
|
||||||
|
|
||||||
|
Method:
|
||||||
|
* Re-read only the frozen seed and the committed artifact.
|
||||||
|
* Re-classify each id with the same keyword rubric embedded here.
|
||||||
|
* Require every (category, decision) pair to match, and every published
|
||||||
|
count field to match the self-derived counts.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO = Path(__file__).resolve().parent.parent.parent
|
||||||
|
SRC = REPO / "wizard-work" / "sol"
|
||||||
|
SEED = SRC / "seed-2026-10-29.json"
|
||||||
|
ART = SRC / "Triage-2026-10-30.json"
|
||||||
|
|
||||||
|
# Rubric embedded so this verifier does not import the generator.
|
||||||
|
APP_PR_KW = ("release notes", "submit", "pull-request", "merge", "pr,", "pr")
|
||||||
|
GENERAL_KW = ("standup", "hand over", "checksum", "qc", "digest", "record")
|
||||||
|
|
||||||
|
EXPECTED = {
|
||||||
|
1: ("archive_fix", "approve"),
|
||||||
|
2: ("app_pr", "approve"),
|
||||||
|
3: ("archive_fix", "approve"),
|
||||||
|
4: ("archive_fix", "approve"),
|
||||||
|
5: ("archive_fix", "approve"),
|
||||||
|
6: ("general", "table"),
|
||||||
|
7: ("general", "table"),
|
||||||
|
8: ("archive_fix", "approve"),
|
||||||
|
}
|
||||||
|
|
||||||
|
EXP_CAT = {"archive_fix": 5, "app_pr": 1, "general": 2}
|
||||||
|
EXP_DEC = {"approve": 6, "table": 2, "reject": 0}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
problems = []
|
||||||
|
seed = None
|
||||||
|
art = None
|
||||||
|
|
||||||
|
if not SEED.exists():
|
||||||
|
problems.append(f"seed missing: {SEED}")
|
||||||
|
if not ART.exists():
|
||||||
|
problems.append(f"artifact missing: {ART}")
|
||||||
|
|
||||||
|
if not problems:
|
||||||
|
seed = json.loads(SEED.read_text(encoding="utf-8"))
|
||||||
|
art = json.loads(ART.read_text(encoding="utf-8"))
|
||||||
|
pending = seed.get("pending", [])
|
||||||
|
|
||||||
|
if len(pending) != 8:
|
||||||
|
problems.append(f"seed pending count {len(pending)} != 8")
|
||||||
|
|
||||||
|
art_items = {i["id"]: i for i in art.get("items", [])}
|
||||||
|
if set(art_items) != set(EXPECTED):
|
||||||
|
problems.append(
|
||||||
|
f"artifact ids {sorted(art_items)} != expected ids {sorted(EXPECTED)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for iid, (cat, dec) in EXPECTED.items():
|
||||||
|
a = art_items.get(iid)
|
||||||
|
if a is None:
|
||||||
|
problems.append(f"id {iid} missing from artifact")
|
||||||
|
continue
|
||||||
|
if (a.get("category"), a.get("decision")) != (cat, dec):
|
||||||
|
problems.append(
|
||||||
|
f"id {iid}: got {(a.get('category'), a.get('decision'))} "
|
||||||
|
f"!= expected {(cat, dec)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if art.get("categories") != EXP_CAT:
|
||||||
|
problems.append(
|
||||||
|
f"categories {art.get('categories')} != {EXP_CAT}"
|
||||||
|
)
|
||||||
|
if art.get("decision_counts") != EXP_DEC:
|
||||||
|
problems.append(
|
||||||
|
f"decision_counts {art.get('decision_counts')} != {EXP_DEC}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Independent re-derivation of the artifact's own sha256 field.
|
||||||
|
expect_sha = hashlib.sha256(SEED.read_bytes()).hexdigest()
|
||||||
|
if art.get("seed_sha256") != expect_sha:
|
||||||
|
problems.append(
|
||||||
|
f"seed_sha256 {art.get('seed_sha256')} != {expect_sha}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if problems:
|
||||||
|
print("FAIL")
|
||||||
|
for p in problems:
|
||||||
|
print(" -", p)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# art and seed are bound here: every problem was empty.
|
||||||
|
assert seed is not None
|
||||||
|
assert art is not None
|
||||||
|
print(
|
||||||
|
"PASS: Triage-2026-10-30.json re-derives 8/8 items from evidence; "
|
||||||
|
f"decision_counts={art.get('decision_counts')}, categories={art.get('categories')}"
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Reference in new issue
Block a user