From cc9788862c33110722a5abc5f5ee2f9257668310 Mon Sep 17 00:00:00 2001 From: David F Glidden Date: Tue, 1 Sep 2026 10:34:39 +0200 Subject: [PATCH] [FIX] Declare wake-digest.py's selftest exemption; correct a stale tracker line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two unrelated things found while establishing what PENDING-134 actually needs, which turned out to be nothing. 1. governance-mcp.py --selftest was FAILING. The delegate read-only guarantee flagged five undeclared mutating calls in wake-digest.py, all inside selftest(), all added by yesterday's REVIEWED-131 (e)/(c) build: a job dir with state.json, and two transcripts with and without a human turn. Declared rather than detector-widened, because failing until someone names it is the mechanism's design, not an obstacle to it. Why it is safe: every write goes to a tempfile.mkdtemp() tree the same function removes, and selftest is reachable from --selftest alone, never from a tool call. Its weakness is declared in the same comment: this is a FUNCTION-level exemption, so a future non-tempdir write inside selftest now passes silently. The narrower rule — "writes confined to a tempdir" — is not expressible in this check without data-flow analysis, and naming that limit is preferred to a detector that would be wrong in a harder-to-see way. Selftest now PASSES, 62 controls. 2. MEMORY.md said "ratio_A_to_B VOID until PENDING-134 lands" and "NEXT: rule PENDING-134". Both stale by 18 days: PENDING-134 was ruled REVIEWED-121 on 2026-08-14. REVIEWED-121's own closing sets the real condition — re-derive ONCE after BOTH it and PENDING-137 land — and PENDING-137 is still [PROPOSAL], awaiting a jurist ruling. The live blocker on the fr cell is -137, and it needs the jurist, not the executor. Corrected in place with the superseded text quoted, per the memory discipline: a conflict between a memory layer and the substrate is a verification trigger, and the substrate wins. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_017vKkg2EJF1rGwdFdBogwqx --- claude/memory/MEMORY.md | 2 +- scripts/governance-mcp.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/claude/memory/MEMORY.md b/claude/memory/MEMORY.md index 1545680..3b28ec3 100644 --- a/claude/memory/MEMORY.md +++ b/claude/memory/MEMORY.md @@ -55,7 +55,7 @@ permalink: claude-memory/memory ## Canonical Workstream Trackers *Read the tracker for any active workstream at /wake-up before composing the briefing. Append substantive moves at /wrap-up — to the **chronological log**, not only "current state". Per `feedback-canonical-workstream-tracker-discipline.md`.* - **[Chamber as versioned releases](project-chamber-versioned-releases.md) — THE GOVERNING FRAME for all library work.** The 2000-year Chamber as versioned releases with soft borders, each serving a PURPOSE; scope every library bite through this. **Open decision: which purpose anchors V1.** Read the file, not this line — it holds the reframe that resolved the purpose/scope paralysis. -- [Studium Engine](project-studium-engine.md) — canonical engine tracker. **N0–N2 + R0 + `voice_stamp` built**; corpus **14 sources, trilingual**, fleet **9 suites / 285**. **fr cell all but closed** — 8 grounded (1 A + 7 B), `ratio_A_to_B` **VOID** until PENDING-134 lands. ⚠ **PENDING-131 (c) never bound the engine** (`chunker.py` has `char_range` since Cluster A). **NEXT: rule PENDING-134 — last blocker is a steward MCP restart.** +- [Studium Engine](project-studium-engine.md) — canonical engine tracker. **N0–N2 + R0 + `voice_stamp` built**; corpus **14 sources, trilingual**, fleet **9 suites / 285**. **fr cell all but closed** — 8 grounded (1 A + 7 B), `ratio_A_to_B` **VOID** until **PENDING-137** lands. ⚠ **PENDING-131 (c) never bound the engine** (`chunker.py` has `char_range` since Cluster A). ⚠ **CORRECTED 2026-09-01 — this line read "VOID until PENDING-134 lands / NEXT: rule PENDING-134" and was stale by 18 days.** PENDING-134 was ruled **REVIEWED-121, 2026-08-14**. The re-derivation condition is REVIEWED-121's own closing: `ratio_A_to_B` is re-derived ONCE after **both** REVIEWED-121 **and PENDING-137** land and all dispositions are recorded. **PENDING-137 is still `[PROPOSAL]`, awaiting a JURIST ruling then steward authorization** — it is the live blocker, not -134. **NEXT: the jurist rules PENDING-137**; the MCP surface it needs is verified live (`v2-stratum-tags` key reads; `governance-mcp.py --selftest` PASS, 62 controls, 2026-09-01). - [Studium engine telos — the chamber of voices](project-studium-engine-telos-chamber-of-voices.md) — **the ultimate goal, above the build plan**: the childhood chamber of hero-voices, rebuilt so the counsel is *accountably* theirs. Why verbatim fidelity is load-bearing. - [The Chamber touchstone — the *why*](~/_Dev/studium-engine/docs/the-chamber-touchstone.md) — seven questions to test work against when lost in the trees. **Read at Step 0 of any chamber work.** Holds no state; does not decay. - [The Chamber vision is NOT in one place](project-chamber-vision-is-not-in-one-place.md) — it lives in **seven** sources across two repos + memory. A single home would become an eighth unless it supersedes or points. diff --git a/scripts/governance-mcp.py b/scripts/governance-mcp.py index 6d4694d..c5ec1b9 100644 --- a/scripts/governance-mcp.py +++ b/scripts/governance-mcp.py @@ -832,7 +832,18 @@ def selftest(): # allowlist: a new mutating function in a delegate fails until someone names it and # says why. wake-digest.py is also a SessionStart hook, and emit_brief() is its hook # role; no tool in this file calls it. - _delegates = {"prior-art.py": set(), "wake-digest.py": {"emit_brief"}} + # + # `selftest` named 2026-09-01, and the naming is the mechanism working rather than a + # concession to it. The 2026-08-31 build (REVIEWED-131 (e) and (c)) added controls that + # write fixtures — a job dir with a state.json, two transcripts with and without a human + # turn — and the check went FAIL until someone said why, which is exactly its design. + # Why: every one of those writes is to a tempfile.mkdtemp() tree that the same function + # rmtree()s, and selftest is reachable from `--selftest` alone, never from a tool call. + # ⚠ ITS WEAKNESS, DECLARED: this is a FUNCTION-level exemption, so a future write inside + # selftest that is NOT to a tempdir now passes silently. The narrower rule the check + # cannot express is "writes confined to a tempdir"; naming that limit is preferred to + # widening the detector into something it would take a data-flow analysis to get right. + _delegates = {"prior-art.py": set(), "wake-digest.py": {"emit_brief", "selftest"}} for _fn, _exempt in sorted(_delegates.items()): _dsrc = open(os.path.join(SCRIPTS, _fn), encoding="utf-8").read() _tree = __import__("ast").parse(_dsrc)