From 5cd5faf66ecc15ccd3f7682812bcc706d20d4530 Mon Sep 17 00:00:00 2001 From: David F Glidden Date: Wed, 5 Aug 2026 21:17:33 +0200 Subject: [PATCH] [HARDENING] governance-mcp: the jurist can now read the constitution it design-gates (PENDING-86 a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steward-authorized 2026-08-05, on the jurist's own request while unable to close PENDING-99's Q2 — a question that turns on the chamber constitution's vocabulary (§II.3's "inline anchor marker", §V's marker exclusion), which governance_read did not expose. Third recorded instance on PENDING-86: the constitution, the skill files, contamination-problem.md. Adds two keys to the existing enum: `chamber-spec`, `graduation-spec`. No new tool, no path argument, no traversal surface — the domain stays enumerable and every refusal control still passes. ⚠ THE NON-OBVIOUS PART. Reachability of the KEY is not reachability of the CLAUSE. This file's operative sections begin around line 354; the ~330 lines above them are SUPERSEDED version headers kept as the amendment trail. A jurist reading with the default limit=400 would land squarely in obsoleted text and could rule on superseded clauses — the new access CAUSING the misruling it exists to prevent. So the trap is disclosed on the key's own description, at the point of use, and two controls pin it: - the §V inline-anchor clause and the §II.3 marker constraint are both reachable in ONE paged call (offset=350, limit=2000) — the actual Q2 text - NEGATIVE CONTROL: a first-page read does land in the "(obsoleted)" region, proving the trap is real rather than hypothetical Selftest 29 → 35 controls, 0 fail. Live stdio round-trip confirms the §V clause arrives verbatim through governance_read. ⚠ Requires a Claude.app restart: the running server process carries the old code and will not show the new keys until respawned. Option (d) — keyword search across PENDING/PENDING-archive/REVIEWED — is NOT in this change and remains open on PENDING-86. It is a new tool surface, not two enum entries, and the jurist asked for (a)+(d) together. Refs PENDING-86, PENDING-99 Q2, PENDING-82. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AB3Kryoy6b1pm2Nz1DYdLh --- scripts/governance-mcp.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/scripts/governance-mcp.py b/scripts/governance-mcp.py index 1e4fa75..191b1fb 100644 --- a/scripts/governance-mcp.py +++ b/scripts/governance-mcp.py @@ -69,6 +69,20 @@ FILES = { "claude-md": (os.path.join(D, "CLAUDE.md"), "the executor's governing document"), "memory-index": (os.path.join(wd.MEM, "MEMORY.md"), "wake-loaded memory index"), "app-brief": (wd.BRIEF_PATH, "last generated .app Standing Context block"), + # PENDING-86 option (a), steward-authorized 2026-08-05. The jurist design-gates + # constitutional supersessions of documents it could not read; three distinct + # instances are recorded on that item. These two are the ones the loop actually + # rules on. Read-only, keyed, no path argument — the enum design is unchanged. + "chamber-spec": (os.path.join(HOME, "_Dev", "chamber-library", "docs", + "chamber-library-specification.md"), + "the chamber library constitution — ⚠ the OPERATIVE version header is " + "at the top, but roughly the next 330 lines are SUPERSEDED version " + "headers kept as the amendment trail; the operative sections start at " + "'## 0. What this document is'. Page past them (offset≈350) or you will " + "be reading obsoleted text"), + "graduation-spec": (os.path.join(HOME, "_Dev", "chamber-library", "_curation", + "graduation-spec.yaml"), + "the constitution's machine-readable convention-data + gate-list"), } REPOS = wd.REPOS @@ -351,6 +365,27 @@ def selftest(): t_read({"file": "../../.ssh/id_rsa"}).startswith("ERROR: unknown file key")) chk("governance_read ACCEPTS a listed key [positive control for the refusal above]", t_read({"file": "pending"}).startswith("[pending —")) + + print("\nPENDING-86 (a) — the documents the jurist design-gates are now reachable:") + chk("chamber-spec key reads", + t_read({"file": "chamber-spec"}).startswith("[chamber-spec —")) + chk("graduation-spec key reads", + t_read({"file": "graduation-spec"}).startswith("[graduation-spec —")) + # Reachability of the KEY is not reachability of the CLAUSE. These two controls + # test the actual thing the item exists for: the §II.3 / §V text a Q2-shaped + # ruling turns on. A key that opens onto 330 lines of superseded headers would + # pass the two checks above and still leave the gap wide open. + _spec_deep = t_read({"file": "chamber-spec", "offset": 350, "limit": 2000}) + chk("§V's inline-anchor clause is reachable in one paged call [the Q2 clause]", + "is content-for-the-reader but is **not a prose word**" in _spec_deep) + chk("§II.3's marker constraint is reachable in the same call [the Q2 clause]", + "must not corrupt the" in _spec_deep and "prose-word-identity check under §V" in _spec_deep) + chk("the superseded-header trap is disclosed on the key itself [it would cause the " + "misruling this access exists to prevent]", + "SUPERSEDED version" in FILES["chamber-spec"][1]) + chk("a first-page read lands in the SUPERSEDED region [negative control: proves the " + "trap is real, not hypothetical]", + "(obsoleted)" in t_read({"file": "chamber-spec", "limit": 300})) chk("repo_activity refuses an unlisted repo", t_repo({"repo": "/etc"}).startswith("ERROR: unknown repo")) chk("repo_activity ACCEPTS a listed repo [positive control]",