From 65c0884dc910ede4ea0a1275ac7b789cdb83ed96 Mon Sep 17 00:00:00 2001 From: David F Glidden Date: Fri, 4 Sep 2026 10:30:41 +0200 Subject: [PATCH] session 2026-09-04: PENDING-179 gates, OWED-5 queued, Active Session rotated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session record, ledger merge, MEMORY.md rotation (prior Active Session demoted verbatim to MEMORY-reference.md), 6 KG triples, and OWED-5 queued in PENDING-141's ratified owed-entries list. OWED-5: a must-detect control must report its denominator, and a denominator of zero is a FAIL. Steward-stated 2026-09-04, queued unruled — the ladder is frozen under REVIEWED-123, and turning the rule on converts currently-green controls to red across the fleet, which is a ruling rather than an edit. Earned on the vacuous PASS (0/0) that nearly certified a broken discriminator. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01X3L79vgAnt1x2kxvf23Qt7 --- PENDING.md | 9 + claude/memory/MEMORY-reference.md | 11 + claude/memory/MEMORY.md | 14 +- claude/memory/knowledge-graph.jsonl | 6 + ...-04-the-discriminator-was-a-coincidence.md | 222 ++++++++++++++++++ 5 files changed, 255 insertions(+), 7 deletions(-) create mode 100644 claude/memory/session-2026-09-04-the-discriminator-was-a-coincidence.md diff --git a/PENDING.md b/PENDING.md index 6fa81a1..31131ec 100644 --- a/PENDING.md +++ b/PENDING.md @@ -3668,6 +3668,15 @@ So **PENDING-138 and this entry are worded to avoid the bare uppercase token**, > A dry run shows what the tool *intends*. It cannot show what the tool will do to a file whose shape the tool misreads. On 2026-08-17 a 16-file stamping pass dry-ran clean, applied clean, and silently orphaned the frontmatter of the 3 files whose shape differed — and the post-hoc check reported `malformed: none`, because it asked whether each file *began with frontmatter and a banner* (true) rather than whether the stamp had *preserved the record's keys* (false). > **The check that worked was the one that could not be written from intent:** recover each file's pre-change text from git, extract its key set, and assert no key was lost. That control cannot be satisfied by a file the tool mangled, because its subject is the *difference* rather than the result. +**OWED-5 — a must-detect control must report its denominator, and a denominator of zero is a FAIL.** · **Authorizing ruling: NONE — steward-stated 2026-09-04, queued unruled.** · **Ladder claim-class: gate-design claims.** +> **A control that finds nothing to test reports success indistinguishable from a control that tested everything and found no fault.** `PASS (0/0)` is not a pass; it is the instrument saying it never ran, in the voice of an instrument that did. Print the denominator on every must-detect line, and make an empty one fail loudly. +> +> Earned 2026-09-03 on gate 2a of the mumble-discriminator check. Ground truth for "is this a mumble" was drawn from a prompt signature copied out of `tarbuckle-invoke.py` — the file just read — which matched **0 of 65** transcripts, because the mumbles are written by three *other* fool surfaces with a different prompt. The gate printed `GATE 2a [must-detect] every known mumble reads 0 : PASS (0/0)`. Accepting it would have certified the discriminator sound and wired a broken predicate into three further sites. It was caught by the standing *a null search is evidence about the QUERY* rule, i.e. by a human-held discipline rather than by the instrument. +> +> ⚠ **This is OWED-1's wrong-subject family seen from underneath, and it does not duplicate it.** OWED-1 asks whether the control's *subject* is the claim's subject. This asks whether the control had any *cases* at all — a control can have the right subject and still be vacuous. The two fail independently and the cheap one is checkable by machine. +> +> ⚠ **The rule generalizes past this instance, which is why it is queued rather than patched in place:** it applies to every must-detect in the fleet, and turning it on will convert some currently-green controls to red. That is the point, and it is also why it is a ruling rather than an edit. + --- ## PENDING-142 — The open/closed criterion answers "does a REVIEWED header name this id?", not "is this item still awaiting the steward" **Date:** 2026-08-17 diff --git a/claude/memory/MEMORY-reference.md b/claude/memory/MEMORY-reference.md index 806f697..e682441 100644 --- a/claude/memory/MEMORY-reference.md +++ b/claude/memory/MEMORY-reference.md @@ -63,6 +63,17 @@ metadata: # MEMORY — Reference layer (consult on demand) +### Demoted from Active Session at the 2026-09-04 wrap + +> 🔴 **NEXT SESSION, FIRST WORK — STEWARD-DIRECTED 2026-09-03:** *"deal with that right away — I need the wake and wrap tools to be reliable."* **ONE root cause, 4–5 consumer sites:** the transcripts dir is a proxy for *"a session"* and **a Tarbuckle mumble is indistinguishable from a session at the file level.** Sites: `governance-drift-check.py:513` (PENDING-178) · `wake-digest.py:354`→`previous_transcript` (**the false `unattended` alarm of 09-01 — diagnosed, code never changed**) · `wake-digest.py` selftest `_tx[-14:-1]` (**fails every run**) · `tarbuckle-invoke.py:40` (⚠ **SUSPECTED, VERIFY FIRST**). 🔑 **The discriminator already exists and is controlled — `wake-digest.py:932 human_turns()`; this is wiring a tested function into 4 call sites, not building a classifier.** ⚠ **It is `[FIX]`, not `[PROPOSAL]` — my wrap-time classification was wrong**: the control's label already says *"a real session"*, so restoring that population repairs it against its own spec. **Does NOT extend to changing what the `>=84` trigger means** — that stays PENDING-178/REVIEWED-123. **Write the positive control FIRST.** Full census + first steps: ADDENDUM 1 of the session record. +> 🔑 **THE INDEX HAD BECOME THE RECORD.** `MEMORY.md` breached its load budget and was being **silently truncated at wake** — but the cause was not bulk. Five tracker entries had grown into paragraphs, and for **three the index was the SOLE custodian of live state**: the studium tracker stopped at **2026-08-13** while the index carried engine news to 09-01 · the Fool's only link was a **sealed seed**, with nowhere legitimate to append · L1's replay **mechanism** (`minCursor` is a minimum over 11 modules, two never participate ⇒ pinned at 0 **by construction**) and **completion criterion** (uninterrupted run length, not rate) existed nowhere else. All relocated verbatim; **Tarbuckle got a tracker**. 26,803 → 23,714 (`2171d91`, both remotes verified). +> ⚠ **PRUNING WOULD HAVE BEEN HARMFUL.** The cut took its rule from the file's own Index discipline — trackers are pointers — and so **left "Rules that fire silently" untouched**: those keep their text inline because they fire when I would not know to look. Cutting the loudest lines would have removed the catches and still left three workstreams undocumented, now deleted rather than truncated. +> ⚠ **THE CANARY WAS CLEAN AND ITS SELFTEST WAS FAILING** (86/87). The failing control samples the 13 most recent transcripts; **all 13 are Tarbuckle mumbles** (~66 KB, one human turn each). **PENDING-178's defect at a SECOND site** — it will now fail on every run, and a control that always fails is one everyone learns to ignore. The **pointer** controls, which the trim rests on, all pass. Not filed (moratorium undecided). +> 📌 **HEADROOM IS THIN AND THE MECHANISM IS UNFIXED.** Rotation handles the Active Session block; **nothing handles slow growth in the tracker list** — which is how this breach formed. +> 📌 **STEWARD OWES:** `~/.claude/agents` under version control (**directed; before anything else edits it**) · the **moratorium decision** · `RE_ID` regex `[FIX]` · PENDING-171 · -177 · -178 · -160 · -168 · the §5 regrade. + +- [Session 2026-09-03 — the index had become the record](session-2026-09-03-the-index-had-become-the-record.md) — the load-integrity breach diagnosed rather than pruned; three sole-custodian workstreams relocated; Tarbuckle tracker established; the digest selftest found permanently failing on a mumble-only sample. **NEXT: the fr cell's last two steps** — unchanged. + ### Demoted from Active Session at the 2026-09-01 wrap > ✅ **THE 270 GOT READ — 40 of them, and the backlog is real.** PENDING-164 AMENDMENT 1's declared-owed classification pass ran, **pre-registered and committed ALONE (`5ba5842`) before any commit body was read.** Systematic sample: **12 of the 17 rows that decide about a mechanism name one the register NEVER mentions** — incl. a **log-chain spec** bump to v0.6 (`logchain` = a named constitutional constraint, 29 register mentions; `data-portability`/`ImportProvenance`/`import trust` = **0**), a whole session-memory protocol retired, and a stopgap env var retired by a plan that calls it a stopgap. **3 of the 5 RECORDED rows arrived 25/46/53 days LATE** — recovery, not routing. → **PENDING-164 AMENDMENT 2** (`1d46d48`). diff --git a/claude/memory/MEMORY.md b/claude/memory/MEMORY.md index 647883c..7c60653 100644 --- a/claude/memory/MEMORY.md +++ b/claude/memory/MEMORY.md @@ -73,14 +73,14 @@ 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 -> 🔴 **NEXT SESSION, FIRST WORK — STEWARD-DIRECTED 2026-09-03:** *"deal with that right away — I need the wake and wrap tools to be reliable."* **ONE root cause, 4–5 consumer sites:** the transcripts dir is a proxy for *"a session"* and **a Tarbuckle mumble is indistinguishable from a session at the file level.** Sites: `governance-drift-check.py:513` (PENDING-178) · `wake-digest.py:354`→`previous_transcript` (**the false `unattended` alarm of 09-01 — diagnosed, code never changed**) · `wake-digest.py` selftest `_tx[-14:-1]` (**fails every run**) · `tarbuckle-invoke.py:40` (⚠ **SUSPECTED, VERIFY FIRST**). 🔑 **The discriminator already exists and is controlled — `wake-digest.py:932 human_turns()`; this is wiring a tested function into 4 call sites, not building a classifier.** ⚠ **It is `[FIX]`, not `[PROPOSAL]` — my wrap-time classification was wrong**: the control's label already says *"a real session"*, so restoring that population repairs it against its own spec. **Does NOT extend to changing what the `>=84` trigger means** — that stays PENDING-178/REVIEWED-123. **Write the positive control FIRST.** Full census + first steps: ADDENDUM 1 of the session record. -> 🔑 **THE INDEX HAD BECOME THE RECORD.** `MEMORY.md` breached its load budget and was being **silently truncated at wake** — but the cause was not bulk. Five tracker entries had grown into paragraphs, and for **three the index was the SOLE custodian of live state**: the studium tracker stopped at **2026-08-13** while the index carried engine news to 09-01 · the Fool's only link was a **sealed seed**, with nowhere legitimate to append · L1's replay **mechanism** (`minCursor` is a minimum over 11 modules, two never participate ⇒ pinned at 0 **by construction**) and **completion criterion** (uninterrupted run length, not rate) existed nowhere else. All relocated verbatim; **Tarbuckle got a tracker**. 26,803 → 23,714 (`2171d91`, both remotes verified). -> ⚠ **PRUNING WOULD HAVE BEEN HARMFUL.** The cut took its rule from the file's own Index discipline — trackers are pointers — and so **left "Rules that fire silently" untouched**: those keep their text inline because they fire when I would not know to look. Cutting the loudest lines would have removed the catches and still left three workstreams undocumented, now deleted rather than truncated. -> ⚠ **THE CANARY WAS CLEAN AND ITS SELFTEST WAS FAILING** (86/87). The failing control samples the 13 most recent transcripts; **all 13 are Tarbuckle mumbles** (~66 KB, one human turn each). **PENDING-178's defect at a SECOND site** — it will now fail on every run, and a control that always fails is one everyone learns to ignore. The **pointer** controls, which the trim rests on, all pass. Not filed (moratorium undecided). -> 📌 **HEADROOM IS THIN AND THE MECHANISM IS UNFIXED.** Rotation handles the Active Session block; **nothing handles slow growth in the tracker list** — which is how this breach formed. -> 📌 **STEWARD OWES:** `~/.claude/agents` under version control (**directed; before anything else edits it**) · the **moratorium decision** · `RE_ID` regex `[FIX]` · PENDING-171 · -177 · -178 · -160 · -168 · the §5 regrade. +> 🔴 **NEXT SESSION, FIRST WORK — STEWARD-DIRECTED 2026-09-04, in this order:** **(1) `git init` the transcript archive** (`~/_Dev/claude-transcript-archive`, 144 MB, currently **no repo, no remote, no second copy** — and `preserve-transcripts.py:11` already *claims* it is git-tracked; **11 transcripts exist there and nowhere else**, so the init is what makes an existing false docstring true rather than requiring it be edited into honesty). **(2) Suspend the automatic grading at `trigger_fired()`.** ⚠ **The steward's precision here is the point: NOT a repair, NOT a filter, NOT -178 option (b). It changes nothing about what the counter counts, so the site-1 exclusion survives intact.** It prevents a grade firing on a population whose contamination is measured and rising. +> ⚖ **THEN THE JOINT RULING — -178 AND -179 ARE ONE DECIDABLE UNIT.** -179 is -178's evidence and says so **in prose, because the numbering cannot carry it** (PENDING-145). The ruling covers **unit · window · recurrence · predicate · seeding**. ⚠ **Seeding has grown a SECOND HALF, new on 09-04:** preservation has **permanently diverged the two stores** — 11 files exist only in the archive — so the question is no longer only *what N* but **over which store**, and **the trigger reads LIVE while any honest grading of a post-08-07 population must read PRESERVED.** Steward's recorded positions: **agrees with -179's option (c)** (a mumble that declares itself cannot be misread by a marker coincidence) **and with its refusal to build it now**. +> 🔑 **THE DISCRIMINATOR WAS A COINCIDENCE, AND THE GATE IS WHAT CAUGHT IT.** The whole repair plan rested on *"human_turns() already exists and is controlled — this is wiring, not classifier-building."* **False.** Against ground truth from the fool's own prompt text: **must-detect 22/24, must-not-flag 35/41.** It skips slash-command markers, and a mumble inherits those markers **only when the session it quoted happened to contain one** — **the 2 leaks are exactly the 2 marker-free mumbles.** ⚠ **`0` never meant "mumble"; it means "nobody spoke", which is equally true of an unattended real session** (`b7e7eb39`, PENDING-172). **No repair made, no replacement built** — three controls passed and a fourth broke, so the finding is **the control set**: all three tested the question the function was *for*, none the question it was *reused* for. **That lesson generalizes past this function** (steward, 09-04). +> ⚠ **THE HANDOVER DID NOT IMPROVE THE FIX; IT PREVENTED IT.** Preservation first (it expires), site-1 excluded on receipt, repair gated behind three read-only checks. Left to my own plan I would have written a positive control for a *fixture* and wired a broken predicate into three more sites, all of it green. +> 📌 **MEASURED, AND THE DIRECTION HAD BEEN RECORDED BACKWARDS:** N-now **65/84** — **41 real + 24 mumble (36.9%)**. The index had carried *"44, DOWN 7, shedding faster than it gains"*; it is **rising fast and for the wrong reason**. Corrected record-only (`c150bdf`, both remotes verified). +> 📌 **STEWARD OWES:** the joint -178/-179 ruling · the **archive remote question** (144 MB; full transcripts = everything ever typed) · `~/.claude/agents` under version control (**before anything else edits it**) · the **moratorium decision** · PENDING-171 · -160 · -168 · the §5 regrade (eighth session). -- [Session 2026-09-03 — the index had become the record](session-2026-09-03-the-index-had-become-the-record.md) — the load-integrity breach diagnosed rather than pruned; three sole-custodian workstreams relocated; Tarbuckle tracker established; the digest selftest found permanently failing on a mumble-only sample. **NEXT: the fr cell's last two steps** — unchanged. +- [Session 2026-09-04 — the discriminator was a coincidence](session-2026-09-04-the-discriminator-was-a-coincidence.md) — gate 2a failed and the repairs correctly never happened; PENDING-179 filed as an item (not a -178 addendum, per -145's suppression mechanism); OWED-5 queued; the transcript archive found unbacked-up while its own script claims otherwise. **NEXT: the two steward-set acts, then the joint ruling.** ## 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). diff --git a/claude/memory/knowledge-graph.jsonl b/claude/memory/knowledge-graph.jsonl index 4469833..5c85163 100644 --- a/claude/memory/knowledge-graph.jsonl +++ b/claude/memory/knowledge-graph.jsonl @@ -773,3 +773,9 @@ {"subject": "claude-code", "predicate": "drift-pattern-good-direction", "object": "DIAGNOSED BEFORE PRUNING, AND THE DIAGNOSIS INVERTED THE ACTION. Asked to fix MEMORY.md's load-budget breach, the obvious move was to cut the longest entries. A per-line byte map plus a duplication check found instead that the index had become the SOLE CUSTODIAN of live state for three workstreams, and that the longest entries in 'Rules that fire silently' are long BY DESIGN. Pruning would have deleted three undocumented workstreams and removed the catches that fire when I would not know to look them up.", "valid_from": "2026-09-03", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-03-the-index-had-become-the-record.md", "extracted_at": "2026-09-03"} {"subject": "the discipline 'prove the instrument before trusting a clean line'", "predicate": "prevention", "object": "CAUGHT A PERMANENTLY-FAILING CONTROL BEHIND A CLEAN REPORT, AND FOUND PENDING-178 AT A SECOND SITE. wake-digest.py reported 407 pointers / 0 dead; its --selftest reported 86 of 87 with overall FAIL. The failing control samples the 13 most recent transcripts and ALL 13 are Tarbuckle mumbles (~66 KB, one human turn each) — the mumble pollution filed as PENDING-178 against the ladder counter has also displaced real sessions out of the digest's own end-to-end control, which will now fail on every run. A lesson banked about instruments stopped a different failure class: alarm-decay, not a false alarm.", "valid_from": "2026-09-03", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-03-the-index-had-become-the-record.md", "extracted_at": "2026-09-03"} {"subject": "MEMORY.md", "predicate": "failure-mode", "object": "AN INDEX BECOMES THE RECORD WHEN ITS TRACKER GOES QUIET. Observed 2026-09-03: the studium tracker's chronological log stopped 2026-08-13 while the MEMORY.md one-line pointer carried engine state to 2026-09-01; the Fool's only link was a SEALED seed with nowhere to append; L1's replay mechanism and completion criterion existed in the index alone. The tell is a tracker going quiet while its one-line pointer grows. The rotation at wrap handles the Active Session block; nothing handles slow growth in the tracker list, so the mechanism that produced this breach is unfixed.", "valid_from": "2026-09-03", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-03-the-index-had-become-the-record.md", "extracted_at": "2026-09-03"} +{"subject": "claude-code", "predicate": "drift-pattern", "object": "A MUST-DETECT CONTROL WENT GREEN ON AN EMPTY DENOMINATOR. Building ground truth for the mumble-discriminator gate, the signature was copied from tarbuckle-invoke.py -- the file just read -- and matched 0 of 65 transcripts, because mumbles are written by three OTHER fool surfaces. The gate printed 'PASS (0/0)'. Accepting it would have certified a broken discriminator and wired it into three more sites. Caught by 'a null search is evidence about the QUERY', a human-held rule, not by the instrument. Now queued as OWED-5: a must-detect must report its denominator and a denominator of zero is a FAIL.", "valid_from": "2026-09-04", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-04-the-discriminator-was-a-coincidence.md", "extracted_at": "2026-09-04"} +{"subject": "claude-code", "predicate": "drift-pattern", "object": "FRAME-INHERITANCE ACROSS A QUESTION CHANGE, and it was the session's whole finding. human_turns() carries three passing controls, all testing the question it was BUILT for ('did an executor run unattended?'). The repair plan reused it for a different question ('is this a mumble?') and inherited the controls' authority across that gap. Re-run at the scope of the extension: must-detect 22/24, must-not-flag 35/41. The exclusion works only when a mumble happens to quote a slash command; the 2 leaks are exactly the 2 marker-free mumbles.", "valid_from": "2026-09-04", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-04-the-discriminator-was-a-coincidence.md", "extracted_at": "2026-09-04"} +{"subject": "claude-code", "predicate": "drift-pattern-good-direction", "object": "STOPPED AT THE GATE AND DID NOT BUILD THE REPLACEMENT. When 2a failed, the handover's stated reason was honoured rather than its instruction alone: three controls passed and a fourth broke, so the finding is about the CONTROL SET, and a successor discriminator written under the momentum of the break inherits whatever made the first set look sufficient. Sites 2-4 left unrepaired on purpose. Gates 2b and 2c were still run, because 2a does not gate them.", "valid_from": "2026-09-04", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-04-the-discriminator-was-a-coincidence.md", "extracted_at": "2026-09-04"} +{"subject": "the rule 'a null search is evidence about the QUERY'", "predicate": "prevention", "object": "STOPPED A VACUOUS PASS FROM CERTIFYING A BROKEN DISCRIMINATOR, 2026-09-03. The rule was banked 2026-08-31 after four name-search errors in two sessions -- a different failure class entirely (reporting 'you don't have X' from a filename search). Here it fired on a control's empty denominator and prevented a broken predicate being wired into three further consumer sites. A lesson banked from one class stopping another is the transfer signature.", "valid_from": "2026-09-04", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-04-the-discriminator-was-a-coincidence.md", "extracted_at": "2026-09-04"} +{"subject": "~/_Dev/claude-transcript-archive", "predicate": "is-not-version-controlled", "object": "NO .git, no parent repo, 144 MB, single copy on one disk -- while preserve-transcripts.py:11 states it copies transcripts 'to a git-tracked location so the population stops shrinking'. 11 transcripts have been pruned at source and exist ONLY here. PENDING-144's class (substrate claims inside governance scripts checked by nothing) at the site where it costs most, because the docstring is what a reader consults to decide whether the evidence is safe. Steward directed a git init as the next session's first act.", "valid_from": "2026-09-04", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-04-the-discriminator-was-a-coincidence.md", "extracted_at": "2026-09-04"} +{"subject": "the ladder trial counter", "predicate": "composition", "object": "N-now 65 of 84 measured 2026-09-03 = 41 real sessions + 24 Tarbuckle mumbles (36.9% machine chatter). Rising fast. The prior record in MEMORY.md said 44 and falling ('shedding faster than it gains') -- wrong in the number and backwards in the direction; corrected record-only. Also: preservation has permanently diverged the two stores (11 archive-only files), so grading must now specify WHICH STORE, not only what N -- the trigger reads live, honest grading of a post-08-07 population must read preserved.", "valid_from": "2026-09-04", "valid_to": null, "confidence": 1.0, "source_file": "session-2026-09-04-the-discriminator-was-a-coincidence.md", "extracted_at": "2026-09-04"} diff --git a/claude/memory/session-2026-09-04-the-discriminator-was-a-coincidence.md b/claude/memory/session-2026-09-04-the-discriminator-was-a-coincidence.md new file mode 100644 index 0000000..f5907b1 --- /dev/null +++ b/claude/memory/session-2026-09-04-the-discriminator-was-a-coincidence.md @@ -0,0 +1,222 @@ +--- +name: Session 2026-09-04 — the discriminator was a coincidence +description: "Woke into the steward's directive to make the wake and wrap tools reliable; a handover reordered the work so that preservation ran first and three read-only gates stood before any repair. Gate 2a failed and the repairs never happened — human_turns(), the function the whole plan called 'already controlled', is not a mumble discriminator at all: it detects slash-command markers, and excludes a mumble only when the session that mumble quoted happened to contain a slash command. The two leaks are exactly the two marker-free mumbles. Filed PENDING-179 as an item rather than a -178 addendum, on PENDING-145's suppression mechanism. Also found: preserve-transcripts.py claims its destination is git-tracked and it is not, so 11 transcripts that exist nowhere else sit on one disk. PULLING THREAD: unchanged in name but now preceded by two steward-set acts — git-init the transcript archive, and suspend automatic grading at trigger_fired() — after which -178 and -179 are ruled jointly." +type: project +metadata: + node_type: memory + type: project + modified: 2026-09-04 +--- + +# Session 2026-09-04 — the discriminator was a coincidence + +Ran from the evening of 2026-09-03 into 2026-09-04. Second session of 09-03; the first was the +MEMORY.md load-integrity breach. + +## PAST — what moved, and why + +### The handover reordered the work, and the reordering is why the session succeeded + +The steward's instruction was *"go ahead with the fix — positive control first"*, accompanied by a +handover that changed the ordering. Three of its moves mattered: + +- **Preservation runs first, because it expires.** The positive control does not. +- **Site 1 (`governance-drift-check.py:513`) is excluded on receipt, not as a step I perform.** The + ladder trigger's meaning is steward and jurist territory. +- **Repair is step 4, gated on 2a and 3** — not the next action after the control. + +⚠ **The handover also caught a claim I had made at the wake.** I reported 31 mumbles from running +`human_turns()` over all 65 transcripts. That *classified using* the function; it did not *validate* +it. Treating it as having discharged 2a would have been the derived-form flag exactly. + +### Step 0 — preservation + +`preserve-transcripts.py`: **76 transcripts, 143.5 MB, read-back PASS.** 33 newly added, 1 refreshed, +and **11 already pruned at source, surviving only in the archive.** That last number is not +incidental — it is one of gate 2b's two terms, and it is also what makes the two stores permanently +divergent. + +### GATE 2a — FAIL in both directions, and the repairs stopped + +Ground truth taken from the fool's own prompt text (written by `tarbuckle-*.py`, not by the function +under test): **24 known mumbles, 41 known non-mumbles**, of 65. + +- **must-detect 22/24** — two mumbles return `human_turns == 1` and read as human-attended. +- **must-not-flag 35/41** — six non-mumbles return `0`, and ⚠ **at least one of those is CORRECT**: + `b7e7eb39` is the unattended executor session of 2026-08-31 (PENDING-172), which genuinely has no + human turn. **`0` never meant "mumble". It means "nobody spoke"**, which is equally true of an + unattended real session. + +**Mechanism, confirmed rather than inferred.** `human_turns()` skips any `user` record containing one +of seven `NONHUMAN` markers. A mumble embeds the *previous session's* material in its prompt, so it +inherits those markers **only when the session it was mumbling about happened to contain a slash +command**. Of 24 mumbles, 22 embed a marker and are excluded; **2 embed none — and those 2 are +precisely the 2 that leak.** The correlation is content-dependent coincidence. The function's own +docstring says it answers *"did an executor just run unattended?"*, and at that job it is correct. + +**No replacement was built, per the handover and for its stated reason:** three controls passed and a +fourth broke, so the finding is about the **control set**, not only the function. All three test the +question the function was *for*; none could see the question it was being *reused* for. + +### GATE 2b — composition stands; two terms do not close + +Reconstructed from the archive by the same ground-truth signature: + +| date | N | real | mumble | % | +|---|---|---|---|---| +| 2026-08-31 | 52 | 41 | 11 | 21.2 | +| 2026-09-01 | 50 | 39 | 11 | 22.0 | +| 2026-09-03 (measured live) | 65 | 41 | 24 | 36.9 | + +**-178's composition claim stands**: 11 mumbles and "roughly a fifth" close exactly on 08-31. Against +-178's enumerated `54 = 43 + 11` on 09-01 I reconstruct `50 = 39 + 11` — **the mumble term identical, +the whole 4-file gap in the real-session term.** ⚠ **Not asserted against -178.** My method models the +prune as a 30-day window over `source_mtime` and is a demonstrated **lower bound**: preservation has +run **twice only** (08-26, 09-03). Where we disagree, -178 enumerated live and is better positioned. + +**Record-only correction applied** (authorized): `MEMORY.md` carried *"N-now 44/84 as of 2026-08-31, +DOWN 7 from 51"* — wrong in the number and **backwards in the direction**. Now **65/84 measured**, +with composition stated, and the stale `governance-drift-check.py:331` pointer corrected to `:513` +(`:331` is a register-check control; both lines read before changing it). + +### GATE 2c — five sites in four files; -178's scope holds + +Controls named before the run. Enumerating consumers: `governance-drift-check.py` (426, 513) · +`wake-digest.py` (354 + the selftest sample) · `tarbuckle-invoke.py` (37, 44) · +`preserve-transcripts.py` (45, 126, 172). `tarbuckle-wrap.py` and `-seam.py` are **not** consumers — +they receive `transcript_path` from the hook payload. + +⚠ **What the census cannot see, as output rather than caveat:** (i) a consumer that builds the path by +component join *and* never enumerates `*.jsonl` on a matching line — **demonstrated: `wake-digest.py` +does exactly this and escaped a literal-fragment grep over the whole fleet**; (ii) anything reaching +the population through a hook-supplied `transcript_path`; (iii) anything outside the swept roots. +**(i) applies retroactively to the four-site census inherited from the previous wrap, which was +grep-derived by the method just shown to be blind.** + +### Filed, corrected, committed + +- **PENDING-179** — as an item, not a `-178 ADDENDUM 1`, on PENDING-145's mechanism: `ruled_pendings` + claims a **number**, so an addendum would be suppressed the moment -178 is ruled. The undecided + filing moratorium is disclosed inside the item, with the previous session's contrary reasoning + preserved rather than overridden. +- **`c150bdf`**, pushed to `github` and `gitea`, **both verified at the same SHA**. +- **OWED-5 queued** in PENDING-141's owed-entries list (the ratified queue, REVIEWED-123 cond. 3). + +### ⚠ The archive is not backed up, and the script says it is + +Found while checking repo state for the commit. `preserve-transcripts.py:11` states it copies +transcripts *"to a git-tracked location so the population stops shrinking."* **`~/_Dev/claude-transcript-archive` +has no `.git`, no parent repo, and is 144 MB.** The copying works — every file is re-hashed on +readback — but the sentence describing where they went is false, and **11 transcripts now exist in +exactly one place on one disk.** PENDING-144's class (substrate claims inside governance scripts +checked by nothing), at the worst possible site: the docstring is what anyone reads to decide whether +the evidence is safe. + +## PRESENT — how it stands + +**The mood.** Unusually clean, and the cleanliness is entirely borrowed. The handover did the work +that made this session good: it put preservation before the control, excluded site 1 so I could not +wander into it, and — decisively — insisted the "already controlled" claim be tested before anything +was wired anywhere. Left to my own plan I would have written a positive control for a fixture and +wired a broken predicate into three more sites, all of it green. + +**What was corrected — three, and the first is mine from four hours earlier.** +1. **My wake census used `<= 1` as the mumble threshold**, silently absorbing 3 transcripts that + return exactly 1. The real distribution is 28 at 0 and 3 at 1, and the ground-truth split is + 24/41. The wake number (31) was wrong and the method behind it was wrong in a more interesting way. +2. **A vacuous `PASS (0/0)`.** My first ground-truth query used the signature from + `tarbuckle-invoke.py` — the file I had just read — and matched **0 of 65**. The gate went green on + an empty denominator. Caught by *a null search is evidence about the QUERY*; opening a transcript + showed the mumbles come from three **other** fool surfaces (`tarbuckle-mumble/-wrap/-seam`) that + the inherited site census never named. **This is now OWED-5.** +3. **The previous wrap predicted the digest selftest would "fail on every run from now on."** + Falsified within 2.2 h: it passed at this wake (5 of 13). The defect is *intermittent* — a + function of the mumble rate in a rolling 13-transcript window — which is harder to notice than a + permanent failure. + +**Confidence to recalibrate.** +- **Verified by running it:** the 2a confusion matrix over all 65 with independent ground truth; the + leak mechanism (2 leaks == 2 marker-free mumbles, exactly); N-now 65 and its 24/41 composition; + preservation readback; both remotes at `c150bdf`; the archive has no `.git`. +- **Reconstructed, lower-bound, NOT asserted against -178:** the 08-31 and 09-01 rows of the 2b table. +- **Inherited and now known to be unreliable:** the four-site census from the previous wrap — + grep-derived by a method this session demonstrated is blind to component-joined paths. + +**Instruments:** 4 run (ground-truth classifier · archive reconstruction · consumer census · +histogram) · **1 carrying a control written before first execution** (the consumer census, whose +must-find and must-not-find were named in the file before it ran — and the must-not-find *fired*, +catching the vendored-docs pollution) · **K = 0** — none duplicated anything banked; all four answered +questions asked once. ⚠ **The census was narrowed three times.** Repeated narrowing can end by +confirming the sites it was built around; the negative control and the explicit blind-spot statement +are what keep that honest, and they are not a substitute for someone checking it. + +**Decisions deferred, and why.** +- **No repair at any site**, and no replacement discriminator — gate 2a's stated consequence. +- **`governance-drift-check.py:513` not examined at all** — excluded on receipt. +- **Did not `git init` the archive.** 144 MB is real weight for both remotes, and full transcripts + contain everything ever typed in these sessions; whether they belong on a hosted remote is a + steward decision, not a chore. +- **Did not correct `preserve-transcripts.py`'s false docstring.** Editing a governance script's + stated rationale to match a worse reality is the direction that makes docstrings worthless. It + should become true, or be corrected as a disclosed change. +- **OWED-5 queued rather than patched in.** Turning the rule on converts currently-green controls to + red across the fleet; that is a ruling, not an edit — and the ladder is frozen regardless. + +## FUTURE — what pulls + +**The pulling thread is unchanged in name and now has two steward-set acts in front of it.** +The fr cell's last two steps still pull. But the steward has set the next session's opening +explicitly, and it is not that. + +### Next session, first work — steward-directed 2026-09-04 + +1. **`git init` the transcript archive.** The steward has named this as the wake's first act. +2. **Suspend the automatic grading at `trigger_fired()`.** ⚠ **Stated precisely by the steward, and + the precision is the point: this is NOT a repair, NOT a filter, and NOT -178 option (b). It + changes nothing about what the counter counts, so the site-1 exclusion survives intact.** It + prevents a grade firing on a population whose contamination is measured and rising. + +### Then the joint ruling — steward, 2026-09-04 + +**-178 and -179 are ONE decidable unit** and will be ruled together. -179 is -178's evidence and says +so in prose, because the numbering cannot carry it (PENDING-145). The joint ruling covers **unit, +window, recurrence, predicate, and seeding.** + +⚠ **Seeding has grown a second half, and it is new today.** Preservation has **permanently diverged +the two stores**: 11 files exist only in the archive. So the question is no longer only *what N*, but +**over which store** — and the trigger reads **live**, while any honest grading of a post-08-07 +population must read **preserved**. + +**Steward's positions, recorded so they are not re-litigated:** +- **Agrees with -179's option (c)** — a mumble that declares itself cannot be misread by a marker + coincidence — **and with the refusal to build it now.** +- **The lesson is the control set, and it generalizes past this function:** three controls passed and + a fourth broke, and all three tested the question the function was *for* rather than the question it + was *reused* for. + +**Other horizons, ranked.** +- **The archive's single copy** — a local second copy is the cheap half and answers none of the + remote question. Unresolved. +- **`preserve-transcripts.py:11`'s false claim** — becomes true after the `git init`, which is the + clean resolution and is why the steward put the init first. +- **`~/.claude/agents` under version control** — steward-directed, still owed, before anything else + edits it. +- **The filing moratorium** — undecided, and PENDING-179 was filed under it with that disclosed. +- **PENDING-171** → unblocks 322 unread of 362 · **-160** · **-168** · the §5 regrade, an eighth session. +- **Parked worker `acaabadf`** — stopped, still carrying `--reply-on-resume`. Untouched again. + +**Pause statement.** I am about to be away from this and the context is being cleared deliberately. +What I want to find still pulling is the fr cell's last two steps — but what I want the next session +to *do first* is the two acts above, in that order, because the steward set them and because the +`git init` is what makes an already-false docstring true rather than requiring it to be edited into +honesty. ⚠ What I want the next session to **notice** is that this session's entire value came from a +gate that stood between a plan and its execution. The plan was mine, it was confident, and it was +wrong. **The handover did not improve the fix; it prevented it.** + +**Literal question for next-Claude** *(checkable; turns on the record, not introspection)*: +**How many other must-detect controls in the fleet currently have a denominator of zero?** OWED-5 is +queued on a single observed instance. The fleet's controls are enumerable and their denominators are +computable without changing any of them. ⚠ If the answer is zero, OWED-5 is a rule earned from one +accident and should be labelled that way rather than carried as a general finding. If it is more than +zero, then some number of currently-green controls have never tested anything — and nobody knows +which, because a vacuous pass and a real pass print the same word.