Files
troupe-standup/wizard-work/sol/library_drop_classify.py
T

47 lines
1.8 KiB
Python

#!/usr/bin/env python3
"""library_drop_classify.py
Re-derive the library-drop triage roster from drops/*/MANIFEST.md. Deterministic;
used by _check_library_drop_roster.sh to diff against the committed
library-drop-roster.json. Exits 0 only if the committed roster matches the
source manifests.
"""
import json
import os
import re
import sys
BASE = '/root/stackchain-library-updates/drops'
def classify(txt):
# Ordered, low-level rules first.
if 'HTTP 402' in txt or 'Insufficient Balance' in txt:
return 'blocked', 'HTTP 402 / Insufficient Balance'
if 'prepared and delivered to Telegram review' in txt and 'not posted' in txt.lower():
return 'prepared_not_posted', 'prepared_and_delivered + not_posted'
if ('**PUBLISHED**' in txt) or ('**PUBLISHED.**' in txt) or ('PUBLISHED by Alexander' in txt) \
or re.search(r'PUBLISHED\.\*\*\s+Posted', txt):
return 'published', 'Status: PUBLISHED / Published by Alexander'
if ('No public change' in txt) or ('No episode' in txt) or ('NOT PUBLISHED' in txt) \
or ('Nothing on the site' in txt) or ('not published' in txt.lower()) \
or ('unpublished' in txt.lower()) or ('public change' in txt.lower() and 'none' in txt.lower()):
return 'no_episode', 'no-public-change / not-unpublished'
return 'unclassified', 'unclassified'
def main():
dirs = sorted([d for d in os.listdir(BASE)
if d.startswith('2026-') and os.path.isdir(os.path.join(BASE, d))])
rows = []
for d in dirs:
txt = open(os.path.join(BASE, d, 'MANIFEST.md'), encoding='utf-8',
errors='replace').read()
bucket, matched = classify(txt)
rows.append({'dir': d, 'bucket': bucket, 'matched': matched})
json.dump(rows, sys.stdout, indent=1)
if __name__ == '__main__':
main()