Files
dotfiles/scripts/verify-quotes.py
T
David F GliddenandClaude Opus 5 1cf79b0f86 [PROPOSAL] PENDING-124 gate passed; five conditions discharged, and the gate found a tenth instance
Q1 is applied, not extended: Constraint 4 has two clauses and my contrary reading
engaged only the second. Limits, not failures — and "I could not look" is a limit. I
had overstated my own uncertainty on the question I withdrew a recommendation over.

The condition that cost most: my quote-verification pass reported verified on a
reconstruction of REVIEWED-104 — contractions, re-punctuation, two blocks spliced, and
the closing sentence dropped. A two-valued verifier inside a package arguing verifiers
must be three-valued. Rebuilt at ~/dotfiles/scripts/verify-quotes.py. The first rebuild
had three tiers and cried wolf on every correctly-copied quote, since a record stored
with hard wraps is byte-different from the same text quoted as one line; splitting
re-wrapped from normalized is the same two-strengths lesson the fleet learned. Both
directions proven: corrected package exit 0, original reconstruction not-found exit 1.

The dropped sentence answered my own Q2. It was in the record the package quoted.

Both citation errors in that package had one cause, which the script cannot diagnose: I
quoted the ADVISORY message and attributed it to the PLACED record. Different
documents; placement adds and cuts, so quoting the advisory loses exactly what
placement contributed.

My "five instances, same shape" was wrong — two are the shape, three belong to the
attested-absence family whose parent is already ratified (REVIEWED-47, 2026-07-05). I
searched for a doctrinal parent among R0 and Constraint 4 and missed the ratified
sibling closest in content. The ladder entry now joins that lineage.

Filed as a watch-item, with an operative memory note: third package running where the
grounding pass was incomplete and every substantive omission cut against my own
argument. It optimises for finding my errors, not my support.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A35wiD55yRHj5U1ECZAX4t
2026-08-08 19:15:14 +02:00

143 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""verify-quotes.py — check a package's blockquotes against the records it cites.
WHY THIS EXISTS, AND WHY IT IS THREE-VALUED (REVIEWED-⟨N⟩ condition 1, PENDING-124).
The inline predecessor of this script reported `verified` for a REVIEWED-104 blockquote
that was a NORMALIZED RECONSTRUCTION, not the placed text: `will not be`→`won't be`,
`does not say`→`doesn't say`, `wrong.`→`wrong:`, `CONDITION:`→`So:`, two separate blocks
spliced into one, and — the part that mattered — THE CLOSING SENTENCE DROPPED. That
sentence was the one that answered the package's own Q2 without asking.
A two-valued verifier said `verified`. The honest report was `matched after
normalization`. It was a two-valued verifier inside a package arguing that verifiers
whose subject can be absent must be three-valued, which is the defect the doctrine
describes, committed by the instrument checking the doctrine's own evidence.
exact byte-for-byte in a cited source
re-wrapped identical after collapsing WHITESPACE only — a record stored with hard
line wraps quoted as one line. Content identical; safe.
normalized found only after folding emphasis/contractions/punctuation — REPORT IT,
because THIS is where a reconstruction hides
not-found in no cited source
⚠ re-wrapped and normalized were one tier in the first version, which cried wolf on
every correctly-copied quote. Splitting them is the same lesson the fleet summary
learned: a warning that fires on the safe case stops being read.
DIAGNOSIS THE SCRIPT CANNOT MAKE, so the author must: BOTH citation errors in that
package had one cause — quoting the ADVISORY message and attributing it to the PLACED
record. They are different documents. Placement can add, cut or re-word, so quoting the
advisory systematically loses whatever the act of placing contributed. When a passage
comes from a relayed message rather than a file, it is not a quotation of the record and
must be labelled advisory.
A blockquote that is the author's own proposed text is not a quotation claim at all and
is excluded from assessment — mark it with `<!-- own-text -->` on the line before. An
unmarked block that is not found is reported, never silently skipped.
Usage: python3 verify-quotes.py PACKAGE.md SOURCE [SOURCE ...]
Exit: 0 all assessed blocks exact · 1 any not-found · 3 any normalized-only
"""
import re
import sys
from pathlib import Path
EXACT, REWRAPPED, NORMALIZED, NOT_FOUND = "exact", "rewrapped", "normalized", "not-found"
def fold(s: str) -> str:
"""Normalization deliberately AGGRESSIVE: the wider it folds, the more it will
classify as `normalized` rather than `exact`, and that is the reporting we want."""
s = re.sub(r"[*_`]", "", s)
s = (s.replace("—", "-").replace("–", "-")
.replace("’", "'").replace("‘", "'")
.replace("“", '"').replace("”", '"'))
for long, short in [("will not", "wont"), ("won't", "wont"),
("does not", "doesnt"), ("doesn't", "doesnt"),
("cannot", "cant"), ("can't", "cant"),
("is not", "isnt"), ("isn't", "isnt")]:
s = s.replace(long, short)
s = re.sub(r"[^\w\s']", " ", s)
return re.sub(r"\s+", " ", s).strip().lower()
def blocks(text: str):
"""Contiguous blockquote runs, with the `own-text` marker honoured."""
out, cur, own = [], [], False
for line in text.splitlines():
if line.strip().lower() == "<!-- own-text -->":
own = True
continue
if line.startswith(">"):
cur.append(line.lstrip(">").strip())
elif cur:
out.append((" ".join(cur).strip(), own)); cur, own = [], False
elif line.strip():
own = False
if cur:
out.append((" ".join(cur).strip(), own))
return [(b, o) for b, o in out if b]
def ws(s: str) -> str:
"""Whitespace ONLY. A record stored with hard line wraps is byte-different from the
same text quoted as one line, and calling that a `normalized match` cries wolf — the
same failure as a fleet summary that never varies. Re-wrapping is safe; re-wording
is not, and they must not share a verdict."""
import re as _re
return _re.sub(r"\s+", " ", s).strip()
def classify(quote: str, sources: dict[str, str]):
for name, text in sources.items():
if quote and quote in text:
return EXACT, name
wq = ws(quote)
for name, text in sources.items():
if wq and wq in ws(text):
return REWRAPPED, name
fq = fold(quote)
for name, text in sources.items():
if fq and fq in fold(text):
return NORMALIZED, name
return NOT_FOUND, None
def main(argv):
if len(argv) < 2:
print(__doc__); return 2
pkg = Path(argv[0]).read_text(encoding="utf-8")
sources = {}
for p in argv[1:]:
path = Path(p).expanduser()
if path.exists():
sources[path.name] = path.read_text(encoding="utf-8")
else:
print(f" ⚠ source unreadable, NOT searched: {p}")
counts = {EXACT: 0, REWRAPPED: 0, NORMALIZED: 0, NOT_FOUND: 0, "own-text": 0}
print(f" checking {len(blocks(pkg))} blockquote(s) against {len(sources)} source(s)\n")
for q, own in blocks(pkg):
if own:
counts["own-text"] += 1
print(f" [own-text ] {q[:66]}…")
continue
state, where = classify(q, sources)
counts[state] += 1
tag = {EXACT: "exact ", REWRAPPED: "re-wrapped", NORMALIZED: "NORMALIZED", NOT_FOUND: "NOT FOUND"}[state]
print(f" [{tag}] {q[:60]}…" + (f" <- {where}" if where else ""))
if state == NORMALIZED:
print(" ^ reconstruction, not the placed text. Diff it before relying on it.")
print(f"\n exact {counts[EXACT]} · re-wrapped {counts[REWRAPPED]} (content identical) · "
f"normalized {counts[NORMALIZED]} · not-found {counts[NOT_FOUND]} · "
f"own-text {counts['own-text']} (unassessed by design)")
if counts[NOT_FOUND]:
return 1
if counts[NORMALIZED]:
return 3
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))