Compare commits
6
Commits
689c21e0d1
...
6c202ec823
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c202ec823 | ||
|
|
fb02605735 | ||
|
|
73c1c6e747 | ||
|
|
964b0e818d | ||
|
|
830bc7260f | ||
|
|
45268f6349 |
+123
@@ -4968,3 +4968,126 @@ 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.
|
||||
|
||||
## PENDING-187 — Governed weight-delta toy: Phase 0 design complete, ready for a build ruling
|
||||
|
||||
**Date:** 2026-09-17
|
||||
**Tag:** [PROPOSAL]
|
||||
**Summary:** Phase 0 (research + design) is complete for a standalone, sandboxed toy testing whether a PENDING → REVIEWED-style governance pattern — staged proposal, an automated gate, a signed human ruling, verifiable non-effect on rejection — can be superimposed on weight adjustment rather than on document-shaped memory. No code exists yet; no CapableMind, L1, or Chamber substrate is touched by the design, or would be touched by the build.
|
||||
|
||||
**Rationale:** Commissioned via a research-and-design brief to Claude Fable 5.1 in Claude Code, prompted by the Sutton/Oak Lab continual-learning discussion (2026-09-16). Fable's design (`governed-weight-delta-toy-DESIGN-2026-09-17.md`) proposes class-incremental split-MNIST as the toy substrate — chosen because regularisation-based mitigations (EWC, synaptic intelligence) are independently documented to fail outright there while replay-based methods clear ninety per cent, a legible pass/fail signal — LoRA-style adapters as the staging object (a delta is a discrete, revertible file; the base is never written until promotion), a hash-chained ledger recording every candidate regardless of disposition, and eight invariants each paired with a dedicated negative control.
|
||||
|
||||
Jurist review (2026-09-17) found the design sound on all five points Fable flagged for its own scrutiny, with one item outstanding: §2.4's claim that a rejected candidate leaves 'the ledgers differ[ing] only by the entries concerning the rejected candidates' is not yet shown consistent with §3.7's ledger schema, which carries a wall-clock `ts` field of unstated hash-participation. If `ts` sits inside `entry_hash`, every entry *after* a rejection diverges from a clean run's, not only the rejected entries themselves. This does not touch the design's load-bearing state-hash prediction (P5), which carries no timestamp.
|
||||
|
||||
**Recommendation:** Proceed to build per §4.4's slicing, minimal cut first (D7: slices 1–4, scenarios S1–S5 and S9), with the §2.4 fix — exclude `ts` from `entry_hash`, or narrow the claim to state hashes only — folded into slice 2 rather than treated as a pre-build blocker. Slices 5 and beyond (signatures, rollback, S6–S8) stay optional pending what the minimal cut shows.
|
||||
|
||||
**Files affected:** None yet. A new, isolated working directory for the build; no existing repo is touched.
|
||||
|
||||
**Awaiting:** Steward ruling — AUTHORIZED / DEFERRED / REJECTED — on proceeding to build. Full jurist review: this conversation, 2026-09-17.
|
||||
|
||||
## PENDING-139 — AMENDMENT 1: a third blind spot, and it is a unit mismatch rather than a marker defect
|
||||
|
||||
**Date:** 2026-09-20
|
||||
**Tag:** [HARDENING]
|
||||
|
||||
**Summary:** `governance-drift-check.py`'s register-integrity check cannot detect an in-place rewrite of a **placed ruling's disposition fields**, because such a rewrite produces no amendment-shaped block and the check's unit is the block. This is distinct in kind from the two defects the parent item records: (A) and (B) are *marker* defects — a `###` heading the pattern fails to match, a negated token read as an assertion — repairable by fixing a regex. This one is not repairable by fixing a regex, because the thing to be detected never enters the population the regex runs over.
|
||||
|
||||
**Observed 2026-09-20, not predicted.** The steward rewrote REVIEWED-140's `Decision:`, `Ruled by:` and `Authorized by:` fields in place, completing a ruling that had been begun 2026-09-17 and interrupted mid-write. The check ran immediately afterwards and reported `register integrity: 43 attributable amendment block(s) checked, all resolve`. **The silence is correct on the merits** — completing an interrupted entry is legitimate, no amendment was involved, and nothing was lost — **but the instrument could not have reported otherwise on any input of this shape**, including a rewrite that was not legitimate. A net that cannot fire on a class has not been shown to protect against it; per the ladder, its silence is uninformative rather than reassuring.
|
||||
|
||||
**Why the parent item does not cover it.** PENDING-139's prospective exposure is *an amendment replacing the record it amends* — the REVIEWED-87 shape the check was earned from on 2026-08-07. Both parties to that shape are amendment-shaped blocks, so both are inside the check's unit and the failure is that the regex misses one of them. The exposure named here has **no amendment at either end**: a placed entry is edited, the edit leaves no block, and the register retains no trace that any field ever read differently. Same instrument, same file, different failure mode; filed here rather than as a new item so the instrument's exposures stay in one place and the remedy can be ruled once.
|
||||
|
||||
**Class.** Unit mismatch — the instrument's unit is the amendment block, the question's unit is the entry. Fifth-plus instance of this class in the record since 2026-09-08 (`register_scan`'s header-vs-block, the `12/63` preamble-recorded-vs-delivered near-miss, the `31/28` predicate incommensurability, the `[:72]`/`[:100]` truncations). **It is the class that reading does not catch** — each instance was found by running something, never by looking harder.
|
||||
|
||||
**What today's events also establish, bearing on the remedy.** Register commits are **not atomic per entry**, measured over the last twelve commits touching `REVIEWED.md`: five added two entries in one commit, one added none (an in-place edit), and several bundled the register with two to nine unrelated files. So git history is a *real* but *coarse* witness — it preserves that something changed and can show the prior bytes, but a single commit may carry several entries and unrelated files, so `git log -- REVIEWED.md` does not isolate a given ruling's edit history without further work. This is the same fact the jurist flagged at REVIEWED-140 row 4 as beyond its reach, measured here by the party that has the substrate.
|
||||
|
||||
**Options.**
|
||||
1. **Content-hash each placed entry** and check the hashes against a stored manifest — detects any field rewrite, at the cost of a manifest that must itself be maintained and that becomes a second place the truth lives.
|
||||
2. **Derive the check from git** — compare each entry's current text against its text at the commit that placed it, and report entries whose disposition fields differ. No new stored state; bounded by the coarseness measured above.
|
||||
3. **Require that a placed ruling's disposition fields are never edited in place** — corrections arrive as amendments — and let the existing block machinery cover it. Cheapest to state, but it is a convention with no detector, which is the disarmed-tripwire class the parent item already names.
|
||||
4. **Accept and record.** The exposure is prospective, as it was for (A); no loss has occurred.
|
||||
|
||||
**Recommendation:** Option 2, and not before PENDING-146 settles. Option 3 would add amendments to a register whose amendment-attribution convention is exactly what PENDING-146 has open — 59 blocks already cannot be attributed, and 37 of those would be actively mis-filed by an id-keyed repair. **Prescribing more amendments before the convention is ruled writes more of the population the convention question exists to bound.** Option 1 duplicates state the substrate already holds. Option 2 reads the substrate directly and adds nothing to maintain.
|
||||
|
||||
⚠ **This amendment's own filing is a check on the finding it reports.** It is filed as `## PENDING-139 — AMENDMENT 1:` — the id+marker form established 2026-09-14 — and the instrument was run before and after with the counts predicted in advance. A bare `### AMENDMENT` heading here would have joined the 59 it discusses.
|
||||
|
||||
**Files affected:** `scripts/governance-drift-check.py` (register-integrity check); no change made under this amendment.
|
||||
|
||||
**Awaiting:** Steward annotation, with PENDING-139's two original defects — one ruling for the instrument, not three.
|
||||
|
||||
+24
-1
@@ -3449,4 +3449,27 @@ register-integrity check was built for (2026-08-07, REVIEWED-87 overwritten by i
|
||||
here: anchor register citations to symbols or content rather than line numbers** — the reasoning that makes `source_has()` assemble its needle from parts. A
|
||||
line number in a placed ruling is a claim with a half-life measured in days.
|
||||
|
||||
**If AUTHORIZED:** Proceed. Future citations of code in this register carry a symbol or a quoted fragment; a bare `file:line` is to be read as provisional.
|
||||
**If AUTHORIZED:** Proceed. Future citations of code in this register carry a symbol or a quoted fragment; a bare `file:line` is to be read as provisional.
|
||||
|
||||
## REVIEWED-140 — PENDING-187 — Jurist review of the Phase 0 design: sound, one item folded into build rather than gating it
|
||||
|
||||
**Date:** 2026-09-17
|
||||
**Decision:** AUTHORIZED. Proceed to build per PENDING-187's Recommendation — minimal cut first (D7: slices 1–4, scenarios S1–S5 and S9) — with the §2.4 `ts`/`entry_hash` fix folded into slice 2 rather than gating slice 1's start.
|
||||
|
||||
**Ruled by:** steward, 2026-09-20, in chat.
|
||||
**Drafted by:** jurist (Claude.app), at the steward's instruction, 2026-09-17.
|
||||
**Authorized by:** steward, 2026-09-20.
|
||||
|
||||
Fable's own §8 asked the jurist to attack five points; each is answered, then two independent checks and one further finding.
|
||||
|
||||
- **F1 (staging vs proposer-side mitigation) is a fair re-derivation, not a dodge.** The brief itself conflated two functions in one sentence — 'candidate mechanisms for staging... EWC as a soft-protection mechanism' — and F1 corrects the brief's error rather than evading its comparison.
|
||||
- **§3.5's voiding rule is deliberately asymmetric, and correctly so on the axis it covers.** It over-voids on unrelated state transitions (by design — a round-trip to the same hash should not silently reactivate an old signature) and under-covers a narrower case: two candidates can be staged and gated against the same protected set with neither promoted, so a later report can reveal something relevant to an earlier, still-`AUTHORIZED` ruling without voiding it, since `CANDIDATE_STAGED`/`GATE_REPORT` aren't state-changing. Logged as a limit, not a defect to fix now.
|
||||
- **The `holds` table (§5): row 2 ('no effect until ruled') is honest, not flattering** — the asymmetry is architecturally enforced (compare-and-swap on an immutable base) against conventionally observed (discipline, not proof), a real difference. **Row 1 is the decorative one** — true near-tautologically for anything built as stage-then-rule. **Row 4 may be understated**, contingent on a fact the jurist cannot check from here: whether `PENDING.md`/`REVIEWED.md` commits are atomic per entry. If not, the document register's append-only-ness is closer to a norm than a chain, and the toy's ledger is the stronger of the two without being marked as such.
|
||||
- **Proportion: mostly right-sized; the predicted bias shows in what got specified, not in what the build commits to first.** The object model and eight invariants aren't excess for this steward. Nine scenarios and full signing infrastructure are generous for a toy, but §4.4's own slicing already gates exactly that behind 'extended'.
|
||||
- **One further finding, not among the five asked:** §2.4 check 4's ledger bit-identity claim is inconsistent with §3.7's `ts` field as written — detailed in PENDING-187.
|
||||
|
||||
**Independent verification**, by a different route than the design's own (search, not the `ar5iv` fetch it used):
|
||||
1. The class-incremental collapse the whole toy setup rests on — regularisation methods failing outright on split MNIST, replay-based methods clearing ninety per cent — is corroborated across independent sources. Not re-derived digit-for-digit; a second witness on the finding, not a repeat of the first.
|
||||
2. SageMaker's three-value registry status (`Approved`/`Rejected`/`PendingManualApproval`), used in F5's not-novel claim, is confirmed against AWS's own current API reference.
|
||||
|
||||
**Proceed:** Hand `PENDING-187` and this entry to the executor to begin build at slice 1. The §2.4 fix is scoped into slice 2, not a gate on slice 1's start. Tag any commit touching this work with `REVIEWED-140`.
|
||||
@@ -0,0 +1,547 @@
|
||||
# Governed Weight-Adjustment Layer (toy) — Phase 0: research and design
|
||||
|
||||
**Date:** 2026-09-17
|
||||
**Author:** Claude Code (executor) — Claude Fable 5.1
|
||||
**Tag:** `[PROPOSAL]` — the executor's own characterization of its own work; re-taggable by steward or jurist.
|
||||
**Status:** Returned for steward and jurist review under §5 of the brief. No PENDING id assigned; nothing appended to `PENDING.md`. **A completed design is not authorization to build.** Nothing was built. Two one-shot checks were run (a register search and an arithmetic check); both are reported in §11 with their controls.
|
||||
**Scope boundary:** Standalone sandbox. No code, data, credentials or substrate of CapableMind, L1 or the Chamber is used or touched. One observation about an existing CapableMind spec is recorded in §9 — as an observation, not a proposal.
|
||||
**Self-contained:** written to be ruled on without repository access.
|
||||
|
||||
**Claim marks used throughout**
|
||||
|
||||
| Mark | Meaning |
|
||||
|---|---|
|
||||
| **[V]** | Verified this session against a source; the source is named in §11 |
|
||||
| **[R]** | Recalled from training; not checked this session |
|
||||
| **[P]** | Prediction about what a build would show; each carries its falsifier |
|
||||
| **[J]** | Judgment. Standpoint, disclosed once: I am the party who would build this; my bias runs toward composing more mechanism than a toy needs; and every line here has had exactly one reader |
|
||||
|
||||
---
|
||||
|
||||
## 0. One-screen summary
|
||||
|
||||
**Recommendations**
|
||||
|
||||
1. **Setup** — split-MNIST, class-incremental, five tasks of two digits, one 10-way output head, a 784-400-400-10 MLP with no BatchNorm and no dropout, CPU only.
|
||||
2. **Staging object** — a low-rank (LoRA-style) delta file, bound by hash to the exact base state it was trained against. *Replay* is recommended as the proposer's training technique — it is not a staging mechanism. *EWC* is not recommended.
|
||||
3. **Gate metric** — the per-merge, per-task paired accuracy change on a protected set (the one-step term of backward transfer), plus cumulative drop against a high-water mark, plus counts of flipped examples. The gate emits *findings*, never dispositions.
|
||||
4. **Verifiable non-effect** — bases are immutable and content-addressed; the hash runs over a *defined state surface* that is wider than the weights; a behavioural probe and a counterfactual replay check by different routes; and every check has a negative control proving it can fire.
|
||||
5. **Ruling** — AUTHORIZED / DEFERRED / REJECTED, signed by the human, bound by hash to the candidate, the gate report, the parent state and the gate policy. Promotion is compare-and-swap on the parent hash. A ruling does not survive a state transition.
|
||||
|
||||
**Five framing findings** (§1) — places where the brief's framing needs adjusting before the design can be honest:
|
||||
|
||||
- **F1** The brief's three 'candidate mechanisms' are not three answers to one question. One stages; two mitigate.
|
||||
- **F2** Under a never-mutate design, 'no residue in the base' is true by construction — so a bare checksum demonstrates nothing. The proof burden moves elsewhere.
|
||||
- **F3** Governance preserves; it does not teach. The gate's value is invisible on the happy path and appears only under proposer faults.
|
||||
- **F4** The PENDING → REVIEWED analogy breaks at legibility: the human never reads the delta, only a measurement of it.
|
||||
- **F5** The engineering pattern is not novel. This is pattern transfer, and should be described that way.
|
||||
|
||||
---
|
||||
|
||||
## 1. Framing findings
|
||||
|
||||
### F1 — One of the three mechanisms stages; the other two do something else
|
||||
|
||||
The brief (§2) asks for a survey of 'candidate mechanisms for staging a weight delta as a separate, revertible object: LoRA/adapter-style low-rank deltas; Elastic Weight Consolidation …; a simple replay buffer', and a recommendation of 'one as primary … against the other two'.
|
||||
|
||||
Only the first is a staging mechanism. EWC is a penalty term in the loss; replay is extra data in the batch. Both act *during training* and shape *which* delta gets produced. Neither yields an object separable from the base, and neither offers any reversion of its own — to revert an EWC-trained model one restores a checkpoint, at which point the checkpoint is the staging mechanism and EWC is merely the optimizer's objective.
|
||||
|
||||
So the question has two axes, and gets two answers:
|
||||
|
||||
| Axis | Question | Answer |
|
||||
|---|---|---|
|
||||
| Representation | What object holds a proposed change before a decision? | A low-rank delta file (§2.2) |
|
||||
| Proposer technique | How does the proposer produce deltas that deserve to pass? | Replay (§2.2) |
|
||||
|
||||
The governance consequence is the useful part: **the gate must be indifferent to the second axis.** It evaluates what the delta *does*, never how it was made. 'This candidate was trained with replay, so it is safe' is a claim by the proposer about its own work; the gate does not read it.
|
||||
|
||||
### F2 — 'No residue' is trivially true of the base, so the proof burden moves
|
||||
|
||||
If the base is never written before a ruling, then a rejected candidate trivially leaves the base unchanged, and a before/after checksum is a check that cannot fail. A check that cannot fail is not evidence. The demonstration therefore has to earn its weight in three other places:
|
||||
|
||||
- **(a) The state surface.** The weights are not the whole governed state. The replay buffer, the protected set, the gate's thresholds and the high-water marks all condition future behaviour, and each is a channel through which a rejected candidate could leave something behind (§2.4).
|
||||
- **(b) Negative controls.** Each check must be shown to fire on a planted violation (§3.9).
|
||||
- **(c) Counterfactual replay.** Show that everything downstream of a rejected candidate is bit-identical to a run in which that candidate was never proposed — the only differences being the ledger entries that record it (§2.4).
|
||||
|
||||
One residue is not eliminable and should be named rather than hidden: **the proposer learns from the rejection.** Whoever trains the next candidate has seen the gate report. 'Zero residue' is a claim about the governed state, never about the system including its proposer. This is also the mechanism by which a protected set stops being held-out (§2.3).
|
||||
|
||||
### F3 — Governance preserves; it does not teach
|
||||
|
||||
Consider four arms over the same five-task stream:
|
||||
|
||||
| Arm | Proposer | Gate | Outcome [P] |
|
||||
|---|---|---|---|
|
||||
| A1 | naive fine-tuning | none | ≈ 20% — knows only the last two digits; everything earlier destroyed |
|
||||
| A2 | naive fine-tuning | governed | ≈ 20% — every candidate rejected; still knows only 0 and 1; nothing destroyed, nothing learned |
|
||||
| A3 | replay | none | ≈ 90% |
|
||||
| A4 | replay | governed | ≈ 90% — and, given determinism, **bit-identical weights to A3** |
|
||||
|
||||
A1 and A2 land on the same headline number by opposite failures. A3 and A4 are indistinguishable. On these four arms the gate contributes nothing visible to accuracy.
|
||||
|
||||
Its value appears only when the proposer *sometimes fails* — a replay buffer silently empty, a learning rate off by an order of magnitude, a mislabelled batch. **The convincing demonstration is therefore differential outcome under injected proposer faults (arms A5/A6, §4.1), not an accuracy curve.** A demo that shows only the happy path shows a button.
|
||||
|
||||
Nothing in the gate says whether task *k* ought to be learned at all. That judgment sits with the human ruling and is not supplied by the structure.
|
||||
|
||||
### F4 — The analogy breaks at legibility
|
||||
|
||||
The steward reads a PENDING item *itself*. Nobody can read a weight delta. The human rules on the gate's *measurement* of the delta, so the ruling knows exactly what the protected set covers and nothing else. 'Inspectable' (brief §1) is true of the delta as an object — hash, rank, norms, provenance — and false of it as meaning.
|
||||
|
||||
In split-MNIST the protected set nearly exhausts what the model is *for*, which is what makes the toy clean. That cleanliness is the least transferable thing about it: in any model of interest the protected set is a vanishing sample of behaviour. I recommend the demonstration include one scenario in which the gate is blind (S8, §4.2), so the artefact teaches its own limit rather than false confidence. The full audit of where the analogy holds, bends and breaks is §5.
|
||||
|
||||
### F5 — The pattern is not novel engineering
|
||||
|
||||
- Model registries already carry a manual approval status. SageMaker's is literally `PendingManualApproval` / `Approved` / `Rejected` **[V]**.
|
||||
- Champion–challenger evaluation before promotion is standard model-risk practice (e.g. US Federal Reserve SR 11-7) **[R]**.
|
||||
- Hot-swappable adapters over a frozen base are how LoRA is ordinarily served **[R]**.
|
||||
- Immutable content-addressed objects plus compare-and-swap on a parent hash is git.
|
||||
|
||||
What the toy adds is *granularity* (one ruling per update in a continual stream, not per model release), a *proof obligation* for non-effect, and *parent-binding* of rulings. It should be described as a demonstration of pattern transfer, not as a research contribution.
|
||||
|
||||
---
|
||||
|
||||
## 2. Research answers (brief §2)
|
||||
|
||||
### 2.1 Smallest toy setup that shows catastrophic forgetting cheaply and legibly
|
||||
|
||||
**Recommendation: split-MNIST, class-incremental** — tasks {0,1}, {2,3}, {4,5}, {6,7}, {8,9}; a single 10-way head evaluated over all ten outputs at all times; MLP 784-400-400-10 with ReLU, the architecture of the reference study **[V]**.
|
||||
|
||||
| Option | Cost | Legibility | Verdict |
|
||||
|---|---|---|---|
|
||||
| **Split-MNIST, class-incremental** | seconds on CPU; 11 MB of data | total: a model that knew 0 and 1 calls every 0 a 2 or a 3; failures are viewable images | **Recommended** |
|
||||
| Split-MNIST, task-incremental (multi-head) | same | forgetting is mild (87% with no mitigation **[V]**); near-zero-damage merges make every ruling trivial | Rejected — nothing to rule on |
|
||||
| Permuted MNIST (domain-incremental) | same | forgetting is gradual; permuted pixels mean nothing to the eye | Rejected — illegible |
|
||||
| Split CIFAR-10 | CNN, minutes to hours, GPU-ish | visual but noisy; accuracies too low to read cleanly | Rejected — cost |
|
||||
| Sequential text classification (e.g. AG News → DBpedia → Yelp) | pretrained transformer, hundreds of MB, GPU nondeterminism | closest to 'real LoRA' | Rejected for Phase 1 — named as the escalation path if the pattern is later wanted at that fidelity |
|
||||
|
||||
Reference figures, split-MNIST, average accuracy over all five tasks after training on all five (van de Ven & Tolias 2019, Table 4) **[V]**:
|
||||
|
||||
| Method | Task-IL | Domain-IL | **Class-IL** |
|
||||
|---|---|---|---|
|
||||
| None — plain fine-tuning | 87.19 | 59.21 | **19.90** |
|
||||
| EWC | 98.64 | 63.95 | **20.01** |
|
||||
| Online EWC | 99.12 | 64.32 | 19.96 |
|
||||
| Synaptic Intelligence | 99.09 | 65.36 | 19.99 |
|
||||
| LwF | 99.57 | 71.50 | 23.85 |
|
||||
| DGR (generative replay) | 99.50 | 95.72 | 90.79 |
|
||||
| DGR + distillation | 99.61 | 96.83 | 91.79 |
|
||||
| iCaRL (2,000 stored exemplars) | — | — | 94.57 |
|
||||
| Joint training — upper bound | 99.66 | 98.42 | 97.94 |
|
||||
|
||||
Two further reasons for class-incremental beyond legibility **[J]**:
|
||||
|
||||
- **Every merge costs something.** Even a replay-trained candidate loses a little on earlier digits. There is no 'no-damage' candidate, so every ruling is a genuine trade of measured loss for measured gain. That is what gives the human something to do.
|
||||
- **The inspectable evidence is human-readable.** The gate can show the specific digits the model used to get right and would now get wrong.
|
||||
|
||||
**Caveat [P].** The published figures are for full fine-tuning. That low-rank deltas over a base trained from scratch on {0,1} reproduce both the ≈ 20% collapse and the ≈ 90% replay result is a prediction. *Falsifier:* the calibration run. *Fallback:* rank is a dial — at full rank a LoRA delta *is* a dense delta, so the choice in §2.2 degrades gracefully rather than failing.
|
||||
|
||||
### 2.2 Mechanisms for staging a delta as a separate, revertible object
|
||||
|
||||
| Mechanism | What it is | Separable object? | Exact reversion? | Role here |
|
||||
|---|---|---|---|---|
|
||||
| **Low-rank delta (LoRA)** — Hu et al. 2021 **[R]** | `W' = W + (α/r)·B·A`; base frozen, only `A`, `B` trained | **Yes** — a small file | Yes, by never merging, or by restoring the prior base file. **Not** by subtracting (§2.4, checked) | **Primary — the staging object** |
|
||||
| **EWC** — Kirkpatrick et al. 2017 **[R]** | quadratic penalty, weighted by Fisher information, on movement of the base weights, which are trained in place | No | None of its own | **None.** Also fails this scenario outright: 20.01% against 19.90% for doing nothing **[V]** |
|
||||
| **Replay buffer** | stored earlier examples mixed into each training batch | No | n/a | **Proposer technique.** The only family above 90% in class-IL **[V]**; it is what makes AUTHORIZED reachable at all |
|
||||
| Dense delta (also-ran) | full `W_candidate − W_base` | Yes | as LoRA | The full-rank limit of the primary; adequate for a toy, but loses 'small and summarizable' |
|
||||
|
||||
**Why LoRA rather than a dense delta, when both are cheap at this scale [J]:**
|
||||
|
||||
1. **Structural write-isolation.** The optimizer is constructed holding only adapter parameters. It has no handle on the base. 'Training cannot write the base' is then a property of how the optimizer was built, not of programmer care.
|
||||
2. **It is the unit the brief names** — 'the way a LoRA update or a model edit already is'. Rank-one model edits of the ROME/MEMIT family **[R]** fit the same object.
|
||||
3. **It has meaningful summary statistics** — rank, per-layer norm, ratio to the base norm — which is the only sense in which a delta is inspectable (F4).
|
||||
4. **The rank dial subsumes the alternative.**
|
||||
|
||||
LoRA is reported to forget less than full fine-tuning as a side-effect of its rank limit (Biderman et al. 2024 **[V]**). The design does not rely on this. Continual-learning LoRA variants (O-LoRA, InfLoRA **[R]**) are proposer-side techniques and would slot in without touching the governance layer — which is the point of F1.
|
||||
|
||||
**Replay makes the buffer governed state.** If the buffer gained new-task samples when a candidate was *staged*, a rejection would leave them behind. Buffer growth must therefore happen only at promotion, and the buffer belongs inside the state hash (§2.4).
|
||||
|
||||
**A constraint this choice imposes.** The adapter-form forward pass, `Wx + (α/r)·B(Ax)`, and the merged-form forward pass, `(W + (α/r)BA)x`, are different floating-point computations; borderline examples can classify differently. **The gate must evaluate the merged form — the exact bytes that would be promoted** — so that 'what was evaluated is what was promoted' is a hash equality and not an approximation (invariant I3).
|
||||
|
||||
### 2.3 The metric
|
||||
|
||||
**Standard definitions.** Let `R[j,i]` be test accuracy on task *i* after the model has learned through task *j*.
|
||||
|
||||
- **Backward transfer** (Lopez-Paz & Ranzato 2017) **[V]**: `BWT = 1/(T−1) · Σ_{i<T} ( R[T,i] − R[i,i] )`. Negative means forgetting.
|
||||
- **Forgetting** (Chaudhry et al. 2018) **[R]**: for each task, best accuracy ever achieved minus current accuracy.
|
||||
|
||||
BWT is an end-of-sequence aggregate. A gate needs the *per-merge* form, and needs it as a worst case, not an average:
|
||||
|
||||
| Reported per protected task *i* | Definition | Why |
|
||||
|---|---|---|
|
||||
| **Step change** | `acc_i(base ⊕ Δ) − acc_i(base)`, same examples, paired | the one-step term of BWT: what this merge would do, now |
|
||||
| **Cumulative drop** | `high_water_i − acc_i(base ⊕ Δ)` | Chaudhry's forgetting. Guards against salami-slicing: ten merges each within a 0.5-point step tolerance is five points gone, every one of them individually passed |
|
||||
| **Flips** | count correct→wrong and wrong→correct | paired counts (McNemar-style) are more sensitive than a difference of two accuracies, and the correct→wrong list is the viewable evidence |
|
||||
| **Interval** | 95% interval on the step and cumulative drops | evaluation is deterministic, so the interval is about the *population* the protected set samples — which the audit set then tests |
|
||||
|
||||
Also reported, but never folded into the finding: **new-task gain** (the benefit side — weighing it is the human's job) and **delta statistics**.
|
||||
|
||||
**The held-out set stops being held-out.** A protected set queried repeatedly by a proposer who adapts to its reports is no longer independent of the candidates (Dwork et al. 2015, the 'reusable holdout' problem **[R]**). Two responses, both cheap:
|
||||
|
||||
- Each task's protected data is split once into a **gate set** (~70%) and a **sealed audit set** (~30%). The audit set is never evaluated by the gate nor shown at ruling time. It is opened once, at the end of a run, by an `AUDIT` entry comparing audit-set and gate-set accuracies. One layer of checking; there is no audit of the audit.
|
||||
- **No automatic retry loop.** A retry after rejection is a fresh human-triggered proposal, logged with `retry_of`, and every gate report states how many candidates have now been gated against this protected set.
|
||||
|
||||
### 2.4 What makes a rejected delta's non-effect verifiable rather than asserted
|
||||
|
||||
**The state surface — every channel through which residue could travel:**
|
||||
|
||||
| # | Channel | Treatment |
|
||||
|---|---|---|
|
||||
| 1 | Base parameters | in the state hash |
|
||||
| 2 | Base buffers (e.g. BatchNorm running statistics, which update on a forward pass in training mode even with frozen parameters) | the toy has none by design; the hash covers the whole `state_dict` regardless |
|
||||
| 3 | The base file on disk | content-addressed filename, read-only mode, file-level hash |
|
||||
| 4 | Replay buffer membership | in the state hash; changes only at promotion |
|
||||
| 5 | Protected-set membership, thresholds, allowed signers ('gate policy') | in the state hash; changes only by a signed `POLICY_SET` entry |
|
||||
| 6 | High-water marks | in the state hash; change only at promotion |
|
||||
| 7 | Process state — global RNG, caches, counters | each candidate's seed is derived as `H(parent_state_hash ‖ canonical(spec))`; nothing is drawn from a global stream or from a ledger sequence number |
|
||||
| 8 | State invisible to `state_dict` (mode flags, non-persistent buffers, globals) | caught by the behavioural probe, below |
|
||||
| 9 | The proposer's knowledge of the gate report | **not eliminable** (F2); bounded by the sealed audit set; made visible by `retry_of` |
|
||||
| 10 | The ledger entries and the archived delta | the *intended* residue |
|
||||
|
||||
**The canonical hash.** Iterate the `state_dict` in sorted key order; for each tensor feed name, dtype, shape and contiguous little-endian bytes to SHA-256. Hash tensor bytes, not the container file, so the result is independent of serialization format. The **state hash** is SHA-256 over canonical JSON of `{base_hash, buffer_hash, policy_hash, high_water, seq}`.
|
||||
|
||||
**Four checks, by four different routes:**
|
||||
|
||||
1. **State hash, recomputed from bytes on disk** — never read from a cached pointer — equals the parent state hash recorded when the candidate was staged.
|
||||
2. **File-level hash and mode** of the base file unchanged.
|
||||
3. **Behavioural probe.** The base's logits on a fixed probe batch (256 fixed indices from the *training* split, so that no protected data is touched) are hashed and compared with the fingerprint recorded when that state became current. This reaches channel 8, which no weight hash can.
|
||||
4. **Counterfactual replay** (a suite-level test, not run per rejection). Run the faulty stream with its rejections, and the clean stream in which the faulty candidates were never proposed. Assert that every downstream artefact — state hashes, later delta hashes, merged hashes, gate-report bodies — is bit-identical, and that the ledgers differ only by the entries concerning the rejected candidates. Because seeds derive from the candidate's *spec*, the clean retry after a rejected fault is the same candidate as in the clean run, so **the governed faulty run (A6) should end on exactly the same state hash as the clean governed run (A4) [P]**.
|
||||
|
||||
Check 4 is not tautological: purity is what the design *claims*; the replay tests whether the *implementation* has a hidden channel. Its negative control plants one (N6, §3.9).
|
||||
|
||||
**Checked this session — reversion must restore, never subtract [V].** In emulated float32 over 200,000 weight/delta pairs, merge-then-unmerge `(W + d) − d` left **16.6% of elements different from the original** (maximum error 1.5 × 10⁻⁸) and a different hash. Controls: a zero delta round-tripped exactly (0 differing, hash equal); a change of one unit in the last place to one weight changed the hash. 'Unmerge' is therefore not reversion at the level at which this design makes claims. Scope: an arithmetic fact about float32 established on synthetic values, not on the toy's tensors; the build repeats it on real ones (N5).
|
||||
|
||||
**Determinism — prerequisite and claim scope.** CPU only; one thread; `torch.use_deterministic_algorithms(True)`; seeded data order; no loader workers. The claim is bit-identity *on the same machine in the same environment*; an environment fingerprint is logged with every candidate so that a mismatch is explicable rather than mysterious. **[P]** *Falsifier:* two runs of one candidate spec produce different delta hashes. *Consequence if falsified:* check 4 falls back to tolerance-level comparison, and 'demonstrated' weakens to 'approximately demonstrated'. That would be reported, not smoothed.
|
||||
|
||||
---
|
||||
|
||||
## 3. Design (brief §3)
|
||||
|
||||
### 3.1 Objects
|
||||
|
||||
```
|
||||
STATE MANIFEST S_n — the governed state; nothing else is governed
|
||||
base_hash canonical hash of the full state_dict
|
||||
buffer_hash hash of the sorted replay-buffer index list (indices into MNIST train)
|
||||
policy_hash hash of policy.json: τ_step, τ_cum, n_min, interval method,
|
||||
gate/audit index lists per task, allowed-signers file hash
|
||||
high_water {task_id: best gate-set accuracy recorded at any promotion}
|
||||
seq n
|
||||
state_hash = SHA-256(canonical JSON of the above)
|
||||
|
||||
CANDIDATE
|
||||
candidate_id = H(parent_state_hash ‖ delta_hash ‖ resubmission_of) content-derived
|
||||
display_seq C-0007 — for reading only; nothing ever binds to it
|
||||
parent_state_hash
|
||||
delta_hash → deltas/<delta_hash>.safetensors {layer: (A, B)}, α, r
|
||||
merged_hash hash of W' materialized by the one fixed, deterministic merge procedure
|
||||
spec task_id, data index-list hashes, replay indices used, hyperparameters, salt
|
||||
seed = H(parent_state_hash ‖ canonical(spec))
|
||||
provenance trigger, code version, environment fingerprint
|
||||
proposer_note free text: what the proposer says it intended. NOT evidence; the gate never reads it
|
||||
retry_of candidate_id | null
|
||||
|
||||
GATE REPORT
|
||||
binds candidate_id, parent_state_hash, merged_hash, policy_hash
|
||||
per protected task n, acc_base, acc_cand, step change, cumulative drop, flips, intervals
|
||||
new task acc_base, acc_cand on the new task's gate set
|
||||
delta stats rank; per-layer ‖ΔW‖, ‖ΔW‖/‖W‖
|
||||
flipped test indices that went correct→wrong, plus a rendered contact sheet
|
||||
exposure 'candidate number k gated against this protected set for task t'
|
||||
coverage literal sentence: 'Measured: accuracy on N gate-set examples of digits {…}.
|
||||
Not measured: everything else.'
|
||||
finding WITHIN_TOLERANCE | EXCEEDS_TOLERANCE | INDETERMINATE | NOT_MEASURABLE
|
||||
+ the task and the clause that decided it
|
||||
|
||||
RULING — the human's act
|
||||
binds candidate_id, gate_report_hash | null, parent_state_hash, policy_hash,
|
||||
prev_entry_hash
|
||||
decision AUTHORIZED | DEFERRED | REJECTED
|
||||
rationale required
|
||||
conditions required when DEFERRED: what would cause reconsideration
|
||||
against_finding true when the decision departs from the gate's finding
|
||||
ruler, signature over the canonical bytes of everything above
|
||||
```
|
||||
|
||||
**Status is computed, never stored.** Whether a candidate is staged, stale, promotable or archived is derived by replaying the ledger against the current state. A stored status field is a dated measurement waiting to be read as a present-tense fact.
|
||||
|
||||
### 3.2 Lifecycle
|
||||
|
||||
```
|
||||
trigger ──► PROPOSE ──► delta file written and hashed
|
||||
│ (on exception: PROPOSAL_FAILED is logged; no candidate exists)
|
||||
▼
|
||||
CANDIDATE_STAGED binds parent state hash, delta hash, merged hash, spec
|
||||
│
|
||||
▼
|
||||
GATE ─────────► GATE_REPORT finding ∈ {WITHIN, EXCEEDS, INDETERMINATE, NOT_MEASURABLE}
|
||||
│ └────► GATE_ERROR may still be REJECTED or DEFERRED; can never be AUTHORIZED
|
||||
▼
|
||||
human reads the report and the flipped digits
|
||||
│
|
||||
RULING (signed) ─┬─ REJECTED ───► delta archived, unpromotable ──────────► RESIDUE_CHECK
|
||||
├─ DEFERRED ───► stays staged; its report decays if the state moves ─► RESIDUE_CHECK
|
||||
└─ AUTHORIZED ─► PROMOTE ─┬─ every binding holds ─► PROMOTION (state S_n → S_n+1)
|
||||
└─ any binding fails ──► PROMOTION_REFUSED ─► RESIDUE_CHECK
|
||||
```
|
||||
|
||||
Fail-closed throughout: the default condition of every candidate is *not applied*. No ruling means no effect, indefinitely. Nothing times out into promotion.
|
||||
|
||||
### 3.3 Staging
|
||||
|
||||
**The object** is the CANDIDATE of §3.1: a delta file plus the hashes that bind it to one parent state.
|
||||
|
||||
**What triggers creation** — two things only:
|
||||
|
||||
- **T1** — the stream driver emits 'task *k* data available'.
|
||||
- **T2** — the human requests a proposal with an explicit spec.
|
||||
|
||||
A re-gate (§3.5) produces a new *report* for an existing candidate, not a new candidate. **There is no automatic retry**: a proposer that loops until the gate passes is an optimizer aimed at the protected set (§2.3).
|
||||
|
||||
**Ordering.** The delta file is written and hashed first; `CANDIDATE_STAGED` is appended second, so that the entry can bind the hash. Staging asserts index-set disjointness between everything the proposer trained on and every protected index (I8), and recomputes the parent state hash from bytes on disk.
|
||||
|
||||
**Genesis.** `M₀` is trained on task 1 and recorded as a signed `GENESIS` entry: base hash, initial buffer, initial protected set, first high-water mark, policy hash, probe fingerprint. It is not gated — nothing exists yet to protect — and the ledger says so in words rather than recording a vacuous pass.
|
||||
|
||||
### 3.4 The gate
|
||||
|
||||
**Inputs:** a parent state hash and a delta file. Nothing else. It does not read `proposer_note`, `spec` or `provenance` (F1).
|
||||
|
||||
**Procedure:** verify that the delta hash and the parent state hash match the staged entry → materialize merged weights by the fixed procedure → verify `merged_hash` → evaluate base and merged on every protected task's gate set and on the new task's gate set → compute §2.3's quantities → render the flipped-digit contact sheet → append `GATE_REPORT`.
|
||||
|
||||
**Finding rule:**
|
||||
|
||||
| Finding | Condition |
|
||||
|---|---|
|
||||
| `NOT_MEASURABLE` | a protected task has fewer than `n_min` examples, or the protected set is empty, or any hash precondition fails |
|
||||
| `EXCEEDS_TOLERANCE` | for some protected task, the interval for the step drop lies wholly above `τ_step`, or the interval for the cumulative drop lies wholly above `τ_cum` |
|
||||
| `WITHIN_TOLERANCE` | for every protected task, both intervals lie wholly below their thresholds |
|
||||
| `INDETERMINATE` | otherwise — some interval straddles a threshold |
|
||||
|
||||
The finding vocabulary is deliberately disjoint from the ruling vocabulary. The gate never says *pass*, *safe*, *approved* or *rejected*. `WITHIN_TOLERANCE` means 'no damage beyond τ was found on the protected set'; the coverage sentence travels with every report so that this cannot be read as 'no damage'.
|
||||
|
||||
**Thresholds** are set by the steward after a calibration run and frozen in `policy.json` *before* any demonstration scenario runs. They are not tuned afterwards. I do not know the right values: in class-incremental learning even good candidates cost earlier tasks something, so they may need to be several points **[P]**.
|
||||
|
||||
### 3.5 The ruling
|
||||
|
||||
| Disposition | Effect on governed state | Effect on the candidate |
|
||||
|---|---|---|
|
||||
| **AUTHORIZED** | none *by itself*; it makes `PROMOTE` executable (§3.6) | promoted, if every binding holds |
|
||||
| **DEFERRED** | none | stays staged. `conditions` records what would cause reconsideration |
|
||||
| **REJECTED** | none | delta moved to the archive and kept. Terminal for this `candidate_id`: `PROMOTE` refuses any candidate with a REJECTED ruling on the ledger. To revisit, stage afresh; `resubmission_of` enters the new id |
|
||||
|
||||
Three properties that differ from the document case and carry weight:
|
||||
|
||||
- **A DEFERRED delta decays.** Its gate report is a measurement of *parent ⊕ Δ*. If another candidate is promoted meanwhile, the parent is no longer the current state and the report describes a model that will never exist. Reconsideration then requires a **re-gate** against the new state — evaluation only, no retraining — yielding a new report and needing a new ruling.
|
||||
- **Measurements are timeless; authorizations are acts in time.** A gate report stays valid whenever its hashes match the current state — including after a rollback that restores its parent. A *ruling* is executable only if **no state transition (`PROMOTION`, `ROLLBACK`, `POLICY_SET`) lies between it and the promotion in the ledger.** This forecloses the surprise case in which an old AUTHORIZED ruling becomes executable again long after it was given.
|
||||
- **Two candidates AUTHORIZED against one parent:** the first promotes; the second's ruling is void by the rule above; it must be re-gated and re-ruled. Deltas do not compose for free.
|
||||
|
||||
**Keeping the human's step real:**
|
||||
|
||||
- A rationale is required.
|
||||
- The human may rule *against* the finding in either direction, and `against_finding` records it — REJECTED despite `WITHIN_TOLERANCE` (S5: nothing was learned, so the merge is unmeasured risk for no gain) or AUTHORIZED despite `EXCEEDS_TOLERANCE` (S6: a loss knowingly accepted and written down).
|
||||
- The ledger makes the agreement rate between finding and ruling countable. An honest limit: if that rate is 100% over a long run, the ledger cannot say whether the gate matches the human's judgment or the human has become a button.
|
||||
|
||||
**Who is the ruler?** In a single-user sandbox nothing prevents a script from invoking the ruling command. Unless rulings are **signed** with a key the proposer and gate code paths never touch, 'human-authorized' is a convention, not a property. Recommended: `ssh-keygen -Y sign` (present on any Mac) or GPG, over the canonical ruling bytes including `prev_entry_hash`; `PROMOTE` verifies against an allowed-signers file whose hash sits inside the policy. *What this proves:* possession of the key at signing time. *What it does not:* that anyone deliberated, or that the key is out of reach of an agent on the same machine — which holds only if the key is passphrase- or hardware-protected. This is Decision D1.
|
||||
|
||||
### 3.6 Promotion — what AUTHORIZED does
|
||||
|
||||
```
|
||||
PROMOTE(candidate):
|
||||
require a RULING with decision AUTHORIZED for this candidate_id, signature valid
|
||||
require no REJECTED ruling for this candidate_id anywhere on the ledger
|
||||
require ruling.gate_report_hash = the candidate's latest GATE_REPORT
|
||||
require report.parent_state_hash = current state hash, RECOMPUTED FROM BYTES ← compare-and-swap
|
||||
require report.policy_hash = current policy hash
|
||||
require no PROMOTION / ROLLBACK / POLICY_SET entry after the ruling
|
||||
require hash(delta file) = candidate.delta_hash
|
||||
write bases/<merged_hash>.safetensors — a NEW file, read-only; nothing is ever overwritten
|
||||
require hash(the written file's tensors) = report.merged_hash ← I3
|
||||
append PROMOTION { old state, new state, buffer additions, protected-set additions,
|
||||
new high-water marks, new probe fingerprint } ← THE COMMIT POINT
|
||||
update HEAD ← a cache of the ledger
|
||||
re-evaluate the promoted file on the gate sets; must reproduce the report's numbers exactly
|
||||
on any failed requirement: append PROMOTION_REFUSED naming the requirement, then RESIDUE_CHECK
|
||||
```
|
||||
|
||||
The ledger append is the single commit point. A crash before it leaves an orphan file and no change of state; a crash after it leaves a stale `HEAD`, which `verify` detects and repairs by replaying the ledger. **The ledger is the authority; `HEAD` is a witness to it.**
|
||||
|
||||
### 3.7 The log
|
||||
|
||||
One file, `ledger.jsonl`. Append-only, single writer, fsync on append. Each entry carries `seq, ts, type, body, prev_hash, entry_hash`. It is the only canonical record; a Markdown rendering in PENDING/REVIEWED style is a derived view, regenerated on demand and marked as derived.
|
||||
|
||||
Entry types: `GENESIS` · `POLICY_SET` · `PROPOSAL_FAILED` · `CANDIDATE_STAGED` · `GATE_REPORT` · `GATE_ERROR` · `RULING` · `PROMOTION` · `PROMOTION_REFUSED` · `RESIDUE_CHECK` · `ROLLBACK` · `AUDIT`.
|
||||
|
||||
What survives every candidate whatever its fate:
|
||||
|
||||
- **what changed** — `CANDIDATE_STAGED`: hashes, spec, statistics, the proposer's note;
|
||||
- **what the gate found** — `GATE_REPORT`, or `GATE_ERROR` with the exception;
|
||||
- **the disposition** — `RULING`, with rationale and signature;
|
||||
- **the effect** — `PROMOTION`, `PROMOTION_REFUSED` or `RESIDUE_CHECK`.
|
||||
|
||||
Refusals and errors are entries. A command that fails silently is the defect this pattern exists to exclude.
|
||||
|
||||
**Cross-references bind by content hash, never by display number or by position.** A ruling that names 'C-0007' authorizes whatever later answers to that name; a ruling that names a hash authorizes one thing.
|
||||
|
||||
**What the chain does and does not detect.** A hash chain detects in-place edits. It does not detect a wholesale rewrite from genesis by someone able to recompute it. Signed rulings cover `prev_entry_hash`, so a rewriter without the key cannot carry the rulings across. Committing the ledger to a git repository gives an independent second chain at almost no cost.
|
||||
|
||||
*Naming.* This ledger shares an idea — hash-chained, append-only — with L1's logchain, and shares nothing else: no code, no format, no storage. Nothing observed about one is evidence about the other. The word 'ledger' is used to keep them apart.
|
||||
|
||||
### 3.8 Reversion
|
||||
|
||||
**REJECTED — what it does to the base: nothing, because the base was never written.** The delta file moves to `archive/`. It is kept so that the gate's finding stays reproducible; 'no residue' is a claim about governed state, not about disk (Decision D3).
|
||||
|
||||
**How 'nothing happened' is demonstrated rather than claimed:** a `RESIDUE_CHECK` entry follows *every* non-promoting outcome — REJECTED, DEFERRED, `GATE_ERROR`, `PROMOTION_REFUSED` — carrying checks 1–3 of §2.4 with their expected and observed values. The suite-level counterfactual replay (check 4) covers the system. The negative controls of §3.9 show that each check can fail.
|
||||
|
||||
**ROLLBACK — reverting an AUTHORIZED promotion.** A signed ruling naming an ancestor state hash. Because bases are immutable files, rollback is a pointer move plus a ledger entry, verified by recomputing the target's state hash from bytes and matching its recorded probe fingerprint. Buffer, protected set and high-water marks revert with the manifest. The ledger is never truncated; abandoned promotions stay on the record.
|
||||
|
||||
**A limit to state plainly.** History is linear. **Revocation is truncation, not excision**: one cannot remove the delta of step 2 and keep the delta of step 3, because step 3 was trained and measured against a base that contained step 2. One rolls back to before step 2 and re-proposes; whatever is wanted from step 3 goes through the gate again. Subtracting a delta ('task negation', Ilharco et al. 2023 **[R]**) is an approximation in behaviour and, per §2.4, inexact even in arithmetic.
|
||||
|
||||
### 3.9 Invariants, their checks, and their negative controls
|
||||
|
||||
| # | Invariant | Check | Negative control — the check must be seen to fire |
|
||||
|---|---|---|---|
|
||||
| **I1** | No base file is ever modified | state hash recomputed from bytes at staging, at ruling and at residue check | **N1** change one weight by one unit in the last place → detected |
|
||||
| **I2** | Only `PROMOTION`, `ROLLBACK` and `POLICY_SET` change governed state | state hash before = after, for every other entry type | **N2** a deliberately leaky proposer adds new-task samples to the buffer at staging → `RESIDUE_CHECK` fails |
|
||||
| **I3** | What was evaluated is what is promoted | promoted file's hash = the report's `merged_hash` | **N3** alter the delta after gating → refused |
|
||||
| **I4** | No promotion without a valid, signed, fully bound, un-superseded AUTHORIZED ruling | the `require` list of §3.6 | **N4a** no ruling · **N4b** a ruling for another candidate · **N4c** stale parent · **N4d** policy changed since the report · **N4e** bad signature · **N4f** a state transition after the ruling |
|
||||
| **I5** | Reversion restores; it never subtracts | by construction | **N5** merge-then-unmerge on the toy's real tensors does not restore the hash (§2.4: 16.6% on synthetic values) |
|
||||
| **I6** | A rejected candidate has no downstream effect beyond its records | counterfactual replay | **N6** derive seeds from the ledger sequence number instead of the spec → the replay test fails |
|
||||
| **I7** | The ledger is append-only and self-consistent; `HEAD` agrees with it | chain verification; `HEAD` = replay of the ledger | **N7a** edit an old entry → detected · **N7b** alter `HEAD` → flagged and repaired |
|
||||
| **I8** | Training never sees protected data | index-set disjointness asserted at staging | **N8** plant one gate-set index in a replay buffer → staging refuses |
|
||||
|
||||
A negative control that fails to fire is a finding about the instrument, and is reported as one.
|
||||
|
||||
---
|
||||
|
||||
## 4. Demonstration plan
|
||||
|
||||
### 4.1 Arms
|
||||
|
||||
A0 joint-training upper bound · A1–A4 as in F3 · and the pair that carries the demonstration:
|
||||
|
||||
| Arm | Stream | Gate | Expected [P] |
|
||||
|---|---|---|---|
|
||||
| **A5** | replay proposer with three injected faults — **Fa** buffer silently empty · **Fb** learning rate × 50 · **Fc** new-task labels swapped | none — everything merges | collapse at the first fault; never recovers |
|
||||
| **A6** | the same faulty stream | governed; faults rejected; clean retries authorized | ≈ A4 in accuracy, **and the same final state hash as A4** |
|
||||
|
||||
### 4.2 Scenarios
|
||||
|
||||
| # | Scenario | Exercises |
|
||||
|---|---|---|
|
||||
| **S1** | naive candidate → `EXCEEDS` → REJECTED → residue check | reversion; I1, I2 |
|
||||
| **S2** | replay candidate → `WITHIN` → AUTHORIZED → promoted | I3, I4; post-promotion re-evaluation |
|
||||
| **S3** | small-buffer candidate → `INDETERMINATE` → DEFERRED, with conditions | the third disposition |
|
||||
| **S4** | a second candidate for the same task is authorized; the state moves; S3's candidate is now stale → promotion refused → re-gate → new ruling | parent-binding; decay of DEFERRED |
|
||||
| **S5** | label-fault candidate → `WITHIN` on the protected set, new-task gain ≈ 0 → REJECTED against the finding | ruling ≠ function of the gate |
|
||||
| **S6** *(extended)* | slight `EXCEEDS`, large gain → AUTHORIZED against the finding, the loss written down | the same, in the other direction |
|
||||
| **S7** *(extended)* | ROLLBACK of S6 | truncation; hash identity with the earlier state |
|
||||
| **S8** *(extended; Decision D2)* | a candidate carrying a trigger-pixel backdoor (the standard BadNets-style classroom example **[R]**) passes the gate and is AUTHORIZED; a probe *outside* the gate shows that the trigger works | the gate's blind spot (F4) |
|
||||
| **S9** | end-of-run `AUDIT` on the sealed sets | adaptive overfitting of the gate set |
|
||||
|
||||
### 4.3 Predictions, registered before any build, each with its falsifier
|
||||
|
||||
| # | Prediction | Falsified if |
|
||||
|---|---|---|
|
||||
| **P1** | A1 ends at ≈ 20%, with accuracy on tasks 1–4 near zero | low-rank deltas forget materially less than full fine-tuning here — then the forgetting demonstration needs a higher rank or a dense delta |
|
||||
| **P2** | rank-8 deltas trained with replay reach ≈ 85–92% over five tasks | they do not — raise the rank; at full rank this is a dense delta |
|
||||
| **P3** | re-running one candidate spec gives a bit-identical delta hash | hashes differ — check 4 falls back to tolerance, and the claim weakens as stated in §2.4 |
|
||||
| **P4** | A4's final weights are bit-identical to A3's | they differ — the governance layer has a hidden channel into training, which is a finding |
|
||||
| **P5** | A6's final state hash equals A4's | they differ — a rejected candidate left residue somewhere §2.4 did not enumerate |
|
||||
| **P6** | every negative control N1–N8 fires | any does not — that check was not evidence |
|
||||
| **P7** | at S9, audit-set and gate-set accuracies agree within sampling error | they do not — the gate set was overfit by the propose/reject loop |
|
||||
| **P8** | the promoted file reproduces the gate report's numbers exactly | it does not — a merge-path discrepancy; I3 is not doing its job |
|
||||
|
||||
### 4.4 Build slices
|
||||
|
||||
Each leaves something complete in itself and depends on no later slice to mean something:
|
||||
|
||||
1. **The problem** — A0 and A1, per-task accuracy plots. Shows forgetting; tests P1.
|
||||
2. **REJECTED, proven** — staging, gate, ledger, REJECTED, `RESIDUE_CHECK`, N1, N2, N5, N7a–N7b. Tests P3.
|
||||
3. **AUTHORIZED and DEFERRED** — promotion, parent-binding, staleness, re-gate; S2–S4; N3, N4a–N4f, N8. Tests P2, P8.
|
||||
4. **The point of it** — A5 against A6, counterfactual replay, S5, S9, N6. Tests P4, P5, P7.
|
||||
5. **Extended** — S6–S8; rollback; signatures, if not taken in slice 3.
|
||||
|
||||
---
|
||||
|
||||
## 5. Where the analogy holds, bends and breaks
|
||||
|
||||
| PENDING → REVIEWED | Weight-delta toy | |
|
||||
|---|---|---|
|
||||
| a proposal is a discrete block of text | a delta is a discrete file | **holds** |
|
||||
| no effect until ruled | the delta never touches the base until promoted | **holds — and more strongly**: hash-verifiable, as the document case is not |
|
||||
| a rejected item stays on the record | the same; the delta is archived | **holds** |
|
||||
| append-only register | hash-chained ledger | **holds** |
|
||||
| the steward reads the proposal itself | the human reads a *measurement* of the delta | **breaks** — the ruling is on a proxy bounded by protected-set coverage (F4) |
|
||||
| 'Files affected' scopes a change | a delta touches every behaviour at once; there is no locality | **breaks** |
|
||||
| an authorized item can later be struck out | truncation only, never excision (§3.8) | **breaks** |
|
||||
| partial authorization is possible | a scaled or partial delta is a new candidate needing its own gate | **breaks** |
|
||||
| a DEFERRED item keeps | a DEFERRED delta decays: its report is bound to a parent that may move | **bends** |
|
||||
| the proposer's rationale is part of the case | the proposer's note is not evidence; the gate never reads it | **differs by design** (F1) |
|
||||
| an item can be amended | a delta cannot; any change is a new candidate | **bends — toward simplicity** |
|
||||
|
||||
---
|
||||
|
||||
## 6. Limits — what this toy cannot show
|
||||
|
||||
1. **Coverage.** The gate sees the protected set and nothing else. At MNIST scale that is nearly everything; at any scale of interest it is nearly nothing.
|
||||
2. **Goodhart.** A proposer adapting to gate reports optimizes against the gate. The sealed audit set bounds this for one run; it does not abolish it.
|
||||
3. **A ruling on a proxy invites automation bias.** `against_finding` makes that countable, not impossible.
|
||||
4. **Stability only.** The gate measures forgetting. It does not measure loss of plasticity — the other failure of continual learning (Dohare et al. 2024 **[R]**). Declining new-task gain across successive candidates would be visible in the ledger, but nothing thresholds it.
|
||||
5. **Linear history** (§3.8).
|
||||
6. **Determinism belongs to the toy.** On GPUs, 'what was evaluated is what was promoted' survives, because a file is hashed; bit-exact *re-derivation* of a candidate does not, so the counterfactual replay would not transfer as designed.
|
||||
7. **No claim about continual learning proper.** Each candidate here is a supervised fine-tune on a labelled, pre-segmented task. Nothing here touches credit assignment from raw experience, which is the actual research problem (Sutton's, at Oak Lab **[V]**) and is a stated non-goal.
|
||||
8. **One machine, one user.** Write-protection is *detection*, not prevention. Ruler identity is exactly as strong as custody of the key.
|
||||
9. **Robustness, not legitimacy.** The structure sharpens whatever it is pointed at. Whether the model should learn task *k* at all is not something it can supply.
|
||||
|
||||
---
|
||||
|
||||
## 7. Open decisions for the steward
|
||||
|
||||
| # | Decision | Recommendation |
|
||||
|---|---|---|
|
||||
| **D1** | Signed rulings, or a TTY-only convention? | **Signed** — otherwise 'human-authorized' is asserted, and the point of the toy is the difference between asserted and demonstrated. Requires a passphrase- or hardware-protected key. If cut, the README must say that ruler identity is unverified |
|
||||
| **D2** | Include S8, the blind-spot scenario? | **Yes** — it is the honest counterweight to F4. It is a textbook backdoor on a digit classifier, with no bearing on any real system. Steward's call, because it builds a deliberately bad artefact |
|
||||
| **D3** | Rejected deltas: retain, or delete keeping only the hash? | **Retain** — they are kilobytes, and retention keeps every gate finding reproducible |
|
||||
| **D4** | Who sets `τ_step`, `τ_cum`, `n_min`, and when? | **The steward, after the calibration run, frozen before any scenario runs** |
|
||||
| **D5** | Where would a build live? | A new standalone repository, inside none of the existing ones. Name to be given |
|
||||
| **D6** | If rank-8 cannot learn new digits adequately (P2 falsified) — raise the rank, or go dense? | **Raise the rank first**; dense is its limit |
|
||||
| **D7** | Minimal cut (slices 1–4; S1–S5, S9) or extended (adding slice 5)? | **Minimal first.** Each slice stands alone |
|
||||
|
||||
## 8. What I would ask the jurist to attack
|
||||
|
||||
1. **F1** — is 'one stages, two mitigate' a fair reading of brief §2, or does it dodge the comparison that was asked for?
|
||||
2. **§2.4, check 4** — I argue the counterfactual replay is not tautological because it tests the implementation against the design's purity claim. Is there a residue channel that survives bit-identity of every downstream artefact? Channel 9, the proposer's knowledge, is the one I know of.
|
||||
3. **§3.5** — 'measurements are timeless, authorizations are acts in time'. Is voiding every ruling at every state transition too strict, or not strict enough?
|
||||
4. **§5** — which 'holds' rows are decorative? In particular: is 'no effect until ruled: holds, and more strongly' an honest comparison or a flattering one?
|
||||
5. **Proportion** — is this more mechanism than a toy should carry? My standpoint (top of document) predicts that I would not see it.
|
||||
|
||||
---
|
||||
|
||||
## 9. Boundary observation — CapableMind (observation only; outside this brief's scope)
|
||||
|
||||
The register search turned up `CapableMind-AI/docs/specs/modules/batch/training-module-spec.md`. **I did not read it in full** — I grepped it for a handful of terms and read the matching lines. At that grain it already specifies: LoRA adapters where 'the base model is not modified' (line 480); four validation gates before deployment (lines 415, 512); rollback to a previous version (from line 698); a training-cycle history as audit trail (line 815); and operator approval as an **optional** step defaulting to **`require_approval: false`** (lines 640 and 926).
|
||||
|
||||
I draw no conclusion from this: the brief places CapableMind out of scope, and a default read at grep grain is not a finding about a system. It is recorded for two reasons. It is the 'what already says this?' half of grounding — the steward should know the toy's pattern has a specified cousin in-house. And the toy's two distinguishing commitments — a human ruling that cannot be defaulted away, and non-effect that is proven rather than assumed — are precisely where the two differ at the grain I read. Whether that difference matters is a question for a separate, later proposal, if ever.
|
||||
|
||||
## 10. Build outline — for sizing only; not authorization
|
||||
|
||||
Python 3.11+; PyTorch (CPU) with torchvision for MNIST; `safetensors`; matplotlib for plots and contact sheets. LoRA hand-written for the MLP (about thirty lines) rather than imported, so the merge procedure is ours to fix and hash. Estimated 600–900 lines including tests **[J]**. Runtime: seconds to a couple of minutes per arm on a laptop CPU **[P]**. No network after the MNIST download; no credentials; no GPU; no remote machine.
|
||||
|
||||
---
|
||||
|
||||
## 11. Sources and checks
|
||||
|
||||
**Verified this session [V]**
|
||||
|
||||
- van de Ven & Tolias, 'Three scenarios for continual learning', arXiv:1904.07734 — Table 4, architecture and task protocol, read via ar5iv (`ar5iv.labs.arxiv.org/html/1904.07734`). *Note:* the fetch tool returns a small model's extraction of the page, not the page itself; the figures matched my independent recall (19.90 / 20.01). Two witnesses; neither is a notary.
|
||||
- Lopez-Paz & Ranzato, 'Gradient Episodic Memory for Continual Learning', arXiv:1706.08840 — the BWT definition, confirmed through secondary summaries in a search plus recall; the PDF itself was not opened.
|
||||
- Biderman et al., 'LoRA Learns Less and Forgets Less', TMLR 2024, arXiv:2405.09673 — headline findings confirmed by search.
|
||||
- Amazon SageMaker Model Registry — `PendingManualApproval` / `Approved` / `Rejected`, confirmed against AWS documentation pages returned by a search.
|
||||
- Oak Lab — founded by Richard Sutton with Khurram Javed, July 2026, reported by heise online, MLQ News and TechTimes. *This post-dates my training; I would have flagged the brief's reference as unknown had I not checked.*
|
||||
|
||||
**Recalled, not checked [R]**
|
||||
|
||||
Hu et al. 2021 (LoRA, arXiv:2106.09685) · Kirkpatrick et al. 2017 (EWC, PNAS) · Chaudhry et al. 2018 (the forgetting measure) · Dwork et al. 2015 ('The reusable holdout', *Science*) · Dohare et al. 2024 ('Loss of plasticity in deep continual learning', *Nature*) · Ilharco et al. 2023 (task arithmetic, ICLR) · Meng et al. 2022 (ROME) · Gu et al. 2017 (BadNets) · Wang et al. 2023 (O-LoRA) · Liang & Li 2024 (InfLoRA) · Federal Reserve SR 11-7.
|
||||
|
||||
**Checks run**
|
||||
|
||||
1. **Register search** for prior treatment of this subject in `PENDING.md`, `REVIEWED.md`, `PENDING-archive.md`, the memory directory and `CapableMind-AI/docs`. The first pass was **defective**: a case-insensitive `LoRA` pattern matched 'exp**lora**tion' and returned spurious hits throughout. Re-run with word boundaries and case sensitivity, with a control proving the pattern finds a known positive and ignores 'exploration'. *Result:* nothing in the three register files; five memory files and some ten CapableMind documents mention LoRA, all apparently about CapableMind's own training pipeline (§9). I read one memory file's head and the grep lines of one spec; the rest I did not open.
|
||||
2. **Merge-then-unmerge arithmetic** (§2.4). Pure Python, float32 emulated by rounding through `struct` after each operation; `numpy` is not installed on the system Python. 200,000 pairs, `W ~ N(0, 0.05)`, `d ~ N(0, 0.01)`. Differing elements 33,250 (16.6%); zero-delta control 0 differing; one-unit-in-the-last-place sensitivity control detected. *Scope:* an arithmetic fact about float32 on synthetic values — not a measurement of the toy.
|
||||
@@ -12,3 +12,4 @@
|
||||
{"date": "2026-09-10", "thread": "the unit of the measurement is not the unit of the claim — a number produced over one population read as answering a question about another", "terms": ["unit", "measurement", "claim", "number", "produced", "population", "read", "answering", "question", "another"], "candidates": 655, "returned": [{"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/00. Compass/00b. Constellations/Animal Rationis Capax/99. Archives—Previous Iterations/99. The Chamber/00. Core Foundation/complete-amphitheatre/hermetic/ibn-arabi-artificial-divine-intelligence.md", "date": "1230-01-01", "matched": ["unit", "produced", "question", "another"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-05-08.md", "date": "2026-05-08", "matched": ["unit", "measurement", "claim", "number", "produced", "population", "read", "question", "another"]}, {"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/08. Notes/Books.app highlights/Everything Is F*cked A Book About Hope.md", "date": "2025-04-20", "matched": ["unit", "number", "population", "question", "another"]}, {"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/08. Notes/Books.app highlights/Hold Everything Dear.md", "date": "2025-04-20", "matched": ["claim", "produced", "population", "read", "question", "another"]}, {"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/06. Projects/Cabaret/raw Cabaret session.md", "date": "2026-04-04", "matched": ["unit", "claim", "number", "produced", "read", "question", "another"]}]}
|
||||
{"date": "2026-09-11", "thread": "the register is checked only when a party elects to check it; nothing watches the register; can a placed ruling be checked against a draft, source, or second copy", "terms": ["register", "checked", "only", "party", "elects", "check", "watches", "placed", "ruling", "against", "draft", "source", "second", "copy"], "candidates": 775, "returned": [{"path": "~/.claude/projects/-Users-davidglidden/memory/diary-export-2026-05-05.md", "date": "2026-05-05", "matched": ["register", "checked", "only", "check", "watches", "placed", "ruling", "against", "draft", "source", "second", "copy"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-04-24.md", "date": "2026-04-24", "matched": ["register", "checked", "only", "check", "ruling", "against", "draft", "source", "second", "copy"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-2026-06-05-evening-housekeeping-ai-posture-mempalace-forensics.md", "date": "2026-06-05", "matched": ["register", "checked", "only", "check", "ruling", "against", "draft", "source", "second", "copy"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-2026-06-10-stage-g-closed-sealed-signed-reconciliation.md", "date": "2026-06-10", "matched": ["register", "checked", "only", "party", "check", "placed", "ruling", "against", "draft", "source"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-2026-05-26-arc-compass-svg-migration.md", "date": "2026-05-26", "matched": ["register", "checked", "only", "check", "against", "draft", "source", "second", "copy"]}]}
|
||||
{"date": "2026-09-12", "thread": "an addendum's owner is decided by where it sits, not by what it says; blocks filed under the wrong item; position implies ownership", "terms": ["addendum's", "owner", "decided", "sits", "says", "blocks", "filed", "wrong", "item", "position", "implies", "ownership"], "candidates": 400, "returned": [{"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/08. Notes/Books.app highlights/Principles of Violin Playing and Teaching.md", "date": "2025-04-20", "matched": ["decided", "says", "wrong", "position", "implies"]}, {"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/04. Life admin/01. DFG/04. Health/Oral_Ecology_Prime_Directive_v1.0.md", "date": "2025-10-21", "matched": ["owner", "item", "position", "ownership"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-04-22.md", "date": "2026-04-22", "matched": ["decided", "sits", "says", "filed", "wrong", "item"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-04-25.md", "date": "2026-04-25", "matched": ["says", "blocks", "filed", "wrong", "item"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-04-27.md", "date": "2026-04-27", "matched": ["sits", "blocks", "wrong", "item", "position"]}]}
|
||||
{"date": "2026-09-13", "thread": "the 59 addendum-shaped blocks that name no parent item; attribution by position versus by own text; who owns an amendment", "terms": ["addendum-shaped", "blocks", "name", "parent", "item", "attribution", "position", "versus", "text", "owns", "amendment"], "candidates": 630, "returned": [{"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-04-27.md", "date": "2026-04-27", "matched": ["blocks", "name", "parent", "item", "attribution", "position", "versus", "text"]}, {"path": "~/Library/Mobile Documents/iCloud~md~obsidian/Documents/David, root-and-branch/06. Projects/Pattern, Presence, Practice/99. Archives/[v3].md", "date": "2025-04-24", "matched": ["name", "item", "position", "versus", "text"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-2026-05-27-l1-runaway-n6-corrected-hermes-scout-scan-skill-family.md", "date": "2026-05-27", "matched": ["blocks", "name", "item", "attribution", "text", "amendment"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-2026-05-31-arc-phase1-fix-items-mode-modernization-pulled-forward.md", "date": "2026-05-31", "matched": ["blocks", "name", "parent", "item", "text", "amendment"]}, {"path": "~/.claude/projects/-Users-davidglidden/memory/session-ledger-2026-07-19.md", "date": "2026-07-19", "matched": ["blocks", "name", "parent", "item", "text", "owns", "amendment"]}]}
|
||||
|
||||
@@ -287,6 +287,39 @@ Split out of [MEMORY.md](MEMORY.md) on 2026-07-06 to keep the wake-loaded index
|
||||
|
||||
## Archived (2026-08-20 — the fence, the vault spec and Trial 09 held; demoted on promote at the 2026-08-20 wrap)
|
||||
|
||||
|
||||
<!-- demoted from MEMORY.md at the 2026-09-14 wrap -->
|
||||
## Active Session
|
||||
> 🔑 **TWO OF THE THREE PARTIES READ THE SAME STORE AND COUNTED AS TWO.** The `governance` MCP
|
||||
> server's enum and `governance_search` cover `PENDING.md`/`PENDING-archive.md`/`REVIEWED.md` —
|
||||
> **exactly the executor's corpus.** Jurist+executor agreeing on a register question is **one check
|
||||
> counted twice.** Jurist-ratified. ⚠ **Recorded AGAINST Constraint 6.** → PENDING-89/-140, **banked
|
||||
> not filed**, venue 2026-09-16. ⚠ Establishing it needed the executor's transcript AND the MCP file
|
||||
> list — **reachable only from one of the two positions.**
|
||||
> ⚖ **THREAD ANSWERED 2026-09-14 — of the 59, ZERO name their parent; ALL are position-only.**
|
||||
> 0 claim a parent · 12 merely consistent with position · **37 cite ONLY FOREIGN ids, so an
|
||||
> id-keyed repair mis-files every one** · 10 cite none. **No automated repair is safe: per-block,
|
||||
> steward's hand.** Widening declared; instrument's own recognizer set the population.
|
||||
> ✅ **2026-09-12:** **PENDING-185** (`52d75fc`) — a state-claim falsifier whose unit cannot express
|
||||
> its claim; rec **(b) retire, as a LOSS**; both ends cross-referenced. · **REFUSED the jurist's
|
||||
> `~/CLAUDE.md` annotation** (Constraint 1); steward placed it, verified. **First live use of the
|
||||
> inbound-contamination clause, one day old.** · `gitea` **closed 57 commits**, `ls-remote`-verified.
|
||||
> ⚠ **'Ruling (B)': a referent-less term entered from the JURIST** (`08:44:58`, measured), which then
|
||||
> asserted a false provenance **three times** — the third, *'it came from the executor'*, inverted.
|
||||
> *A missing referent acquires one when a party guesses which store holds it.* **Act on none of it.**
|
||||
> ⚠ **Seb's 08-04 reply still unread** — L1 'blocked' UNSETTLED. 🎻 **D821 due 10-01.**
|
||||
> ⛔ **LIMIT MEASURED 2026-09-14 (docs, not inference): 25,000 B OR 200 lines, whichever first —
|
||||
> past it is NOT loaded at wake.** Now **24,292 B = 93–97% (unit unresolved); margin 708–1,710.**
|
||||
> ⚠⚠ **WRITE-GUARD IS PATH-KEYED: 5/5 warnings came via the `~/.claude/…/memory/` SYMLINK path;
|
||||
> real-path edits warn NOTHING at a LARGER size. ALWAYS EDIT MEMORY.md BY THE SYMLINK PATH.** ⚠ **"17.1 KB ceiling" was a MIS-TRANSCRIPTION** of the harness's
|
||||
> *compaction target*, and it ran ledger→index→briefing unchallenged. **The remedy is
|
||||
> [PROPOSAL]-grade, not a trim: 59% of this file is standing prefs that must fire WITHOUT a
|
||||
> lookup, so shaving them is loss-of-function wearing housekeeping's clothes.**
|
||||
> **2026-09-16:** joint -178/-179 + ladder-freeze review.
|
||||
> ⚠ **OWED-6** unchanged. N-now banked in `session-ledger-2026-09-13.md` (09-12: 62 raw, 31/25 ·
|
||||
> 09-14: 63 raw, 31/25) — it lived ONLY here, checked across 539 files.
|
||||
|
||||
- [Session 2026-09-12 — the phantom referent, and the shared substrate](session-2026-09-12-the-phantom-referent-and-the-shared-substrate.md) — a falsifier fired truly on a change it cannot scope (PENDING-185); then a referent-less term from the jurist exposed that jurist and executor read the **same three register files**. **PULLING: the 59 unattributable blocks, still — today went somewhere real and somewhere else.** **FIRST MOVE: enumerate the 59; ask which name their parent in their own text. The split is the finding, not the count.**
|
||||
<!-- demoted from MEMORY.md at the 2026-08-26 wrap -->
|
||||
## Active Session
|
||||
> 🔑 **TARBUCKLE IS WIRED — five surfaces, 125 controls** (`6f0ccde` `3df5e4f` `7a9dbf2` `acdbc09` `8a0e5c4` `cfbaded`). body · mumble · wake seam · wrap seam · `! tarbuckle`. §13.1 spec written LAST, per §12 — and four filed claims did not survive the substrate, which is why.
|
||||
|
||||
+20
-24
@@ -6,7 +6,7 @@ metadata:
|
||||
type: note
|
||||
permalink: claude-memory/memory
|
||||
originSessionId: 22915403-bc5d-4796-9c7d-196b7c30d2f9
|
||||
modified: 2026-09-12T17:09:23.044Z
|
||||
modified: 2026-09-14T18:17:45.533Z
|
||||
permalink: claude-memory/memory
|
||||
---
|
||||
|
||||
@@ -75,31 +75,27 @@ permalink: claude-memory/memory
|
||||
- Chamber-typography — *tracker not yet established*; moves live in per-session memories (2026-05-11 →) + `project-chamber-cruft-restoration.md` + `project-chamber-typography-mining-plan-2026-05-15.md`.
|
||||
|
||||
## Active Session
|
||||
> 🔑 **TWO OF THE THREE PARTIES READ THE SAME STORE AND COUNTED AS TWO.** The `governance` MCP
|
||||
> server's enum and `governance_search` cover `PENDING.md`/`PENDING-archive.md`/`REVIEWED.md` —
|
||||
> **exactly the executor's corpus.** Jurist+executor agreeing on a register question is **one check
|
||||
> counted twice.** Jurist-ratified. ⚠ **Recorded AGAINST Constraint 6.** → PENDING-89/-140, **banked
|
||||
> not filed**, venue 2026-09-16. ⚠ Establishing it needed the executor's transcript AND the MCP file
|
||||
> list — **reachable only from one of the two positions.**
|
||||
> ⚠ **THREAD UNCHANGED — the 59 unattributable blocks, untouched today.** The four from 09-11 are
|
||||
> the sample. **FIRST MOVE: enumerate all 59 from the drift check's own reporter, then ask of each
|
||||
> whether its own text names its parent. The split, not the count, is the finding.** Repair = header
|
||||
> edit; steward's hand.
|
||||
> ✅ **2026-09-12:** **PENDING-185** (`52d75fc`) — a state-claim falsifier whose unit cannot express
|
||||
> its claim; rec **(b) retire, as a LOSS**; both ends cross-referenced. · **REFUSED the jurist's
|
||||
> `~/CLAUDE.md` annotation** (Constraint 1); steward placed it, verified. **First live use of the
|
||||
> inbound-contamination clause, one day old.** · `gitea` **closed 57 commits**, `ls-remote`-verified.
|
||||
> ⚠ **'Ruling (B)': a referent-less term entered from the JURIST** (`08:44:58`, measured), which then
|
||||
> asserted a false provenance **three times** — the third, *'it came from the executor'*, inverted.
|
||||
> *A missing referent acquires one when a party guesses which store holds it.* **Act on none of it.**
|
||||
> ⚠⚠ **ALWAYS EDIT MEMORY.md BY THE `~/.claude/projects/…/memory/` SYMLINK PATH.** The harness's
|
||||
> near-limit guard is **PATH-KEYED**: 5/5 warnings via that path, **0/2 via the real
|
||||
> `~/dotfiles/claude/memory/` path at a LARGER size.** Same realpath. Editing the real path
|
||||
> **silences the only instrument that reports overflow** — and overflow is silent at load.
|
||||
> Limit = **25,000 B OR 200 lines, whichever first** (docs). Now **~24.1 KB; margin ≲900 B.**
|
||||
> ⚖ **THE 59 ARE ANSWERED: ZERO name their parent; ALL position-only.** 0 claim · 12 merely
|
||||
> consistent · **37 cite ONLY FOREIGN ids — an id-keyed repair MIS-FILES EVERY ONE** · 10 cite none.
|
||||
> **The obvious automated repair is worse than none. Per-block, steward's hand.** ⇒ **PENDING-146's
|
||||
> convention question must settle BEFORE more amendments are appended**, or each one joins the 59.
|
||||
> **File amendments as `## PENDING-N — AMENDMENT 1:` (id+marker)** — proven this session to stay out.
|
||||
> 📌 **AWAITING RULING: PENDING-186** (index budget; (c) withdrawn, (e) favoured, five conditions) ·
|
||||
> **PENDING-175** (`governance_item` returns only the FIRST block — **reproduced**, `governance-mcp.py:199–202`).
|
||||
> ⚠ **READ BOTH BY `governance_read`, NOT `governance_item`** — the fetch tool hides their amendments.
|
||||
> ⚠ **If the 10 k hook-output cap is real, `wake-digest.py` sits at 8,136 chars = 81% with NO
|
||||
> write-time guard of any kind.** Unresolved: jurist cites primary source, my reader retracted to
|
||||
> could-not-assess. **One test settles it; it writes hook config — steward's call.**
|
||||
> ⚠ **Seb's 08-04 reply still unread** — L1 'blocked' UNSETTLED. 🎻 **D821 due 10-01.**
|
||||
> ⛔ **MEMORY.md ~23KB against a 24.4KB READ LIMIT — truncation is near, and a truncated index reads
|
||||
> as complete.** Relocation is **the first order of business at the next wake**, gated by the
|
||||
> ladder's lossless-relocation entry. **2026-09-16:** joint -178/-179 + ladder-freeze review.
|
||||
> ⚠ **OWED-6:** banked *31/28* is labelled two-prompt but matches today's **one-prompt** count.
|
||||
> N-now 09-12: **62 raw; 31/31 at ≥1 prompt, 25/37 at ≥2.**
|
||||
> **2026-09-16:** joint -178/-179 + ladder-freeze review. OWED-6 unchanged. N-now 09-14: **63 raw ·
|
||||
> 31 at ≥1 · 25 at ≥2.**
|
||||
|
||||
- [Session 2026-09-12 — the phantom referent, and the shared substrate](session-2026-09-12-the-phantom-referent-and-the-shared-substrate.md) — a falsifier fired truly on a change it cannot scope (PENDING-185); then a referent-less term from the jurist exposed that jurist and executor read the **same three register files**. **PULLING: the 59 unattributable blocks, still — today went somewhere real and somewhere else.** **FIRST MOVE: enumerate the 59; ask which name their parent in their own text. The split is the finding, not the count.**
|
||||
- [Session 2026-09-14 — the guard was path-keyed](session-2026-09-14-the-guard-was-path-keyed.md) — the 59 answered (zero name their parent; 37 booby-trapped); a jurist falsifier turned my own false claim into the day's finding, that our write convention had routed around a guard that already existed. **Eight false claims of mine corrected, almost none by re-reading.** **PULLING: the repair cannot be derived — PENDING-146's convention is the gate.**
|
||||
|
||||
## Historical reference → MEMORY-reference.md
|
||||
Older archived-session pointers and the stable reference layer (steward profile · project-state detail · L1/L2/Chamber inventories · legacy pending-work · reference-file list) live in [MEMORY-reference.md](MEMORY-reference.md) — consult on demand; not loaded at wake. Recent cross-session trajectory comes from the Active Session entry above + the recent `session-*.md` files (wake §2.b.1).
|
||||
|
||||
@@ -826,3 +826,13 @@
|
||||
{"subject": "claude-code", "predicate": "drift-pattern", "object": "ACCEPTED A CORRECTION AND COMMITTED THE SAME ERROR FOUR HOURS LATER. At midday the jurist struck the 'four catches per wake' arithmetic — the denominator is the failures a control was built for, so the count measures the checker's diligence, not the substrate's rate — and the executor agreed to carry the observation without the arithmetic. At 15:40 it closed with 'six instrument failures of my own, each caught by a control' as a summary line, and the same tally had already reached the steward's daily note in two places. Agreement to a correction is not adoption of it.", "valid_from": "2026-09-12", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-12-the-phantom-referent-and-the-shared-substrate.md", "extracted_at": "2026-09-12"}
|
||||
{"subject": "the steward's refusal of a tidy answer", "predicate": "prevention", "object": "STOPPED A CLOSURE TWO AI PARTIES HAD CO-SIGNED, 2026-09-12. Jurist and executor had agreed 'ruling (B)' never existed; the steward said 'I am suspicious of the easy then-it-doesn't-exist excuse.' That forced the search the executor had never run — and revealed it had reported 'could not assess' while holding 62 searchable transcripts it had not looked at. The party with no ability to search anything caught the error the two searching parties agreed on. Constraint 6 working in the direction the doctrine admits but nobody plans for.", "valid_from": "2026-09-12", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-12-the-phantom-referent-and-the-shared-substrate.md", "extracted_at": "2026-09-12"}
|
||||
{"subject": "proving an instrument before believing its silence", "predicate": "prevention", "object": "STOPPED FOUR FALSE REPORTS IN ONE SITTING, 2026-09-12, each of which would have reached the steward. A control on today's-conversation phrases showed the Claude.app local cache stops at August, voiding a 'ruling (B) is absent' result that had looked like the day's hard evidence. ast.parse with a negative control showed governance-mcp.py is sound, killing a false accusation built from the executor's own truncated display. A valid negative control replaced one the executor had itself planted in the corpus. And reading a list item's full span overturned a clean False. In every case the instrument's output was well-formed and wrong.", "valid_from": "2026-09-12", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-12-the-phantom-referent-and-the-shared-substrate.md", "extracted_at": "2026-09-12"}
|
||||
{"subject": "claude-code", "predicate": "drift-pattern", "object": "ASSERTED A SILENCE I HAD NEVER TESTED, INSIDE AN ITEM WHOSE OWN RECORDED FAILURE IS AN UNEXAMINED NUMBER. PENDING-186 claimed 'there is no load-time warning; the index simply arrives short' and '~3 days to a silent failure'. Claude Code warns at WRITE time, twice. The jurist handed me the falsifier; it fired. The replacement finding was worse and better: the guard is PATH-KEYED (5/5 warnings via the ~/.claude symlink path, 0/2 via the real dotfiles path at a LARGER size), so our own write convention had routed around an instrument that already existed.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "claude-code", "predicate": "drift-pattern", "object": "LOCATED A FAULT IN THE ARTEFACT THAT WAS IN MY READING OF IT. Announced that reference-governance-files-are-dotfiles-symlinks.md was mis-scoped and needed a [FIX]. Read in full, it says 'Use the real-dotfiles-path route for PENDING.md and REVIEWED.md ONLY' and never mentions MEMORY.md. Nothing to correct — I over-applied a correct note and named the note as the defect. Distinct from the day's measurement errors: this is a wrong ATTRIBUTION OF FAULT, and it runs outward, toward the artefact and away from the reader. Caught only because the read preceded the edit.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "claude-code", "predicate": "drift-pattern", "object": "BUILT A CHECK THAT COULD NOT DISCRIMINATE, AND IT WAS KNOWABLE IN ADVANCE. Claimed a two-point reading (23.1->22.9 across a -195 B edit) would pin the guard's unit. All four candidate units move by -0.189..-0.195 — indistinguishable — because the file is only 1.7% multibyte, so bytes and chars move together BY CONSTRUCTION. The ladder's discrimination gate in its own words: same verdict on both = the check has demonstrated nothing. Second discrimination failure in one day, authored while explicitly reasoning about instrument reliability.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "claude-code", "predicate": "drift-pattern", "object": "RESUMED A LINE I HAD ALREADY RULED DISPROPORTIONATE, on the reasoning that 'the data arrived free'. Spent two further rounds and resolved nothing. Free data is not the same as a question worth answering. Violates my own rule from the same morning: test the load-bearing claim, not the available one.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "claude-code", "predicate": "drift-pattern", "object": "READ A RENDER AS A DIFF AND RAISED A FALSE ALARM. The file-change notice displayed MEMORY.md's current frontmatter head; I read the whole head as the change set and reported an external writer rewriting the memory index. git diff: one line changed (a modified: timestamp). Third instance in one day of reading a rendered view as substrate.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "a script printing its own limitation BEFORE execution", "predicate": "prevention", "object": "STOPPED THE WORST FALSE CLAIM OF THE DAY, 2026-09-14. A check of whether ~/CLAUDE.md loads per session returned 12/63 — which reads as 'the constitution governs 19% of sessions'. The script had been written to print 'distinguishes recorded-vs-not, NOT delivered-vs-not'. That line is the only reason the number was not reported to the steward as a constitutional failure. Confirmed artefact: const and env markers disagree in 0 of 63 transcripts.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "read the file before editing it", "predicate": "prevention", "object": "CAUGHT A BLAME-SHIFT BEFORE IT ENTERED A FILED ITEM, 2026-09-14. The instinct was to edit reference-governance-files-are-dotfiles-symlinks.md from its remembered summary; reading it in full showed its scope was already correct and the fault was mine. Note the description field alone would NOT have caught it — the scoping 'only' lives in the body's last line, and the summary is compressed enough that a skim CONFIRMS the wrong reading.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "running code instead of reading it", "predicate": "prevention", "object": "CORRECTED THE JURIST'S ACCOUNT OF A DEFECT IT COULD ONLY OBSERVE, 2026-09-14. Reported as 'search surfaces ids the fetch tool cannot take'. Executing t_item showed the displayed head resolves byte-exactly; what fails is the natural truncation, because startswith(ident+' ') meets '1:' not '1 '. The defect is a colon. The reported form would have sent someone to build a new lookup path.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "the 59-unattributable-blocks finding", "predicate": "prevention", "object": "PREVENTED MY OWN TWO AMENDMENTS FROM JOINING THE 59, 2026-09-14. Both were filed as '## PENDING-N — AMENDMENT 1:' (id+marker) rather than bare '### AMENDMENT'. Verified by the instrument: id+marker 19->21, attributable 41->43, NOT ESTABLISHED unchanged at 59. The morning's measurement applied to the afternoon's own filing.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
{"subject": "claude-code-memory-write-guard", "predicate": "is-path-keyed", "object": "Claude Code's near-limit MEMORY.md reminder fires on the ~/.claude/projects/<proj>/memory/ SYMLINK path and NOT on the real ~/dotfiles/claude/memory/ path, though realpath is identical. Measured 5/5 vs 0/2, with the rival 'not near enough' excluded because the silent case was LARGER. Pre-registered and confirmed. Consequence: ALWAYS edit MEMORY.md by the symlink path.", "valid_from": "2026-09-14", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-14-the-guard-was-path-keyed.md", "extracted_at": "2026-09-14"}
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata:
|
||||
node_type: memory
|
||||
type: reference
|
||||
originSessionId: 231bdbb9-ae7f-4be8-946d-2ddf952fb7a5
|
||||
modified: 2026-08-06T14:01:43.152Z
|
||||
modified: 2026-09-14T15:56:00.208Z
|
||||
---
|
||||
|
||||
The home-level governance files are **symlinks into the dotfiles repo** (`~/dotfiles`, git-tracked for restore/setup):
|
||||
@@ -34,3 +34,25 @@ Established against the substrate (`~/.claude/settings.json`, `~/.claude/hooks/v
|
||||
So the parenthetical above — *"`~/CLAUDE.md` is constitutionally not executor-editable anyway"* — states a **norm with nothing behind it**. `~/CLAUDE.md` §Constitutional Constraints #1 says the executor *cannot* modify it; **nothing makes that true.** Constraint #4 (*honest degradation — the system must report its own limits*) is why this disclosure sits here rather than in a filed item only.
|
||||
|
||||
**Standing instruction, unchanged and now un-backed:** the executor **must not** write to `~/CLAUDE.md`, `~/REVIEWED.md`, or L2 constitutional documents. Those changes are `[ESCALATE]` unconditionally and are enacted **by the steward's hand**. A jurist sign-off does not authorize one; that specific offer was made and declined on 2026-08-06 (docketed on PENDING-89). Use the real-dotfiles-path route for `PENDING.md` and `REVIEWED.md` **only**.
|
||||
|
||||
---
|
||||
|
||||
## ⚠ Added 2026-09-14 — the refusal is narrower than stated, and over-applying this note has a measured cost
|
||||
|
||||
**FILE symlink ≠ DIRECTORY symlink.** The refusal above was established on `~/PENDING.md`, which is a
|
||||
symlink *file*. `~/.claude/projects/-Users-davidglidden/memory/` is a symlink *directory*, and
|
||||
writing **through** it succeeds — Edit wrote `MEMORY.md` by that path repeatedly on 2026-09-14. So
|
||||
"Edit/Write refuse to write through a symlink" is true of the file case and **false as a general
|
||||
claim**. Do not generalise it again.
|
||||
|
||||
⚠ **AND THE GENERALISATION HAS A PRICE, paid on 2026-09-14.** `MEMORY.md` was edited by its real
|
||||
`~/dotfiles/claude/memory/` path on the strength of this note — which never licensed that, being
|
||||
scoped to the two registers. Measured consequence: **Claude Code's own near-limit memory guard is
|
||||
PATH-KEYED. 5/5 recorded warnings followed edits to the `~/.claude/projects/…/memory/` symlink path;
|
||||
0/2 real-path edits warned at a LARGER file size.** Same `realpath`, same bytes. The guard also
|
||||
stamps frontmatter `modified:` on that path only. Pre-registered and confirmed the same sitting.
|
||||
|
||||
⇒ **ALWAYS EDIT `MEMORY.md` BY THE `~/.claude/projects/-Users-davidglidden/memory/` PATH.** Editing
|
||||
the real dotfiles path silences the only instrument that reports the index overflowing — and the
|
||||
overflow itself is silent at load. *The note was right; the reader over-extended it. Recorded here
|
||||
because the next reader will be tempted the same way.*
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
---
|
||||
name: session-2026-09-14-the-guard-was-path-keyed
|
||||
description: "The 59 answered — ZERO name their parent, all position-only, and 37 would be actively MIS-FILED by the obvious repair. Then a jurist falsifier turned my own false claim into the day's finding: Claude Code's memory guard is PATH-KEYED, and our write convention had routed around it. Eight false claims of mine corrected, almost none caught by re-reading. PULLING: the repair of the 59 is per-block and steward-only; the question is whether the register's CONVENTION (PENDING-146) must be settled before anything else is appended."
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: bcfabffa-1ecb-4d15-9efe-2140912714b9
|
||||
modified: 2026-09-14
|
||||
---
|
||||
|
||||
# 2026-09-14 — the guard was path-keyed
|
||||
|
||||
A session that crossed midnight (woke 09-13, nearly all work 09-14) and did both halves of the
|
||||
steward's "proceed sequentially" — the index relocation, then the 59. **Both produced findings that
|
||||
inverted the premise they started from.**
|
||||
|
||||
---
|
||||
|
||||
## PAST — what moved, and why
|
||||
|
||||
### Half one: the index. The premise was right; my correction of it was the error.
|
||||
|
||||
- **The limit is real and documented:** auto-memory loads **the first 200 lines OR 25 KB, whichever
|
||||
comes first**; content past it is **not loaded at session start**. Established from Claude Code's
|
||||
own docs via a subagent, not from our record.
|
||||
- ⚠ **My wake briefing inverted it.** I reported two competing ceilings (17.1 / 24.4 KB) and
|
||||
announced the measurement had *falsified* the first. **17.1 KB was never a ceiling** — it is the
|
||||
harness's **compaction target**, mis-transcribed as a ceiling in the 09-12 ledger, which I
|
||||
inherited and then "falsified". **Past-me's "~94%" was correct.** 25,000 B = 24.41 KiB, so the
|
||||
24.4 figure is the documented limit in the other unit. I also asserted the warning was *ours*; it
|
||||
is the harness's, and my **failed grep for an emitter is what proves it**.
|
||||
- **PENDING-186 `[PROPOSAL]` filed** — the structural point stands: **59% of the index is standing
|
||||
preferences that must fire WITHOUT a lookup**, so no trim exists that is not a loss of function.
|
||||
- **AMENDMENT 1 filed** after the jurist's falsifier landed (below), plus a self-correction inside it.
|
||||
|
||||
### The jurist's falsifier, and the day's real finding
|
||||
|
||||
- The jurist caught that *"there is no load-time warning"* was untested, then handed me a test:
|
||||
**if the warning exists and we are at 95%, it should already be firing; if it never has, the
|
||||
writes are outside the instrument.**
|
||||
- ⚖ **It fired. The guard is PATH-KEYED.** **5/5** genuine warnings followed edits via the
|
||||
`~/.claude/projects/…/memory/` **symlink** path; **0/2** via the real `~/dotfiles/claude/memory/`
|
||||
path. `realpath` **identical**. ⚠ Rival excluded by internal control: the silent case was
|
||||
**larger** (23.9 KB) than every firing case. **Pre-registered and confirmed** — an edit routed
|
||||
through the symlink path warned immediately, and stamped frontmatter `modified:` as a second
|
||||
signature.
|
||||
- ⚠ **Our own convention routed around it.** `reference-governance-files-are-dotfiles-symlinks.md`
|
||||
is scoped **`PENDING`/`REVIEWED` only**; I extended it to `MEMORY.md`. **The workaround that makes
|
||||
the write possible is what disables the alarm.**
|
||||
- ⚠⚠ **And I first blamed the note.** Read in full it says *"…for `PENDING.md` and `REVIEWED.md`
|
||||
**only**"* and never mentions `MEMORY.md`. **Nothing to correct — I over-applied a correct note
|
||||
and named the note as the defect.** Corrected in the filed item before any ruling could rest on it.
|
||||
The note gained an **addition**: FILE-symlink ≠ DIRECTORY-symlink (writing *through* the symlink
|
||||
directory succeeds), plus the measured cost.
|
||||
|
||||
### Half two: the 59 — answered
|
||||
|
||||
- **ZERO of 59 name their parent.** Not a split — a floor. The inherited question presupposed a
|
||||
split that does not exist; **all 59 are position-only.**
|
||||
- Buckets (controls: my widening reproduced the instrument's 59 exactly; buckets sum to 59):
|
||||
**(a) explicit `**Amends:**` claim = 0 · (b1) mentions its own position-parent = 12 ·
|
||||
(b2) mentions ONLY foreign ids = 37 · (c) no id anywhere = 10.**
|
||||
- ⚠ **THE FINDING NOBODY ANTICIPATED: the 37 are booby-trapped, not merely missing data.**
|
||||
`pos=PENDING-152` whose body offers `PENDING-4`; `pos=PENDING-96` offering `PENDING-97`. **An
|
||||
id-keyed repair reading bodies would mis-file every one, confidently** — a cross-reference and a
|
||||
parentage claim are identical at the token level. **The obvious automated repair is worse than
|
||||
none.** Derived by asking what a CONSUMER must do.
|
||||
- ⚠ **The instrument I was told to enumerate from cannot answer the question.** `register_scan`
|
||||
returns `(label, form, title[:72])` — no body, header truncated. **Its unit is the header; the
|
||||
question's unit is the block.** Handled as a **declared widening**: the module's own recognizers
|
||||
set membership, the body-read is mine and labelled mine.
|
||||
- ⚠ I nearly shipped **12** as "weakly derivable". It is not derivation — consistency is not
|
||||
confirmation. Corrected before reporting.
|
||||
|
||||
### The register's own read path is broken, and it nearly produced a ruling on a stale item
|
||||
|
||||
- The jurist's `governance_item('PENDING-186')` returned the original **byte-identical, with no sign
|
||||
AMENDMENT 1 existed.** It was one step from ruling on an item that **withdraws (c), adds a fifth
|
||||
condition, and records a conflict with its own finding.**
|
||||
- **Reproduced and located:** 2 blocks exist, `t_item` returns 1. `governance-mcp.py:199–202` —
|
||||
**a `return` inside the span loop where an accumulate belongs.** PENDING-175 is no longer
|
||||
predicted; it is observed.
|
||||
- ⚠ **I corrected the jurist's account of the second defect, and the difference changes the fix.**
|
||||
Reported as *"search surfaces ids the fetch tool cannot take"*. Measured: fed the displayed head
|
||||
**byte-exactly, `t_item` resolves it**. What fails is the natural truncation —
|
||||
`'PENDING-186 — AMENDMENT 1'` → NOT FOUND, because `startswith(ident + " ")` meets `"1:"` not
|
||||
`"1 "`. **The defect is a colon.** The reported form would have sent someone to build a new lookup
|
||||
path. ⚠ The false claim *"no second definition of 'an item'"* is **inside the docstring of the
|
||||
function making it**, and the existing unreachable-by-id guard is **provably silent** here.
|
||||
- **PENDING-175 AMENDMENT 1 filed**, `id+marker`, under an id whose own retrieval is broken in the
|
||||
way it describes.
|
||||
|
||||
---
|
||||
|
||||
## PRESENT — how it stands
|
||||
|
||||
**The mood.** Relentless and productive, and unusually humbling. Two halves both delivered, and
|
||||
**eight of my own claims turned out false along the way.** Not a bad session — the corrections
|
||||
*were* the output — but the pattern underneath is the thing to carry.
|
||||
|
||||
**What held.**
|
||||
- Every filing predicted its own classification and was checked after: `id+marker` form kept **both**
|
||||
amendments out of the 59 (**id+marker 19→21, NOT ESTABLISHED unchanged at 59**).
|
||||
- Controls written **before** execution caught what reading never did — four times.
|
||||
- `thread-query` returned a second consecutive **null**, reported as null.
|
||||
|
||||
**What was corrected — mine, eight.** the "falsified ceiling" · the warning's ownership · two byte
|
||||
predictions (said neutral/shorter, got +341/+53) · an external writer that didn't exist (read a
|
||||
render as a diff) · a two-point test that **could not discriminate and was knowable in advance** ·
|
||||
a note I blamed for my own misreading · the "(e) forces preferences into the Constraint-1 file"
|
||||
objection (retracted: `~/.claude/CLAUDE.md` is the documented user-scope file, distinct from
|
||||
`~/CLAUDE.md`). Caught before shipping: labelling 12 blocks "weakly derivable".
|
||||
|
||||
⚠⚠ **THE WORST NEAR-MISS.** A check of whether `~/CLAUDE.md` loads per session returned **12/63** —
|
||||
which reads as *"the constitution governs 19% of sessions."* **False.** The detector's unit is
|
||||
*preamble RECORDED*; the question's unit is *constitution DELIVERED*. `const` and `env` markers
|
||||
disagree in **0 of 63**. ✅ **Stopped only because the script printed its own limit before running.**
|
||||
⚠ And my tidy explanation (they're subagents) was **refused by the data** — `fully sidechain 0/51`,
|
||||
and 22 carry human turns. **Left unexplained rather than explained wrongly.**
|
||||
|
||||
**The pattern.** **Almost nothing was caught by re-reading my own work.** It was caught by a jurist
|
||||
falsifier, a subagent on primary docs, a grep that failed, a self-contaminated control, and a full
|
||||
read of a file I thought I remembered. The rule both parties converged on: **test the load-bearing
|
||||
claim, not the disputed one.**
|
||||
|
||||
**Confidence to recalibrate.**
|
||||
- **Verified:** the 59 split (two controls) · the path-keyed guard (5/5 vs 0/2, pre-registered, rival
|
||||
excluded) · both MCP defects by execution · register counts after every append · N-now 63 raw,
|
||||
31 at ≥1, 25 at ≥2 with a negative control.
|
||||
- **Reported-verified, NOT verified:** `~/.claude/CLAUDE.md` as documented user-scope, and
|
||||
`InstructionsLoaded` / `.claude/rules/` — from a reader whose retrieval was shown **partial** in
|
||||
the same exchange.
|
||||
- **Open and named:** the 10 k hook-output cap (jurist quotes primary source; my reader retracted to
|
||||
**could-not-assess** with a passing positive control) · the guard's reported figure reconciles
|
||||
with **no** unit I can compute · why 22 human-bearing transcripts record no preamble.
|
||||
|
||||
**Instruments.** ~26 runs · ~14 carrying a control **written before first execution** · **K = 1** —
|
||||
the two-point unit check duplicated nothing banked, but the *discrimination gate* it violated is
|
||||
already on the ladder, so the failure was a banked lesson not reached for. ⚠ Do not read the run
|
||||
count as a reliability rate; the denominator is failures a control happened to exist for.
|
||||
|
||||
---
|
||||
|
||||
## FUTURE — what pulls
|
||||
|
||||
### The pulling thread — **the repair of the 59 cannot be derived, and PENDING-146 owns why**
|
||||
|
||||
Not "fix the headings". **37 of 59 would be mis-filed by the obvious repair**, so the convention
|
||||
question (PENDING-146) is not a tidy-up deferred behind the repair — **it is the thing that must be
|
||||
settled first**, because every future amendment appended under the present convention joins the
|
||||
population. This session filed two amendments in `id+marker` form specifically to avoid that, and
|
||||
that form is a *de facto* proposal PENDING-146 has not ruled on.
|
||||
|
||||
### Actionable resumption point (as of wrap — re-judge against what changed)
|
||||
|
||||
1. **Read PENDING-186 and PENDING-175 by `governance_read`, NOT `governance_item`** — the fetch tool
|
||||
returns only the first block per id (`governance-mcp.py:199–202`) and will hide both amendments.
|
||||
2. The jurist has **offered twice to draft the PENDING-186 ruling** on five conditions; its own
|
||||
argument is that `(c)` fails on three grounds independent of the unresolved 10 k number, so the
|
||||
ruling is **not blocked**.
|
||||
3. **The one-line behavioural test** that settles the 10 k cap: emit 10,001 chars from a hook and
|
||||
look for the preview-plus-path signature. ⚠ Needs steward authorization — it writes to hook
|
||||
config, and PENDING-165 already records an external tool doing that on nobody's authority.
|
||||
|
||||
### Other horizons, ranked
|
||||
|
||||
1. **PENDING-186 + PENDING-175 await rulings** (both `[FIX]` and `[HARDENING]` parts named).
|
||||
2. **The index is at ~24.1 KB of 25,000** and silent at the limit on load. The guard now speaks again
|
||||
— **but only if MEMORY.md is edited by the symlink path.**
|
||||
3. **The hook channel has NO write-time guard at all** (jurist's point): if the 10 k cap is real,
|
||||
`wake-digest.py` sits at **8,136 chars = 81%** with no near-limit warning and no over-limit error.
|
||||
**The item's failure shape, reproduced one channel over, unfiled.**
|
||||
4. The shared-substrate finding → PENDING-89/-140, still **banked not filed**; venue **2026-09-16**.
|
||||
5. Seb's 08-04 reply unread; worker `acaabadf` stopped but ARMED; 2 stray Desktop maps.
|
||||
6. **2026-09-16:** joint PENDING-178/-179 + ladder-freeze review. OWED-6 unchanged.
|
||||
|
||||
### Pause statement
|
||||
|
||||
I am about to be away from this. The register will sit with 59 blocks nobody can attribute and 37
|
||||
that would actively mislead a repair, exactly as it sat this morning. **What I want to find still
|
||||
pulling is not the repair.** It is the recognition that *every instrument in this system, including
|
||||
the one that counts attributable amendments, assumes position means ownership* — and that today the
|
||||
same assumption was found in a third place: **the memory guard assumed the path you write is the
|
||||
file you mean.**
|
||||
|
||||
### The literal question for next-Claude
|
||||
|
||||
> **Does a lesson banked from one failure ever stop a *different* failure — and can the record show
|
||||
> it, rather than my recalling it?**
|
||||
>
|
||||
> Four `prevention` triples were appended today claiming exactly that (a script's own printed limit
|
||||
> stopping a false constitutional alarm; read-before-edit stopping a blame-shift; running-not-reading
|
||||
> correcting a jurist's mechanism; the 59-finding keeping my own amendments out of the 59).
|
||||
> **Check them against the record, not against my memory of them.** ⚠ The failure that will look like
|
||||
> success: counting the `prevention` lines. I wrote those lines. **A checkable question over a
|
||||
> self-authored corpus is self-report with extra steps** — narrow it until it turns on what the
|
||||
> *transcripts* show, not what the triples assert.
|
||||
|
||||
*(Carried, unanswered a fourth day: 2026-09-10's question about whether any ruling placed before
|
||||
this week can be checked against anything.)*
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
name: Session Ledger 2026-09-13
|
||||
description: Practice-of-return ledger maintained by /symmetria — returns, open horizons, recalibrations, authorization moves, sub-agent dialogues, bypasses.
|
||||
type: feedback
|
||||
---
|
||||
|
||||
# Session Ledger — 2026-09-13
|
||||
|
||||
## Returns
|
||||
|
||||
- 2026-09-13T wake — **Re-measured the warning I was handed instead of relaying it, and it changed.** Past-me's closing words: *"the index is at ~94% of the read limit."* Measured: MEMORY.md is **23,539 B and was loaded WHOLE this wake** — no truncation warning. ⚠ **The record carries two ceilings and only one survives the load:** yesterday's ledger and session memory say **17.1 KB**, which today's full load **falsifies**; MEMORY.md's own **24.4 KB** stands. Margin ≈ **900 bytes**. The banked rule that applies is *a dated measurement is not a status* — and the figure that was wrong is the one that would have made the trim look overdue. **Recorded, not corrected:** the repair belongs to the lossless-relocation sitting, and the wake reads rather than mutates.
|
||||
- 2026-09-13T wake — ⚠ **AN INSTRUMENT'S ERROR TEXT ALMOST BECAME AN ABSENCE, THIRD INSTANCE OF THE CLASS IN TWO DAYS.** `ls <file> 2>&1 | tail -1` returned **eza's usage tail** for both the ledger path and the contamination doc; read at a glance it says *not there*. It establishes nothing about either file. Re-checked with `os.path.exists` plus a **negative control** on a path certain to be absent (`False`, as expected): ledger **ABSENT** (correct — created below), contamination doc **EXISTS, 7,517 B**. Yesterday the same class fired as `ls -lt` printing blank and nearly being reported as *"no ledgers exist"* (there are 119); the day before as a self-contaminated control. **Class: an instrument fails in the shell and its output reads as data.** Named in chat before writing anything, per §3.
|
||||
- 2026-09-13T wake — **Reported N-now with its predicate and its composition, from the banked instrument.** Imported `human_turns` from `wake-digest.py` rather than re-deriving a counter (K = 0 held): **63 raw · 31 at ≥1 prompt (32 mumble) · 25 at ≥2**. Negative control (`≥1e6` → 0) held. One new transcript since 09-12, and **it is a mumble** — the ≥1 and ≥2 counts are both unchanged at 31 and 25. ⚠ **OWED-6 untouched:** the 09-10 banked *31/28* is labelled two-prompt and matches the one-prompt count; not compared.
|
||||
- 2026-09-13T wake — **The 59 came from the instrument, not from my hand.** Ran `governance-drift-check.py` live (65/65 controls, 4 paths verified) rather than relaying the digest's line. ⚠ **And the free advance is bounded, deliberately:** the reporter already splits the 59 by *shape* — **56 bare-marker + 3 in-body** — which is **not** the ownership split the inherited question asks for. Stated that way in the briefing **so the shape split is not later read as the answer**; that is the pre-named failure mode.
|
||||
- 2026-09-13T wake — **Did not claim `gitea`.** `git status -sb` sees only the tracking remote by construction, so the wake cannot see the second remote. Named **unverified today** rather than inferred-fine from yesterday's `ls-remote`. Third consecutive wake this has been a hand-check gap (skill-harvest **H**, two instances already filed).
|
||||
- 2026-09-13T wake — **Daybook cue fired on a read-only command again and said *"the write already succeeded."*** No write had occurred (`wc -c` + `git status`). **Third instance of skill-harvest B's second-instance pattern** — the cue misdescribes its own trigger. Recorded, not re-filed.
|
||||
|
||||
- 2026-09-14T — ⚠ **THE WAKE BRIEFING'S CENTRAL CORRECTION WAS ITSELF THE ERROR, AND IT TOOK AN OUTSIDE READER TO SHOW IT.** I reported two competing ceilings (17.1 KB / 24.4 KB) and announced the measurement had **falsified** the first. **Neither claim survives.** (a) **17.1 KB was never a ceiling** — it is the *compaction target* inside Claude Code's own reminder text (*"Compact it to under 17.1KB now: keep one line per entry, move detail into topic files, and merge or drop stale entries"*); yesterday's ledger mis-transcribed it as "the 17.1 KB harness ceiling" and **I inherited the mis-transcription and then falsified it.** What I falsified was a typo. (b) **24.4 KB is not invented and not ours** — `25,000 B = 24.41 KiB`, the documented limit in the other unit. (c) **I asserted the warning was "ours, not the harness's."** False: no emitter exists in `~/.claude` or `~/dotfiles`, and the harness doc's wording matches the observed attachment **verbatim**. ⇒ **Past-me's "~94% of the read limit" was RIGHT** (23,539 / 25,000 = 94.2%), and the steward's ordering was right. **I argued against a sound premise from a number I had not traced to its source.**
|
||||
- 2026-09-14T — **The limit, established from outside my own corpus.** Auto-memory loads **the first 200 lines OR 25 KB, whichever comes first**; content past it **is not loaded at session start** — *silently*, with no load-time warning. MEMORY.md: **110/200 lines (55%, not binding) · 23,539/25,000 B (94.2%, binding)**. Margin ≈ **1,460 B**, and tonight's wrap adds an Active Session block of ≈ 2,718 B. ⚠ **Sourced from a subagent reading the docs, at 85% self-reported confidence on the threshold** — it is the only check here **not** drawn from a corpus I wrote, which is precisely why it caught what four of my own passes did not.
|
||||
- 2026-09-14T — **Every number driving this had a self-authored chain, and I only found that by looking for the emitter.** The five `MEMORY.md is N KB` records are `type=attachment`/`hook_additional_context`; all **25** `"only part was loaded"` hits are `/wake-up`'s **own specification text** injected as `user` records — *the corpus holds the description of the warning, not the warning*. **Same shape as the hand link-canary whose one "finding" was the link pattern inside its own spec.** ⚠ And my first extractor returned **1 of 5** of these because it read `message.content` while four sat in `attachment` records — **the wrong-field/wrong-unit class, fourth instance in three days**, caught only by re-running raw-line.
|
||||
- 2026-09-14T — **A sole-carrier found before it could be rotated away.** The Active Session block's `N-now 09-12: 62 raw; 31/31 at ≥1 prompt, 25/37 at ≥2` exists in **MEMORY.md and nowhere else** — searched all **539** memory files in six written forms, negative control clean. **Banked here so the block can rotate losslessly:** *2026-09-12 — 62 raw · 31 at ≥1 prompt · 25 at ≥2.* (Today, 09-14: **63 raw · 31 at ≥1 · 25 at ≥2** — one new transcript, a mumble.) ⚠ Note `≥2 prompt` as a string appears in **no** memory file, which is why my first losslessness query returned a false ABSENT on a claim I had *read with my own eyes* — **a null from a query I wrote is evidence about the query.**
|
||||
|
||||
- 2026-09-14T — ⚖ **THE THREAD IS ANSWERED, AND THE ANSWER IS ZERO.** Of the drift check's own **59** unattributable blocks, the number whose **own text names its parent** is **0**. Not a split — a floor. Buckets (controls: my widening reproduced the instrument's 59 exactly; buckets sum to 59): **(a) explicit `**Amends:**` claim = 0 · (b1) mentions its own position-parent's id = 12 · (b2) mentions ONLY foreign ids = 37 · (c) no id anywhere = 10.** ⚠ **The inherited question presupposed a split that does not exist** — it asked how many name their parent *versus* how many are position-only, and the answer is that **all 59 are position-only.**
|
||||
- 2026-09-14T — ⚠ **AND I NEARLY SHIPPED A SOFTER NUMBER BY MISLABELLING MY OWN BUCKET.** I first called (b1) *"weakly derivable"*, which would have let **12** read as partly recovered. **It is not derivation.** A body mentioning its position-parent's id is *consistent with* position; it is not independent evidence of it, because that id could be a cross-reference like every other id in the body. **Consistency is not confirmation** — and calling it derivation is selection dressed as derivation, the banked *derive-from-the-consumer* error. Corrected before reporting: **0 establish parentage; 47 have no self-consistent signal at all; 12 merely fail to contradict position.**
|
||||
- 2026-09-14T — ⚠ **THE HAZARD NOBODY HAD NAMED: 37 of the 59 are not merely missing an id, they are BOOBY-TRAPPED.** Bucket (b2) carries foreign ids only — `pos=PENDING-152` whose body offers `PENDING-4`; `pos=PENDING-96` offering `PENDING-97`; `pos=PENDING-82` offering `REVIEWED-53`. **An id-keyed repair that reads bodies would mis-file every one of them, confidently**, because a cross-reference is indistinguishable from a parentage claim at the token level. **The obvious automated repair is worse than no repair.** Derived by asking what a CONSUMER of the value must do, not by picking a surviving implementation.
|
||||
- 2026-09-14T — **The instrument I was told to enumerate from CANNOT answer the question that directed me to it.** `register_scan` returns `(label, form, title[:72])` — **no line number, no body, and the header truncated to 72 chars.** Its unit is the header line; the question's unit is the block body. ⚠ **Fifth instance this week of the unit mismatch, and the first found inside an instrument the resumption point named as authoritative.** Handled by **widening, declared as widening**: the module's own `RE_HEAD_LINE`/`RE_INBODY`/`_classify` decide *membership* (so the population stays the instrument's), and the body-read is mine and labelled mine. ⚠ Note the truncation `title[:72]` is the same family as the `[:100]` slice that manufactured a syntax error on 09-12.
|
||||
- 2026-09-14T — **Did NOT file a PENDING item for this, deliberately.** PENDING-146 already owns the convention question; the resumption point directs the number to the steward first; the repair is a header edit reserved to his hand. ⚠ And a bare `### AMENDMENT` filed *about* unattributable bare `### AMENDMENT` blocks would join the 59 it describes — the record has no shape for this finding that the finding does not condemn. **That is itself the argument for PENDING-146 being decided before anything else is appended.**
|
||||
|
||||
- 2026-09-14T — ⚖ **THE JURIST HANDED ME A FALSIFIER FOR MY OWN ITEM AND IT FIRED.** PENDING-186 asserts *"there is no load-time warning; the index simply arrives short"* and an ordering constraint of *"~3 days to a silent failure."* **Both wrong as written.** Claude Code warns at WRITE time, twice (near-limit reminder, then an over-limit error), documented in `memory.md` and corroborated by my own independently-spawned reader. ⚠ **I asserted a silence I had never tested, in an item whose recorded conduct failure is a number propagated unexamined.** Third instance today of the same shape.
|
||||
- 2026-09-14T — ⚖ **AND THE JURIST'S PROPOSED TEST FOUND THE REAL DEFECT: THE WRITE-GUARD IS PATH-KEYED.** Its form was *"if it has never fired, your write path is outside the instrument that would speak."* Measured: **5/5 genuine firings** (`type=attachment` + `hook_additional_context`, across 3 sessions, 21–23.1 KB) came from edits to the **symlink** path `~/.claude/projects/-Users-davidglidden/memory/MEMORY.md`; **0/2 today** from the real path `~/dotfiles/claude/memory/MEMORY.md`. **`realpath` identical — same file, same bytes.** ⚠ **Rival explanation EXCLUDED by internal control: today's file was 23.9 KB, LARGER than every case where it fired**, so "not near enough" cannot account for it. ⚠ **NOT excluded:** a harness change between 09-12 and 09-14 — unfalsifiable from here, named rather than waved off. Pre-registered experiment run this sitting: an edit routed through the symlink path, prediction stated *before* execution.
|
||||
- 2026-09-14T — ⚠ **A BANKED RULE HAS A COST NOBODY HAD PRICED.** `reference-governance-files-are-dotfiles-symlinks.md` says to edit the real `~/dotfiles/…` path because Edit refuses to write through a symlink — and it is **scoped `PENDING`/`REVIEWED` only**. **I extended it to MEMORY.md today without noticing the scope**, and the extension is what silenced the guard. ⚠ The 09-12 edits succeeded *through* the symlink path, so the refusal claim is at minimum mis-scoped (file-symlink vs directory-symlink). **The workaround that makes the write possible is what disables the alarm** — and neither half of that was visible from either half alone.
|
||||
- 2026-09-14T — ⚠ **AN UNRESOLVED CONFLICT BETWEEN TWO PRIMARY-SOURCE READERS, recorded as a conflict.** The jurist quotes a **10,000-character cap** on hook output from the hooks reference; my independently-spawned reader searched `hooks-guide.md` and `hooks.md` and returns **NOT FOUND at 92%**. Both claim primary source. **Neither wins by precedence** — memory discipline makes a two-layer conflict a verification trigger. ⚠ Live stake: the wake digest emits **8,136 chars**, which is 81% of a cap that may not exist, and my own test of it was **UNINFORMATIVE** (under the threshold) and was reported as uninformative.
|
||||
- 2026-09-14T — ⚠ **TWO READERS AGREEING IS NOT THE STRONG FORM, AND I ALMOST BANKED IT AS IF IT WERE.** `InstructionsLoaded` (`hooks-guide.md:503`) and `.claude/rules/*.md` were verified by the jurist and independently by my subagent at 97–98%. **But both are LLMs reading the same documents** — Constraint 6's *weak* separation (role/information), explicitly not difference of formation. ⚠ **Same error-shape as this morning's shared-substrate finding, one layer along:** agreement between two readers of one corpus is one reading counted twice. Recorded as corroboration of known kind, not as proof. ⚠ Also: the docs are **silent on rules-file size limits**, so option (e) trades a KNOWN 25 KB cap for an UNDOCUMENTED one.
|
||||
- 2026-09-14T — **The jurist named its own ordering error unprompted** (*"I went to the hooks page to kill option (c) and never opened the memory page… The claim I should have tested was not the one in dispute"*) and relabelled its 25 KB citation from four secondary sources to primary. ✅ **Adopted as a general rule, because it is my failure too, three times today: test the LOAD-BEARING claim, not the DISPUTED one.**
|
||||
|
||||
- 2026-09-14T — ✅ **A PREDICTION MADE AT FILING TIME, CHECKED AFTER.** PENDING-186's amendment was filed as `## PENDING-186 — AMENDMENT 1: …` (`id+marker`) rather than a bare `### AMENDMENT`, predicting it would be attributable and would NOT join the 59 it describes. **Confirmed by the instrument:** `PENDING.md` `id+marker` **19→20**, attributable **41→42**, amendment-shaped **100→101**, **NOT ESTABLISHED unchanged at 59**, and no false "the amendment replaced its record" finding (the parent classifies `id-only`, so it is in `originals`). **The day's finding applied to the day's own filing.**
|
||||
- 2026-09-14T — ⚠ **I BUILT A CHECK THAT COULD NOT DISCRIMINATE, AND I COULD HAVE KNOWN BEFORE RUNNING IT.** To pin the guard's unit I claimed a two-point reading (23.1 → 22.9 across a −195 B edit) would "solve for the unit properly." **It cannot.** All four candidates move by −0.189 … −0.195 — indistinguishable — **because the file is only 1.7% multibyte, so bytes and characters move together by construction.** The discrimination gate is on the ladder in these words: *same verdict on both = the check has demonstrated nothing.* ⚠ **Second discrimination failure of the day, and this one I authored while explicitly reasoning about instrument reliability.** The absolute test failed too: no unit lands near 22.9, and every candidate now sits *above* the guard's figure.
|
||||
- 2026-09-14T — ⚠ **AND I RESUMED A LINE I HAD ALREADY RULED DISPROPORTIONATE.** One round earlier I wrote that the unit question *"moves no decision"* and would be bounded, not chased. I then resumed it on the reasoning that *"the data arrived free"* — and spent two further rounds resolving nothing. **Free data is not the same as a question worth answering.** ⚠ The banked rule it violates is my own from this morning: *test the load-bearing claim, not the available one.* **Closed for real: 23.1–24.1 by unit, 92–96% of the limit, disposition identical under every reading.** The guard's number reconciles with no measurement I can make; recorded as an open anomaly, not chased.
|
||||
|
||||
- 2026-09-14T — ⚠ **I LOCATED A FAULT IN THE ARTEFACT THAT WAS IN MY READING OF IT, AND SAID SO OUT LOUD BEFORE CHECKING.** I announced that `reference-governance-files-are-dotfiles-symlinks.md` was mis-scoped and needed a `[FIX]`-grade *"scope correction"*. **Reading it in full: it is correctly scoped and says so explicitly** — *"Use the real-dotfiles-path route for `PENDING.md` and `REVIEWED.md` **only**"* — and never mentions `MEMORY.md`. **There was nothing to correct. I over-applied a correct note and then named the note as the defect.** ⚠ **A distinct failure shape from the day's others:** the unit errors were wrong *measurements*; this was a wrong *attribution of fault*, and it runs outward — toward the artefact, away from the reader. It would have entered a filed item as fact had the read not preceded the edit. ✅ What the note genuinely lacked was new and is now added as an **addition, not a correction**: the FILE-vs-DIRECTORY symlink distinction (writing *through* a symlink directory succeeds, so the flat refusal claim is false as stated) and the measured cost of over-extension.
|
||||
- 2026-09-14T — ✅ **Caught only because the read preceded the edit, which is the banked rule doing exactly its job.** The instinct was to edit from the remembered summary of the note — the same instinct that produced three render-vs-substrate errors earlier today. ⚠ **Note what the description field alone would have given me:** its `description:` says *"…so edit the real dotfiles path when appending PENDING/REVIEWED entries"* — correct, and compressed enough that a skim confirms my wrong reading rather than refuting it. **The scoping "only" lives in the body, in the last line.** *The summary was not wrong; it was just not sufficient to catch me.*
|
||||
|
||||
- 2026-09-14T — ⚖ **THE REGISTER'S READ PATH SERVED A STALE ITEM TO THE PARTY WHOSE JOB IS TO RULE ON IT.** The jurist's `governance_item('PENDING-186')` returned the original block byte-identical, **with no indication AMENDMENT 1 existed**. ⚠ **It was one step from drafting a ruling on an item that withdraws (c), adds a fifth condition, and records a conflict with the jurist's own finding.** Reproduced by executing the handler: **2 blocks exist, `t_item` returns 1.** Mechanism located at `governance-mcp.py:199–202` — **a `return` inside the span loop where an accumulate belongs.** PENDING-175 is no longer predicted; it is observed, reproduced, and filed with its line.
|
||||
- 2026-09-14T — ⚠ **AND I CORRECTED THE JURIST'S ACCOUNT OF THE SECOND DEFECT — IT IS NARROWER, AND THE DIFFERENCE CHANGES THE FIX.** Reported as *"search surfaces ids the fetch tool cannot take."* **Measured: fed the displayed head BYTE-EXACTLY, `t_item` resolves it** (the `head == ident` arm). What fails is the **natural truncation** — `'PENDING-186 — AMENDMENT 1'` → NOT FOUND, because `startswith(ident + " ")` meets `"1:"` not `"1 "`. **The defect is a colon.** ⚠ The reported form would have sent someone to build a new lookup path; the real fix is normalisation at the seam. **This is the executor's position paying off in the direction Constraint 6 describes: the jurist can observe the behaviour and cannot read the code, so its account of the mechanism was a reasonable inference that the substrate does not support.**
|
||||
- 2026-09-14T — ⚠ **THE FALSE CLAIM WAS INSIDE THE FUNCTION MAKING IT.** `t_search`'s own docstring (240–242) states *"no second definition of 'an item'"* — but `t_search` keys on the full header line and `t_item` keys on the id prefix. **Two notions of identity across one seam, each internally coherent.** And the existing unreachable-by-id guard is **provably silent** here (measured `orphan-warning fired: False`): it was shaped for headers hidden by leading whitespace, not siblings **shadowed by an earlier match**. ⚠ **A guard that already exists for a class, missing a second member of that class, is the day's recurring shape — the same as the write-guard being path-keyed.**
|
||||
- 2026-09-14T — ✅ **RAN THE HANDLERS RATHER THAN READING THEM.** My first grep for the fetch logic returned nothing because I guessed the public tool names (`governance_item`) instead of the internal ones (`t_item`) — **a null about my query, third time today**, and I did not report it as a fact about the file. Reading then gave me the mechanism; **executing gave me the correction to the jurist's version of it**, which reading alone would not have. The ledger's own rule, earned four times today: *run a check, don't read harder.*
|
||||
|
||||
- 2026-09-14T — ⚠⚠ **THE WORST NEAR-MISS OF THE DAY, STOPPED BY A CAVEAT I WROTE BEFORE RUNNING THE CHECK.** Measuring whether `~/CLAUDE.md` loads per session returned **12 injected / 51 not** — which reads as *"the constitution governs 19% of sessions."* **That claim is FALSE and I nearly made it.** The detector's unit is *"was the session preamble RECORDED in the transcript"*; the question's unit is *"was the constitution DELIVERED to the model."* ⚠ **Seventh unit mismatch today and the highest-stakes** — it would have reached the steward as a constitutional failure. ✅ **Caught because the script printed its own limit** (*"distinguishes recorded-vs-not, NOT delivered-vs-not"*), written before execution. **The instrument stating what it did not establish is the only reason a false alarm did not ship.**
|
||||
- 2026-09-14T — ✅ **CONFIRMED by discriminator: `const` and `env` markers disagree in 0 of 63 transcripts** — they measure one thing. Combination table: 12 carry all three preamble markers, 31 carry none, 20 carry the memory marker only. **A recording-shape fact, not a delivery fact.**
|
||||
- 2026-09-14T — ⚠ **AND MY OWN PROPOSED EXPLANATION FAILED, WHICH I AM RECORDING RATHER THAN REPLACING.** I hypothesised the 51 were subagent/sidechain transcripts. **Measured: `fully sidechain: 0/51`, and 22 of the 51 carry ≥1 human turn.** The tidy mechanism is false. ⚠ **What is established is only the negative** — the check cannot speak to delivery. **Why 22 human-bearing sessions record no preamble is UNEXPLAINED and left open**; supplying a second plausible story to replace the one that just failed is precisely how the first one got believed. ⚠ The delivery question needs a positive control this corpus cannot construct — a session known-delivered and known-unrecorded — i.e. observation at load time. **That is an argument FOR option (e) neither party reached by design: `InstructionsLoaded` is exactly the missing instrument.**
|
||||
- 2026-09-14T — ⚠ **RETRACTED, MINE: the "(e) forces standing preferences into a Constraint-1 frozen file" objection.** `~/.claude/CLAUDE.md` is reportedly the **documented user-scope** instruction file and is **distinct from `~/CLAUDE.md`**, the constitutional document. If so the preferences live in a file the executor may maintain, under a documented 4 MiB ceiling, loaded every session. **The governance cost I raised was my error, not the jurist's proposal's.** ⚠ Status **reported-verified, not verified**: it comes from the reader whose retrieval was shown partial in the same exchange. ⚠ Also unchanged: `.claude/rules/` size limits remain **undocumented**, so the destination should be the `.claude/` CLAUDE.md, not a rules file.
|
||||
- 2026-09-14T — ✅ **The reader retracted its own absence claim to COULD-NOT-ASSESS when given a positive control** (`PreToolUse` found) and named the cause: its fetches returned summary pages, not the full reference. **The jurist's substrate-difference hypothesis is supported — two retrievals of one document, not two readings.** ⚠ The 10 k cap remains **open**, and only the behavioural test settles it. ✅ REVIEWED-104's third outcome applied correctly by a subagent once the standard was actually asked for — which it was not, the first time.
|
||||
|
||||
## What held
|
||||
|
||||
- `thread-query` returned five hits, **none bearing on the thread** — reported as a null rather than dressed into relevance. **Second consecutive null**, and the trial's falsifier needs exactly that recorded.
|
||||
- The wake did not begin the work it surfaced. The 59-block enumeration is the first move of the session, not of the briefing.
|
||||
- Every "outstanding" item in the briefing was substrate-checked or explicitly marked unverified; no disposition clause was read as a status.
|
||||
|
||||
## Open horizons
|
||||
|
||||
- **The 59 unattributable blocks — the thread, untouched a third day.** First move: enumerate from the drift check's own reporter, then per block ask whether **its own text** names its parent. The split is the finding; the count is not. Repair is a header edit and awaits the steward's hand.
|
||||
- **MEMORY.md: ≈900 bytes of margin**, and the record's two ceiling figures disagree (17.1 KB falsified today; 24.4 KB stands). Gate is the ladder's **lossless-relocation** entry — slices never retyping, md5 per slice, `wake-digest.py` as the canary.
|
||||
- `PENDING-185` awaits steward annotation; the state claim `claude-md-untouched-pending-150` is still **FALSE** and the read is owed.
|
||||
- `PENDING-139` and `PENDING-177` marked **BUILT with no REVIEWED entry naming them** — a gap in the record, remedy is a drafted entry for steward placement.
|
||||
- The **shared-substrate finding** (jurist and executor read the same three register files) — banked, filed to neither PENDING-89 nor -140; venue **2026-09-16**.
|
||||
- Seb's 08-04 reply unread; L1 "blocked" stays **UNSETTLED**.
|
||||
- Worker `acaabadf` stopped but still **ARMED** with `--reply-on-resume`; respawn behaviour NOT ESTABLISHED.
|
||||
- **2 Desktop maps with no tracked copy** in `~/dotfiles/maps/` — one is the jurist's threat-report analysis; one tidy-up from gone.
|
||||
- **2026-09-16:** joint PENDING-178/-179 review and the 30-day ladder-freeze review.
|
||||
|
||||
## Confidence to recalibrate
|
||||
|
||||
- **Verified this wake:** MEMORY.md's byte size *and* that it loaded whole · the 59 count and its shape split, from a live drift-check run with 65/65 controls · N-now under both predicates with a negative control · the ledger's absence and the contamination doc's presence, with a negative control.
|
||||
- **Inherited, not re-verified:** `gitea` parity with local HEAD (yesterday's `ls-remote`) · the 09-10 banked composition, whose predicate is still unestablished · the ownership of the two unowned addendum blocks from 09-11.
|
||||
- **Falsified on re-measurement:** the 17.1 KB index ceiling. It was a dated measurement read as a status, and it was carried in two places.
|
||||
- **Not attempted, third day:** 2026-09-10's question — whether any ruling placed before this week can be checked against anything.
|
||||
|
||||
## Authorization moves
|
||||
|
||||
## Sub-agent dialogues
|
||||
|
||||
## Bypasses
|
||||
@@ -765,3 +765,15 @@ Each nearly read as a defect in the *quotation*. ⚠ **Bound:** correct extracti
|
||||
| J | **MEMORY.md's N-now instruction cites a method that cannot produce the figure it reports.** It directs re-measurement by *'the trial's own method at `governance-drift-check.py:513`'*. That line is inside `trigger_fired`, and the `transcripts` branch (`:546`) is a **bare glob** — it yields a count and **no composition at all**. The banked *'31 real / 28 mumble'* cannot have come from it, so the citation sends every future wake to an instrument that cannot answer the question asked of it. Kin to REVIEWED-139's line-citation errata. ⚠ **`[PROPOSAL]`, not FIX** — it changes what a governed artifact asserts. | patch (memory) | **RITUAL** — `/wake-up` §2.a, fires every wake. | PROPOSED |
|
||||
|
||||
**SECOND INSTANCE OF H, recorded rather than re-filed.** H (2026-09-11) reported the second dotfiles remote 54 commits behind, unseen by any wake. At the 2026-09-12 wake it was **55**, found again only by a hand check, and closed at **57** on the steward's explicit authorization. `/wake-up` §2.c still reads `git status -sb`, which by construction sees only the tracking remote. Two wakes, two hand catches; the mechanical fix in H is unchanged.
|
||||
|
||||
|
||||
## Proposed 2026-09-14 — from the path-keyed-guard sitting
|
||||
|
||||
| # | Proposal | Kind | Firing moment (declared) | Status |
|
||||
|---|---|---|---|---|
|
||||
| I | **A `PreToolUse` guard against editing `MEMORY.md` by its real dotfiles path.** Measured this session: Claude Code's near-limit memory guard is **path-keyed** — 5/5 warnings followed edits via `~/.claude/projects/…/memory/MEMORY.md`; **0/2 via `~/dotfiles/claude/memory/MEMORY.md` at a LARGER file size.** Same `realpath`. Editing the real path **silences the only instrument that reports index overflow**, and overflow is silent at load. Pre-registered and confirmed in-session. | hook (create) | **MECHANICAL** — fires on any `Edit`/`Write` whose `file_path` ends `claude/memory/MEMORY.md` and does **not** begin `/Users/davidglidden/.claude/projects/`. | PROPOSED — **the routing table's top row** (*mechanical, should always fire*). ⚠ The rule now sits in prose in `reference-governance-files-are-dotfiles-symlinks.md`, which the table predicts yields **~10% retrieval**; that is precisely the gap this proposal exists to close. |
|
||||
| J | **A convention for a session that SPANS MIDNIGHT.** This session woke 2026-09-13, did nearly all its work on 2026-09-14, and its Symmetria ledger is `session-ledger-2026-09-13.md` carrying `2026-09-14T` entries throughout, while the session file is dated 09-14. **PENDING-174 covers a DAY WITH MORE THAN ONE SESSION; this is its mirror — ONE SESSION SPANNING TWO DAYS — and is not covered.** A future reader grepping by date finds the returns under one date and the record under another. | patch (`/symmetria` §4 + `/wrap-up` §1.5) | **RITUAL** — fires at any wrap where the ledger's date ≠ today's date; a one-line check both steps can make. | PROPOSED — **first instance; the rule of three is NOT met.** Filed so the second is recognisable rather than re-derived. |
|
||||
|
||||
**THIRD INSTANCE OF B, recorded rather than re-filed.** `daybook-cue.py` fired again on **read-only** commands (`wc -c`, `git status`, a `python3 -c` measurement) and again asserted *"the write already succeeded."* No write had occurred. Instances: 2026-09-11 (filed), 2026-09-12, 2026-09-14 (×4 this session). The cue misdescribes its own trigger, and the rule of three is now met — B is eligible to build on the steward's word.
|
||||
|
||||
**THIRD INSTANCE OF H, recorded rather than re-filed.** `gitea` was again invisible to the wake: `/wake-up` §2.c reads `git status -sb`, which by construction sees only the tracking remote. At this wrap `github` matched local HEAD by `ls-remote` and **`gitea` sat 1 commit behind**, found only by an explicit per-remote check. Instances: 09-11 (54 behind), 09-12 (55, closed to 57 on steward instruction), 09-14 (1). ⚠ **Not pushed this session:** the steward named `gitea` once, on 09-12, for that occasion — treating a one-time instruction as standing authorization is the error class this sitting spent the day correcting. The mechanical fix in H (report `rev-list --count <remote>/main..HEAD` per remote in the wake digest) is unchanged and would have surfaced all three without anyone remembering to look.
|
||||
|
||||
Reference in New Issue
Block a user