Files

114 lines
4.1 KiB
Bash

#!/usr/bin/env bash
# Verify the queue status index reproduces from WORK-QUEUE.md.
# Exit 0 = correct, nonzero = wrong.
set -u
Q=/root/troupe-standup/WORK-QUEUE.md
J=/root/troupe-standup/wizard-work/sol/queue-status-index.json
M=/root/troupe-standup/wizard-work/sol/queue-status-index.md
[ -f "$Q" ] || { echo "MISSING $Q"; exit 1; }
[ -f "$J" ] || { echo "MISSING $J"; exit 1; }
python3 - "$Q" "$J" <<'PY'
import json, re, sys, collections
qpath, jpath = sys.argv[1], sys.argv[2]
lines = open(qpath, encoding="utf-8").read().split("\n")
N = len(lines)
heads = [(i, ln) for i, ln in enumerate(lines, 1) if re.match(r"^##\s+\S", ln)]
ITEM_RE = re.compile(r"^##\s+Q(\d+)\s+(?!closure\b)(?=[—–-]|[A-Za-z0-9])")
def clean(txt):
return re.sub(r"\*\*", "", txt).strip()
def extract(block):
for idx, bl in enumerate(block):
m = re.match(r"^\s*\*\*Status:\s*(.*)$", bl)
if not m:
continue
raw = m.group(1)
prim = re.match(r"^\s*\*\*Status:\s*(.*?)\*\*", bl)
if prim and prim.group(1) and prim.group(1).find("**") == -1:
return clean(prim.group(1)), idx, True
txt = raw
for b2 in block[idx+1:]:
txt += "\n" + b2
if b2.rstrip().endswith("**"):
break
return clean(txt), idx, True
return None, None, False
def cat(text):
if text is None: return "NO-MARKER"
low = text.lower()
if "falsified" in low: return "FALSIFIED"
if "verified" in low and "closed" in low: return "VERIFIED-CLOSED"
if "unclaimed" in low: return "UNCLAIMED"
if "resolved" in low: return "RESOLVED"
if "re-scoped" in low or "closed" in low: return "CLOSED"
if "satisfied" in low: return "DONE"
if "decision" in low or "pending" in low or "undecided" in low: return "OPEN"
if "open" in low: return "OPEN"
if "done" in low or "complete" in low: return "DONE"
return "UNSPECIFIED"
def section(a, b):
return lines[a-1:b-1]
expected = []
for hi, (i, head) in enumerate(heads):
mm = ITEM_RE.match(head)
if not mm: continue
q = int(mm.group(1))
nxt = heads[hi+1][0] if hi+1 < len(heads) else N + 1
st, _, found = extract(section(i, nxt))
expected.append({"q": q, "expected_category": cat(st), "found": found, "status": st})
data = json.load(open(jpath, encoding="utf-8"))
items = data.get("items", [])
errors = []
if data.get("total_items") != len(expected):
errors.append(f"total_items {data.get('total_items')} != re-derived {len(expected)}")
for e, rec in zip(expected, items):
if rec.get("q") != e["q"]:
errors.append(f"q mismatch {rec.get('q')} vs {e['q']}")
continue
if rec.get("category") != e["expected_category"]:
errors.append(f"Q{e['q']}: category {rec.get('category')} != {e['expected_category']}")
if rec.get("status") != e["status"]:
errors.append(f"Q{e['q']}: status text mismatch")
if rec.get("found") != e["found"]:
errors.append(f"Q{e['q']}: found mismatch")
if errors:
print("VERIFY FAIL:")
for e2 in errors:
print(" -", e2)
sys.exit(1)
print(f"VERIFY OK: {len(expected)} items, categories {dict(collections.Counter(e['expected_category'] for e in expected))}")
PY
rc=$?
if [ $rc -ne 0 ]; then exit $rc; fi
python3 - "$Q" <<'PY'
import re, sys
lines = open(sys.argv[1], encoding="utf-8").read().split("\n")
states = {"CLOSED":0, "DONE":0, "RESOLVED":0, "UNCLAIMED":0, "OPEN":0, "NO-MARKER":0, "FALSIFIED":0, "VERIFIED-CLOSED":0, "UNSPECIFIED":0}
for ln in lines:
if re.match(r"^\s*\*\*Status:", ln):
t = re.sub(r"\*\*", "", ln)
tl = t.lower()
if "falsified" in tl: states["FALSIFIED"] += 1
elif "verified" in tl and "closed" in tl: states["VERIFIED-CLOSED"] += 1
elif "unclaimed" in tl: states["UNCLAIMED"] += 1
elif "resolved" in tl: states["RESOLVED"] += 1
elif "closed" in tl: states["CLOSED"] += 1
elif "open" in tl: states["OPEN"] += 1
elif "done" in tl or "complete" in tl: states["DONE"] += 1
else: states["UNSPECIFIED"] += 1
print("independent marker counts:", states)
PY
echo "INDEX CHECK: OK"