From 0a48e6934da82c96c0760979bf5e2ce94419e2c2 Mon Sep 17 00:00:00 2001 From: David F Glidden Date: Mon, 3 Aug 2026 20:57:41 +0200 Subject: [PATCH] [FIX] L1 pin root-caused and cleared; S-series closed; instrument census MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mindfabric-00 had been event-loop-pinned for 6+ days (100% CPU, /health silent). Profile + CDP inspector named two hot paths, both from runTemporalPipeline: checkForCycle -> getCausalEdgesFromSqlite 99.8% of samples tryExtendChains -> getChainsContainingSeq now dominant (json_each scan) Cause of the first: ANALYZE had never been run, so SQLite preferred a boolean index (idx_caused_tombstoned, matching ~all 836k edges) over idx_caused_from. ANALYZE across 15 module DBs flipped the plan; 6.4x on a microbenchmark and 99.8% -> 6.0% in the live profile. /health went from silent to 200 in 0.13s. B1.1's fan-out cap is IMPLEMENTED AND WORKING (today: max in-degree exactly 20, zero violations; pre-23-June: max 629, avg 67.6). The defect is data, not code — 836k edges / 813k chains minted under ungoverned fan-out before the fix landed. Repair run: derived stores wiped, logchain preserved, replay in flight. S-series closed (jurist had already ruled all of Q1-Q5 on 2026-05-18): S6/S7/S9 implemented (Symmetria §3 flags, `suspend` outcome, wrap-up §8 tenses) S2 rebuilt as [FIX] — wake-digest unwrapped-session detector, discrimination- gated on real sessions (11 wrapped / 2 unwrapped) S4/S5 withdrawn with MemPalace (steward ruling) Dormant legacy dispositioned: PENDING-4/5/11/12, CD-03, ICP-19 duplicate. Open authorization items 22 -> 10. Census 01: which instruments have no real negative instance. Finding — the governance drift-check has 3 of 5 families inert against the current CLAUDE.md, and 71 of 75 verification-ladder entries are cited nowhere outside the ladder. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WuMjg3ipEVa3n8CoSzoyvc --- PENDING.md | 54 +++++++--- ...s-01-negative-instances-PREREGISTRATION.md | 68 ++++++++++++ .../census-01-negative-instances-RESULT.md | 98 +++++++++++++++++ claude/memory/project-L1-reliability.md | 26 ++++- claude/memory/session-ledger-2026-08-03.md | 73 +++++++++++++ claude/skills/symmetria/SKILL.md | 8 +- claude/skills/wrap-up/SKILL.md | 15 ++- scripts/wake-digest.py | 101 ++++++++++++++++++ 8 files changed, 427 insertions(+), 16 deletions(-) create mode 100644 claude/governance/fool/census-01-negative-instances-PREREGISTRATION.md create mode 100644 claude/governance/fool/census-01-negative-instances-RESULT.md create mode 100644 claude/memory/session-ledger-2026-08-03.md diff --git a/PENDING.md b/PENDING.md index 5d0a68b..bd276ab 100644 --- a/PENDING.md +++ b/PENDING.md @@ -17,14 +17,16 @@ does not. -## PENDING-4 — Bug D: Idle stall + batch embedding during replay +## PENDING-4 — Bug D: Idle stall + batch embedding during replay (CLOSED 2026-08-03 — done since March; the register never caught up) **Date:** 2026-03-22 **Tag:** [FIX] — reclassified from next-PR to this-PR by steward authorization **Summary:** Idle state machine transitions during replay freeze async operations. Batch embedding and vector replay skip reduce Phase 1 from 83 hours to ~10 minutes. **Files affected:** replay-coordinator.ts, bootstrap.ts, ollama-embeddings.ts, vector/index.ts, idle-state-machine.ts **Status:** Implemented and verified. -## PENDING-5 — Recall query path returns 0 results +**CLOSED 2026-08-03 — verified against substrate, not taken from the self-assessment.** The `**Status:** Implemented and verified.` line above is the item's own claim about itself; it was checked rather than believed. Corroborated in `BetterMemories.io`: `betterMemories_app#120` (*Phase 2 replay stuck in infinite resource-pause loop*) **closed**, `#133` (*modules report 'ready' during active replay*) **closed**, plus `03b6a78`, `5b14db7`, `decbdee`, and `3332772` (N6, #175 merged) continuing the replay/idle work well past March. **Why it stayed open 4½ months:** the wake digest recognises `(CLOSED)`/`COMPLETED` in a *header*, not a `**Status:**` line in a *body* — so a completed item advertised itself as open every morning. + +## PENDING-5 — Recall query path returns 0 results (CLOSED 2026-08-03 — instance resolved via GH; the CLASS is still open at #165) **Date:** 2026-03-22 **Tag:** [FIX] **Summary:** After Phase 1 completes, recall() returns 0 results despite modules reporting ready and vector processing live events. Module dispatch timeouts in query-router. Write path works; read path has separate issue. @@ -32,6 +34,10 @@ does not. **Files affected:** `src/core/keystone/query-router.ts`, `src/core/keystone/query-types.ts`, possibly `src/modules/vector/queries.ts` **Awaiting:** Investigation — likely needs Seb's input on the query dispatch architecture. +**CLOSED 2026-08-03 — the work migrated to GitHub and this register kept a March snapshot.** Seb did the investigation through the issue tracker: `betterMemories_app#124` (*Ollama unavailability silently empties vector query results*) **closed**, `#135` (*temporal query errors silently return empty results*) **closed**, resolved by `bd1f650 feat: typed query status — distinguish 'no results' from 'module failed'` — which is precisely this item's symptom (*"returns 0 results despite modules reporting ready"*). Also `c6689eb` (recall ranking, #120/#80/#89/#107). + +⚠ **The instance is closed; the CLASS is not.** `#165 — H2: silent recall failure on battery` is **open, priority:critical, production blocker**, and is the same failure shape from a different cause: recall returning empty without saying so. Closing PENDING-5 must not read as "silent-empty-recall is solved." Tracked at #165, not here — the register should not hold a second stale copy of an issue GitHub owns. + ## PENDING-10 — Skip vector embedding during replay (architectural) **Date:** 2026-03-22 **Tag:** [PROPOSAL] @@ -46,7 +52,7 @@ does not. **Consequence for the split:** these are two separable pieces of work and should probably be two items. The performance proposal is architectural and awaits review; the audit question is load-bearing for the provenance story and is now scoped inside Seb's #176 restore drill. Splitting them is the steward's call — flagged, not done. -## PENDING-11 — Approve I15 (ICP-9 Pilot Registry Entry: The Accusative Default) +## PENDING-11 — Approve I15 (ICP-9 Pilot Registry Entry: The Accusative Default) (CLOSED 2026-08-03 — REVIEWED-11 AUTHORIZED 2026-03-23) **Date:** 2026-03-23 **Tag:** [PROPOSAL] **Summary:** Approve I15 as the pilot registry entry, validating both the invariant (The Accusative Default) and the `l1_contamination_profile` schema field. Full entry drafted in `relational-gap-registry-amendment.md` §2 since 2026-03-09. @@ -58,7 +64,11 @@ does not. **Files affected:** Registry (governance metadata, not code). **Awaiting:** Steward entry in REVIEWED.md. -## PENDING-12 — Lodge Design Notes DN-GOV-01 through DN-GOV-04 +**CLOSED 2026-08-03 — the entry it awaits has existed since the day it was written.** `REVIEWED-11 — Approve I15 (ICP-9 Pilot Registry Entry)`, **Date 2026-03-23, Decision AUTHORIZED**, ratifying `l1_contamination_profile` as mandatory for all non-contingent principles and deferring `residual_risk` pending pilot evidence. The downstream this item lists as blocked was ruled months ago: **REVIEWED-15 (I17)** and **REVIEWED-16 (I16)**. Registry file verified present. + +**Why it stayed open 4½ months — two independent defects, either alone sufficient.** (1) The REVIEWED-11 and REVIEWED-12 blocks are **indented by one space**, so every `^## REVIEWED` anchor steps over them; a fence-tracked census of `REVIEWED.md` finds exactly **3** such orphans (these two and REVIEWED-74). (2) Their headers **name no PENDING**, and resolution is by named item, not by number — so even flush-left they would discharge nothing. Correcting `REVIEWED.md` is **not the executor's to do** (Constitutional Constraint #1); flagged for the steward, closed here instead. + +## PENDING-12 — Lodge Design Notes DN-GOV-01 through DN-GOV-04 (CLOSED 2026-08-03 — REVIEWED-12 AUTHORIZED 2026-03-23; all four files verified present) **Date:** 2026-03-23 **Tag:** [HARDENING] **Summary:** File four design notes from the Governance Velocity seed brief into `l2-constitution/`: @@ -71,6 +81,10 @@ does not. **Steward authorization:** Steward authorized filing 2026-03-23. DN-GOV-03 (baseness elevation) requires separate steward declaration before advancing beyond DESIGN NOTE. DN-GOV-04 (pace governor) is tooling and can iterate without further authorization. **Awaiting:** Steward entry in REVIEWED.md. +**CLOSED 2026-08-03 — ruled the same day, and the series ran on without it.** `REVIEWED-12 — Lodge Design Notes DN-GOV-01 through DN-GOV-04`, **Date 2026-03-23, Decision AUTHORIZED** (*"DN-GOV-03 requires separate declaration before elevation. DN-GOV-04 is tooling, iterate freely"*). All four files verified present in `CapableMind-AI/docs/thinking/David/l2-constitution/`. The series continued far past this item — **REVIEWED-13** ruled DN-GOV-05/06/07 and **REVIEWED-14** ruled DN-GOV-08 — so the register was reporting a blocked item whose successors had already been decided. Same two-defect cause as PENDING-11 (indented header; names no PENDING). + +**Still genuinely outstanding from this item, and NOT closed by it:** DN-GOV-03's *separate steward declaration* before it advances beyond DESIGN NOTE. That is a live steward action with no home now that this item is closed — surfaced 2026-08-03 rather than allowed to vanish with the closure. + ## PENDING — ICP-19 Remit Expansion (Observer Problem) **Date opened:** 2026-04-07 **Action required:** Steward-reviewer conversation with the External Auditor before Observer Problem mechanisms advance to constitutional language. @@ -90,7 +104,9 @@ does not. --- -## PENDING — ICP-19 Remit Expansion +## PENDING — ICP-19 Remit Expansion (CLOSED 2026-08-03 — DUPLICATE of the ICP-19 entry above; the live one is retained there) + +**Duplicate note, 2026-08-03.** Same subject, same `**Date opened:** 2026-04-07`, same requirement (a direct steward–reviewer conversation on remit expansion before Observer Problem mechanisms advance to constitutional language) as `## PENDING — ICP-19 Remit Expansion (Observer Problem)` earlier in this file. Two records of one obligation, counted twice by every tally and violating *one canonical source of truth per document*. **The substance is not withdrawn** — the prerequisite conversation about the incommensurable foundational positions (OP-CN-01) is preserved in the retained entry, which is the canonical one. Closing the copy, not the obligation. **Title:** ICP-19 External Review — Human-Side Governance Scope **Date opened:** 2026-04-07 @@ -105,7 +121,9 @@ does not. --- -## PENDING — CD-03 Operative +## PENDING — CD-03 Operative (CLOSED 2026-08-03 — bookkeeping only: this is a RECORD of an operative declaration, never an open item) + +**Bookkeeping note, 2026-08-03.** Nothing constitutional is decided or altered here. This entry's own `**Status:**` reads **OPERATIVE — immediate effect**, and its `**Date authorized:**` is 2026-04-07: it is a *notification* that CD-03 is in force, filed in the register because that is where notifications went. The register's tooling reads every `## PENDING` block as an item awaiting authorization, so for four months the wake reported an in-force declaration as an outstanding `[CONSTITUTIONAL]` decision. Marked closed **as a register entry only**. The declaration itself is untouched and remains operative at `CapableMind-AI/docs/thinking/David/l2-constitution/observer-problem/Constitutional Declaration — CD-03.md` — note the path drifted from the one recorded below (`observer-problem/` is now under `l2-constitution/`). CD-03 §IV.4 continues to bind all mechanism proposals. **Title:** Constitutional Declaration CD-03 — The Observer Condition and the Limits of Constitutional Architecture **Date authorized:** 2026-04-07 @@ -120,7 +138,7 @@ does not. --- -## PENDING-S2 — Hook-aware deposit detection in wake-up (awaiting Q1 hooks contract) +## PENDING-S2 — Hook-aware deposit detection in wake-up (CLOSED 2026-08-03 — obligation rebuilt as [FIX]; never awaited the jurist) **Date:** 2026-05-18 **Tag:** [PROPOSAL] **Phase 4 — awaits Jurist contract definition.** @@ -133,9 +151,11 @@ does not. **Awaiting:** Jurist shape-review of contract language (candidate text in Jurist shape-review document: *"The authoritative deposit is a wrap-up deposit. A hook-only deposit is an emergency fallback, not a complete inheritance. Wake-up must detect which it received and calibrate accordingly."*). Then steward authorization. +**CLOSED 2026-08-03 — obligation harvested, mechanism rebuilt as `[FIX]`.** The `Awaiting` line above was **wrong for 2½ months**: the jurist affirmed Q1 on 2026-05-18 and explicitly assigned the contract to the steward — *"CC cannot define what 'authoritative deposit' means — that's constitutional language, and it belongs to you."* Nothing was ever awaited from the jurist. Meanwhile the premise died: no Stop hook is configured, and MemPalace — whose `mempal_save_hook.sh` was the deposit — is retired, steward-ruled 2026-08-03 (*"MemPalace is retired and any associated functionality also, except some of the concepts we harvested and implemented in our own way"*). **The obligation survived its instrument**: `wake-digest.py` computed `Last wrap` from mtime, so a session ending without `/wrap-up` left the next wake reporting an *older* session's thread as current, silently. Rebuilt on our own substrate — the transcripts are the only witness that a session ran. `sec_unwrapped()` + `transcript_span()` + `wrap_inside()`, self-tested with four unit controls and a **discrimination check over real sessions (11 wrapped / 2 unwrapped)**; the warning states what it does not establish. No doctrinal contract required — the mechanism is now ours, not a cross-repo hook. Two real unwrapped sessions found in history: 07-28 06:07, 07-29 16:21. + --- -## PENDING-S4 — Post-compression marker; cross-repo with mempalace (awaiting Q1) +## PENDING-S4 — Post-compression marker; cross-repo with mempalace (CLOSED 2026-08-03 — WITHDRAWN with MemPalace; concept kept as a Symmetria §3 flag) **Date:** 2026-05-18 **Tag:** [PROPOSAL] **Phase 4 — cross-repo coordination.** @@ -148,9 +168,11 @@ does not. **Awaiting:** Jurist contract definition (Q1); steward authorization; mempalace upstream coordination. +**WITHDRAWN 2026-08-03 — MemPalace-associated functionality, retired with it** (steward ruling: *"MemPalace is retired and any associated functionality also"*). The marker was to be a MemPalace **diary entry** written by `mempal_precompact_hook.sh`; no PreCompact hook is configured, and the diary no longer exists. **The concept was harvested rather than lost**: post-compression confidence claims are now a standing Symmetria §3 contamination flag (*"the working memory was trimmed; what feels certain now may rest on what was lost"*), landed with S6 the same day. That is the durable half — a flag needs no hook to fire. + --- -## PENDING-S5 — Authoritative-diary marker; wrap-up ↔ Stop hook (awaiting Q1) +## PENDING-S5 — Authoritative-diary marker; wrap-up ↔ Stop hook (CLOSED 2026-08-03 — WITHDRAWN; the race it names can no longer occur) **Date:** 2026-05-18 **Tag:** [PROPOSAL] **Phase 4 — cross-repo coordination.** @@ -163,9 +185,11 @@ does not. **Awaiting:** Jurist contract definition (Q1); steward authorization; mempalace upstream coordination. +**WITHDRAWN 2026-08-03 — the race it names can no longer occur.** Both parties to the collision are gone: the MemPalace diary (retired 2026-07-07) and the Stop hook that wrote the second entry (`mempal_save_hook.sh` — not configured; live hooks are `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`). With a single writer — `/wrap-up` writing the session memory file — there is no depleted-context second entry to be mistaken for the canonical one. Withdrawn as **discharged by events**, not deferred. Distinguished from S2 deliberately: S2's obligation outlived its instrument and was rebuilt; S5's obligation died with the substrate that created it. If a second automated writer of session records is ever introduced, this item is the precedent to re-open. + --- -## PENDING-S6 — Symmetria §3 contamination flag applications of the Directive elaboration +## PENDING-S6 — Symmetria §3 contamination flag applications of the Directive elaboration (CLOSED 2026-08-03 — IMPLEMENTED) **Date:** 2026-05-18 **Tag:** [HARDENING] **Phase 3b — depends on S0 (now CLOSED).** @@ -184,9 +208,11 @@ does not. **Awaiting:** Steward authorization (S0 closure unblocks). +**IMPLEMENTED 2026-08-03** — `~/.claude/skills/symmetria/SKILL.md` §3. All six flags landed: the three time-the-task-requires applications (lectio · diagnose-don't-fix · dwell-on-composition) grouped as one entry under the now-constitutional Q4 elaboration, plus premature-closure-pulse (D1), query-shaped-by-what-it-wants-to-find (D5), and post-compression-confidence (D4). D4 is retained on its own merit though S4 was withdrawn the same day — compaction still occurs; only the MemPalace marker died. Unblocked since Q4 landed in `~/CLAUDE.md`; the delay was bookkeeping, not dependency. + --- -## PENDING-S7 — Symmetria `check` mode: add `suspend` outcome (awaiting Q5 + relates to Q4) +## PENDING-S7 — Symmetria `check` mode: add `suspend` outcome (CLOSED 2026-08-03 — IMPLEMENTED; Q5 was affirmed 2026-05-18) **Date:** 2026-05-18 **Tag:** [HARDENING] **Phase 5.** @@ -199,9 +225,11 @@ does not. **Awaiting:** Steward authorization. +**IMPLEMENTED 2026-08-03** — `~/.claude/skills/symmetria/SKILL.md` §6 now reads `proceed | return-and-reframe | suspend | escalate`, with `suspend` defined against its two neighbours (not `escalate`, which carries urgency; not `return-and-reframe`, which says the work is wrong) and required to name what is suspended and what would resume it. The header's *"awaiting Q5"* was stale: **Q5 was affirmed 2026-05-18** (*"Yes, add it"*), conditional only on Q4, which has since landed. Used in this session before it was written — the hold on CONTROL-A v2 is a `suspend`, not an `escalate`. + --- -## PENDING-S9 — Wrap-up §8 output template enriched to match practice +## PENDING-S9 — Wrap-up §8 output template enriched to match practice (CLOSED 2026-08-03 — IMPLEMENTED; Q2/Q3 were affirmed 2026-05-18) **Date:** 2026-05-18 **Tag:** [HARDENING] **Phase 5 — depends on Q2 + Q3 (Q3 confirmed by Jurist).** @@ -214,6 +242,8 @@ does not. **Awaiting:** Steward authorization. Optional relationship to S1: implement S1 first (minimal additive), then S9 as deeper revision; or fold S1 into S9 as single revision. +**IMPLEMENTED 2026-08-03** — `~/.claude/skills/wrap-up/SKILL.md` §8 restructured into the three tenses. S1 had already landed (archived), so this is the deeper revision on top of it. **The diagnosis was exact and sharper than the item stated: Future was already well-specified — pulling thread, resumption point, literal question, and Q3's constitutive pause statement were all present — while Past and Present were *wholly absent*.** Added: what-happened / what-held / what-was-corrected (Past) and the-mood / confidence-to-recalibrate (Present), with deferred-decisions and skill-harvest relocated under Present. Future deliberately still leads, inverting the memory file's narrative order: the steward reads this at departure, but it is written for arrival. Q2 was affirmed 2026-05-18 and Q3 elevated to constitutive the same day; both had landed. Every pre-existing field survives — none dropped. + --- ## PENDING-76 — Authorization class follows claim class (REMANDED; executor recommends withdrawal) diff --git a/claude/governance/fool/census-01-negative-instances-PREREGISTRATION.md b/claude/governance/fool/census-01-negative-instances-PREREGISTRATION.md new file mode 100644 index 0000000..d29ac29 --- /dev/null +++ b/claude/governance/fool/census-01-negative-instances-PREREGISTRATION.md @@ -0,0 +1,68 @@ +# Census 01 — Which instruments have no real negative instance? + +**Pre-registered:** 2026-08-03, before reading any instrument source or the verification ladder. +**Origin:** the literal question left by the 2026-08-02 evening wrap. + +--- + +## The question + +Five times on 2026-08-02, a passing check certified a property of the *code* while +claiming a property of the *result*. The discrimination gate (`e9f3544`) is the mechanical +answer **for checks that have a real negative instance to test against**. + +So: **which of our current instruments have no real negative instance available, and is +that absence recorded anywhere, or does it look like coverage?** + +## Unit of census + +An **instrument** = any check, gate, guard, or test suite whose verdict is used to license +a claim. Two populations, both censused entire (no sampling, no `| head`): + +1. Everything in `~/dotfiles/claude/governance/fool/` that returns a verdict. +2. Every named entry in `reference-verification-ladder.md`. + +## The test applied to each + +**Was this instrument demonstrated returning its FAIL verdict on a REAL artifact** — one +drawn from actual work, not authored so the test would exercise the branch? + +Three outcomes: + +- **DEMONSTRATED** — names the real artifact it was shown failing on. +- **ABSENT-RECORDED** — no real negative instance, and the instrument or its record says so. +- **ABSENT-UNRECORDED** — no real negative instance, and nothing says so. **This is the finding**: absence that reads as coverage. + +Synthetic fixtures do not count as negative instances. That is the whole point of the +discrimination gate: fixtures derived from the check inherit the check's blind spot. + +## Predictions (recorded before the read) + +1. **The discrimination gate itself → DEMONSTRATED.** It was built and shown rejecting the + §3.3 pattern as it actually shipped, on two real artifacts. +2. **`test_reduce.py` and `test_twin.py` → ABSENT-UNRECORDED.** Expectation is that they + are fixture-based and say nothing about it. +3. **The trial-03 degraded guard → ABSENT, now RECORDED.** It had no negative instance + until trial 03 supplied one by failing; the record exists because the failure did. +4. **Verification-ladder entries → mixed, skewed DEMONSTRATED.** Ladder entries were earned + from real failures, so most should name the artifact. If they do *not* name it — if the + entry states the rule but drops the instance — that is the same concealment shape as + yesterday's, at the level of the record rather than the document. +5. **Overall skew → ABSENT-UNRECORDED dominant.** Prior: this is the pattern that surfaced + five times in one session. + +## The census's own discrimination condition + +This census is an instrument. Its negative instance is an instrument that genuinely *does* +have a real negative instance, correctly classified DEMONSTRATED, standing beside one that +does not, classified ABSENT. + +**If every instrument lands in one bucket, the census has discriminated nothing** and must +be reported as such rather than as a result. If the skew comes out opposite to prediction 5 +— mostly DEMONSTRATED — the first hypothesis to test is that my classification went lenient, +not that the instruments are sound. + +## Stopping rule + +The census is complete when both populations are enumerated entire and every member is +classified. Unclassifiable members are reported as unclassifiable, not dropped. diff --git a/claude/governance/fool/census-01-negative-instances-RESULT.md b/claude/governance/fool/census-01-negative-instances-RESULT.md new file mode 100644 index 0000000..97745b3 --- /dev/null +++ b/claude/governance/fool/census-01-negative-instances-RESULT.md @@ -0,0 +1,98 @@ +# Census 01 — RESULT + +**Run:** 2026-08-03. Pre-registered at `census-01-negative-instances-PREREGISTRATION.md` before any instrument source or the ladder was read. +**Question:** which of our instruments have no real negative instance, and is that absence recorded, or does it look like coverage? + +--- + +## Verdict in one line + +**The instruments built under this discipline are sound. The instruments built *before* it decay silently — and three of them are currently reporting a clean number they are structurally incapable of dirtying.** + +The census discriminated (both buckets populated, per the pre-registered condition), so it is reportable as a result rather than as nothing. + +--- + +## Population A — `fool/` (7 instruments, censused entire) + +| Instrument | Negative instance | Verdict | +|---|---|---| +| `test_degraded_guard.py` | The **real trial-03 artefact** that defeated its predecessor. Fails loudly (`INSTRUMENT NOT VERIFIED`) if the artefact is absent. | **DEMONSTRATED** — gold standard | +| `test_discrimination.py` | **Two real governance documents**; shown rejecting the §3.3 pattern *as it actually shipped*. | **DEMONSTRATED** — gold standard | +| `test_twin.py` | The **real CONTROL-A/B pair**; shown failing in both laundering directions. | **DEMONSTRATED** | +| `test_reduce.py` | Mixed: fixtures are synthetic, but each is a **minimisation of a real defect** found by contact with a real ruling/package; plus a real-document tiling check and the real false-pass string. | **DEMONSTRATED (derived)** | +| `reduce.py` §3.3 screen | Tested in `test_reduce.py` against heading strings **in isolation** — the exact code-not-result shape. Backstopped by `test_discrimination.py` at document level. | **weak alone, covered by the suite** | +| `reduce.py` §3.2 Q-resolution | Real `CLAUDE.md` + a genuine clause and a plausible fabrication; rejects the fabrication. | **DEMONSTRATED** | +| `twin.py` bidirectional gate | Covered by `test_twin.py`. | **DEMONSTRATED** | + +**Prediction 2 was wrong.** I expected `test_reduce.py` and `test_twin.py` to be fixture-based and silent about it. Both explicitly derive fixtures from the property and say so. Nothing here is concealing an absence. + +## Population B — the verification ladder (75 entries, censused entire) + +Mechanically extracted all 75 entry names, then counted citations elsewhere in `memory/`, `governance/`, `skills/`. **Instrument positive-controlled first** (the same grep finds `Fowler` in 28 files, `verify-before-compose` in 18, `pre-registration` in 13 — it detects presence readily). + +- **71 of 75 entries are referred to by name nowhere outside the ladder.** +- The 4 that are cited: *Byte-identical compile gate* · *Two-hat commit separation* · *Revert-and-redo-smaller* · *The gate itself can be PASS-BUT-FALSELY*. Three of the four are **meta-instruments** — about the practice of gating, not about a domain. + +**What this does NOT establish:** that 71 entries never fire. Name-absence is not use-absence; a discipline can be applied without anyone writing its name. Overclaiming here would be the same error the census exists to catch. + +**What it does establish:** the ladder's own header calls these *"the **named** gates any session reaches for instead of re-deriving."* Naming is the whole mechanism. If 71 names appear nowhere, then either the naming does no work, or the entries are not reached for — **and the record cannot distinguish the two.** Each entry records its *origin* (the real failure that earned it) and nothing about its subsequent life. + +The ladder contains the rule that judges it: + +> *A silent safety net is uninformative, not reassuring — a fallback that never fires across N real cases has not been shown to work.* + +75 entries read as 75 units of coverage. What the record attests is 75 units of *past* catch. + +**Structural cause: ladder entries have no IDs.** They are bolded prose. There is no handle to write in a session record, so firing history cannot be recorded even by someone who wanted to. + +## Population C — the wake instruments (the numbers the steward acts on) + +### `governance-drift-check.py` — reported **0 substrate-contradicted claims** this morning + +Five check families. Tested each against the **real** `~/CLAUDE.md`: + +| # | Family | State | Evidence | +|---|---|---|---| +| 1 | Referenced paths | **LIVE** — examines 4 paths | but **silently skips any backticked path containing a space**: the Compass vault path is never checked. It happens to exist today, so no false negative — but if it broke, the report would still read 0. | +| 2 | Named MCP tools | **INERT** — 0 tool names found | keyed to `kg_*`/`diary_*`/mempalace, which the 2026-07-07 wind-down and the obligation-before-instrument rewrite removed from the document | +| 3 | Hooks claimed to fire | **INERT** — 0 claims found | and its control sits *inside* the `if`, so **the control does not run either** | +| 4 | Expired horizons | **INERT** — 0 phrases found | its control is written to pass on absence (`… or "through end of" not in text`) | +| 5 | Doctrine-id parser | **LIVE**, with a proper discriminating triple (detects definition, detects citation, rejects non-id) | the good one | + +**Three of five families cannot currently report anything, all controls pass, and the instrument never says `INSTRUMENT NOT VERIFIED`.** The 0 is honest about what it measured and silent about what it can no longer see. + +**The general class this exposes — and it is new:** + +> **A drift-checker keyed to a document's current wording goes inert when the document is improved.** It can only ever detect the drift that existed the day it was written. + +Family 2 died *because of a good change*: the memory-discipline rewrite that states *"Instruments for reaching it change; the obligations below do not — state the obligation first and the instrument second, or the next retired tool takes a rule down with it."* That rewrite protected the doctrine from instrument-decay and silently retired the checker watching the doctrine. The rule caught everything except its own watchman. + +### `wake-digest.py` — reported **361 pointers, 0 dead** + +Self-test carries presence **and** absence controls and names the specific real bugs each was built from (*the v1 splitter's blind spot*, *the 2026-08-01 bug*, *the drafting-habit trigger*). Same shape as `test_reduce.py`: synthetic fixtures that are minimisations of real defects. **DEMONSTRATED (derived).** No finding. + +--- + +## Scope boundary — what this census did NOT cover + +Named so the result is not read as complete: + +- the `verify-before-compose` PreToolUse hook +- chamber-library tooling (`audit_cruft`, `verify_conversion`, `resolve_archived_source`, `apply_char_glyphs`, …) +- studium-engine `verify-quote` V1 / `fidelity_equivalence@2` +- BMF/L1 test suites + +Each is a live instrument whose verdicts license claims. Uncensused is uncensused. + +--- + +## Predictions, graded + +1. Discrimination gate → DEMONSTRATED. **Held.** +2. `test_reduce.py` / `test_twin.py` → ABSENT-UNRECORDED. **Wrong** — both are property-derived and explicit. +3. Trial-03 degraded guard → ABSENT, now RECORDED. **Held**, and stronger than predicted: it fails loudly when the real artefact is missing. +4. Ladder entries skewed DEMONSTRATED-at-origin. **Held** — every entry names its origin failure. The gap is *subsequent* history, which I did not anticipate as the axis. +5. ABSENT-UNRECORDED dominant overall. **Held, but for the opposite reason.** I expected weakness in the newest work. It is in the oldest. Instruments do not start blind; **they go blind as the substrate they watch improves.** + +The prediction-5 inversion is the finding worth carrying: freshly-built instruments are strong because the lesson is fresh. Decay is the failure mode, not construction. diff --git a/claude/memory/project-L1-reliability.md b/claude/memory/project-L1-reliability.md index a2da3e3..9df5036 100644 --- a/claude/memory/project-L1-reliability.md +++ b/claude/memory/project-L1-reliability.md @@ -18,7 +18,23 @@ permalink: claude-memory/project-l1-reliability --- -## Current state (as of 2026-06-06) +## Current state (as of 2026-08-03) + +- **The baton rule is LIFTED.** The 2026-06-06 instruction — *"Do not re-enter L1 until Seb responds or pushes — his move"* — was steward-lifted 2026-08-03 (*"if we can move this ahead then let's do what it takes"*). Context the steward supplied: Seb is not silent by choice; he is deep in a frustrating rabbit hole on Peter's side project, which borrows heavily from L1. Seb's last commit remains **2026-06-07**; the steward's own **2026-06-23** (`#175` N6, `/health` auth tiering). +- **mindfabric-00 was event-loop-pinned for 6+ days and nobody was looking.** 100% CPU, `/health` silent while port 3011 listened, PID 874 up 6d 9h. Same signature as the June pin, *after* the N6 fix. +- **Pin root-caused by profile, then by inspector — two hot paths, both June-named.** Main thread: `uv__run_timers` → `Statement::JS_all` (better_sqlite3 **synchronous** `.all()`) → SQLite btree traversal. CDP profile named them exactly: + 1. `runTemporalPipeline` → `checkForCycle` → **`getCausalEdgesFromSqlite`** (`storage-sqlite.ts:359`) — **99.8% of samples. FIXED (see below) → 6.0%.** + 2. `runTemporalPipeline` → `tryExtendChains` → **`getChainsContainingSeq`** (`storage-sqlite.ts:657`) — now dominant at **88%**. `SELECT * FROM causal_chain WHERE EXISTS (SELECT 1 FROM json_each(event_seqs) WHERE value = ?)` — a full scan of 813,178 chains, **measured 4.0 s per call**. **Unindexable as written**; needs `event_seqs` normalised into an indexed join table. Schema change ⇒ Seb's call. STILL OPEN. +- **`ANALYZE` had never been run in four months.** With no statistics, SQLite preferred `idx_caused_tombstoned` (a **boolean** index matching ~all 836k rows) over `idx_caused_from`. Every cycle-check query therefore scanned the whole edge table. `ANALYZE` on all 15 module DBs (4.4 s total) flipped the plan to `idx_caused_from`; microbenchmark **3.671 s → 0.573 s (6.4×)**; production profile 99.8% → 6.0%. +- **B1.1 fan-out cap is IMPLEMENTED AND WORKING — the code is not the problem.** `causal_edges_per_event_cap: 20` (`temporal/types.ts:201`), applied at `pipeline.ts:276`. Edges created **today: max in-degree exactly 20, avg 13.4, zero violations.** Edges created **pre-2026-06-23: max 629, avg 67.6, 4,677 nodes over cap.** +- **Therefore the defect is DATA, not CODE.** 836,467 edges / 813,178 chains were minted 2026-04-18 → 2026-06-23 under ungoverned fan-out. The fix landed *after* the damage, and the legacy graph taxes every future operation because `getChainsContainingSeq` scans all chains regardless of how disciplined new writes are. **This is why no ingest ever completed: cost per event grew with corpus size — divergent, not merely slow.** It also explains #65's "each attempt fails differently" — same wall, different points on the curve. +- **`coherence_evaluated = 0` of 813,178 chains — 0.00%, not one, ever.** June recorded "97%+ unevaluated"; it is now categorically zero. The epistemic layer that would prune chains has never executed. Separate from the pin; unfixed by the repair (a rebuild resets the count, it does not start the evaluator). +- **REPAIR RUN 2026-08-03 (steward-authorized).** `cm-ctl.sh repair --yes` — wiped `sqlite/ lance/ reasonchain/ perception/`, **preserved `logchain/` (145 MB, 109 files)**. Backup `mindfabric-00-20260803-wedged-preinvestigation` (1.4 G, 256/256 files, `quick_check: ok` ×4) taken **before** any change. Replay in flight, fan-out governed from the first event (`max_in=2, over_cap20=0`), **~10 nodes/min → ~33 h** for ~19,925 events. Finite now where it was divergent. Survives session end (launchd `com.capablemind.bettermemories`). **⚠ No `KeepAlive`** — a crash leaves it down silently. Steward has caffeine on indefinitely. +- **Other findings, unfixed:** **4,648 empty Lance index directories** under `vector_chunks.lance/_indices/` (4,653 dirs, 5 real), leaking ~40/day since April. **#176 confirmed in source** — `BackupOrchestrator.countUnprotectedEntries` returns `0` when `lastBackupSuccess` is null, i.e. never-backed-up reads as fully protected. +- **GH backlog swept** per Seb's own standing instructions (`#170`, filed 2026-04-23, **never delivered** — circle-forward push failed, GitHub fallback unread for 3½ months). Closed `#125` (superseded: vector storage moved to LanceDB) and `#151` (done by `4f5b870`); narrowed `#121` to its live second cause (latency baseline frozen after first N samples, `resource-monitor.ts:145`). +- **Pattern across the day:** governors exist and do not engage — coherence evaluation never run, `ANALYZE` never run, `countUnprotectedEntries` safe-cases an absence, drift-check 3-of-5 families inert, verification ladder 71-of-75 entries never cited. + +## Previous state (as of 2026-06-06 — superseded 2026-08-03) - **The reply arc is COMPLETE and the baton is with Seb.** Three notes pushed 2026-06-06 (CM-AI `b255e74` → `0ecb45e` → `2e87bab`): Tier A reply to his cover note (`b4daa71`) + same-day addendum + Tier B code-grounded read. Do not re-enter L1 until Seb responds or pushes — his move. - **mindfabric-00 root-caused**: found event-loop-pinned 4 days; CPU-profiled (proven, not inferred) to the temporal causal-chain path — `getChainsContainingSeq` `json_each` full scan over 272,172 chains per created link + chain-bloat feedback (new 2-node chain per no-extension) + uncancelled 30s timeout. Restarted clean; **re-wedge expected** as temporal re-encounters the dense pre-B1.1 graph (280k edges / 7,959 nodes, top fan-out 324); restart = holding pattern. Backup at `~/.capablemind/backups/mindfabric-00-20260606-prefix-state` (same-disk APFS clone, 224/224 verified). @@ -172,6 +188,14 @@ Each verified against `BetterMemories.io@3bc8b75` source. Re-verification agains ## Chronological log (most recent first; append substantive moves) +### 2026-08-03 — The wedge named, ANALYZE applied, rebuild in flight; the code was right and the data was not +- **Entered L1 against the standing baton rule, on explicit steward lift.** The session had first proposed a *clasp* build (M4 Pro as circle-inference clasp per 43L/43M) to unblock ingest — measured and abandoned: §4.13's 2000 ms budget vs 192 ms transatlantic RTT, and a benchmark of Qwen3.6-35B-A3B-8bit on the M4 (median 2927 ms for 150 tokens, ~92-token break-even). **The clasp was the wrong lever** — the instance was never inference-bound. Profiling the running process answered in five minutes what reasoning from specs had not. +- **Method that worked, and is the transferable lesson:** ask the machine, not the specs. `sample` → main thread pinned in a timer callback; SIGUSR1 → CDP inspector → exact JS frames; read-only row counts and `EXPLAIN QUERY PLAN` off a *backup copy*, never the live DB. +- Diagnosis, fix, verification and the repair: see **Current state** above. Health went from silent-for-6-days to **200 in 0.13 s**. +- **Corrections made in-session, recorded because they were load-bearing:** (a) hypothesised the `json_each` scan was the pin — it was the *second* path, masked by the cycle-check; (b) hypothesised `slice(0, undefined)` had made B1.1 inert — **wrong, the cap works perfectly**; (c) reported "never backed up" — false, four manual clones exist; `backup.last_success: null` refers to the *automated* pipeline only; (d) reported PENDING-82 not installed — wrong config surface, it has been installed in the Claude.app desktop config all along. +- **Steward framing to carry:** the distance from being away is what made this visible. *"Unless the time off gives us the necessary distance to identify what we couldn't see by being in too intensively."* Nothing found today needed cleverness; it needed someone to profile a running process and count rows in a table — which nobody does from inside the work, because from inside you reason about the code you just wrote. + + ### 2026-06-07 — Ops finding: training-loop Ollama client leaks connections, retries a hard-down dependency forever (A-class; note-don't-send) - **Trigger:** steward asked "why is ollama devouring my cpu?" Diagnosis: a two-failure pile-up. (1) The morning's brew upgrade to ollama 0.30.6 installed a **bottle with no `llama-server` runner** (known upstream: ollama#16535, homebrew-core#285917) — every model load 500'd after paying full setup cost. (2) **mindfabric-00 held 829 open TCP connections to Ollama** and re-sent `/api/chat` endlessly — requests 18s–2m47s in scheduler retry loops, ~50 POSTs per log window, for hours. No backoff, no circuit breaker, connections never released. Ollama serve at ~76% CPU with zero models loaded. - **The finding for Seb (joins the uncancelled-timeout family from the 06-06 CPU profile):** the training/graduation loop's Ollama client treats a hard-down dependency as transient indefinitely. A2.4 (degraded-environment refusal) is the constitutional shape; mechanically it wants: bounded retries with backoff, a circuit breaker on consecutive 5xx, and connection release on request failure. **Not sent — baton with Seb; relay at next exchange.** diff --git a/claude/memory/session-ledger-2026-08-03.md b/claude/memory/session-ledger-2026-08-03.md new file mode 100644 index 0000000..672eb8c --- /dev/null +++ b/claude/memory/session-ledger-2026-08-03.md @@ -0,0 +1,73 @@ +--- +name: Session Ledger 2026-08-03 +description: Practice-of-return ledger maintained by /symmetria — returns, open horizons, recalibrations, authorization moves, sub-agent dialogues, bypasses. +type: feedback +--- + +# Session Ledger — 2026-08-03 + +## Returns + +- **09:37 — named at wake, before any action.** The inherited pulling thread (CONTROL-A v2) was parked on a stated reason: *distance from the hand that concealed a defect inside that document*. The pause is 41 minutes. Naming this rather than opening the document, because a hold whose reason has not been satisfied is not discharged by the calendar rolling over. Surfaced to the steward as a judgment for them, not a decision I make. + +- **10:1x — prediction 2 fell, and the pre-registration made that usable.** I predicted `test_reduce.py`/`test_twin.py` would be fixture-based and silent about it. Both are property-derived and explicit. Because the prediction was on record, the miss became evidence about *where* decay lives (old instruments, not new) rather than something I could quietly not mention. +- **10:2x — declined to bank the happy result.** When the `fool/` population came out mostly sound, the pre-registration's own clause required testing "did I go lenient?" before accepting it. Testing it moved the census to the wake instruments, which is where the real finding was. + +## What held + +- Wake substrate-check fired correctly: `fool/` is at `~/dotfiles/claude/governance/fool/`, not the path I first guessed. Every artifact the wrap named is present (both kernels, both controls + tags + units, `twin-ledger.json` with `inherited_defects`, four test suites, three pre-registrations). Nothing half-edited. +- The 22 open authorization items were reported to the steward as **unverified against substrate**, per the wake's disposition-clause-is-not-a-status rule, rather than stated flat. + +## Open horizons + +- **CONTROL-A v2** — four defects, not two (jurist Findings 1 & 2 + candidates I2, I3). I3 attacks the conclusion at its root. Held on distance. +- **The literal question** — census of every gate in `fool/` and every verification-ladder entry: does it name the real artifact it was shown failing on, or does its absence look like coverage? Answerable now; needs no distance. +- **False-positive rate: still unmeasured after four attempts.** Prediction on record from the last wrap: a *fifth new reason* would stop being reassuring. +- Correlation 02 (formation-same pair: jurist vs executor) → PENDING-89. +- Skill-harvest register exceeds read caps; compaction owed. + +## Findings — census 01 (full result in `governance/fool/census-01-negative-instances-RESULT.md`) + +- **`governance-drift-check.py`: 3 of 5 check families are INERT against the current `~/CLAUDE.md`** (MCP-tools, hooks, horizons — 0 matches each). All controls pass; the hooks control sits inside its own `if` and does not run. The morning "0 substrate-contradicted claims" is honest about what it measured and silent about what it can no longer see. **[HARDENING] — owed to PENDING.** +- **New class named:** *a drift-checker keyed to a document's current wording goes inert when the document is improved.* Family 2 died because of the obligation-before-instrument rewrite — the rule that protects doctrine from instrument-decay silently retired its own watchman. +- **Path family silently skips any backticked path containing a space** — the Compass vault path is never checked. Exists today; a break would still report 0. +- **71 of 75 verification-ladder entries are cited by name nowhere outside the ladder** (grep positive-controlled first). Does NOT establish they never fire — establishes the record cannot distinguish firing from silence. Root cause: **ladder entries have no IDs**, so firing history is unrecordable by construction. +- **`~/PENDING.md`: PENDING-4 self-reports "Implemented and verified" and is counted OPEN** (digest recognises `(CLOSED)`/`COMPLETED` headers, not a body `**Status:**`). **ICP-19 Remit Expansion is recorded twice** (L74, L93 — same date opened, same requirement): a one-canonical-source violation. + +## Confidence to recalibrate + +- Drift to hold today: **removing a claim conceals the reliance** (earned yesterday, in my own hand). +- What compounded: **pre-registration written before the run** — stopped trial 04 repeating trial 03's fatal omission. + +## Authorization moves + +- **S-series closed, 22 → 16 open.** Steward delegated the choice (*"Which would you choose? This is tooling for you…"*) and ruled MemPalace-associated functionality retired. Acted on that as authorization for the three items already awaiting only a steward nod, and as a disposition for the two MemPalace-dependent ones. + - **S6 IMPLEMENTED** — Symmetria §3, six flags. + - **S7 IMPLEMENTED** — Symmetria §6, `suspend` outcome. + - **S9 IMPLEMENTED** — wrap-up §8, three tenses (Past and Present were wholly absent; Future was already complete). + - **S2 CLOSED, rebuilt as [FIX]** — `wake-digest.py` unwrapped-session detector, positive-controlled + discrimination-gated on real sessions (11 wrapped / 2 unwrapped). + - **S4, S5 WITHDRAWN** — retired with MemPalace. S4's concept harvested into the §3 flag; S5's race provably cannot recur. +- **Framing challenged rather than executed.** The steward asked me to *"prepare everything for the jurist."* The jurist had already ruled on all of Q1–Q5 on 2026-05-18 and had explicitly assigned the one open piece to the steward. Building the requested package would have spent the jurist on answered questions and dead mechanisms. Said so before building. +- **Not acted on, flagged for the steward:** PENDING-82 is installed (verified in the Claude.app desktop config), which also bears on PENDING-86. Both still counted open. Disposition is the steward's. + +### Dormant legacy against the repos — 16 → 10 open + +- **`betterMemories_app#170` is a standing instruction addressed to David's Claude Code, undelivered since 2026-04-23.** Its own body records why: circle-forward delivery failed (*"2 of 4 paired peers failed delivery with `fetch failed` — David's BMF was offline"*), and the GitHub copy was the durable fallback nobody read. It prescribes exactly this task (periodic backlog review; close/narrow/leave/supersede; verify before closing on someone else's evidence). **Three months of a channel failing open.** +- **PENDING-4 CLOSED** — verified against substrate, not from its own `Status: Implemented and verified` line. GH #120 and #133 closed; four corroborating commits. +- **PENDING-5 CLOSED** — resolved via GH #124/#135 + `bd1f650`. ⚠ **Class still open at #165** (H2 silent recall failure on battery, priority:critical) — closing the instance must not read as closing the class. +- **PENDING-11 / PENDING-12 CLOSED** — both ruled AUTHORIZED on **2026-03-23**. Two independent defects kept them open 4½ months: the REVIEWED blocks are **indented one space** (3 such orphans in the whole file, fence-tracked census), *and* their headers name no PENDING, so resolution-by-name finds nothing. `REVIEWED.md` is not mine to correct — flagged. +- **CD-03 CLOSED as a register entry** — its own status is OPERATIVE; it was a notification counted as an open constitutional decision for four months. Declaration untouched. +- **ICP-19 CLOSED as duplicate** — two records, one obligation, both dated 2026-04-07. +- **PENDING-10 is NOT dormant** — my classification was wrong; its 2026-08-02 amendment scopes it into the open #176 backup-pipeline audit. +- **Root cause, both halves:** the register and GitHub diverged. L1 work migrated to issues; `PENDING.md` kept March snapshots and no one reconciled. The governance half had the mirror problem — rulings existed, tooling couldn't see them. +- **Flagged, not fixed (Seb's territory):** `BetterMemories.io/CLAUDE.md` claims "embedded SurrealDB", says tests use in-memory SurrealDB, and lists `src/core/storage/surrealdb.ts` — which is absent. Dependency is `better-sqlite3`; **steward confirmed SurrealDB is legacy**. This also supersedes the premise of open issue **#125** (BM25 broken in SurrealDB 3.0.1). + +### Correction + +**Instrument error, self-caught mid-task.** I told the steward "80 of 158 REVIEWED headers are indented" — a ~27× overstatement produced by `^\s+## REVIEWED`, where `\s` matched the preceding newline and so counted every flush-left header. The fence-tracked census gives **3**. Third time in one day that a dramatic number from an uncontrolled instrument had to be walked back; the census I wrote this morning names exactly this failure and I still shipped the number before checking it. + +Earlier this session I reported PENDING-82 as "built, not installed", having checked **Claude Code's** MCP configs — the wrong surface for a jurist-facing server. Steward corrected. The right file (`~/Library/Application Support/Claude/claude_desktop_config.json`) has had it since it was built. + +## Sub-agent dialogues + +## Bypasses diff --git a/claude/skills/symmetria/SKILL.md b/claude/skills/symmetria/SKILL.md index a5cc838..7fb35c2 100644 --- a/claude/skills/symmetria/SKILL.md +++ b/claude/skills/symmetria/SKILL.md @@ -77,7 +77,10 @@ Notice these in your own writing or in code you read: - A claim asserted from a **derived or recalled form when the substrate is checkable** — a regex over derived text, a fuzzy-matcher hit read as membership, a soft classification where a checkable number/fact/test was producible, an answer from training where the banked record (docs, registers, prior briefs) already holds the considered answer, instructions re-derived instead of citing the governed doc, acting in a repo before reading its CLAUDE.md. Verify against the substrate first; produce the checkable claim; if it can't be produced cleanly, that inability is the finding. - **Completion is a tripwire** — the *feeling* of "done" (a fluent pass, a wall of green, a "finally", a closable-now bucket) is the cue to verify the tail, not the signal to ship. Ask which failure class each green check can actually *see*; reconcile any closed/complete claim against the authoritative source, not the derived close-list; treat the closable-vs-blocked partition as itself a claim to check. - **The say–do seam** — a record composed ahead of its acts (an Addendum/tracker/brief asserting APPLIED or DONE before the act ran); a grounding *quoted* but not *traced* (for each quoted clause, trace the plan's END-state against it — and one level deeper: which way does the inference run in the new state; is any class you named actually two kinds with opposite dispositions). Record after the act, or mark the record prospective. - +- **Applications of the time-the-task-requires principle** — the Directive elaboration made constitutional in `~/CLAUDE.md`, at the discipline level: **lectio** (reading a corpus faster than the corpus asks); **diagnose-don't-fix** (patching the instance before tracing the class); **dwell-on-composition** (giving a recommendation the time the executor wants it to take rather than the time it wants). +- **An alignment pulse returning `aligned` without naming a specific tension** — premature closure wearing the form of a check. +- **A search query shaped by what the session wants to find** rather than by what it needs to find — the result set is then evidence about the query, not about the substrate. +- **Post-compression confidence claims** — the working memory was trimmed; what feels certain now may rest on what was lost. Say what was inherited versus what was re-verified. When you notice one, name it. In chat, in the ledger, or both. Don't accumulate observations for "a good moment" — there is no good moment, only now. @@ -160,7 +163,8 @@ Any failure → annotate and re-query. 3. Walk the three dimensions. 4. Walk calibration (confidence, uncertainty). 5. Flag any contamination patterns visible. -6. Recommend: proceed | return-and-reframe | escalate. +6. Recommend: proceed | return-and-reframe | **suspend** | escalate. + - **`suspend`** — the work is right and not urgent, but it needs unhurried steward judgment. Distinct from `escalate` (which carries urgency) and from `return-and-reframe` (which says the work is wrong). *The time the steward's judgment requires is task-time, not interruption-time.* Name what is being suspended and what would resume it. 7. If anything was caught, log a return to the ledger. ### `audit-agent` diff --git a/claude/skills/wrap-up/SKILL.md b/claude/skills/wrap-up/SKILL.md index 1856fa7..e351d51 100644 --- a/claude/skills/wrap-up/SKILL.md +++ b/claude/skills/wrap-up/SKILL.md @@ -212,13 +212,24 @@ Produce a brief summary for the steward: ``` ## Wrap-up — [date] +### Future — what pulls **Pulling thread:** [the singular concern] **Actionable resumption point:** [where things concretely stand + the candidate first move toward the thread, as of wrap — to confirm or revise against what changed. The thread is the direction; this is the first step.] **Question we're leaving open:** [the literal question for next-Claude] **Pause statement:** [explicit acknowledgment that the work is being paused; what is wanted-to-find-still-pulling on return. The ligature is laid at departure, not discovered at return — this field is constitutive, not optional.] + +### Past — what moved, and why +**What happened:** [the session's substantive moves, each with the reason it was taken — not a task list. What a reader needs to reconstruct the session's shape.] +**What held:** [which disciplines, gates or predictions were applied and did their work. A practice that is never observed working is not known to work.] +**What was corrected:** [claims retracted, framings the steward or jurist overturned, instruments found unsound — or "none". Corrections are the session's most perishable output.] + +### Present — how it stands +**The mood:** [the Stimmung — what this session felt like from inside, and what that signals. Carried because confidence and unease both travel across the pause.] +**Confidence to recalibrate:** [what is being claimed at what confidence, and specifically what was verified versus inherited.] **Decisions deferred (and why):** [the negative space — what was chosen-not-to-do this session, and the reason. Absent this field, the unborn session cannot know the scope of what was held back.] **Skill harvest:** [skill create / patch / retire proposals surfaced this session (§1.6), each as a proposal for steward authorization — or "none". Never an autonomous skill edit.] +### Restoration material **Session captured:** [memory file path] **KG appended:** [count of lines appended to knowledge-graph.jsonl, or "none"] **Uncommitted work:** [list or "none"] @@ -230,7 +241,9 @@ Produce a brief summary for the steward: [Any warnings or things to address before closing] ``` -The pulling thread + question are first because they are what *waking* needs to inherit. The rest is restoration material. +The three tenses mirror the session memory file (§2), so the output and the durable record no longer disagree about what a session consists of. **Future leads** — inverting the memory file's narrative order — because the thread and the question are what *waking* inherits; the steward reads this at departure, but it is written for arrival. + +A template that drops a tense under compression is itself an instance of the failure mode the Directive elaboration names. ## Important constraints diff --git a/scripts/wake-digest.py b/scripts/wake-digest.py index 490fa40..e3bf042 100755 --- a/scripts/wake-digest.py +++ b/scripts/wake-digest.py @@ -132,6 +132,82 @@ def sec_pause(): return newest, span +def wrap_records(): + """Wrap records only — session-ledger-*.md is a Symmetria artifact, not a wrap.""" + return [os.path.join(MEM, f) for f in os.listdir(MEM) + if f.startswith("session-") and not f.startswith("session-ledger-")] + + +def transcript_span(path): + """ + A session's true span, from the timestamps INSIDE the transcript — never mtime. + mtime says when the file was last touched; it cannot say when the session ran. + Returns (first_epoch, last_epoch), or (None, None) if unreadable. + """ + first = last = None + try: + with open(path, errors="ignore") as f: + for line in f: + m = re.search(r'"timestamp"\s*:\s*"([0-9T:\-]{19})', line) + if m: + if first is None: + first = m.group(1) + last = m.group(1) + except OSError: + return None, None + + def epoch(s): + try: + return time.mktime(time.strptime(s, "%Y-%m-%dT%H:%M:%S")) + except (ValueError, OverflowError): + return None + return epoch(first), epoch(last) + + +def wrap_inside(span, wrap_mtimes, lead=300, lag=900): + """Did a wrap record get written inside this session's span?""" + a, b = span + if a is None or b is None: + return None # unreadable — not the same as 'no wrap' + return any(a - lead <= m <= b + lag for m in wrap_mtimes) + + +def sec_unwrapped(): + """ + PENDING-S2's obligation, rebuilt on our own substrate. + + A session that ends without /wrap-up writes no memory file, so `Last wrap` + — computed from mtime — silently reports the session BEFORE it, and the + thread below is inherited from the wrong session. The original proposal + detected this via a MemPalace Stop hook; that hook is retired, but the + failure it named is live. The transcripts are the only witness that a + session ran at all. + """ + proj = os.path.dirname(os.path.join(HOME, ".claude", "projects", + "-Users-davidglidden", "memory")) + try: + tx = [os.path.join(proj, f) for f in os.listdir(proj) if f.endswith(".jsonl")] + except OSError: + return None + now = time.time() + # The current session's transcript is being appended right now; the previous + # session's is the newest one that has gone quiet. + prior = [p for p in tx if now - os.path.getmtime(p) > 60] + if not prior: + return None + last = max(prior, key=os.path.getmtime) + verdict = wrap_inside(transcript_span(last), + [os.path.getmtime(w) for w in wrap_records()]) + if verdict is None or verdict: + return None + ended = time.strftime("%b %d %H:%M", time.localtime(os.path.getmtime(last))) + return (f"⚠ PREVIOUS SESSION DID NOT WRAP (ended ~{ended}). The thread and " + f"question below are inherited from an OLDER session — treat them as " + f"possibly stale, and expect no record of what that session did.\n" + f" Not established: whether that session did work worth keeping. The " + f"transcript is on disk and can be read if the gap matters.") + + def ruled_pendings(reviewed_text): """ The set of PENDING ids that rulings actually DISPOSE OF. @@ -539,6 +615,28 @@ def selftest(): not is_homed(os.path.join(MAPS_DIR, "README.md"), MAPS_DIR)) chk("is_homed FALSE for a symlink pointing OUTSIDE maps/", not is_homed(os.path.join(HOME, ".claude"), MAPS_DIR)) + print("\nunwrapped-session detector [PENDING-S2's obligation, our substrate]:") + chk("wrap_inside TRUE when a wrap falls inside the span", + wrap_inside((1000.0, 2000.0), [1500.0])) + chk("wrap_inside TRUE for a wrap just after the last write [wraps land near the end]", + wrap_inside((1000.0, 2000.0), [2400.0])) + chk("wrap_inside FALSE when every wrap is outside [negative control]", + not wrap_inside((1000.0, 2000.0), [500.0, 5000.0])) + chk("wrap_inside returns None on an unreadable span [must NOT read as 'no wrap']", + wrap_inside((None, None), [1500.0]) is None) + # Discrimination on REAL sessions: the detector must return BOTH verdicts over + # the actual transcript history. One verdict everywhere = it discriminates nothing. + _proj = os.path.dirname(MEM) + _tx = sorted((os.path.join(_proj, f) for f in os.listdir(_proj) + if f.endswith(".jsonl")), key=os.path.getmtime)[-14:-1] + _wm = [os.path.getmtime(w) for w in wrap_records()] + _v = [wrap_inside(transcript_span(p), _wm) for p in _tx] + chk(f"real sessions read as WRAPPED [{sum(1 for x in _v if x is True)} of {len(_v)}]", + any(x is True for x in _v)) + chk(f"real sessions read as UNWRAPPED [{sum(1 for x in _v if x is False)} of {len(_v)}]" + " — the negative instance; without one the detector is unproven", + any(x is False for x in _v)) + print("\nlive substrate:") chk("PENDING.md readable", read(PENDING) is not None) chk("REVIEWED.md readable", read(REVIEWED) is not None) @@ -557,6 +655,9 @@ def main(): o = ["=== WAKE DIGEST (computed now — not a stored snapshot) ==="] o.append(f"Last wrap: {span} ago ({newest})" if span else "Last wrap: UNKNOWN") + unwrapped = sec_unwrapped() + if unwrapped: + o.append(unwrapped) if th: o.append(f"\nPULLING THREAD — {th}") if q: