157 lines
5.1 KiB
Python
157 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Self-check for the wizard-work triage report.
|
|
|
|
Re-derives the completion state of every top-level `wizard-work/` directory
|
|
from the filesystem (same deterministic markers as triage_work_status.py) and
|
|
cross-checks the committed report at
|
|
`wizard-work-triage-2026-10-21.md`:
|
|
|
|
* every top-level dir appears in the report, and
|
|
* the reported markers line matches what the disk now shows, and
|
|
* the reported state is consistent with the markers under the documented rule.
|
|
|
|
Exit 0 = the artifact is correct; exit 1 = mismatch or missing report.
|
|
"""
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
REPO = "/root/troupe-standup"
|
|
SRC = os.path.join(REPO, "wizard-work")
|
|
REPORT = os.path.join(REPO, "wizard-work", "sol", "wizard-work-triage-2026-10-21.md")
|
|
|
|
MARKER_NAMES = [
|
|
"has_CHECK", "has_final", "has_verification", "has_checksum",
|
|
"has_verify_py", "has_test_py", "has_readme", "has_runbook",
|
|
]
|
|
NESTED = "nested_dirs"
|
|
DESC = "file_count"
|
|
|
|
|
|
def _walk_files(d):
|
|
out = []
|
|
for root, dirs, files in os.walk(d):
|
|
dirs[:] = [x for x in dirs if x not in ("__pycache__", ".git")]
|
|
for f in files:
|
|
out.append(os.path.relpath(os.path.join(root, f), d))
|
|
return out
|
|
|
|
|
|
def _markers(d):
|
|
files = _walk_files(d)
|
|
m = {
|
|
"has_CHECK": os.path.exists(os.path.join(d, "CHECK"))
|
|
and os.path.getsize(os.path.join(d, "CHECK")) > 0,
|
|
"has_final": os.path.exists(os.path.join(d, "FINAL_REPORT.md")),
|
|
"has_verification": any(
|
|
os.path.exists(os.path.join(d, n)) for n in
|
|
("VERIFICATION.md", "VERIFICATION.txt", "VERIFICATION.json")
|
|
),
|
|
"has_checksum": any(f.startswith("checksum") for f in files),
|
|
"has_verify_py": any(
|
|
f.endswith(".py") and (f.startswith("verify_") or f.startswith("_verify_"))
|
|
for f in files
|
|
),
|
|
"has_test_py": any(f.startswith("test_") and f.endswith(".py") for f in files),
|
|
"has_readme": os.path.exists(os.path.join(d, "README.md"))
|
|
and os.path.getsize(os.path.join(d, "README.md")) > 0,
|
|
"has_runbook": any(
|
|
f in ("runbook.md", "incident-runbook.md") for f in files
|
|
),
|
|
NESTED: any(
|
|
x not in ("__pycache__", ".git") and os.path.isdir(os.path.join(d, x))
|
|
for x in os.listdir(d)
|
|
),
|
|
DESC: len(files),
|
|
}
|
|
return m
|
|
|
|
|
|
def _state(m):
|
|
if m["has_final"] and m["has_verification"] and m["has_checksum"]:
|
|
return "verified"
|
|
if m["has_final"] or m["has_checksum"] or m["has_test_py"]:
|
|
return "done"
|
|
if m["has_readme"] and m["has_verify_py"]:
|
|
return "completed"
|
|
if m["has_verify_py"] or m["has_runbook"]:
|
|
return "in-progress"
|
|
if m["has_readme"] and m["file_count"] <= 1:
|
|
return "pending"
|
|
if m["has_readme"]:
|
|
return "completed"
|
|
return "framework"
|
|
|
|
|
|
def rederived():
|
|
rows = []
|
|
if not os.path.isdir(SRC):
|
|
return rows
|
|
for name in sorted(os.listdir(SRC)):
|
|
d = os.path.join(SRC, name)
|
|
if not os.path.isdir(d):
|
|
continue
|
|
m = _markers(d)
|
|
rows.append({"dir": name, "state": _state(m), "markers": m})
|
|
return rows
|
|
|
|
|
|
def parse_report():
|
|
"""Return {dir: (state, [markers])} from the committed report markdown."""
|
|
data = {}
|
|
if not os.path.exists(REPORT):
|
|
return data
|
|
text = open(REPORT).read()
|
|
for m in re.finditer(r"^### `([^`]+)` - `([^`]+)`", text, re.M):
|
|
dir_name, state = m.group(1), m.group(2)
|
|
rest = text[m.end():]
|
|
mk = None
|
|
for line in rest.splitlines():
|
|
if line.startswith("- markers: "):
|
|
val = line[len("- markers: "):].strip()
|
|
mk = [] if val == "none" else [x.strip() for x in val.split(",")]
|
|
break
|
|
data[dir_name] = (state, mk)
|
|
return data
|
|
|
|
|
|
def main():
|
|
rederived_rows = rederived()
|
|
report = parse_report()
|
|
|
|
# 1) every top-level dir must be reported
|
|
missing = [r["dir"] for r in rederived_rows if r["dir"] not in report]
|
|
if missing:
|
|
print("CHECK FAILED: dirs absent from report: %s" % ", ".join(missing))
|
|
sys.exit(1)
|
|
|
|
# 2) markers and state must match the disk
|
|
ok = True
|
|
for r in rederived_rows:
|
|
dir_name, state, m = r["dir"], r["state"], r["markers"]
|
|
rep_state, rep_markers = report[dir_name]
|
|
exp_markers = [k for k in MARKER_NAMES if m.get(k)]
|
|
if rep_state != state:
|
|
print("CHECK FAILED: %s state is `%s`, disk says `%s`"
|
|
% (dir_name, rep_state, state))
|
|
ok = False
|
|
if rep_markers != exp_markers:
|
|
print("CHECK FAILED: %s markers are %s, disk says %s"
|
|
% (dir_name, rep_markers, exp_markers))
|
|
ok = False
|
|
|
|
# 3) every reported dir must re-derive cleanly (no phantom rows)
|
|
extra = [d for d in report if d not in {r["dir"] for r in rederived_rows}]
|
|
if extra:
|
|
print("CHECK FAILED: phantom dirs in report: %s" % ", ".join(extra))
|
|
ok = False
|
|
|
|
if ok:
|
|
print("CHECK PASSED: %d directories match disk (markers + state)." % len(rederived_rows))
|
|
else:
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|