Files
dotfiles/claude/governance/check_containment.py
T
David F GliddenandClaude Opus 5 bdf24c044b [FIX] Addendum-1: make the central claim checkable; add containment proof
Two defects in the addendum as first filed, both found by checking rather than
by reading.

First, it asserted a set comparison over documents the jurist cannot read. Its
own header promises every clause reasoned about is quoted verbatim, but the
claim the addendum rests on -- mutual divergence in 3 of 3 comparable pairs --
was a summary of the executor's own analysis. The appendix now reproduces one
pair as an eleven-row side-by-side of extracted claims, verbatim where quoted,
so the comparison can be checked independently. The pair chosen is the least
confounded rather than the most favourable: the v1 standard prompt is
model-agnostic and needs no compressed variant, so both parties demonstrably
read the same file. What the jurist still cannot check is stated explicitly.

Second, Part E rendered a bullet list from the 2025-01-20 source as running
prose with terminal periods the source does not contain, inside a blockquote.
A blockquote asserts verbatim. Same family as the truncation that closed a
sentence with an invented word on 2026-08-01, and again caught mechanically.
Corrected in all three files where it appeared; the fabricated period is now a
positive control, so the instrument proves it catches this defect.

check_containment.py generalises the check that found it. Positive controls are
mandatory -- it exits non-zero if none are declared, because a check reporting
all-pass without them cannot be distinguished from one unable to detect absence.
Addendum-1 now carries its result: 28/28 contained, 5/5 controls absent.

Not filed as satisfying PENDING-86 option (b), which is unruled and concerns
whether such a proof should be REQUIRED of every package. This is the executor
checking its own work before filing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WuMjg3ipEVa3n8CoSzoyvc
2026-08-02 11:43:27 +02:00

109 lines
3.6 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
"""
Verbatim containment check for jurist packages.
The packages in this directory are written for a jurist with NO repository access,
under a contract stated in their own headers: "every clause reasoned about is quoted
verbatim". That contract is only worth what a mechanical check makes it worth. Reading
does not catch a fabricated terminal period, an elision presented as contiguous, or a
truncation that closes a sentence with a word the source does not contain — all three
have occurred in packages from this directory, and all three were caught by a check
like this one rather than by careful reading.
Every run carries POSITIVE CONTROLS: near-miss strings that must be absent. If a control
is found, the instrument is not discriminating and its passes mean nothing. An absence
is not evidence until the instrument is shown capable of detecting presence.
USAGE
./check_containment.py manifest.json
MANIFEST
{
"sources": {"key": "/abs/path/to/source", ...},
"claims": [["key", "quoted text"], ...],
"controls": [["key", "near-miss that MUST be absent"], ...]
}
EXIT
0 all claims contained, no control leaked
1 a claim is not contained
2 a control leaked — instrument not verified, result unusable
"""
from __future__ import annotations
import json
import re
import sys
import unicodedata
from pathlib import Path
# Typographic normalisation. Quotation is compared on content, not on which flavour of
# apostrophe an editor inserted — but NOT on punctuation the source does not contain.
_SUBS = [
("‘", "'"), ("’", "'"),
("“", '"'), ("”", '"'),
("—", "-"), ("–", "-"), ("‑", "-"),
(" ", " "),
]
def norm(s: str) -> str:
s = unicodedata.normalize("NFKC", s)
for a, b in _SUBS:
s = s.replace(a, b)
return re.sub(r"\s+", " ", s).strip().lower()
def main() -> None:
if len(sys.argv) != 2:
sys.exit(__doc__)
manifest = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
bodies = {}
for key, path in manifest["sources"].items():
p = Path(path).expanduser()
if not p.is_file():
sys.exit(f"FATAL: source '{key}' not found: {p}")
bodies[key] = norm(p.read_text(encoding="utf-8"))
def contained(key: str, quote: str) -> bool:
if key not in bodies:
sys.exit(f"FATAL: claim references undeclared source '{key}'")
return norm(quote) in bodies[key]
print("QUOTED CLAIMS")
failures = []
for key, quote in manifest["claims"]:
ok = contained(key, quote)
if not ok:
failures.append((key, quote))
print(f" {'PASS' if ok else 'FAIL'} [{key}] {quote[:70]}")
print(f"\n {len(manifest['claims']) - len(failures)}/{len(manifest['claims'])} contained\n")
print("POSITIVE CONTROLS (must all be absent)")
leaked = []
for key, quote in manifest.get("controls", []):
ok = contained(key, quote)
if ok:
leaked.append((key, quote))
print(f" {'LEAKED' if ok else 'absent'} [{key}] {quote[:70]}")
if not manifest.get("controls"):
print("\nINSTRUMENT NOT VERIFIED — no positive controls declared.")
sys.exit(2)
if leaked:
print(f"\nINSTRUMENT NOT VERIFIED — {len(leaked)} control(s) leaked. Passes above are meaningless.")
sys.exit(2)
print("\nINSTRUMENT VERIFIED")
if failures:
print(f"CONTAINMENT FAILED — {len(failures)} quoted claim(s) not found verbatim in the named source.")
sys.exit(1)
print("CONTAINMENT PASSED")
if __name__ == "__main__":
main()