From 73922e1bc7dd629edc208ece1b24da0e96aa8be1 Mon Sep 17 00:00:00 2001 From: David F Glidden Date: Tue, 25 Aug 2026 19:21:55 +0200 Subject: [PATCH] [FIX] PENDING-151 step 2: the jurist can reach the pairs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit governance_pair serves both arms of one enumerated v1 Chamber pair, verbatim, and chamber-v1-diff joins the governance_read whitelist. Steward-authorized. ⚠ STATICALLY ENUMERATED RATHER THAN DIRECTORY-WALKED, and the distinction is the point. t_read's design property is 'no path argument'; its SUBSTANCE is that the reachable set is reviewed rather than matched. Walking the archive at import would preserve the letter — the caller still passes no path — and lose the substance, because a file dropped in later would become jurist-readable with nobody having looked at it. The 2025 archive is a closed record, so static enumeration costs nothing and keeps the guarantee. The unit served is the PAIR, not the file, because that is the unit of step 2's question: neither arm alone answers whether a divergence is content or register. Derived from the consumer rather than from how the files sit on disk. All three filename defects reproduced exactly and NOT repaired — leading space, doubled extension, trailing space in a directory name. A reader sees the archive, not a tidied copy. The tool's own header states the step-2 question and the length confound, so a reader arriving through it cannot receive the material without the caveat. ⚠ Two raw files carry stray header lines (a filename, and '[gpt reply]'). Real content, not pointers; ~3 tokens each into term extraction. Declared, not stripped — stripping would edit the record. ⚠ chamber-sessions-private: first non-governance material on this surface. Noted in the code because the surface exists to be bounded. The instrument's own AST read-only controls still pass: no mutating call, git read-only. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01J6hZXNYSxEfZseBGTni4sf --- PENDING.md | 21 ++++++++- scripts/governance-mcp.py | 93 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index 1360d7e..b25ecdc 100644 --- a/PENDING.md +++ b/PENDING.md @@ -4449,7 +4449,26 @@ extractor is a capitalisation heuristic, not a named-entity recogniser. It will lower-case entities and admit ordinary capitalised nouns. Counts are indicative; the lists are the evidence. -**Files affected:** `scripts/chamber-v1-formation-diff.py` (new), the output document (new). +#### ⚠ Two raw files carry a stray header line, declared rather than stripped + +`[standard]claude-raw.txt.txt` (Savall) begins with the literal line `[standard]claude-raw.txt`, +and `[standard]gpt-raw.txt` begins with `[gpt reply]`. Both are 2025 artifacts. They are +**real content files** — 1,211 and 682 words — not pointers. The header lines contribute +roughly three tokens each to term extraction. **Not stripped:** removing them would edit the +record, and the diff is supposed to read what is there. Declared because a step-2 reader will +see them in the verbatim text and should know they are archive noise, not output. + +#### The jurist can now reach both, as of 2026-08-25 + +`governance-mcp.py` gains `governance_pair` — both arms of one enumerated pair, verbatim — and +`chamber-v1-diff` joins the `governance_read` whitelist. **Steward-authorized.** The pairs are +**statically enumerated, not directory-walked:** `t_read`'s design property is *"no path +argument"*, and its substance is that the reachable set is REVIEWED rather than matched. A +walk would keep the letter and lose that. ⚠ **Requires a Claude Desktop restart** — MCP +servers load at app start, so until then the tool is absent rather than empty. + +**Files affected:** `scripts/chamber-v1-formation-diff.py` (new), the output document (new), +`scripts/governance-mcp.py` (pair reader + one whitelist entry). Archive **untouched and unrenamed** — filename defects preserved as the 2025 record. **Awaiting:** a **non-executor** reader for step 2. diff --git a/scripts/governance-mcp.py b/scripts/governance-mcp.py index 5de5752..f85cd6b 100644 --- a/scripts/governance-mcp.py +++ b/scripts/governance-mcp.py @@ -141,6 +141,11 @@ FILES = { "the fr fixture's CITATION TEXTS — the quoted strings " "themselves. This is the file that answers 'whose " "proposition does the claim assert?'"), + "chamber-v1-diff": (os.path.expanduser( + "~/dotfiles/claude/governance/chamber-v1-formation-diff-2026-08-25.md"), + "PENDING-151 STEP 1 — the mechanical formation diff over the 9 v1 Chamber pairs. " + "Counts and word lists only. ⚠ It renders NO verdict: whether a divergence is " + "content or register is step 2, and the executor is barred from it."), } REPOS = wd.REPOS @@ -345,6 +350,84 @@ def t_repo(args): return f"[{name}]\n\n{status}\n\nLAST {n} COMMITS\n{log}" + +# ── PENDING-151 step 2 ──────────────────────────────────────────────────────────── +# The step-2 judge reads a PAIR, not a file: the question is whether two arms diverge in +# content or only in register, and neither arm answers it alone. So the unit served here +# is the unit of the work — derived from the consumer, not from how the files happen to +# sit on disk. +# +# ⚠ STATICALLY ENUMERATED, and deliberately. `t_read`'s design property is "no path +# argument", and the point of it is that the reachable set is REVIEWED rather than +# matched. Walking the directory at import would preserve the letter (the caller still +# passes no path) and lose the substance: a file dropped into the archive would become +# jurist-readable with nobody having looked at it. The 2025 archive is a closed record. +# +# ⚠ The three filename defects are reproduced EXACTLY and are not repaired: a leading +# space in one claude arm, a doubled extension in another, a trailing space in a +# directory name. PENDING-151: they are the 2025 record and renaming is a separate [FIX] +# the steward owns. A reader who sees them here is seeing the archive, not a tidied copy. +# +# ⚠ This is `chamber-sessions-private`. Steward-authorized 2026-08-25 to reach the jurist +# for step 2; noted because it is the first non-governance, non-public material on this +# surface, and the surface exists to be bounded. +V1_ROOT = os.path.expanduser( + "~/_Dev/animal-davidglidden-eu/chamber-sessions-private/2025") +PAIRS = { + "06-14-owl-emblem/shadow": + ("2025-06-14-owl-emblem/[shadow]gpt-raw.txt", + "2025-06-14-owl-emblem/ [shadow]claude-raw.txt"), + "06-14-owl-emblem/standard": + ("2025-06-14-owl-emblem/[standard]gpt-raw.txt", + "2025-06-14-owl-emblem/[standard]claude-raw.txt"), + "06-16-first-submission-first-light/first-light": + ("2025-06-16-first-submission-first-light/[first-light]gpt-raw.txt", + "2025-06-16-first-submission-first-light/[first-light]claude-raw.txt"), + "06-17-the-ethics-of-the-reply/shadow": + ("2025-06-17-The Ethics of the Reply /[shadow]gpt-raw.txt", + "2025-06-17-The Ethics of the Reply /[shadow]claude-raw.txt"), + "06-17-the-ethics-of-the-reply/standard": + ("2025-06-17-The Ethics of the Reply /[standard]gpt-raw.txt", + "2025-06-17-The Ethics of the Reply /[standard]claude-raw.txt"), + "06-19-savall-prometheus-21/standard": + ("2025-06-19-Savall-Prometheus-21/[standard]gpt-raw.txt", + "2025-06-19-Savall-Prometheus-21/[standard]claude-raw.txt.txt"), + "07-01-marginalia/standard": + ("2025-07-01-marginalia/[standard]gpt-raw.txt", + "2025-07-01-marginalia/[standard]claude-raw.txt"), + "07-11-the-ethics-of-the-reply-part-ii/shadow": + ("2025-07-11-the-ethics-of-the-reply-part-ii/[shadow]gpt-raw.txt", + "2025-07-11-the-ethics-of-the-reply-part-ii/[shadow]claude-raw.txt"), + "07-11-the-ethics-of-the-reply-part-ii/standard": + ("2025-07-11-the-ethics-of-the-reply-part-ii/[standard]gpt-raw.txt", + "2025-07-11-the-ethics-of-the-reply-part-ii/[standard]claude-raw.txt"), +} + + +def t_pair(args): + """Both arms of one enumerated v1 Chamber pair, verbatim. No path argument.""" + key = (args.get("pair") or "").strip() + if key not in PAIRS: + return ("ERROR: unknown pair %r. Allowed: %s" + % (key, ", ".join(sorted(PAIRS)))) + g_rel, c_rel = PAIRS[key] + out = [f"[v1 Chamber pair — {key} — verbatim, both arms]", + "", + "⚠ STEP 2 IS THE QUESTION THIS SERVES: does a divergence carry DIFFERENT", + "CONTENT, or the SAME CONTENT IN A DIFFERENT REGISTER? PENDING-151 reserves it", + "to the jurist or steward: the executor is one of the two formations compared.", + "⚠ The Claude arm is longer in 9 of 9 pairs (1.41x-3.40x). Distinctive-term", + "counts rise with length by construction; see chamber-v1-diff for the", + "length-normalised columns and their declared limits.", + ""] + for arm, rel in (("GPT", g_rel), ("CLAUDE", c_rel)): + text = read(os.path.join(V1_ROOT, rel)) + out += [f"───────── {arm} arm ── {rel}", ""] + out += [text if text is not None + else f"UNREADABLE: {rel} is absent or unreadable at this time.", ""] + return "\n".join(out) + + TOOLS = [ ("governance_state", t_state, "Current governance state, computed live: every open authorization item with its " @@ -366,6 +449,16 @@ TOOLS = [ "offset": {"type": "integer", "description": "0-based first line (default 0)."}, "limit": {"type": "integer", "description": "Lines to return, max 2000 (default 400)."}}, "required": ["file"]}), + ("governance_pair", t_pair, + "Both arms of one v1 Chamber formation pair (2025 GPT and 2025 Claude reading the " + "same submitted text), verbatim, chosen by key. This is PENDING-151 step 2's " + "material: the executor may run the mechanical diff but MAY NOT judge whether a " + "divergence is content or register, being one of the two formations compared. " + "Read chamber-v1-diff first for the counts and their length confound.", + {"type": "object", "properties": { + "pair": {"type": "string", "enum": sorted(PAIRS), + "description": "Which pair, as session/protocol."}}, + "required": ["pair"]}), ("governance_search", t_search, "Keyword search across PENDING.md, PENDING-archive.md and REVIEWED.md. Use this to " "DISCOVER a relevant prior item or ruling whose id you do not already know — the case "