session 2026-09-14: the 59 answered (zero name their parent); PENDING-186 + PENDING-175 amendments; the memory write-guard is path-keyed
- The 59 unattributable register blocks: ZERO name their parent in their own text; all position-only. 37 cite only FOREIGN ids, so an id-keyed repair would mis-file every one. The obvious automated repair is worse than none. - PENDING-186 [PROPOSAL] filed + AMENDMENT 1: the 'silent failure' ordering constraint is falsified (the harness warns at write time), and the real defect is that our write convention routed around that guard. - Claude Code's near-limit MEMORY.md guard is PATH-KEYED: 5/5 warnings via the ~/.claude symlink path, 0/2 via the real dotfiles path at a LARGER size. Pre-registered and confirmed. MEMORY.md must be edited by the symlink path. - PENDING-175 AMENDMENT 1: governance_item returning only the first block is no longer predicted but REPRODUCED, located at governance-mcp.py:199-202; the second defect is narrower than reported - it is a colon. - Both amendments filed id+marker so they do not join the 59 they describe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJM5fwqp456LDGzqiZXsgu
This commit is contained in:
co-authored by
Claude Opus 5
parent
689c21e0d1
commit
45268f6349
+78
@@ -4968,3 +4968,81 @@ Owner of the claim: `claude/governance/fool/seed/FOOL-SEED-RULE.md`, `<!-- STATE
|
||||
**Files affected:** `claude/governance/fool/seed/FOOL-SEED-RULE.md` (the STATE-CLAIM block); `scripts/governance-drift-check.py` if the unit changes; this item.
|
||||
|
||||
**Awaiting:** Steward annotation. Placement design-gated by the jurist 2026-09-12 — new item rather than an amendment, on PENDING-145's suppression hazard.
|
||||
|
||||
## PENDING-186 — The index's byte budget binds hardest on exactly the content that must load unconditionally
|
||||
|
||||
**Date:** 2026-09-14
|
||||
**Tag:** [PROPOSAL]
|
||||
**Summary:** `MEMORY.md` sits at 23,880 B of a hard 25,000 B auto-load limit past which content is silently dropped at wake, and the 59% of the file that costs the most bytes is the standing-preferences section — rules written out in full precisely because a pointer would not fire — so no trim exists that is not a loss of function.
|
||||
|
||||
**Rationale:** Measured 2026-09-14 from Claude Code's documentation rather than from our own record: auto-memory loads **the first 200 lines OR 25 KB, whichever comes first**, and content beyond that **is not loaded at session start**. There is no load-time warning; the index simply arrives short, and a truncated index reads as complete. Current state: **23,880 B (95.5%) · 114/200 lines** — bytes bind, ≈1,120 B of margin, growth ≈+400 B/day (21 KB on 08-17 → 23.9 KB today). On that rate the limit is crossed in roughly three days.
|
||||
|
||||
The precedent is not hypothetical. The 2026-07-06 two-file split was authorized after the index reached 204.5 KB, where **~88% of it did not load at wake** and nothing detected it. The same failure is re-approaching by ordinary accretion.
|
||||
|
||||
⚠ **The structural point, which is why this is not housekeeping.** The section that dominates the budget is the one whose entries must fire *at moments the session would not know to look* — the rule about nulls being evidence about the query, the rule about reading at the grain a number was produced at. Those are written inline because a pointer to a file only fires if something opens the file. Moving them out to save bytes converts a rule that fires by itself into a rule that fires by luck. **That is loss of function wearing housekeeping's clothes, and byte-count alone cannot see the difference.**
|
||||
|
||||
⚠ **Recorded against my own conduct in the sitting that produced this item:** the numbers driving this had propagated unexamined. A *compaction target* (17.1 KB) was recorded in a ledger as a *ceiling*, carried into this index, and then into a wake briefing where it was announced as falsified. The executor argued against a sound premise from a figure it had never traced to its source, and the error was caught only by a reader positioned outside the executor's own corpus.
|
||||
|
||||
**Options:**
|
||||
- **(a) Trim the index by size.** Rejected above: the bytes are in the content that must load unconditionally.
|
||||
- **(b) Move standing preferences to a second file read explicitly at wake §2.a.** Removes the cap entirely — the 25 KB limit applies *only* to `MEMORY.md`. ⚠ But it converts unconditional auto-injection into a step that must be invoked, and this system has **two recorded instances of described-not-invoked**: the link canary, described here and hand-typed twice instead of run, and `thread-query`, described and almost never reached until it was pointed at an executable.
|
||||
- **(c) Move standing preferences to a file injected by a `SessionStart` hook.** `wake-digest.py` already injects text at `SessionStart` unconditionally, on every session, with no invocation step to forget. This appears to buy the cap-removal of (b) while keeping the unconditional firing of auto-injection. ⚠ **UNVERIFIED ASSUMPTION, named as such: I have not established that hook-injected output has no size cap of its own.** That is one cheap experiment — emit a file of known size from the hook and measure what arrives — and it should be run *before* this option is chosen, not after.
|
||||
- **(d) Hard byte budget on the Active Session block, enforced at wrap.** Treats the symptom; the section is only 12% of the file. Worth doing regardless as a stopgap, and it buys days, not a solution.
|
||||
|
||||
**Recommendation: run the (c) experiment first, then (c) if it holds, with (d) as an immediate stopgap either way.** (c) is the only option that preserves both properties the current design depends on — no cap, and no step anyone can forget. It should not be adopted on its plausibility; the cap question is checkable and cheap, and this item's own history is what happens when a number is adopted without being traced.
|
||||
|
||||
**Files affected:** `claude/memory/MEMORY.md`; a new standing-preferences file if (b)/(c); `.claude/settings.json` and a new hook script if (c); `claude/skills/wake-up/SKILL.md` §2.a if (b); `claude/skills/wrap-up` if (d).
|
||||
|
||||
**Awaiting:** Steward authorization. ⚠ Note the ordering constraint: the index crosses the limit in ~3 days at current growth, and the failure is silent when it arrives.
|
||||
|
||||
## PENDING-186 — AMENDMENT 1: the ordering constraint is falsified, and the real defect is that our write path routes around the guard
|
||||
|
||||
**Date:** 2026-09-14
|
||||
**Tag:** [PROPOSAL] (amends the item above; filed in `id+marker` form deliberately — a bare `### AMENDMENT` here would join the 59 unattributable blocks this same sitting measured)
|
||||
|
||||
**What in the item is now FALSE.** The item asserts *"there is no load-time warning; the index simply arrives short"* and an ordering constraint of *"~3 days to a silent failure."* Both fail. Claude Code warns at **write** time, twice — a near-limit reminder, then an over-limit error — documented in `memory.md` and confirmed by two independent readers. **The silence I asserted was never tested.** In an item whose own recorded conduct failure is a number propagated unexamined, that is the same error one layer along.
|
||||
|
||||
**What replaces it, and it is worse than the original claim.** The jurist's falsifier — *"if the warning has never fired at 95% of the limit, your writes are outside the instrument that would speak"* — was run. Result: **the guard is PATH-KEYED.**
|
||||
- **5/5** genuine warnings (`type=attachment` + `hook_additional_context`, 3 sessions, 21–23.1 KB) followed edits to the **symlink** path `~/.claude/projects/-Users-davidglidden/memory/MEMORY.md`.
|
||||
- **0/2** edits this session to the **real** path `~/dotfiles/claude/memory/MEMORY.md` produced any warning.
|
||||
- `realpath` is **identical**. Same file, same bytes, different instrument behaviour.
|
||||
- ⚠ **Rival explanation excluded by internal control:** today's file was *larger* (23.9 KB) than every case where the guard did fire, so "not near enough to warn" cannot account for it.
|
||||
- ⚠ **Pre-registered and confirmed:** the prediction was stated before execution, an edit was routed through the symlink path, and the warning fired immediately. A second signature appeared unbidden — the frontmatter `modified:` stamp updated on that path only.
|
||||
|
||||
⚠ **THE IMPLICATED RULE.** `reference-governance-files-are-dotfiles-symlinks.md` directs edits to the real `~/dotfiles/…` path, and is **scoped `PENDING`/`REVIEWED` only**. The executor extended it to `MEMORY.md` without noticing the scope, and **that extension is what silenced the guard**. The workaround that makes the write possible is what disables the alarm. Neither half was visible from the other half alone. **This adds a remedy the item does not have: a write-path convention, which is cheaper than every relocation option and independent of all of them.**
|
||||
|
||||
**Option (c) is WITHDRAWN** on the jurist's documented cap. ⚠ **But the cap itself is in conflict and the conflict is recorded, not resolved:** the jurist quotes a 10,000-character hook-output cap from the primary source; an independently-spawned reader searched `hooks-guide.md` and `hooks.md` and returns **NOT FOUND at 92% confidence**. Both claim primary source. Neither wins by precedence. Live stake: `wake-digest.py` emits **8,136 characters** into that channel every session, which is 81% of a cap that may not exist — and the executor's own test of it was **uninformative** (under threshold) and was reported as uninformative.
|
||||
|
||||
**Option (e) is confirmed, with two qualifications the recommendation should carry.** `InstructionsLoaded` (`hooks-guide.md:503`) and `.claude/rules/*.md` are verified by the jurist and independently at 97–98%. ⚠ **Both readers are LLMs reading the same documents** — Constraint 6's *weak* separation, not difference of formation; agreement here is one reading counted twice, the same shape as this sitting's shared-substrate finding. ⚠ And the docs are **silent on rules-file size limits**, so (e) trades a **known** 25 KB cap for an **undocumented** one. That is not obviously a gain on honest-degradation grounds; `InstructionsLoaded` is what redeems it, by supplying the positive control the present arrangement lacks.
|
||||
|
||||
**CORRECTION to this item's own figure.** The item cites the 2026-07-06 split as following the index reaching **204.5 KB**. The registers also record **213 KB → 17 KB, 91.8%** (`PENDING-archive.md:1872`; `skill-harvest-archive.md:82`). The 204.5 figure appears once, in the proposal row, phrased *"Tonight the index is 204.5KB"* — so these are plausibly **two moments**, proposal-writing and execution, rather than two claims about one moment. That reading is **not established**. What is established is that the item cited one figure without recording that another existed. Also: the authorization the jurist could not locate is at `skill-harvest-archive.md:367`, **outside the three register files the governance tools cover** — the shared-substrate asymmetry working in the useful direction.
|
||||
|
||||
⚠ **An anomaly named and deliberately not chased.** The guard reports **23.1 KB**; the file measured 23,933 B when it fired and 24,292 B after. **No unit reconciles** — bytes/1000, bytes/1024, chars/1000, chars/1024 give 23.93, 23.37, 23.54, 22.99. And 23.1 is the *identical* value reported on 2026-09-12, so a stale or cached reading is live. Current size is therefore **93–97% with a margin of 708–1,710**, bounded rather than pinned. Left unresolved because **the disposition is the same under every reading**, and a third measurement round on a figure that moves no decision fails proportionality.
|
||||
|
||||
**Concur with DEFERRED on the jurist's four conditions, and add a fifth:** settle the MEMORY.md write-path convention first. It is a one-line change, it restores an instrument that already exists, and it is independent of which relocation option is eventually chosen.
|
||||
|
||||
**Files affected:** adds `claude/memory/reference-governance-files-are-dotfiles-symlinks.md` and `scripts/wake-digest.py` (hook-output size, if the 10 k cap is real) to the item's list.
|
||||
|
||||
⚠ **SELF-CORRECTION, same sitting, before any ruling rests on it.** This amendment first described that note as needing a *"scope correction"*. **False — the note is correctly scoped.** Read in full, it says *"Use the real-dotfiles-path route for `PENDING.md` and `REVIEWED.md` **only**"* and never mentions `MEMORY.md`. **The executor over-applied a correctly-scoped note and then characterised the note as the defect.** What the note actually lacked was (i) the FILE-symlink vs DIRECTORY-symlink distinction — writing *through* the symlink directory succeeds, so the flat refusal claim is false as stated — and (ii) the measured cost of over-extension. Both are now added to it as an **addition**, not a correction. ⚠ The blame-shift is the point worth keeping: the executor's first account located the fault in the artefact rather than in its own reading, and only a full read of the artefact caught it.
|
||||
|
||||
**Awaiting:** Steward authorization. The executor has already adopted the symlink write path for `MEMORY.md` as of this sitting.
|
||||
|
||||
## PENDING-175 — AMENDMENT 1: reproduced with the line located, and the second defect is narrower than reported — it is a colon
|
||||
|
||||
**Date:** 2026-09-14
|
||||
**Tag:** [FIX] for defect 1 · [HARDENING] for defect 2
|
||||
**Filed `id+marker` deliberately.** ⚠ And with an irony worth stating rather than leaving to be discovered: this amendment lands under an id whose retrieval is broken **in precisely the way it describes**, so `governance_item('PENDING-175')` will not return it.
|
||||
|
||||
**Defect 1 — PENDING-175 is no longer predicted. Reproduced, with the line.** Observed by the jurist today: `governance_item('PENDING-186')` returned the original block byte-identical with no sign that AMENDMENT 1 existed. Reproduced by executing the handler: **2 blocks exist under `PENDING-186`; `t_item` returns 1** (the original, 4,606 chars, `AMENDMENT 1` absent). Mechanism, located: `scripts/governance-mcp.py:199–202` — `t_item` iterates `wd.item_spans` and **`return`s on the first match**. `head.startswith(ident + " ")` matches the original first, so every later sibling is unreachable. **A `return` where an accumulate belongs.** Controls held: `PENDING-185` resolves; `PENDING-99999` returns NOT FOUND.
|
||||
|
||||
⚠ **THE NEAR-MISS IS THE POINT, and it is not hypothetical.** The jurist was about to draft a ruling from that first read. It would have ruled on a version of PENDING-186 that **withdraws option (c), adds a fifth condition, and records a conflict with the jurist's own finding** — none of which the tool showed it. **The register's read path can serve a stale item to the party whose job is to rule on it, silently, with no indication anything was omitted.**
|
||||
|
||||
**Defect 2 — REPORTED AS "search surfaces ids the fetch tool cannot take". That is not quite what happens, and the difference changes the fix.** Fed the displayed head **byte-exactly**, `t_item` **does** resolve it — the `head == ident` arm at line 200 succeeds. What fails is the **natural truncation** a reader would actually type: `'PENDING-186 — AMENDMENT 1'` → NOT FOUND, because `startswith(ident + " ")` compares against `"1:"` and not `"1 "`. **The defect is a colon.** ⚠ Filed this way because the reported form would send someone to build a new lookup path; the actual fix is **normalisation at the seam** — strip a trailing `:`-terminated fragment, or have `t_search` emit a copy-paste-safe id beside the head.
|
||||
|
||||
**The deeper form, and why no guard caught it.** `t_search` prints `head` (the full header line) and closes *"Next: governance_item(id)"*; `t_item` keys on the **id prefix**. Two notions of an item's identity across one seam, each internally coherent. ⚠ The function's own docstring (lines 240–242) asserts *"no second definition of 'an item'"* — **the false claim is inside the function making it.** And the existing unreachable-by-id warning is **provably silent here** (measured: `orphan-warning fired: False`): it covers headers hidden by leading whitespace, not siblings **shadowed by an earlier match**. A second class the guard was never shaped for.
|
||||
|
||||
**Recommendation.** (1) `t_item` accumulates and returns **all** blocks under an id, with a count in the header line, so a single-block return becomes a claim rather than a default. (2) `t_search` emits a copy-paste-safe id, or `t_item` normalises the truncation. (3) The docstring's "no second definition" claim is struck — it is now false and it is load-bearing for anyone extending this file.
|
||||
|
||||
**Files affected:** `scripts/governance-mcp.py` (`t_item` 186–204, `t_search` 230–325 + docstring).
|
||||
|
||||
**Awaiting:** Steward authorization for (1) and (3) as `[FIX]`; (2) is `[HARDENING]` — it is the seam class, not the instance.
|
||||
|
||||
Reference in New Issue
Block a user