Files
Sylpheed/tools/re-capture/check_refuted.py
sylph-decoder 6509927000 tools: check_refuted gets a harness self-test, which found it could not fail on an empty register
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 that loaded no claims, which
reported clean forever.

The self-test drives the REAL machinery over synthetic corpora as subprocesses and
reads actual exit codes -- their first version reasoned about what the machinery
would do instead of running it, which is the error this whole thread is about
committed inside the tool built to prevent it.

Four cases, all passing: clean corpus 0, verbatim revival 1, marked revival 0, and
empty register 2. The fourth was a real hole, not a modelled one: the tool now
refuses instead of passing when it parses no claims. Exit convention is theirs --
0 fine, 1 a real check failed, 2 the harness is broken.

Also confirms the real corpus still runs clean at exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 01:12:09 +00:00

189 lines
9.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Is any REFUTED claim still asserted, unmarked, elsewhere in the corpus?
`REFUTED.md` publishes deaths; it does not enforce them. `sylpheed-port`'s
`check-claims` register fails their run when a refuted claim is quoted without a
`[refuted]` token, and feeding it four withdrawals immediately flagged three still
asserted unmarked -- every one inside a correction they had written themselves.
Their point is the one worth stealing: **the token tests for something an author
must place, not for language that sounds retracted.** All three read as
corrections to a human and the marker fired anyway.
This is the equivalent for a prose corpus. For each `* "claim"` in REFUTED.md it
searches `docs/` for that exact claim text and reports every occurrence whose
neighbourhood carries no refutation marker.
⚠️ Its known weakness, stated rather than discovered: it matches the claim's
EXACT wording. A restatement in different words is invisible to it. So a clean run
means "no verbatim revival", not "no revival".
check_refuted.py [--context N]
"""
import os
import re
import sys
from pathlib import Path
MARKERS = ("refuted", "REFUTED", "withdrawn", "WITHDRAWN", "retracted", "RETRACTED",
"🔴", "~~", "used to say", "used to read", "was wrong", "is wrong",
"no longer", "superseded", "corrected", "retracts", "an earlier version",
# text explicitly DECLINING to revive a claim reads as an assertion to
# a neighbourhood scan; two real hits were exactly this.
"does **not** revive", "does not revive")
# ⚠️ STRUCTURAL LIMIT, found by running this against the corpus. `BACKLOG.md` is an
# APPEND-ONLY DATED LOG: an entry under a 2026-08-12 header recording what was
# believed then is history, not revival, and reads identically to a live claim.
# A neighbourhood-language detector cannot separate "asserted now" from "recorded
# as believed then". sylpheed-port's `check-claims` avoids this by testing for a
# TOKEN AN AUTHOR MUST PLACE rather than for language -- their design is right and
# this one is a weaker approximation of it. Files that are chronological records
# are skipped rather than reported, and that is a real hole, not a fix.
CHRONOLOGICAL = {"BACKLOG.md"}
CTX = int(sys.argv[sys.argv.index("--context") + 1]) if "--context" in sys.argv else 4
# 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()
for line in ref.read_text().splitlines():
m = re.match(r'\s*\*\s*~?~?"([^"]{25,})"', line)
if m:
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()
for c in claims:
needle = c.strip()
for f in root.rglob("*.md"):
if f == ref or f.name in CHRONOLOGICAL:
continue
lines = f.read_text(errors="replace").splitlines()
for i, l in enumerate(lines):
if needle in l:
lo, hi = max(0, i - CTX), min(len(lines), i + CTX + 1)
# ⚠️ A +-CTX neighbourhood misses the commonest real marker: a
# SECTION HEADER that retracts a whole list. Two false positives
# were exactly this -- bullets under "## 🔴 What this retracts",
# each bullet a claim being killed, no marker within 4 lines.
# Scope, not proximity, is what marks them, so include the
# nearest preceding header in the scan.
hdr = ""
for j in range(i, -1, -1):
if re.match(r"#{1,4} ", lines[j]):
hdr = lines[j]
break
near = "\n".join(lines[lo:hi]) + "\n" + hdr
marked = any(m.lower() in near.lower() for m in MARKERS)
if marked:
# dedup like the reported path: two registered claims can be
# substrings of one line, which printed it twice.
if (f, i) not in seen_marked:
seen_marked.add((f, i))
suppressed.append((f, i + 1, needle, l.strip()))
continue
if (f, i) not in seen_report:
seen_report.add((f, i))
hits += 1
print(f"🔴 {f}:{i+1}")
print(f' claim: "{needle[:80]}"')
print(f" line : {l.strip()[:110]}\n")
print(f"{hits} unmarked assertion(s) of a refuted claim")
# 🔴 A CLEAN RUN IS NOT A PASS, and until 2026-08-30 it was reported as though it
# were. Measured: 8 of 8 mentions of a registered claim in this corpus are
# suppressed by marker language, so the count above was 0 whether or not any of
# them was a live revival. A planted REAL revival, written into a paragraph that
# merely discussed corrections, was missed silently -- the marker words in the
# surrounding prose vouched for it.
#
# sylpheed-port's token-based hook has the opposite bias: it OVER-reports on
# well-written corrections, which is the safe direction. This one under-reports,
# which is not. So the suppressed set is printed rather than hidden.
print(f"{len(suppressed)} mention(s) suppressed by nearby marker language "
f"-- NOT verified, only vouched for by neighbouring prose")
if "--show-marked" in sys.argv:
for f, ln, c, l in suppressed:
print(f" · {f}:{ln}\n claim: \"{c[:70]}\"\n line : {l[:100]}")
elif suppressed:
print(" re-run with --show-marked to read them")
# 🔴 EXIT CODE, added 2026-08-31. This printed its findings and returned 0 no
# matter what -- a planted unmarked revival was reported and the run still
# succeeded, so any pipeline using it asserted NOTHING. sylpheed-port shipped the
# same shape (`return 0` unconditional) one day after writing that defect up in
# someone else's work; mine had been live since the tool was written.
# Unmarked assertions FAIL. Suppressed mentions do not -- they are unverified,
# not wrong, and failing on them would make the clean state unreachable.
if hits:
sys.exit(1)