sylpheed-port found audit-kinds auditing 16 of 71 authored justifications and never saying so -- a checker that fails correctly while describing a sixth of the corpus. Their line is the one that generalises: 'I checked and it was fine' and 'I checked the part that declared itself' read identically in a log, and only one of them is what gets quoted. Measured here: of 86 refutation-shaped bullets in REFUTED.md, 83 are in the registered form. 97 %, which is better than their 16/71 but was equally unstated. The three gaps are deliberate, not a bug. They quote their claim in backticks and are bare identifiers -- +0x29d0, position = instance - 0x12c -- so registering them would match every live mention of the same offset and train the check to be ignored. Reported rather than forced to 100 %, for the same reason they report the ratio instead of demanding it: forcing a counter invites mislabelling, which is worse than the gap. Selftest and the real run both still exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
281 lines
15 KiB
Python
Executable File
281 lines
15 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),
|
|
# sylpheed-port's point: a control that runs where the tool does not look
|
|
# proves nothing about the tool. Case 2 plants INSIDE the scanned root and
|
|
# demands exit 1; this plants the SAME text OUTSIDE it and demands exit 0.
|
|
# The pair asserts that the scan boundary is real, instead of leaving it
|
|
# to be reasoned about.
|
|
("plant OUTSIDE the scanned root — tool must not see it", REG, None, 0),
|
|
]
|
|
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(",", "")
|
|
if other is None:
|
|
# register inside the root, revival text deliberately outside it
|
|
(d / "re").mkdir(parents=True, exist_ok=True)
|
|
(d / "re" / "REFUTED.md").write_text(refuted)
|
|
out = Path(td) / (d.name + "_elsewhere")
|
|
out.mkdir(exist_ok=True)
|
|
(out / "other.md").write_text(f"A live assertion: {CLAIM}.\n")
|
|
else:
|
|
_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"))
|
|
|
|
# 🔴 THIS SCANNED `docs/` ONLY, AND CODE IS WHERE A RETRACTION FAILS TO LAND.
|
|
# sylpheed-port found three live stale claims in their own source, each already
|
|
# retracted in DECISIONS.md days earlier -- "a correction that does not reach the
|
|
# artifact a consumer reads has not been made", and a comment sits BESIDE the
|
|
# thing it describes. Running this register over code for the first time on
|
|
# 2026-08-31 found one here too: jp_title_session.sh justified its own existence
|
|
# with "a free-running clock lands somewhere else on a fresh boot", which I had
|
|
# refuted myself the day before.
|
|
# ⚠️ crates/sylpheed-viewer is excluded: it is the human's tool, not mine to edit.
|
|
CODE_GLOBS = ("tools/**/*.py", "tools/**/*.sh", "crates/**/*.rs")
|
|
CODE_SKIP = ("target/", "sylpheed-viewer")
|
|
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))
|
|
|
|
# ── SCOPE, printed before the verdict ────────────────────────────────────────
|
|
# sylpheed-port found `audit-kinds` auditing 16 of 71 authored justifications and
|
|
# never saying so -- a checker that FAILS CORRECTLY while describing a sixth of
|
|
# the corpus. Their line is the one that matters: "I checked and it was fine" and
|
|
# "I checked the part that declared itself" read identically in a log.
|
|
#
|
|
# Measured here 2026-08-31: of 86 refutation-shaped bullets in REFUTED.md, 83 are
|
|
# in the registered `* "claim"` form -- 97 %.
|
|
#
|
|
# ⚠️ THE THREE GAPS ARE NOT A BUG AND ARE NOT REGISTERED ON PURPOSE. They quote
|
|
# their claim in BACKTICKS and are bare identifiers -- `+0x29d0`,
|
|
# `position = instance - 0x12c`. Registering those would match every live mention
|
|
# of the same offset, producing permanent false hits and training the check to be
|
|
# ignored -- the unregistrable-claim limit this corpus already records for the
|
|
# 0.32 collision. Reported, not forced to 100 %.
|
|
_bul = [l for l in ref.read_text().splitlines() if l.lstrip().startswith("* ")]
|
|
_kill = [l for l in _bul if re.search(r"(→|->|—|--)\s*\*{0,2}(refuted|withdrawn|retracted"
|
|
r"|wrong|dead|no\b|it is)", l, re.I)]
|
|
_unreg = [l for l in _kill if not re.match(r'\s*\*\s*~?~?"([^"]{25,})"', l)]
|
|
_cov = 100 * (len(_kill) - len(_unreg)) / max(len(_kill), 1)
|
|
print(f"{len(claims)} quoted claims in REFUTED.md")
|
|
print(f"SCOPE: {len(_kill) - len(_unreg)} of {len(_kill)} refutation-shaped bullets are "
|
|
f"registered ({_cov:.0f}%); {len(_unreg)} quote their claim in backticks and are "
|
|
f"deliberately unregistrable\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()
|
|
code_files = []
|
|
if "--code" in sys.argv:
|
|
import glob as _g
|
|
for _p in CODE_GLOBS:
|
|
code_files += [Path(x) for x in _g.glob(_p, recursive=True)
|
|
if not any(k in x for k in CODE_SKIP)]
|
|
for f in list(root.rglob("*.md")) + code_files:
|
|
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.
|
|
# ── PEER-OWNED FILES ARE SCANNED FROM A COPY I DO NOT OWN ────────────────────
|
|
# This scans all of docs/, which includes files sylpheed-port authors. My copies
|
|
# of those come from `main` and are days behind their branch head, so a verdict
|
|
# here about one of their files is a verdict about a stale copy.
|
|
#
|
|
# The direction that matters is the FALSE POSITIVE: flagging a claim they have
|
|
# already corrected. That is not hypothetical -- on 2026-08-31 I did it by hand,
|
|
# telling them a BLOCKED.md row was wrong when it had been struck for days, and
|
|
# their live file was one `git show` away in a ref already fetched here.
|
|
#
|
|
# ⚠️ REPORTED, NOT EXCLUDED. Skipping their files silently would hide the
|
|
# exposure; being behind a peer's topic branch is the normal state and making it
|
|
# an error would be scenery within a day (sylpheed-port's call on their own
|
|
# peer-head tool, and it is right).
|
|
PEER_REF = os.environ.get("PEER_REF", "origin/auto/port-p6-audio")
|
|
PEER_OWNED = ("BLOCKED.md", "DECISIONS.md", "PORT-MISSION.md",
|
|
"AUDIO-VERIFICATION.md", "MODDING.md", "FORMAT.md", "RUNNING.md")
|
|
if "--selftest" not in sys.argv:
|
|
import subprocess as _sp
|
|
stale = []
|
|
for _f in PEER_OWNED:
|
|
rel = f"docs/port/{_f}"
|
|
def _d(ref):
|
|
r = _sp.run(["git", "log", "-1", "--format=%ad", "--date=short"]
|
|
+ ([ref] if ref else []) + ["--", rel],
|
|
capture_output=True, text=True)
|
|
return r.stdout.strip()
|
|
mine, theirs = _d(None), _d(PEER_REF)
|
|
if theirs and mine != theirs:
|
|
stale.append((_f, mine or "<absent>", theirs))
|
|
if stale:
|
|
print(f"\n⚠️ {len(stale)} peer-owned file(s) scanned from a STALE local copy "
|
|
f"— a verdict on these is a verdict on my copy, not theirs:")
|
|
for _f, mine, theirs in stale:
|
|
print(f" {_f:24} mine {mine} {PEER_REF} {theirs}")
|
|
print(f" read the live one: git show {PEER_REF}:docs/port/<file>")
|
|
|
|
if hits:
|
|
sys.exit(1)
|