diff --git a/tools/re-capture/check_refuted.py b/tools/re-capture/check_refuted.py index 0683f1f8..51568964 100755 --- a/tools/re-capture/check_refuted.py +++ b/tools/re-capture/check_refuted.py @@ -19,6 +19,7 @@ means "no verbatim revival", not "no revival". check_refuted.py [--context N] """ +import os import re import sys from pathlib import Path @@ -41,7 +42,65 @@ MARKERS = ("refuted", "REFUTED", "withdrawn", "WITHDRAWN", "retracted", "RETRACT CHRONOLOGICAL = {"BACKLOG.md"} CTX = int(sys.argv[sys.argv.index("--context") + 1]) if "--context" in sys.argv else 4 -root = Path("docs") +# Overridable so the harness self-test can drive the REAL machinery over a +# synthetic corpus instead of reasoning about what it would do. +if "--selftest" in sys.argv: + # ── HARNESS SELF-TEST ──────────────────────────────────────────────────── + # sylpheed-port closed this gap first: their controls asserted + # failure-on-perturbation but nothing asserted that a BROKEN harness reports + # broken. Their stub is a check that cannot fail; the equivalent here is a + # register with NO CLAIMS LOADED, which reports clean forever. + # + # These push synthetic corpora through this script as a SUBPROCESS and read + # its real exit code. An earlier version of their test reasoned about what + # the machinery would do instead of running it -- the error this whole thread + # is about, committed inside the tool built to prevent it. + # + # Exit convention, theirs: 0 fine · 1 a real check failed · 2 the HARNESS is + # broken and nothing it reports can be trusted. + import subprocess, tempfile, textwrap + + def _corpus(d, refuted, other): + (d / "re").mkdir(parents=True, exist_ok=True) + (d / "re" / "REFUTED.md").write_text(refuted) + (d / "re" / "other.md").write_text(other) + + CLAIM = 'the synthetic widget is on the disc nowhere' + REG = f'* "{CLAIM}"\n' + cases = [ + ("clean corpus, claim not revived", REG, "Nothing to see here.\n", 0), + ("verbatim revival, no marker", REG, + f"A live assertion: {CLAIM} and that is that.\n", 1), + ("revival WITH a marker nearby", REG, + f"~~{CLAIM}~~ was refuted on 2026-01-01.\n", 0), + ("EMPTY REGISTER — must refuse, not pass", "no quoted claims at all\n", + f"A live assertion: {CLAIM}.\n", 2), + ] + bad = 0 + print("── check_refuted harness self-test ──", flush=True) + with tempfile.TemporaryDirectory() as td: + for name, refuted, other, want in cases: + d = Path(td) / name.replace(" ", "_").replace(",", "") + _corpus(d, refuted, other) + env = dict(os.environ, CHECK_REFUTED_ROOT=str(d)) + r = subprocess.run([sys.executable, __file__], env=env, + capture_output=True, text=True) + n = 0 + for line in r.stdout.splitlines(): + if "quoted claims in REFUTED.md" in line: + n = int(line.split()[0]) + ok = (r.returncode == want) + bad += not ok + print(f" {'✅' if ok else '🔴'} {name:38} exit={r.returncode} " + f"(want {want}), claims={n}") + if bad: + print("🔴 HARNESS SELF-TEST FAILED — nothing this tool reports can be " + "trusted.", flush=True) + sys.exit(2) + print(" ✅ harness self-test passed", flush=True) + sys.exit(0) + +root = Path(os.environ.get("CHECK_REFUTED_ROOT", "docs")) ref = root / "re" / "REFUTED.md" claims = [] seen_report = set() @@ -51,6 +110,15 @@ for line in ref.read_text().splitlines(): claims.append(m.group(1)) print(f"{len(claims)} quoted claims in REFUTED.md\n") + +# 🔴 A register that loaded NOTHING cannot fail, and would report clean forever -- +# the same shape as sylpheed-port's stub that prints "everything is fine" and +# asserts nothing. Refuse rather than pass. Found by this tool's own harness +# self-test, which is the only reason it was visible. +if not claims: + print("🔴 NO CLAIMS PARSED from REFUTED.md — this run asserts NOTHING. " + "Exiting 2 (harness broken), not 0.") + sys.exit(2) hits = 0 suppressed = [] seen_marked = set()