From d0cec353654c57328e99f461abee373140ce9940 Mon Sep 17 00:00:00 2001 From: sol Date: Fri, 30 Oct 2026 22:50:26 +0000 Subject: [PATCH] sol: classify 2026-09-26 inbox seed - 13 items (archive_fix 7, app_pr 3, trial 2, decided_approved 1) --- wizard-work/sol/CHECK-sol-triage-seed-2026-09 | 73 ++++++++++++ wizard-work/sol/build_triage_seed.py | 74 +++++++++++++ wizard-work/sol/triage-seed-2026-09.json | 104 ++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100755 wizard-work/sol/CHECK-sol-triage-seed-2026-09 create mode 100644 wizard-work/sol/build_triage_seed.py create mode 100644 wizard-work/sol/triage-seed-2026-09.json diff --git a/wizard-work/sol/CHECK-sol-triage-seed-2026-09 b/wizard-work/sol/CHECK-sol-triage-seed-2026-09 new file mode 100755 index 0000000..7eae12e --- /dev/null +++ b/wizard-work/sol/CHECK-sol-triage-seed-2026-09 @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +"""CHECK-sol-triage-seed-2026-09 + +Verifies the triage classification artifact for the 2026-09-26 inbox seed. +Exits 0 when the artifact is present, valid JSON, internally consistent +(item_count == len(items) == sum(buckets)), and every item is classified +with a known bucket. Nonzero otherwise. +""" +import json +import os +import sys + +ART = '/root/troupe-standup/wizard-work/sol/triage-seed-2026-09.json' +ALLOWED_BUCKETS = {'archive_fix', 'push_branch', 'trial', 'decided_approved'} + + +def fail(msg): + print('FAIL: %s' % msg) + sys.exit(1) + + +def main(): + if not os.path.exists(ART): + fail('artifact missing: ' + ART) + try: + art = json.load(open(ART)) + except Exception as exc: + fail('artifact not valid JSON: %s' % exc) + + if not isinstance(art, dict): + fail('artifact top level is not an object') + for key in ('seed', 'buckets', 'item_count', 'items'): + if key not in art: + fail('missing key: %s' % key) + + buckets = art['buckets'] + items = art['items'] + if not isinstance(buckets, dict): + fail('buckets is not an object') + if not isinstance(items, list): + fail('items is not a list') + + for b, c in buckets.items(): + if b not in ALLOWED_BUCKETS: + fail('unknown bucket: %s' % b) + if not isinstance(c, int): + fail('bucket %s count not int' % b) + + if art.get('item_count') != len(items): + fail('item_count %r != len(items) %d' % (art.get('item_count'), len(items))) + + actual = {} + for it in items: + for key in ('id', 'bucket'): + if key not in it: + fail('item missing key %s' % key) + if it['bucket'] not in ALLOWED_BUCKETS: + fail('item id=%s unknown bucket %r' % (it.get('id'), it['bucket'])) + actual[it['bucket']] = actual.get(it['bucket'], 0) + 1 + + if actual != buckets: + fail('bucket counts recomputed %r != artifact %r' % (actual, buckets)) + + if sum(buckets.values()) != art.get('item_count'): + fail('sum(buckets) != item_count') + + print('OK: %s buckets=%s items=%d' % ( + os.path.basename(ART), json.dumps(buckets), len(items))) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/wizard-work/sol/build_triage_seed.py b/wizard-work/sol/build_triage_seed.py new file mode 100644 index 0000000..32d11ce --- /dev/null +++ b/wizard-work/sol/build_triage_seed.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +"""Generate a real triage classification artifact from the 2026-09-26 inbox seed. + +Classifies each seed entry deterministically by summary prefix: + - archive_fix : 'Archive fix: magazine-XXXX ...' publication corrections + - push_branch : 'Turd app: approve pushing branch ...' branch/PR requests + - trial : 'Trial by Timmy ...' or 'Q9: hand unreleased audio ...' + - decided_approved : already-decided approved items (in 'decided') +Writes wizard-work/sol/triage-seed-2026-09.json +""" +import json +import os + +BASE = '/root/troupe-standup' +SEED = os.path.join(BASE, 'inbox', 'seed-2026-09-26.json') +OUT = os.path.join(BASE, 'wizard-work', 'sol', 'triage-seed-2026-09.json') + +ALLOWED = {'archive_fix', 'push_branch', 'trial', 'decided_approved'} + + +def classify(item): + s = (item.get('summary') or '').lower() + if item.get('decision') == 'approved': + return 'decided_approved' + if s.startswith('archive fix'): + return 'archive_fix' + if s.startswith('turd app: approve'): + return 'push_branch' + if s.startswith('trial by timmy') or s.startswith('q9: hand unreleased audio'): + return 'trial' + return 'unclassified' + + +def main(): + d = json.load(open(SEED)) + items = [] + for it in d.get('decided', []): + items.append({ + 'id': it.get('id'), + 'bucket': classify(it), + 'kind': 'decided', + 'summary': it.get('summary'), + 'reason': 'already-decided approved item', + }) + for it in d.get('pending', []): + b = classify(it) + if b not in ALLOWED: + raise SystemExit('unclassified id=%s: %s' % (it.get('id'), it.get('summary'))) + items.append({ + 'id': it.get('id'), + 'bucket': b, + 'kind': 'pending', + 'summary': it.get('summary'), + 'reason': 'summary prefix matched %s' % b, + }) + + buckets = {} + for it in items: + buckets[it['bucket']] = buckets.get(it['bucket'], 0) + 1 + + art = { + 'seed': os.path.basename(SEED), + 'source': os.path.join('inbox', 'seed-2026-09-26.json'), + 'buckets': buckets, + 'item_count': len(items), + 'items': items, + } + os.makedirs(os.path.dirname(OUT), exist_ok=True) + json.dump(art, open(OUT, 'w'), indent=2) + print(json.dumps({'buckets': buckets, 'item_count': len(items)})) + + +if __name__ == '__main__': + main() diff --git a/wizard-work/sol/triage-seed-2026-09.json b/wizard-work/sol/triage-seed-2026-09.json new file mode 100644 index 0000000..6163639 --- /dev/null +++ b/wizard-work/sol/triage-seed-2026-09.json @@ -0,0 +1,104 @@ +{ + "seed": "seed-2026-09-26.json", + "source": "inbox/seed-2026-09-26.json", + "buckets": { + "decided_approved": 1, + "archive_fix": 7, + "push_branch": 3, + "trial": 2 + }, + "item_count": 13, + "items": [ + { + "id": 13, + "bucket": "decided_approved", + "kind": "decided", + "summary": "Archive fix: magazine-091 lists Strategy among compared firms", + "reason": "already-decided approved item" + }, + { + "id": 1, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-021 says only Loko and Happy responded", + "reason": "summary prefix matched archive_fix" + }, + { + "id": 2, + "bucket": "push_branch", + "kind": "pending", + "summary": "Turd app: approve pushing branch zephyrus/62-symptom-escalation-regression", + "reason": "summary prefix matched push_branch" + }, + { + "id": 3, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-011 calls John the 'founder' of Proof of Ink", + "reason": "summary prefix matched archive_fix" + }, + { + "id": 4, + "bucket": "push_branch", + "kind": "pending", + "summary": "Turd app: approve submitting the a11y PR from zephyrus/65-a11y-gates", + "reason": "summary prefix matched push_branch" + }, + { + "id": 5, + "bucket": "push_branch", + "kind": "pending", + "summary": "Turd app: approve pushing branch zephyrus/67-hard-stool-followup", + "reason": "summary prefix matched push_branch" + }, + { + "id": 6, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-011 says merch was made for the Boston Bitcoin Festival", + "reason": "summary prefix matched archive_fix" + }, + { + "id": 7, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-061 misattributes the centerfold reference", + "reason": "summary prefix matched archive_fix" + }, + { + "id": 8, + "bucket": "trial", + "kind": "pending", + "summary": "Trial by Timmy: send Timmy the local-inference trial brief for your Mac", + "reason": "summary prefix matched trial" + }, + { + "id": 9, + "bucket": "trial", + "kind": "pending", + "summary": "Q9: hand unreleased audio to Timmy under checksum for independent QC", + "reason": "summary prefix matched trial" + }, + { + "id": 10, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-061 claims a 'weekly Thursday intelligence-style cadence'", + "reason": "summary prefix matched archive_fix" + }, + { + "id": 11, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-040 'last block he mined' sentence replacement", + "reason": "summary prefix matched archive_fix" + }, + { + "id": 12, + "bucket": "archive_fix", + "kind": "pending", + "summary": "Archive fix: magazine-041 calls it 'Stackchain's rowdiest fork war'", + "reason": "summary prefix matched archive_fix" + } + ] +} \ No newline at end of file