Files
dotfiles/claude/governance/fool/twin.py
T
David F Glidden ecf5f95b0a [FIX] CONTROL-B: the defect twin, and ground truth that is not my reading
Kernel v1.1 §7 realised. Five defects injected into CONTROL-A as RECORDED
TRANSFORMATIONS, each with unit target, exact find/replace, what is
undemonstrated, and why no mechanical check can catch it.

THE RESULT THAT MATTERS: the twin passes EVERY mechanical check. Tiling, §3.1
tagging completeness, §3.2 Q-resolution, §3.3 heading screen, A-prohibition —
59/59 units, 100% sound, zero quarantined. It carries five load-bearing claims
that do not hold.

So the pair is the cleanest demonstration yet of the class the steward asked
about: two documents, one sound and one defective, are MECHANICALLY
INDISTINGUISHABLE. Both report 100%. The difference is visible only by reading.
That is not a flaw in the instruments — it is the design. A defect a check could
catch would not be testing the reader.

THE FIVE, each a distinct failure mode:
 D1 SCOPE-WIDENING   — asserts this file has a 'stated review date'; the quoted
                       clause is triggered by one and nothing establishes it
 D2 UNDEFINED-TERM   — imports 'limit of the system' and an obligation to report
                       limits; neither is in the axiom set or the quotations
 D3 PREMISE-WEAKENED — drains the premise of the content the conclusion needs,
                       leaving both premise and conclusion standing
 D4 SUPPORT-DELETED  — removes the fifth quotation entirely and keeps the three
                       claims that rested on it, rewriting the lead so nothing dangles
 D5 CIRCULAR         — makes a premise rest on the conclusion it is a step toward

D1 and D2 are the two defects I found in my OWN draft 2 of CONTROL-A and removed.
Reintroducing them deliberately is the only honest use for them, and it means at
least two of the five are defects a careful author actually made.

GROUND TRUTH BY LEDGER. twin.py gates it bidirectionally: forward(control) == twin
AND inverse(twin) == control, both byte-exact. Forward alone would pass a ledger
that OMITS an edit, since the omitted edit is simply carried in the twin file —
which is exactly how laundering would enter. The inverse is what makes the ledger
complete rather than merely non-empty.

test_twin.py shows the gate FAILING in both laundering directions: a twin quietly
altered beyond the ledger, and a ledger recording an edit the twin does not
contain. Fixtures derived from the property, not from the code.

The tags file for the twin contains five deliberate falsehoods, marked and named,
because that is what a defective document's own tagging would say. The ledger and
the tag file disagree on purpose; the ledger governs.

Not run. The Fool has seen neither document.
2026-08-02 18:28:49 +02:00

159 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Defect-twin construction — ground truth by ledger rather than by reading.
WHY THIS EXISTS
Every grade in the Fool programme has been assigned by the executor, whose
own reading is the thing under test. Kernel v1.1 §7 removes that for the
detection arm: a defect is a RECORDED TRANSFORMATION of a kernel-sound
control, so what counts as a real finding is a ledger entry, not a judgement.
A defect must be invisible to every mechanical check. If §3 caught it, the
Fool would not be the thing being measured. Injected defects therefore live
entirely in Kernel §4's judgement residue — a `D` that no longer demonstrates,
while still parsing, still tagged, and still resolving every quotation.
THE BIDIRECTIONAL GATE
forward(control) == twin AND invert(twin) == control, both byte-exact.
Forward alone is not enough. Forward alone would pass a ledger that omits an
edit, because the omitted edit is simply carried in the twin file — which is
precisely how laundering would enter. The inverse is what makes the ledger
COMPLETE rather than merely non-empty: an unlogged edit survives inversion and
the round trip fails.
USAGE
./twin.py build <control.md> <ledger.json> -o <twin.md>
./twin.py verify <control.md> <twin.md> <ledger.json>
"""
from __future__ import annotations
import argparse
import hashlib
import json
import sys
from pathlib import Path
def sha256(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def load_ledger(path: Path) -> dict:
led = json.loads(path.read_text(encoding="utf-8"))
for d in led["defects"]:
for e in d["edits"]:
if "find" not in e or "replace" not in e:
sys.exit(f"FATAL: defect {d['id']}: edit needs 'find' and 'replace'")
return led
def _edits_in_order(ledger: dict) -> list[tuple[str, str, str]]:
return [
(d["id"], e["find"], e["replace"])
for d in ledger["defects"]
for e in d["edits"]
]
def apply_forward(control: str, ledger: dict) -> str:
"""Apply every edit exactly once. A `find` that is absent or ambiguous is fatal."""
text = control
for did, find, repl in _edits_in_order(ledger):
n = text.count(find)
if n == 0:
sys.exit(f"FATAL: {did}: 'find' not present in control:\n {find[:90]!r}")
if n > 1:
sys.exit(f"FATAL: {did}: 'find' occurs {n} times; must be unique:\n {find[:90]!r}")
text = text.replace(find, repl, 1)
return text
def apply_inverse(twin: str, ledger: dict) -> str:
"""Undo every edit, in reverse, to reconstruct the control."""
text = twin
for did, find, repl in reversed(_edits_in_order(ledger)):
n = text.count(repl)
if repl == "":
# A deletion cannot be located by searching for the empty string, so
# its inverse is an insertion at the point the surrounding text
# determines. Handled by requiring deletions to carry an `anchor`.
sys.exit(
f"FATAL: {did}: deletion has no invertible anchor. Express a deletion "
"as a replacement of the block INCLUDING a unique neighbouring line."
)
if n == 0:
sys.exit(f"FATAL: {did}: 'replace' text absent from twin; ledger is stale")
if n > 1:
sys.exit(f"FATAL: {did}: 'replace' occurs {n} times in twin; must be unique")
text = text.replace(repl, find, 1)
return text
def cmd_build(control_path: Path, ledger_path: Path, out: Path) -> None:
control = control_path.read_text(encoding="utf-8")
ledger = load_ledger(ledger_path)
twin = apply_forward(control, ledger)
back = apply_inverse(twin, ledger)
if back != control:
sys.exit("FATAL: ledger is not invertible; refusing to write a twin.")
out.write_text(twin, encoding="utf-8")
print(f"control {control_path.name} sha256 {sha256(control)[:16]}…")
print(f"twin {out.name} sha256 {sha256(twin)[:16]}…")
print(f"defects {len(ledger['defects'])} "
f"({sum(len(d['edits']) for d in ledger['defects'])} edits)")
print("round trip verified: forward and inverse both byte-exact.")
def cmd_verify(control_path: Path, twin_path: Path, ledger_path: Path) -> None:
control = control_path.read_text(encoding="utf-8")
twin = twin_path.read_text(encoding="utf-8")
ledger = load_ledger(ledger_path)
problems: list[str] = []
if apply_forward(control, ledger) != twin:
problems.append(
"FORWARD FAILED: control + ledger does not reproduce the twin. The twin "
"contains a change the ledger does not record, or records one it does not "
"contain."
)
if apply_inverse(twin, ledger) != control:
problems.append(
"INVERSE FAILED: twin - ledger does not reproduce the control. The ledger "
"is incomplete — an edit was made and not written down."
)
print(f"control sha256 {sha256(control)[:16]}…")
print(f"twin sha256 {sha256(twin)[:16]}…")
print(f"defects {len(ledger['defects'])}")
if problems:
print("\nLEDGER GATE FAILED — ground truth is NOT established:")
for p in problems:
print(f" - {p}")
sys.exit(1)
print("\nLEDGER GATE PASSED — every difference between the two documents is")
print("recorded, and nothing recorded is absent. Ground truth is the ledger.")
def main() -> None:
ap = argparse.ArgumentParser(description="Build and verify a defect twin.")
sub = ap.add_subparsers(dest="cmd", required=True)
b = sub.add_parser("build")
b.add_argument("control", type=Path)
b.add_argument("ledger", type=Path)
b.add_argument("-o", "--out", type=Path, required=True)
v = sub.add_parser("verify")
v.add_argument("control", type=Path)
v.add_argument("twin", type=Path)
v.add_argument("ledger", type=Path)
args = ap.parse_args()
if args.cmd == "build":
cmd_build(args.control, args.ledger, args.out)
else:
cmd_verify(args.control, args.twin, args.ledger)
if __name__ == "__main__":
main()