130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Independent verifier for the daily local-pipe triage artifact (2026-10-26).
|
|
|
|
The artifact records the repository's pending-work index (files the worktree has
|
|
that git does not track) at capture time, frozen into the stored index list. This
|
|
verifier:
|
|
|
|
1. Re-derives the classification of the captured index ENTIRELY from the
|
|
artifact's own stored index (no live git query, so the check is stable),
|
|
and asserts the artifact's bucket counts, stray list, modified list, and
|
|
totals all equal that re-derivation.
|
|
2. Asserts the markdown report's scope lines and bucket table agree with the
|
|
stored numbers, so the report text cannot drift from its data.
|
|
|
|
Exit 0 only when the artifact is internally correct; nonzero otherwise.
|
|
"""
|
|
import collections
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
REPO = "/root/troupe-standup"
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
JSON_PATH = os.path.join(HERE, "daily-local-pipe-triage-2026-10-26.json")
|
|
MD_PATH = os.path.join(REPO, "wizard-work/sol/daily-local-pipe-triage-2026-10-26.md")
|
|
|
|
|
|
def classify(path):
|
|
b = path.split("/")
|
|
base = b[-1]
|
|
if ".hermes-tmp." in path or base.startswith(".triage_"):
|
|
return "STRAY"
|
|
if "beam" in b:
|
|
return "STRAY"
|
|
if base == "CHECK" and chr(10) in path:
|
|
return "STRAY"
|
|
if base.startswith("README-"):
|
|
return "DOC"
|
|
if base.startswith("CHECK"):
|
|
return "CHECK"
|
|
if base.startswith("_probe") or base.startswith("probe_"):
|
|
return "PROBE"
|
|
if "forge" in b:
|
|
return "FORGE"
|
|
if "sphinx" in b:
|
|
return "SPHINX"
|
|
if "recoveries" in b:
|
|
return "RECOVERY"
|
|
if "ledger" in b:
|
|
return "LEDGER"
|
|
if "wizard-work/null/" in ("/" + path + "/"):
|
|
return "NULL"
|
|
if path.startswith("wizard-work/"):
|
|
return "LORE"
|
|
return "MISC"
|
|
|
|
|
|
def main():
|
|
errors = []
|
|
|
|
# --- load stored artifact (contains the captured index) ---
|
|
try:
|
|
with open(JSON_PATH, encoding="utf-8") as fh:
|
|
stored = json.load(fh)
|
|
except Exception as exc:
|
|
print("VERIFY FAIL: cannot read %s: %s" % (JSON_PATH, exc))
|
|
sys.exit(1)
|
|
|
|
# --- re-derive classification from the captured index ---
|
|
captured = stored.get("untracked_paths", [])
|
|
buckets = collections.Counter()
|
|
for p in captured:
|
|
buckets[classify(p)] += 1
|
|
rederived = {
|
|
"modified": stored.get("modified", []),
|
|
"untracked": len(captured),
|
|
"total_pending": len(captured),
|
|
"buckets": {k: buckets[k] for k in sorted(buckets)},
|
|
"stray": sorted(p for p in captured if classify(p) == "STRAY"),
|
|
}
|
|
|
|
checks = [
|
|
("modified", rederived["modified"], stored.get("modified", [])),
|
|
("untracked", rederived["untracked"], stored.get("untracked")),
|
|
("total_pending", rederived["total_pending"], stored.get("total_pending")),
|
|
("buckets", rederived["buckets"], stored.get("buckets")),
|
|
("stray", rederived["stray"], stored.get("stray")),
|
|
]
|
|
for key, got, want in checks:
|
|
if got != want:
|
|
errors.append("%s: rederived=%r stored=%r" % (key, got, want))
|
|
|
|
# --- report scope lines must agree with stored numbers ---
|
|
try:
|
|
text = open(MD_PATH, encoding="utf-8").read()
|
|
except OSError:
|
|
text = ""
|
|
for marker in (
|
|
"**modified**: %d" % len(stored.get("modified", [])),
|
|
"**untracked**: %d" % stored.get("untracked"),
|
|
"**total pending**: %d" % stored.get("total_pending"),
|
|
):
|
|
if marker not in text:
|
|
errors.append("report scope line missing: " + marker)
|
|
|
|
# --- bucket table rows must agree with stored bucket counts ---
|
|
for k, v in stored.get("buckets", {}).items():
|
|
if "| %s | %d |" % (k, v) not in text:
|
|
errors.append("report bucket row missing/incorrect: %s | %d" % (k, v))
|
|
|
|
if errors:
|
|
print("VERIFY FAIL")
|
|
for e in errors:
|
|
print(" -", e)
|
|
sys.exit(1)
|
|
|
|
print("VERIFY PASS")
|
|
print(json.dumps({
|
|
"modified": len(stored.get("modified", [])),
|
|
"untracked": stored.get("untracked"),
|
|
"total_pending": stored.get("total_pending"),
|
|
"buckets": stored.get("buckets"),
|
|
"stray": len(stored.get("stray", [])),
|
|
}, indent=2))
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|