[FIX] Resolve the STATE-CLAIM; [HARDENING] file PENDING-163; add the preservation instrument

STATE-CLAIM: memory-index-claims-reviewed-127-unplaced -> resolved, pointing at
7a92460. Verified end to end by re-running governance-drift-check.py rather than
trusting the write: "1 of 3 open are NOW FALSE" -> "2 tracked, none falsified /
plus 1 RESOLVED", no dangling-pointer defect, so the resolution parses AND its
pointer resolves. The `resolved:` form was derived from the parser, not from
memory of the schema, which is also why the correction commit had to come first.

What that discharge is evidence for is written into the item so it cannot be
quoted as more: one marked claim, marked by its own author, corrected in the
immediately following session. Expressibility, not adoption. The 57 unmarked
claims are untouched.

PENDING-163 [HARDENING]: the global pre-commit hook refuses files over 5MB and
prints "Consider using Git LFS", but measures `wc -c < "$file"` — working-tree
size — so an LFS-tracked file stages as a ~130-byte pointer and is still refused.
Tried it; same refusal, same file. The hook is NOT modified: it is global and
governed by REVIEWED-100/105.

preserve-transcripts.py: PENDING-147 option (i). The archive itself is NOT in this
repo — 115MB of transcripts is not dotfiles material, which is what the hook was
right about even though its reasoning measures the wrong thing. It lives at
~/_Dev/claude-transcript-archive, outside the harness's pruned path, which is what
actually stops the clock. 43 transcripts, read-back PASS.

No guard was bypassed: no --no-verify, no per-repo core.hooksPath override, and no
empty .git left behind that would make the archive look tracked when it is not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvZAKSf9aqratbqHbU9LK5
This commit is contained in:
David F Glidden
2026-08-26 17:26:22 +02:00
co-authored by Claude Opus 5
parent 7a92460a60
commit 57f83740a5
4 changed files with 321 additions and 4 deletions
+47 -3
View File
@@ -5461,10 +5461,19 @@ on the coverage inversion this exposes.**
<!-- STATE-CLAIM: memory-index-claims-reviewed-127-unplaced
since: 2026-08-25
claims: the memory index says the steward still owes the placement of REVIEWED-127. ⚠ The line MOVED at the 2026-08-25 evening wrap: it is now in MEMORY-reference.md with the demoted Active Session block, not in MEMORY.md. Deliberately carried rather than discharged by the rotation — correcting it is next session's agreed first act, and a claim that vanishes as a side effect of housekeeping is not a claim that was answered.
falsified-by: text-present REVIEWED.md ## REVIEWED-127 — PENDING-157 + PENDING-158 -->
falsified-by: text-present REVIEWED.md ## REVIEWED-127 — PENDING-157 + PENDING-158
resolved: 2026-08-26 — commit 7a92460 corrected the line in MEMORY-reference.md, struck rather than deleted so instance six keeps its evidence -->
**Awaiting:** nothing. Discharged by correcting the MEMORY.md line at the next wrap or wake, then
setting `resolved:` with a pointer to the commit that did it.
**Awaiting:** nothing — **DISCHARGED 2026-08-26**, as the agreed first act of the next session.
The line was corrected in `7a92460` and struck rather than deleted, because it is the evidence for
instance six and a silent deletion removes the error and the record of it together.
⚠ **What this discharge is evidence FOR, stated before it gets quoted as more.** The marker worked:
it reported FALSIFIED at every wake until someone acted, and the correction happened in the first
session after it was filed. That is one instance, on a claim its own author marked, in the session
immediately following — the easiest possible case. **It bears on expressibility, not on adoption,
and adoption is the open question REVIEWED-127 C2 named.** The 57 unmarked claims are untouched by
this and nothing here says otherwise.
---
@@ -5809,3 +5818,38 @@ central finding is that care is not a mechanism.
**Files affected:** none.
**Awaiting:** steward and jurist. ⚠ **The 09-08 read should not be run as though clean until this is ruled.**
---
## PENDING-163 — The pre-commit size guard measures the working tree, so the remedy it prints cannot satisfy it
**Date:** 2026-08-26
**Tag:** [HARDENING]
**Summary:** The global pre-commit hook refuses any staged file over 5 MB and prints *"Consider using Git LFS for large files."* The check reads `wc -c < "$file"` — the **working-tree** size — so an LFS-tracked file, which stages as a ~130-byte pointer, still measures 17 MB and is still refused. Following the guard's own instruction does not clear the guard.
**Measured, not inferred** (2026-08-26, while preserving transcripts under PENDING-147):
| | |
|---|---|
| hook | `~/dotfiles/git/hooks/pre-commit`, global via `core.hooksPath` |
| the check | `for file in $(git diff --cached --name-only); … size=$(wc -c < "$file"); if [ $size -gt 5242880 ]` |
| the advice | `echo "Consider using Git LFS for large files"` |
| tried | `git lfs install --local` + `git lfs track "*.jsonl"` + `git add -A` → **same refusal, same file** |
| `git-lfs` present | 3.7.1, and already declared in `Brewfile:40` — so this is not an unavailable remedy |
**Why this is a defect and not the rule working.** ⚠ Filed with the 2026-08-25 flag deliberately applied first — *filed a non-defect as a defect, twice in one direction in one day* — so the working-as-intended reading is stated before the defect reading:
- **Working-as-intended reading:** the ceiling means *"no large files in the working tree of any repo, LFS or not"*, and the LFS line is merely a pointer to a different workflow, not a promise.
- **Against it:** the LFS line is printed **by the failing branch, as its remediation**, immediately after the error. A remedy printed at the point of refusal is a claim that it resolves the refusal. And LFS *does* serve the check's evident purpose — repository bloat — because the committed blob is a pointer; it is only the implementation, working-tree size, that LFS cannot change.
**So the narrow claim, and it is the only one made here:** the check and its printed advice disagree. Either the advice is wrong and should be removed or reworded, or the check should measure the staged blob (`git cat-file -s :"$file"`) so LFS actually clears it. **Which of those is correct is a policy question, not a bug fix** — it decides whether large files may enter these repos at all.
**⚠ Not fixed, and deliberately.** This hook is global to every repo and is governed by REVIEWED-100 and REVIEWED-105; its own doctrine is that *a disarmed hook must not look like an armed one*. Changing what it measures changes what it permits everywhere at once. It was also not bypassed: no `--no-verify`, no per-repo `core.hooksPath` override.
**Options:**
- **(i) Reword the advice** to say the ceiling applies to the working tree and LFS does not exempt it. Smallest change; keeps current permissions exactly.
- **(ii) Measure the staged blob** (`git cat-file -s :"$file"`), so LFS-tracked files pass. Makes the printed advice true; **widens what may be committed everywhere**, which is the part needing a ruling.
- **(iii) Per-repo declaration** — let a repo opt out of the ceiling via the existing `.precommit-triggers` mechanism REVIEWED-100 already established, rather than a global change.
**Recommendation: (i) now, (iii) if a large-file repo is actually wanted.** (i) costs nothing and stops the guard from giving advice that fails; (ii) is the one that changes policy and should not ride in on a wording fix. ⚠ **No option here is urgent** — nothing is currently blocked by this. The transcript preservation it surfaced during is complete on disk and needs no commit to be safe.
**Files affected:** `~/dotfiles/git/hooks/pre-commit` (not modified).
**Awaiting:** Steward authorization.
+1 -1
View File
@@ -79,7 +79,7 @@ permalink: claude-memory/memory
> ⚠ **THE WRAP SEAM FAILED, WAS DIAGNOSED, FIXED, FIRED, AND WAS THEN REJECTED — all after the wrap.** The heartbeat proved the `Stop` hook was firing all along, so the silent-net prediction was **right that it would fail and wrong about why**. The detector sought the steward *typing* `/wrap-up`; the wrap arrived as prose + a Skill call. ⚠ **The earlier, correct fix is what blinded it.** PENDING-160's sixth and sharpest instance.
> ⚠ **PENDING-162 `[ESCALATE]` — the executor breached REVIEWED-128 condition 3** within seven hours, reading the rejection log for content while diagnosing. **Conditions 1 and 2 were made structural; only 3 was left to care.** ⚠ It surfaced the clustering signal (2 seam rejections, 10 and 11 words vs a cap of 9) that the fortnight was meant to arbitrate — **not acted on, and must not be.**
> 📌 **STEWARD OWES:** place the REVIEWED-129 amendment · rule PENDING-160 · **restart Claude Desktop** or `governance_pair` is absent · the §5 regrade ruling.
> ⚠ **DELIBERATELY NOT FIXED:** the `STEWARD OWES: place REVIEWED-127` line now sits in `MEMORY-reference.md` with this block's predecessor. It is **false**, it is **marked** by `STATE-CLAIM: memory-index-claims-reviewed-127-unplaced`, and correcting it is **next session's agreed first act** — carried forward rather than discharged as a side effect of this rotation.
> ✅ **DISCHARGED 2026-08-26 — the agreed first act, done.** The false `STEWARD OWES: place REVIEWED-127` line in `MEMORY-reference.md` is corrected (`7a92460`), **struck rather than deleted** so instance six keeps its evidence, and the `STATE-CLAIM` block carries `resolved:` with that pointer. ⚠ **This is one marked claim corrected in the very next session — evidence for expressibility, NOT for adoption**, which is the open question (REVIEWED-127 C2). The 57 unmarked claims are untouched.
- [Session 2026-08-25 evening — Tarbuckle wired, and the gap controls cannot see](session-2026-08-25-tarbuckle-wired-and-the-contact-gap.md) — five surfaces built and every one failed on first real use; PENDING-151 step 1 + step 2 both run. **NEXT: the §5 regrade gate — the control is already degraded and decays with every exposure.**
@@ -0,0 +1,90 @@
---
name: Session Ledger 2026-08-26
description: Practice-of-return ledger maintained by /symmetria — returns, open horizons, recalibrations, authorization moves, sub-agent dialogues, bypasses.
type: feedback
---
# Session Ledger — 2026-08-26
## Returns
- 2026-08-26T~wake — `/wake-up` ran; Symmetria `init` at its close (the clasp's lineage hand).
N-now **re-measured, not relayed**: **43**, down from 51 on 08-25. The obligation found it,
not the vigilance — same shape as PENDING-147's own disclosure.
- 2026-08-26T~afternoon — **Chose the wrong container and the guard caught it.** Put the
archive in `~/dotfiles` by habit, because the governance record lives there, without asking
whether 115 MB of raw transcripts is dotfiles material. The pre-commit hook refused it. The
return was reading the refusal as a **fit signal** rather than an obstacle — τὸ πρόσφορον —
and moving the archive rather than moving the guard.
- 2026-08-26T~afternoon — **Three chances to bypass a guard, none taken:** `--no-verify`, a
per-repo `core.hooksPath` override, and leaving a `.git` with no commits behind (which would
have made the archive *look* tracked). ⚠ The third is the one I nearly did by inertia; it is
the same shape as the hook's own doctrine that *a disarmed hook must not look like an armed one*.
## What held
- Ran `thread-query.py` on the actual thread and reported the **null honestly** (689 candidates,
nothing on-thread). A step that can only conclude "keep it" is not a trial.
- Did **not** run the literal question's grep at wake. The question is held open, per the wake's
own constraint; and `tarbuckle-rejects.jsonl` was not opened — REVIEWED-128 condition 3.
- Substrate-checked before calling anything outstanding: PENDING-147 (i) verified **unbuilt**
(no `claude/governance/transcripts*`, no git-tracked copy, no REVIEWED entry) rather than
read off its own recommendation line.
- Verified the STATE-CLAIM resolution **end-to-end by re-running the instrument**, not by
trusting the write: `1 of 3 open are NOW FALSE` → `2 tracked, none falsified / plus 1 RESOLVED`,
with no dangling-pointer defect, so both the `resolved:` parse and its pointer were proved.
- Derived the `resolved:` form **from the parser** (`governance-drift-check.py:299,486,498`),
not from memory of the schema — and therefore made the correction commit FIRST, because
`pointer_resolves()` requires a commit that already exists. The say–do seam, avoided by ordering.
- Applied the *filed-a-non-defect-as-a-defect* flag **before** filing PENDING-163: stated the
working-as-intended reading first, then the argument against it, and kept the claim narrow
(the check and its printed advice disagree) rather than "the hook is broken".
- Preserved **all 43** transcripts rather than the 23 the item scoped, because the files expiring
soonest are the ones outside its scope — and said so in the README rather than letting the
wider action pass unremarked.
## Open horizons
1. **Agreed first act:** correct the false `STEWARD OWES: place REVIEWED-127` line now in
`MEMORY-reference.md`; set `resolved:` on the `STATE-CLAIM` block in `PENDING.md` with a
commit pointer. Carried deliberately across the rotation rather than discharged by side effect.
2. **PENDING-147 (i) — preserve the post-2026-08-07 transcripts.** Needs no ruling by its own
text. Earliest cohort deletes **2026-09-06**. ⚠ The only open item whose cost rises daily,
and N-now falling 51→43 in one day is that deletion happening in view.
2b. ⚠ **The archive has NO BACKUP.** Preserved from pruning; lost to a disk failure. The
steward's call: leave it, add a remote (a disclosure question — raw transcripts are more
verbose than the session memories that already reach `git.skemantix.com`), or Time Machine
it. **Cheapest fix for the actual gap is not git.**
2c. **PENDING-163** filed — the pre-commit hook's 5 MB check reads working-tree size, so the
Git LFS remedy it prints cannot satisfy it. Not urgent; nothing is blocked.
3. **The §5 regrade gate** — steward's and judge's to settle, not the executor's. The honest
outcome may be to record the control as degraded rather than run it and call it a control.
4. Steward-owed: place the REVIEWED-129 amendment · rule PENDING-160 · restart Claude Desktop.
5. Dated, 2026-09-08: two obligations in one sitting — mumble rate report + rejection log deletion.
## Confidence to recalibrate
- ⚠ Yesterday's finding is still the governing caution: **controls verify the code, not the
contact.** Anything built today is untested at the seam with a model, a shell, or a corpus
containing its own reader — and no control written today will see that either.
- ⚠ **Care failed inside a day** on REVIEWED-128 condition 3 (PENDING-162). Conditions made
structural held; the one left to care did not. Prefer a mechanism over a resolution today.
- ⚠ Bias observed twice on 08-25: **filing a non-defect as a defect.** Before calling something
broken, ask whether it is the rule working.
## Authorization moves
- **PENDING-147 option (i) executed WITHOUT a ruling**, on the item's own text — *"copying files
preserves evidence and changes no instrument, no doctrine and no ladder."* ⚠ **The option
bundles a second act the same sentence does not license:** *"re-express the trigger over the
preserved set"* changes `governance-drift-check.py`, which REVIEWED-95's falsifier leans on,
inside a trial under the REVIEWED-123 freeze. **Split; only the copy was done.** The archive is
currently inert with respect to every governance gate, and its README says so on its face.
- **PENDING-163 filed `[HARDENING]`, hook NOT modified.** It is global to every repo and governed
by REVIEWED-100 / REVIEWED-105; changing what it measures changes what it permits everywhere.
## Sub-agent dialogues
## Bypasses
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env python3
"""Preserve Claude Code session transcripts out of the harness's pruned directory.
WHY THIS EXISTS
~/.claude/projects/-Users-davidglidden is pruned on a ~30-day retention policy
(cleanupPeriodDays default 30). PENDING-147 established that the ladder trial's
evidence therefore sits on a deletion clock nobody set: the pre-registered
20-session falsifier in REVIEWED-95 Q6 cannot be graded if its earliest cohort
has been deleted before the 20 sessions have run.
This copies transcripts to a git-tracked location so the population stops
shrinking. It is PENDING-147 option (i), and ONLY option (i): copying files
"changes no instrument, no doctrine and no ladder" and needs no ruling.
WHAT THIS DELIBERATELY DOES NOT DO
It does NOT re-express governance-drift-check.py's `transcripts N` trigger over
the preserved set. That would change an instrument a placed ruling leans on,
inside a trial under the REVIEWED-123 freeze, and is not covered by the
no-ruling justification above. The preserved set is inert with respect to the
trigger until someone with the authority rules on it.
IDEMPOTENT
Safe to re-run. New transcripts are added; transcripts whose source has grown
(they are append-only) are refreshed; already-preserved files are re-verified.
Preserved files are never deleted here, even when the source is pruned — that
is the entire point.
INTEGRITY
Preservation is proved by READING BACK, not by copy success. Every preserved
file is re-hashed from disk after the copy and compared to the manifest. A
write that "succeeded" into an unreadable file is the failure mode this guards
(steward rule 2026-05-04, learned on MemPalace).
"""
import hashlib
import json
import os
import shutil
import sys
import tempfile
from datetime import datetime, timezone
from pathlib import Path
HOME = Path.home()
SRC = HOME / ".claude/projects/-Users-davidglidden"
DST = HOME / "_Dev/claude-transcript-archive"
MANIFEST = DST / "manifest.json"
def sha256(path: Path) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
for block in iter(lambda: f.read(1 << 20), b""):
h.update(block)
return h.hexdigest()
def iso(ts: float) -> str:
return datetime.fromtimestamp(ts, timezone.utc).isoformat(timespec="seconds")
def now_iso() -> str:
return datetime.now(timezone.utc).isoformat(timespec="seconds")
# ---------------------------------------------------------------- controls
def run_controls() -> bool:
"""Same-run positive AND negative controls.
An absence is not evidence until the instrument is shown capable of detecting
presence (epistemic standard, jurist Q2 ruling). These run on EVERY invocation
rather than in a separate suite, so a failure cannot be re-run until green.
"""
ok = True
with tempfile.TemporaryDirectory() as td:
td = Path(td)
# positive: a known byte string hashes to its known digest
p = td / "pos.bin"
p.write_bytes(b"capablemind")
expected = hashlib.sha256(b"capablemind").hexdigest()
if sha256(p) != expected:
print("CONTROL FAIL: hashing does not reproduce a known digest", file=sys.stderr)
ok = False
# negative: a corrupted copy MUST be detected as differing
a, b = td / "a.bin", td / "b.bin"
a.write_bytes(b"x" * 4096)
shutil.copy2(a, b)
if sha256(a) != sha256(b):
print("CONTROL FAIL: identical copy reported as differing", file=sys.stderr)
ok = False
with open(b, "r+b") as f: # flip one byte
f.seek(2048)
f.write(b"y")
if sha256(a) == sha256(b):
print("CONTROL FAIL: one-byte corruption NOT detected", file=sys.stderr)
ok = False
# negative: mtime preservation must actually preserve
old = 1_600_000_000
os.utime(a, (old, old))
c = td / "c.bin"
shutil.copy2(a, c)
if abs(c.stat().st_mtime - old) > 1:
print("CONTROL FAIL: copy2 did not preserve mtime", file=sys.stderr)
ok = False
return ok
def main() -> int:
if not run_controls():
print("INSTRUMENT NOT VERIFIED — controls failed; result is unestablished.",
file=sys.stderr)
return 2
if not SRC.is_dir():
print(f"source directory absent: {SRC}", file=sys.stderr)
return 2
DST.mkdir(parents=True, exist_ok=True)
manifest = json.loads(MANIFEST.read_text()) if MANIFEST.exists() else {"files": {}}
files = manifest.setdefault("files", {})
added, refreshed, unchanged = [], [], []
for src in sorted(SRC.glob("*.jsonl")):
digest = sha256(src)
rec = files.get(src.name)
dst = DST / src.name
if rec and rec["sha256"] == digest and dst.exists():
unchanged.append(src.name)
continue
shutil.copy2(src, dst) # -p: mtime is load-bearing here
entry = {
"sha256": digest,
"bytes": src.stat().st_size,
"source_mtime": iso(src.stat().st_mtime),
"first_preserved": (rec or {}).get("first_preserved") or now_iso(),
"last_refreshed": now_iso(),
}
(refreshed if rec else added).append(src.name)
files[src.name] = entry
# ---- READ BACK. Preservation is proved from disk, never from copy success.
failures, orphaned = [], []
for name, rec in files.items():
p = DST / name
if not p.exists():
failures.append(f"{name}: MISSING from preserved set")
continue
if sha256(p) != rec["sha256"]:
failures.append(f"{name}: HASH MISMATCH on read-back")
if not (SRC / name).exists():
orphaned.append(name) # pruned at source — preserved here. The point.
manifest["last_run"] = now_iso()
manifest["readback"] = "PASS" if not failures else "FAIL"
manifest["counts"] = {
"preserved_total": len(files),
"present_at_source": len(files) - len(orphaned),
"pruned_at_source_but_preserved": len(orphaned),
}
MANIFEST.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
total = sum(r["bytes"] for r in files.values())
print(f"preserved total : {len(files)} transcripts, {total/1048576:.1f} MB")
print(f" newly added : {len(added)}")
print(f" refreshed : {len(refreshed)} (append-only growth at source)")
print(f" unchanged : {len(unchanged)}")
print(f" pruned at source, surviving only here : {len(orphaned)}")
print(f"N-now at source (the trial's own counter): "
f"{len(list(SRC.glob('*.jsonl')))}")
if failures:
print("\nREAD-BACK FAILURES:", file=sys.stderr)
for f in failures:
print(" " + f, file=sys.stderr)
return 1
print("read-back : PASS (every preserved file re-hashed from disk)")
return 0
if __name__ == "__main__":
sys.exit(main())