114 lines
4.1 KiB
Bash
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"
|