diff --git a/claude/governance/fool/twin-ledger.json b/claude/governance/fool/twin-ledger.json index 56fbe13..3851fe6 100644 --- a/claude/governance/fool/twin-ledger.json +++ b/claude/governance/fool/twin-ledger.json @@ -5,7 +5,23 @@ "kernel_sha256": "d4b48db23612b30ff66e26b6235065a3c2f3c9be19d750dafc97e80a1329974d", "created": "2026-08-02", "principle": "Each defect converts a D into a claim resting on something unstated, WITHOUT naming an assumption. Every defect must survive all mechanical checks: tiling, §3.1 tagging completeness, §3.2 Q-resolution, §3.3 heading screen, and the A-prohibition. A defect a check can catch is not testing the reader.", - "grading": "A finding is a TRUE POSITIVE iff it identifies a claim this ledger records as de-demonstrated. Anything else is a false positive, EXCEPT a finding that identifies a genuine defect in CONTROL-A itself — which would void the control rather than count against the reader.", + "grading": "AMENDED 2026-08-02 after trial 04. A finding is a TRUE POSITIVE iff it identifies a claim recorded EITHER in `defects` (injected) OR in `inherited_defects` (present in CONTROL-A, surviving into the twin). Anything else is a false positive. The original rule counted only `defects`, and would have scored a correct finding on the inherited defect as a false positive.", + + "ground_truth_scope": "WHAT THE BIDIRECTIONAL GATE ESTABLISHES, AND WHAT IT DOES NOT. twin.py verifies that the ledger records every DIFFERENCE between control and twin. It does NOT verify that the ledger records every DEFECT in the twin — those are different claims, and the file previously asserted the second while proving only the first. A defect already present in the control passes the gate untouched, because it is not a difference. Trial 04 found two such defects in CONTROL-A; `inherited_defects` below records the one that survives the transformations. The gate remains correct for what it checks.", + + "inherited_defects": [ + { + "id": "I1", + "type": "ASSERTED-PRECEDENCE", + "origin": "Present in CONTROL-A; not injected. Found by the jurist (Fable 5) in trial 04, as the second half of its Finding 1.", + "text": "It stands over every clause above.", + "undemonstrated": "Asserts that Constitutional Constraint 1 overrides the other quoted clauses. Constraint 1 establishes no such precedence, and the constitution's own precedence language ranks the constraints above 'any session instruction, seed, or convenience' — not above other constitutional clauses. That preamble is not quoted in either document. The severance is load-bearing: the Memory Discipline clause's method terminates in 'then correct whichever layer was wrong', and both documents conclude that correction is closed.", + "survives_because": "No transformation touches it. In CONTROL-B the quotation it severs has itself been deleted by D4, so the assertion is left standing over a remedy the document no longer quotes." + } + ], + + "defects_not_surviving": "CONTROL-A's other two trial-04 defects do NOT appear in the twin, and this is recorded so the twin is not mistaken for a superset of the control. The clause-5 scope violation is gone because D4 deletes that quotation outright. The dropped-qualifier defect is gone because D1 replaces that sentence with an explicit version of the same error — which is why the twin carries openly what the control carried concealed.", + "defects": [ { "id": "D1", diff --git a/claude/governance/fool/twin.py b/claude/governance/fool/twin.py index 57f0c65..257e4b6 100755 --- a/claude/governance/fool/twin.py +++ b/claude/governance/fool/twin.py @@ -132,8 +132,19 @@ def cmd_verify(control_path: Path, twin_path: Path, ledger_path: Path) -> None: 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.") + print("\nLEDGER GATE PASSED — every DIFFERENCE between the two documents is") + print("recorded, and nothing recorded is absent.") + print("\nThis is NOT a claim that the ledger records every DEFECT in the twin.") + print("A defect already present in the control is not a difference, so it passes") + print("this gate untouched and must be recorded by reading, under") + print("`inherited_defects`. Trial 04 found two such defects in a control this") + print("gate had already passed. Ground truth = defects + inherited_defects.") + inherited = ledger.get("inherited_defects") + if inherited is None: + print("\n WARNING: no `inherited_defects` key. Absent is not the same as none —") + print(" it means no one has looked. State an empty list to record that they have.") + else: + print(f"\n inherited defects recorded by reading: {len(inherited)}") def main() -> None: