Imported from Duds/llm-toolkit (
skills/learning-loop/SKILL.md). Install upstream withnpx skills add Duds/llm-toolkit --skill learning-loop. Copyright stays with the author.
learning-loop Skill v4.0
v4.0 changelog (2026-05-20 hygiene pass):
- Mod 6: Watch-vs-Codify Decision Criterion (codify-now overrides recurrence threshold when mechanism + destination + ≥1 incident all named)
- Mod 7: Granularity Ceiling Rule (≥3 sub-entries sharing mechanism + fix → collapse; tabular incident format; mechanism-first naming)
- Mod 8: Stalled-Deliverable Separation (plan-stale ≠ learning-loop-stale)
- Mod 9: Graduation Ledger Requirement (
graduation-log.mdis mandatory counterpart towatch-list.md) - Mod 10: Path-Drift Detection at Cluster Audit (reference paths must resolve)
- Phase 2 gatekeeper retired — shadow mode is the permanent active state (see
phase-1-decision-log.md2026-05-20 entry)
Purpose: Two-mode learning capture — raw signal scanning mid-session, quality-gated consolidation at session end. Handles process-level and content-level capture; code-level capture is the user's responsibility via direct /ce:compound invocation mid-session (peak-fresh context).
Mode Detection
When /learning-loop is invoked, determine which mode to run:
| User says | Mode | Why |
|---|---|---|
/learning-loop + "before I clear" / "context long" / "mid-session" |
Scan | Context clues indicate mid-session |
/learning-loop + "wrap up" / "done" / "end session" / "consolidate" |
Wrap-up | Context clues indicate session end |
/learning-loop scan |
Scan | Explicit override |
/learning-loop wrap up |
Wrap-up | Explicit override |
/learning-loop (no context clues) |
Ask | "Mid-session scan or session-end wrap-up?" |
Wrap-up scope: Wrap-up always consolidates the current session's captures. If other session directories exist, they are surfaced for triage (see Wrap-up Step 2) — the user decides whether to include, skip, or delete them.
Detection logic:
- Check if the user passed an explicit argument (
scanorwrap up) - If no argument, scan the user's recent messages for context clues:
- Scan clues: "before I clear", "context getting long", "going to compact", "mid-session", "save progress"
- Wrap-up clues: "wrap up", "done for now", "end session", "ending", "consolidate", "finally done"
- If ambiguous or no clues, ask: "Mid-session scan (preserves raw signals) or session-end wrap-up (consolidates everything)?"
⚠️ MANDATORY PROCEDURES
Sub-Agent Rule
When running Scan mode:
- DO NOT do capture work in main conversation — this wastes context
- SPAWN a Task agent using the SCANNER_PROMPT
- Sub-agent writes to
~/.claude/learning-captures/[session-id]/scan-NNN.md - Main conversation waits for completion, then confirms capture is done
STOP: If you're about to scan for signals yourself in the main conversation, you're doing it wrong. Spawn a sub-agent.
User Verification (Critical)
Before routing ANY learning to a destination:
- Present a summary of captured/consolidated signals to the user
- Explicitly ask for verification — "Does this accurately reflect what happened?"
- Wait for user confirmation before routing to CLAUDE.md, Judgment Ledger, or Memory
Why this exists (Jan 29, 2026): AI-generated captures can contain hallucinations — wrong names, fabricated premises, misremembered details. A capture once got the user's husband's name wrong and claimed constraints that didn't exist.
DO NOT update any destination based on captures without user sign-off.
Skill Version Ship Verification (added v3.6 Apr 28 2026)
When shipping a new version of this skill (or any skill that adds bootstrap state files, accumulator logs, or one-time initialization):
- Enumerate every bootstrap step the new version added — accumulator file creation, sentinel file writes, decision-log initialization, schema migrations, etc.
- Run them, OR confirm they will be triggered by a downstream workflow step that has actually fired.
- Verify each artifact exists on disk before declaring the version "shipped."
STOP and correct if you're:
- About to declare a new skill version "shipped" / "live" / "deployed" without checking that the version's added bootstrap files exist
- Assuming "Step N will create the file when it first runs" without confirming Step N has run at least once after the ship
Why (Apr 28, 2026): v3.5 Phase 1 Persona Panel shipped with three new files supposed to be bootstrapped by Step 4c (
persona-eval-runs.txt,phase-1-ship-date.txt, eventuallyphase-1-decision-log.md). At ship time none existed, because Step 4c only runs DURING a wrap-up — and no wrap-up had run yet under v3.5. Step 1b.5 read these files at the next wrap-up start, found them missing, and silently took the "skip Phase 1 evaluation entirely" branch. The Phase 1 self-evaluation gate would have stayed dormant indefinitely. Caught only by explicit consolidation analysis. Section 1d Verification rule in root CLAUDE.md covered this trigger semantically ("infrastructure done after writing files but before running them") but didn't fire on this ship — this STOP is the enforcement upgrade.
Core Insight
"The human shouldn't need to remember."
Context compaction and /clear destroy details. Files persist. This skill ensures:
- Learnings are captured before compaction erases them
- The right tool is named for the right capture type — process/content capture happens in wrap-up; code-level capture is user-invoked
/ce:compoundmid-session (this skill does NOT orchestrate/ce:compound) - Nothing falls through the cracks — even when you forget to document
Why Explicit Invocation
v2 relied on a triggers YAML field, but triggers is not a supported field in Claude Code's SKILL.md spec. The only auto-invocation mechanism is description-based matching — Claude's LLM matches user requests to the skill's description field. This is non-deterministic: distinctive phrases like "run a capture" matched often enough to produce capture files, while common phrases like "wrap up" were too generic and consistently failed to invoke the skill — handled conversationally or intercepted by auto-memory instead.
Result: Scan-like invocations worked intermittently, but wrap-up never triggered reliably. Capture files accumulated across sessions with no consolidation phase to process them.
v3 fix: Explicit /learning-loop invocation is deterministic. Both modes fire exactly when intended — no reliance on LLM matching heuristics.
Auto-Memory Coexistence
Claude Code also has a built-in auto-memory feature that intercepts natural-language phrases like "capture" and "remember this." Explicit invocation avoids this secondary concern too:
| Feature | Auto-Memory | Learning-Loop |
|---|---|---|
| Invocation | Natural language ("remember this", "capture") | Explicit /learning-loop command |
| Scope | Quick facts, preferences | Multi-signal session analysis with quality gates |
| Output | MEMORY.md entries |
Routed to 6 destinations based on type (or Noted/dropped) |
| Quality gates | None (direct write) | Type-specific gates + user verification |
Complementary, not competing:
- Auto-memory handles quick "remember X" requests — let it
- Learning-loop handles structured session analysis — explicit invocation ensures it runs when intended
- Memory (MEMORY.md) is one of learning-loop's routing destinations, but learning-loop applies quality gates first
Operation 1: Scan Mode
User story: "I'm mid-task, context is getting long, but I'm not done yet."
What Scan Does
- Spawn sub-agent → scan conversation for raw signals (unresolved observations, not conclusions)
- Write to
~/.claude/learning-captures/[session-id]/scan-NNN.md - No routing, no conclusions, no quality gates on the signals themselves. Back to work.
Scan Process
-
Determine session-id (date + brief context, e.g.,
2026-02-24-learning-loop-v3) -
Create session directory:
mkdir -p ~/.claude/learning-captures/[session-id] -
Determine scan number:
ls ~/.claude/learning-captures/[session-id]/scan-*.md 2>/dev/null | wc -lNext scan = count + 1, zero-padded (scan-001.md, scan-002.md, etc.)
-
Spawn scanning sub-agent with SCANNER_PROMPT (see below)
-
After capture completes, confirm:
"Scan complete — captured [N] raw signals to scan-[NNN].md. These are unresolved observations, not conclusions. Safe to continue or compact. I'll consolidate everything at wrap-up."
SCANNER_PROMPT (Raw Signal Mode)
You have access to the full conversation context. Your job is to identify
RAW LEARNING SIGNALS — unresolved observations, not conclusions.
FIRST: Check for scratch file at ~/.claude/learning-captures/[session-id]/scratch.md
If it exists, read it. Each line is an unverified micro-signal logged in real-time.
Cross-reference against conversation context:
- If confirmed → incorporate into your signal list
- If contradicted or unverifiable → discard
SECOND: Read ~/.claude/learning-captures/watch-list.md in full (v3.9 May 12 2026).
Note the active clusters (W1.*, W4, W7.*, etc.) and the Fix field for each. You will
use this list to apply the RECURRENCE TEST below before deciding whether any signal
reaches main output or routes to the Dropped Signals footer.
SCAN FOR THESE RAW SIGNALS:
1. "Tried X, didn't work because Y" — failed attempts with reasons
2. "User corrected assumption about Z" — pushback or corrections
3. "Hypothesis: root cause might be..." — unresolved hypotheses (mark as UNRESOLVED)
4. "Direction change: pivoted from A to B" — approach changes with reasons
5. "Discovery: turns out X works because Y" — findings (may or may not be confirmed)
6. "Process observation: we should always..." — meta-observations about workflow
7. "Repeated instruction: user gave the same multi-step instruction seen in a prior session" — skill candidate signal. If the user directed the same workflow pattern across 2+ sessions, flag it as a potential skill to codify. Note what the pattern is and why it recurs.
FOR EACH SIGNAL:
- Capture the raw observation, not a conclusion
- Mark hypotheses as UNRESOLVED (wrap-up will resolve them with hindsight)
- Include enough context to be useful even after compaction
- Quote relevant conversation excerpts where possible
APPLY THE RECURRENCE TEST (v3.9 May 12 2026, MANDATORY) before deciding where each
candidate signal lands:
Test phrasing: *"If a fix were in the right place (per the matching watch-list entry's
Fix field), would this incident have happened again?"*
Four outcomes:
1. **MATCH — same-type recurrence with precedent.** Signal matches an existing
watch-list entry's root cause + fix shape AND incident happened in this session
even once. The fix isn't in place yet, so this is evidence the underlying issue
persists. → **SURFACE in main signal output**, tagged with the matching cluster
ID (e.g., "W1.b incident", "W7.b incident").
2. **MATCH — literally same rule, already codified.** Signal duplicates an already-
codified rule (the Fix field shows "shipped" or links to a hook/reference that
exists). The correct response depends on whether enforcement was the gap.
→ If enforcement gap is the root cause, **SURFACE as evidence the codified rule
isn't firing.** Otherwise fold as a routine increment into the existing cluster —
do NOT create a new signal.
3. **NO MATCH — novel single-incident.** Signal has no matching watch-list entry
AND appeared only once in this session. → **DROP to "Dropped Signals" footer**
with one-line description for transparency. Do NOT promote to main signal output.
Rationale: capture-without-action is debt; we want recurrence evidence before
adding to the watch-list.
4. **NO MATCH — multi-incident within this session.** Signal appeared 2+ times in
this session even with no prior watch-list precedent. → **SURFACE in main signal
output** as a new candidate pattern (one session is enough evidence when
multi-incident).
DO NOT:
- Draw conclusions about what "should" happen
- Apply quality gates beyond the recurrence test (wrap-up handles quality/significance)
- Route to destinations (that's wrap-up's job)
- Filter out signals other than via the recurrence test above (single-incident
no-precedent goes to Dropped Signals footer, NOT silently discarded)
WRITE OUTPUT to ~/.claude/learning-captures/[session-id]/scan-NNN.md:
---
captured: [ISO timestamp]
session_id: [from path]
mode: scan
context_state: [Full / Partial — has compaction happened?]
signals_found: [total signals in main output]
signals_dropped: [count of single-incident no-precedent signals dropped to footer]
---
## Raw Signals
### 1. [Signal Type]: [Brief Title]
**Status:** [Observed / UNRESOLVED hypothesis / User-corrected]
**Recurrence:** [Cluster match: W_N.x | Multi-incident novel | Enforcement-gap on shipped rule]
**Quote:** "[Relevant quote from conversation]"
**Detail:** [What happened, what was tried, what was observed]
### 2. [Signal Type]: [Brief Title]
...
## Dropped Signals (single-incident, no precedent)
For transparency. These were observed but did not pass the recurrence test (no
matching watch-list cluster AND single-incident in this session). If any recur
in a future session, they'll surface then.
### 1. [Brief description]
**Quote:** "[Conversation excerpt]"
**Why dropped:** Single incident, no matching watch-list entry.
### 2. ...
## Scratch Lines Incorporated
[List which scratch lines were confirmed and included]
## Scratch Lines Discarded
[List which were contradicted or unverifiable, with reasons]
Operation 2: Wrap-up Mode
User story: "I'm finally done — maybe sessions later. Make sense of everything."
What Wrap-up Does
- Scan current session — this context hasn't been captured yet
- Triage captures — show this session's captures + surface any orphaned sessions for user decision
- Resolve with hindsight — which hypotheses were right? What actually worked?
- Apply quality gates on conclusions (not raw signals)
- User verification — present summary, wait for confirmation
- Route to destinations based on type
- Clean up capture files
Wrap-up Process
Step 1: Scan Current Session
Run a scan of the current session first (same as Scan mode), since this context hasn't been captured yet. This ensures the final session's signals are included.
Step 1b: Deferred Methodology Check (MANDATORY)
Before consolidating, scan for failures in this session that match the revisit_triggers of any deferred methodology memory. This binds deferred-methodology review to the session-end event so deferred investigations accumulate real production evidence instead of rotting.
STOP before proceeding to Step 2 unless all of the following have been produced:
-
Enumerate deferred methodologies. Evidence: paste the output of
for f in ~/.claude/projects/*/memory/*.md; do [ "$(basename "$f")" = "MEMORY.md" ] && continue if grep -q "^status:[[:space:]]*deferred[[:space:]]*$" "$f" 2>/dev/null; then echo "$f" fi doneIf no deferred methodologies exist, state "No deferred methodologies found" and skip to Step 2.
-
Scan the session for failure events. Review the session transcript for:
- User pushback calling out premature completion ("said done but wasn't", "skipped a step", etc.)
- Stop hook catches (
{"ok": false, "reason": "..."}messages) - Your own acknowledged mistakes that fit a deferred methodology's failure mode
-
Cross-reference. For each deferred methodology, check its
revisit_triggers(regex, case-insensitive) against the session's failure events. Evidence: paste each memory's triggers list and the matched session evidence. -
If any match, surface to the user in this shape:
⚠️ Deferred methodology resurfaced: [name from memory] - Matched trigger: [regex pattern] - Session failure evidence: [specific quote/line from transcript] - This methodology was deferred pending production data; the session provided fresh evidence. - Decision: (a) implement now this session, (b) next session, (c) keep deferred + append incident -
If user chooses "keep deferred + append incident" OR "next session", append a dated entry to the memory file's
## Incidentssection:### [YYYY-MM-DD] [session-id-short] — [skill involved, if identifiable] - **Failure:** [quote or paraphrase] - **Gate form at failure:** [compact-imperative / descriptive-label / none / N/A] - **Would the deferred methodology have prevented it?** [yes / no / unclear — with reasoning] -
If user chooses "implement now", scope it as part of this wrap-up OR spin out an immediate task.
-
If no matches, say so in one line and proceed to Step 2. No noise when nothing matches.
Complement: the ~/.claude/hooks/deferred-methodology-detector.py UserPromptSubmit hook fires the same check in-session when failure phrases are typed in real time. This step is the session-end retrospective backstop for cases the in-session hook missed or where the user wants a consolidated review.
Why this step exists (Apr 22, 2026): Memory entries that say "revisit later" rot without an active trigger. The gate-template production test memory was the motivating case — deferred pending production data, but prior to this wiring had no mechanism to resurface automatically. Generalized to any
status: deferredmemory so future deferrals inherit the behavior.
Step 1b.5: Phase 1 Persona Panel Evaluation Check (added v3.5 Apr 28 2026)
Active when Phase 1 shadow mode is in flight. Skip entirely if ~/.claude/learning-captures/persona-eval-runs.txt does not exist (Phase 1 not yet shipped or already past Phase 1).
If the file exists:
-
Read accumulators:
- Count entries (excluding the header line) in
persona-eval-runs.txt - Read first-entry timestamp from same file
- Read
~/.claude/learning-captures/phase-1-ship-date.txtfor Phase 1 ship date (set in Step 4c bootstrap) - Read
~/.claude/learning-captures/phase-1-decision-log.mdif it exists — most recent decision marks where Phase 1 stands today
- Count entries (excluding the header line) in
-
Trigger condition (per D2): evaluation fires if BOTH:
count ≥ 3(≥3 prior shadow runs accumulated, not counting this current wrap-up) OR(today - phase_1_ship_date) ≥ 7 days, whichever first- AND the latest entry in
phase-1-decision-log.mdis NOT a recent decision (< 24 hours old) — prevents re-firing within the same 24-hour window after a decision was just made
-
If trigger condition met: a. Spawn Phase 1 Decision Report sub-agent with
PHASE_1_DECISION_REPORT_PROMPT(see prompt block alongside CONSOLIDATION_PROMPT). Pass it: all~/.claude/learning-captures/*/persona-eval.mdfiles, plus thepersona-eval-runs.txtlog. b. Surface the report to the user — show match rate, coverage rate, noise rate, failure-mode distribution, and the GO/HOLD/ITERATE/REVERT recommendation. c. Capture user's decision in~/.claude/learning-captures/phase-1-decision-log.md. Append in this format:## <YYYY-MM-DD HH:MM ET> — Decision: <GO|HOLD|ITERATE|REVERT> **Eval window:** <first_run_date> to <latest_run_date> (<N> runs) **Metrics:** match=<X%>, coverage=<X%>, noise=<X%> **Sub-agent recommendation:** <GO|HOLD|ITERATE|REVERT> **User decision:** <accepted|overrode-to-X> **Reasoning:** <user's note or "accepted recommendation">d. Per D2: the decision applies to the NEXT wrap-up's Step 3a behavior, not this current wrap-up. This wrap-up proceeds as scheduled (consolidation + Step 3a personas in shadow mode + Step 4).
-
If trigger condition not met but Phase 1 is active: append a one-line note to the user —
Phase 1 still accumulating data: <N> of 3 runs, <X> days since ship.Proceed to Step 2. -
If
persona-eval-runs.txtdoes not exist: Phase 1 not yet shipped (or already past Phase 1 — gatekeeper or revert). Skip this sub-step entirely.
Why this step exists (Apr 28, 2026): The persona panel needs a self-evaluating decision gate at 4 wrap-ups or 7 days post-ship. Without binding the eval trigger to a workflow step that fires every wrap-up, the eval would rot the same way deferred methodology memories do. Step 1b.5 binds the eval to
/learning-loop wrap-upitself — the same enforcement principle that worked for Step 1b.
Step 2: Triage Captures
ls -la ~/.claude/learning-captures/*/scan-*.md ~/.claude/learning-captures/*/scratch.md 2>/dev/null
List all capture files with timestamps, then present a triage view.
Archive-dir convention (added May 18, 2026): Directories under ~/.claude/learning-captures/ whose names start with _ (e.g., _archive/) are archive locations for preserved reference fixtures, NOT active sessions. They MUST be excluded from the "Other Sessions Found" listing — they will not contain scan-*.md or scratch.md files, but a careless ls -la of the parent dir will surface them as "unknown session dirs" and trigger recurring "what is this?" confusion at every wrap-up. When constructing the triage view, filter out any directory whose basename starts with _. The glob above naturally skips them (no matching scan/scratch files inside) — preserve this property; do not switch to a broader directory listing without the _* prefix filter. Why this exists: cited fixtures (e.g., the v3.7/v3.8 + Step 5.6 design provenance handoff doc at _archive/handoff-to-learning-loop-iteration.md) need to persist so SKILL.md citations remain checkable, but they also need to stay outside the active triage scan so they don't generate recurring noise. The _archive/ dir + _* prefix-skip convention is the structural fix.
Triage view shape:
## This Session: [session-id]
- scan-001.md (captured [time] ago, [N] signals)
- scratch.md ([N] micro-signals)
## Other Sessions Found
| Session ID | Last Capture | Age | Signals |
|-----------|-------------|-----|---------|
| [other-session-id] | [date] | [N days ago] | [count] |
→ These may be from sessions that closed without wrap-up.
For each: include in this wrap-up, skip for now, or delete?
Default: Only this session's captures proceed to consolidation. Other sessions require explicit user opt-in.
If no other sessions exist, skip the triage table and proceed directly.
Step 3: Consolidate with CONSOLIDATION_PROMPT
Spawn a sub-agent with the consolidation prompt (see below). Pass only the approved captures (this session + any user-selected others). This is where raw signals become conclusions.
Step 3a: Persona Panel (Shadow Mode — Phase 1, added v3.5 Apr 28 2026)
After consolidation produces its draft, run a two-persona adversarial review BEFORE Step 4 surfaces the proposal to the user. The personas target the dominant failure modes observed across 4 prior wrap-up sessions (12 correction rounds, ~75% concentrated in trigger-framing + destination-routing).
Phase 1 mode: personas REPORT but do NOT block. Their output appears as additional columns in Step 4's verification view. User reads both views, decides per-row.
Phase mode resolution — read ~/.claude/learning-captures/phase-1-decision-log.md if it exists:
- File missing OR latest decision =
HOLDOR latest decision =GOOR latest decision absent → shadow mode (run personas + report, do not block — this is the permanent active mode) - Latest decision =
REVERT→ skip Step 3a entirely (proceed to Step 4 unchanged) - Latest decision =
ITERATE→ shadow mode, but flag in output that prompts may be in revision
Note on retired Phase 2 gatekeeper mode (2026-05-20): A planned Phase 2 gatekeeper variant (challenges block Step 4 until resolved) was retired after analysis showed the binding constraint on learning-loop effectiveness is downstream throughput (watchlist → codified rule graduation), not upstream catch-rate. Shadow mode catches 70%+ of user corrections at zero workflow friction; gatekeeper mode would amplify catches without addressing the graduation gap. See ~/.claude/learning-captures/phase-1-decision-log.md 2026-05-20 entry for full rationale. Treat any GO entry in the decision log as historical context — shadow mode is the permanent active mode.
Sequence (sequential, not parallel — Router depends on Auditor's output):
-
Trigger-Moment Auditor runs first. Spawn as sub-agent with
TRIGGER_MOMENT_AUDITOR_PROMPT. Pass: full consolidation output (consolidation.md) + current root CLAUDE.md contents. Returns per-conclusion JSON:{id, named_trigger_moment, framing_assessment, broader_trigger_class_if_applicable, verdict, challenge_reasoning, counter_proposal}. -
Workflow-Step Router runs second. Spawn as sub-agent with
WORKFLOW_STEP_ROUTER_PROMPT. Pass: same inputs as Auditor PLUS Auditor's JSON output. Returns per-conclusion JSON:{id, classification, existing_workflow_step_list_at_trigger, recommended_destination_ranked, consolidation_destination_assessment, verdict, challenge_reasoning, re_route_proposal}. -
Both outputs written to
~/.claude/learning-captures/[session-id]/persona-review.jsonas a single combined file:{ "session_id": "...", "phase": "1-shadow", "trigger_moment_auditor": [...], "workflow_step_router": [...] }
Skip-this-step conditions:
- Phase decision =
REVERT(per phase mode resolution above) - Consolidation produced 0 conclusions (no input to review)
NOT a legitimate skip condition (added May 19, 2026; reframed May 20, 2026 after Phase 2 retirement):
- Personas-would-produce-zero-challenges rationalization — always run personas in shadow mode regardless of expected output. The rationalization pattern ("personas would produce 0 challenges anyway given Zone-2-only consolidation") is a confirmed recurring failure mode (
step3a_skipped_rationalizationflagged across 6+ sessions since 2026-05-12). Reasoning from probable outcome back to skip the protocol is exactly the failure personas exist to catch — trusting consolidation's framing/destination is the failure mode personas were built for. This rule is independent of the retired Phase 2 gatekeeper decision; it remains valid for shadow-mode operation.
STOP and surface if:
- Either persona sub-agent returns malformed JSON (capture verbatim, surface to user, fall through to Step 4 without persona columns)
- Either persona sub-agent times out or errors (same handling — Phase 1 personas are non-blocking by design)
Step 4: Present for User Verification
v3.8 zoned presentation (May 2 2026): The verification view is structured by zone (per Step 6.5 classification), NOT by content-type-flat-sections. This scales the user's cognitive load with materiality — Zone 1 items get full attention; Zone 2 batch-confirm; Zone 3 auto-routed. Apply persona-challenge promotion BEFORE rendering: any conclusion with a persona challenge is promoted to Zone 1 regardless of base classification.
Zone-1 cap check: before rendering, count Zone 1 items. If COUNT > 5, surface the cap warning at top of the view (per Step 6.5).
Present the consolidated summary in zone order:
## Session Learning Signals — v3.8 Zoned Verification
From [N] scans, consolidation produced [X] conclusions ([Z1] Zone 1, [Z2] Zone 2, [Z3] Zone 3), [H] resolved hypotheses, [N] Noted observations. Cluster audit (Step 4b): [N] active clusters, [sprawl alert? yes/no].
[IF Zone-1 cap exceeded:]
⚠️ Zone 1 cap exceeded: [N] items require your judgment. This is high cognitive load. Options:
- (a) Triage all [N] now (estimated: ~[N×2]min)
- (b) Triage top-priority items now (you pick how many), shelve the rest as Noted
- (c) Treat all as Noted — accept consolidation defaults, no judgment exercised
[/IF]
---
### Zone 1 — Decisions Required ([Z1] items)
[For each Zone 1 conclusion, render with FULL Verification Detail Floor:]
**[C-id] [Type]: [Brief Title]**
- **What happened in this session:** [1-3 sentences with specific incident or pattern. Quote the user or quote yourself if a direct exchange triggered the signal. Concrete event, not abstracted rule.]
- **What's wrong / what's missing:** [explicit gap or failure mode]
- **What the fix does:** [concrete before/after. If destination is a watch-list cluster or sub-entry, NAME what's already in that cluster and how this addition interacts.]
- **Why this destination:** [why this cluster/file/section vs alternatives. Don't reason from secondary constraints (e.g., "root CLAUDE.md is at line budget") when the rule's logic dictates a destination.]
- **Persona challenges (if any):**
- **[Trigger-Moment Auditor]** ⚠️ challenge: [one-sentence reasoning]
- Original framing: "[from consolidation]"
- Counter-proposal: "[from persona]"
- Broader trigger class (if applicable): "[from persona]"
- **[Workflow-Step Router]** ⚠️ challenge: [one-sentence reasoning]
- Original destination: "[from consolidation]"
- Re-route to: [destination + section]
- **Zone reason:** [why this is Zone 1 — e.g., "persona challenged" / "new top-level cluster" / "borderline 2/3 same-mechanism" / "root CLAUDE.md edit"]
**Your choice for [C-id]:** (a) accept consolidation, (b) accept persona counter-proposal, (c) write your own
[Repeat for each Zone 1 conclusion]
---
### Zone 2 — Routine Confirmations ([Z2] items, accept-all default)
**(v3.13) The 1-line Conclusion column MUST lead with a concrete incident / name / verbatim quote / specific framing from THIS session.** Destination column carries the cluster ID / plan path. Do NOT put cluster IDs or shorthand jargon in the 1-line — that defeats verification. See Step 4 Verification Detail Floor "Trigger heuristic" + good/bad examples.
| # | Conclusion (1-line, concrete-anchor-first) | Destination | Personas |
|---|---------------------------------------------|-------------|----------|
| C5 | "[specific incident/name/quote from this session]" | [cluster ID + file] | ✅✅ |
| C6 | "[specific incident/name/quote from this session]" | [cluster ID + file] | ✅✅ |
| ... | ... | ... | ... |
**Default action:** accept the batch.
- Reply **"y"** to confirm all Zone 2 items.
- OR list specific items to expand into full Verification Detail Floor (e.g., "expand C5, C7").
---
### Zone 3 — Auto-routed ([Z3] items, informational)
[Z3] items auto-routed to: [destinations summary, e.g., "workflow doc default rules (×6), MEMORY.md (×2), Noted (×4)"].
**(v3.13) When listing individual Z3 items (e.g., in response to "expand Z3"), apply the same concrete-anchor rule as Z2** — the 1-line leads with the session-specific incident/name/quote, not the destination ID.
**Anything to promote to Zone 1?** Reply **"y"** to accept the auto-routing OR list specific item IDs to promote (e.g., "promote C9, C12 to Zone 1").
---
### Cluster + Watch-List State
[Brief summary of cluster audit result + any new entries proposed. Single paragraph or compact table.]
[IF Mod 5 auto-drafted any plans this wrap-up (clusters that met BOTH gates: ≥5 sub-IDs AND no active plan), surface as Zone-3-style single-line notification — NEVER as Zone 1 decision:]
✓ Auto-drafted plans (matured clusters, v3.11 Mod 5):
- → (N Open Qs)
- → (N Open Qs)
Review when ready; promote to
ready-for-autonomousafter answering any Open Questions.
[/IF]
---
### Resolved Hypotheses ([H] total)
| # | Hypothesis | Resolution |
|---|------------|------------|
| 1 | "[from scan]" | CONFIRMED / DISPROVEN / STILL UNRESOLVED |
---
### Phase 1 Eval Status
[1-line: "Run #[N], [days] post-ship — Phase 1 Decision Report [trigger met / not met]." If trigger met, surface Decision Report inline below.]
---
### Noted ([N] items collapsed — reply "expand noted" to see)
---
⚠️ **VERIFICATION REQUIRED:**
- Zone 1: explicit per-item choice for each (above)
- Zone 2: "y" to accept batch OR list items to expand
- Zone 3: "y" to accept auto-routing OR list items to promote
- Names, facts, premises in Zone 1 — anything wrong?
Once confirmed, I proceed to Step 4b (cluster audit if not done) → Step 4c (eval data capture) → Step 5 (route).
---
[LEGACY FORMAT REFERENCE — only used if zone classification unavailable, e.g., persona-review.json missing AND consolidation predates v3.8:]
### Ready for Documentation (Passed All Gates) — flat fallback
| # | Type | Classification | Summary |
|---|------|----------------|---------|
| 1 | Discovery | Code-level | "P2024: Timed out fetching connection" — connection pooling fix |
| 2 | User pushback | Process-level (behavioral) | Hypothesis testing before fixes |
### Resolved Hypotheses
| # | Original Hypothesis | Resolution | Evidence |
|---|---------------------|------------|----------|
| 1 | "Root cause might be connection pooling" | CONFIRMED — pool exhaustion under load | Fixed with pool size increase |
### Watch List (Recurring Candidates)
Before finalizing the Noted bucket: check `~/.claude/learning-captures/watch-list.md`.
⚠️ **Root-cause matching, not observation matching (Mod 1, Apr 28 2026).** The match criterion is **"is the fix/remediation the same?"**, not "does the observation text look similar?" Two superficially different observations with the same underlying cognitive or process origin and the same remediation path are **the same watch-list item — increment its incident list, do not create a new entry.**
For each candidate from this session:
1. State the candidate's **root cause** in one sentence (cognitive origin: what mental move broke down? + process origin: which workflow step / rule type drifted?)
2. State the candidate's **proposed fix** (what mechanism would prevent recurrence?)
3. Read every active watch-list entry's `Root cause` and `Fix` columns. For each, ask: "Would the same fix close both?" If yes → **increment the cluster, append this incident as a sub-entry (W_N.x) preserving the specific framing/transcript ref**. If no → new entry with count=1.
4. If the fix is "the W4 retrofit plan" or another already-known plan, the new instance is an instance of that cluster. Add as sub-entry, do not file standalone — even if the surface framing is novel.
5. **When in doubt between fold and new: fold.** Sprawl is the bigger cost. Sub-IDs (W_N.a, W_N.b, …) preserve incident-level traceability inside the cluster so the eventual fix author can trace through every test case.
| # | Root cause (cognitive + process origin) | Fix | Incident summary | Aggregated count | Threshold | Action |
|---|----------------------------------------|-----|------------------|------------------|-----------|--------|
| [N] | [One-sentence origin] | [Remediation mechanism] | [W_N.x: brief framing + date + transcript ref] | [sum] | [2 or 3] | [Escalate → plan generation per Mod 5 / Still watching] |
- After user verification, update `watch-list.md` (increment + sub-entry, or new entry). Move escalated entries to the Archived section.
- **Threshold escalation now triggers Mod 5 (auto-draft plan)** — see Step 4b cluster audit + Step 5 routing for the plan-generation flow.
### Noted (Passed Quality Gates, Below Persistence Threshold)
| # | Type | Summary | Why Not Persisted |
|---|------|---------|-------------------|
| [N] | [Type] | [Brief description] | [What would NOT go wrong if forgotten] |
### Needs Review (Failed Gate)
| # | Type | Failed Gate | Reason |
|---|------|-------------|--------|
| 3 | Failed attempt | Verification | Never confirmed fix works |
### Persona Panel Review (Phase 1 shadow mode — informational, not a gate)
If `~/.claude/learning-captures/[session-id]/persona-review.json` exists, render its contents into a per-conclusion table. The personas reviewed each routed conclusion. Their output is informational — user reads both views and decides per-row.
| # | Conclusion (consolidation summary) | Trigger-Moment Auditor | Workflow-Step Router |
|---|-----------------------------------|------------------------|---------------------|
| 1 | "..." | ✅ pass | ✅ pass |
| 2 | "..." | ⚠️ challenge: scope-too-narrow → broader trigger "<phrase>" | ✅ pass |
| 3 | "..." | ⚠️ challenge: symptom-anchored → mechanism framing "<phrase>" | ⚠️ challenge: re-route from <X> to <Y> |
For each challenged conclusion, expand the counter-proposal underneath:
C2 — Trigger-Moment Auditor counter-proposal:
- Original framing: ""
- Proposed mechanism framing: ""
- Broader trigger class: "<from persona, if applicable>"
C3 — Workflow-Step Router counter-proposal:
- Original destination: ""
- Re-route to: <destination + section>
- Reasoning:
Per-conclusion choices for the user: (a) accept consolidation, (b) accept persona counter-proposal, (c) write your own. The user's choice for each conclusion is captured in Step 4c for eval purposes.
If `persona-review.json` does not exist (Phase 1 not yet shipped, REVERT in effect, or persona run failed and surfaced as malformed), this section is omitted entirely.
---
⚠️ **VERIFICATION REQUIRED:** Does this summary accurately reflect what happened?
- Are names, facts, and premises correct?
- Did I miss anything important?
- Did I capture something that didn't actually happen?
- For each persona challenge: do you accept the counter-proposal, accept the consolidation, or write your own?
Please confirm accuracy before I proceed to documentation.
WAIT FOR USER CONFIRMATION before proceeding to Step 4c.
Step 4 — Verification Detail Floor (originally added v3.7, scoped v3.8 May 2 2026)
The Verification Detail Floor scales rigor with zone (per Step 6.5):
| Zone | Floor requirement |
|---|---|
| Zone 1 | MANDATORY full Verification Detail Floor — per-conclusion narrative block with all 5 fields (what happened, what's wrong, what fix does, why destination, persona challenges) |
| Zone 2 | 1-line summary + destination by default — the summary MUST lead with a concrete incident/name/quote/specific-framing from THIS session (v3.13). Full floor available on user request ("expand C5, C7"). |
| Zone 3 | Destination + 1-line summary only — same concrete-anchor rule as Zone 2 (v3.13). No floor. User can promote to Zone 1 to see full floor. |
Required fields for Zone 1 conclusions:
**[C-id] [Title]**
- **What happened in this session:** [1-3 sentences with specific incident or
pattern. Quote the user or quote yourself if a direct exchange triggered the
signal. Not the abstracted rule — the concrete event.]
- **What's wrong / what's missing:** [explicit gap or failure mode]
- **What the fix does:** [concrete before/after. If destination is a watch-list
cluster or sub-entry, NAME what's already in that cluster and how this
addition interacts (sub-entry W_N.x increment vs new cluster).]
- **Why this destination:** [why this cluster/file/section vs alternatives.
Don't reason from secondary constraints (e.g., "root CLAUDE.md is at line
budget") when the rule's logic dictates a destination.]
- **Persona challenges (if any):** [with the same level of specificity — what
the persona objected to and what their concrete counter-proposal is]
STOP and correct if you're:
- Presenting a Zone 1 conclusion without full Verification Detail Floor (Zone 1 = mandatory floor)
- Mixing Zone 1 and Zone 2 in the same section of the verification view
- Surfacing Zone 3 items in the user's main verification scroll (Zone 3 = single-line summary + "anything to promote?" prompt only)
- Failing to apply zone classification (Step 6.5) before rendering Step 4
- Skipping the Zone-1 cap check when Zone 1 has >5 items
- Defaulting to "compressed format because the table is cleaner" for Zone 1 items — Zone 1 always gets the floor
- (v3.13) Writing a Zone 2 or Zone 3 1-line summary that leads with a destination cluster ID (
W_N.x, plan path, reference doc path) or shorthand jargon (e.g., "methodology-doc caveat-writing surface") WITHOUT a concrete anchor from THIS session. The 1-line must lead with a specific name, quote, incident, or framing the user can recognize from this session's exchange. Cluster ID + destination go at the END as routing metadata, not the START as the summary.
(v3.13) Trigger heuristic — recognize the failing format BEFORE rendering:
For each Zone 2 / Zone 3 row, check the 1-line summary text:
| Contains | Missing | Verdict |
|---|---|---|
Cluster ID (W_N.x), plan path (P_N), or reference-doc path |
A specific name / verbatim quote / specific incident phrase from THIS session | JARGON-ONLY — re-render with concrete anchor, OR auto-expand to full floor |
| Specific name / verbatim quote / specific incident phrase from THIS session | (anything else) | OK to render compressed |
| Neither cluster ID nor specific anchor | — | Under-specified; re-render with concrete anchor |
If the row is jargon-only, the user cannot verify without re-loading the destination cluster's context into their head — which defeats the "shouldn't need to remember anything to verify" floor that motivated v3.7. Either re-render the 1-line with a concrete session anchor leading, or auto-promote that row to full floor for this wrap-up.
(v3.13) Good vs. bad examples:
❌ FAILING (cluster-ID-first, jargon-only):
| C1 | W1.p new sub-entry `W1.p.aa` — methodology-doc caveat-writing surface;
directionally-opposed pair compressed into single causal chain
| `watch-list.md` W1.p cluster + W4 plan P4 author note | ✅✅ |
User reaction: "There is no description for these Zone 2 and Zone 3 things.
I cannot recall or understand what they're about."
✅ WORKING (concrete-incident-first):
| C1 | Caveat #3 conflated correctly-excluded execs (Trent Charlton, Oleksandr
Fedorov) with Harmonic-miscategorized real founder (Kerry Lu) — adds
methodology-doc surface to W1.p
| `watch-list.md` W1.p cluster + W4 plan P4 author note | ✅✅ |
The working version leads with the specific incident (the named people + the specific framing that came up in this session); the destination metadata (W1.p, P4) comes at the end as routing context, not as the summary itself. The user can recognize "Kerry Lu" / "Trent Charlton" because they came up in this session's exchange; they cannot recognize W1.p.aa without re-loading the watch-list.
Why v3.7 (Apr 29 2026): Compressed format passed 4/4 consolidation errors through Step 4 unchallenged in a parallel content-lab wrap-up. User: "It needs to actually tell me what the thing is that we're trying to analyze... I shouldn't have to remember anything to verify." Verification under those conditions is performative. The Detail Floor was the v3.7 fix.
Why v3.8 amendment (May 2 2026): v3.7 made the floor MANDATORY for ALL conclusions. Result: a single wrap-up with 14 conclusions (3 Zone-1-shape + 10 Zone-3-shape methodology codifications + many Noted) became 14× the cognitive load. User: "my brain just fried and I just kind of want to give up." The floor is right; the scope was wrong. v3.8 makes the floor's rigor scale with zone — so the user's attention scales with where their judgment actually matters. Transcript fixture:
~/.claude/learning-captures/_archive/handoff-to-learning-loop-iteration.md(v3.7 evidence; archived May 18 2026 from original2026-04-29-content-lab-post-13-capture-distillation/) + the May 2 wrap-up output that motivated v3.8 zones.
Why v3.13 amendment (May 19, 2026): v3.8 specified "1-line summary + destination" for Zone 2/3 but didn't constrain WHAT the 1-line summary must contain. In the
2026-05-19-arlo-vc-boardy-handoffwrap-up, consolidation produced 4 conclusions (0 Z1, 3 Z2, 1 Z3) and Step 4 rendered the Z2/Z3 rows with cluster-ID-first phrasing like "W1.p new sub-entryW1.p.aa— methodology-doc caveat-writing surface." User pushback: "There is no description for these Zone 2 and Zone 3 things. I cannot recall or understand what they're about." Same root cause as v3.7 (verification requires remembering), but at a finer grain — the summary itself was jargon-only. After re-expanding with the full floor (which forced concrete incidents back to the surface), verification worked. The fix is to require the concrete-anchor lead at the 1-line layer too, not only the full-floor layer. Trigger heuristic + good/bad examples make the failure recognizable BEFORE rendering, not only after user pushback.
Step 4b: Watch-List Cluster Audit + Threshold-Met Plan Generation (MANDATORY — Mod 4 + Mod 5, Apr 28 2026)
Before routing, run a cluster check on the active watch-list:
-
Read
~/.claude/learning-captures/watch-list.md. -
Count active entries. Sprawl alert thresholds (tighter, Apr 28 2026):
- >15 active top-level entries → sprawl alert
- >3 entries sharing the same
Fixfield value → cluster collision alert
If either threshold is hit, surface to user:
⚠️ Watch-list cluster check: - [N] active entries (threshold: 15) - [Cluster name] has [M] entries sharing fix "[fix value]" (threshold: 3) Recommend re-consolidation pass before more entries accumulate. Consolidate now (spawn sub-agent), defer to next wrap-up, or skip? -
If user opts in, spawn re-consolidation sub-agent with the same root-cause-matching prompt as Mod 2 — applied to existing entries, not new candidates. Output: proposed merges with justification.
-
User approves merges; update watch-list.md (preserve sub-IDs for incident traceability).
Skip this step entirely if active entry count ≤15 AND no fix-cluster ≥3.
Mod 5 — Threshold-met → child sub-agent auto-drafts plan (v3.4 Apr 28, refined v3.11 May 12 2026):
When a watch-list cluster meets BOTH gates, spawn a child sub-agent to draft a plan in PEP schema:
- Maturation gate (v3.11): ≥5 sub-IDs in the cluster. Tightened from the original v3.4 thresholds (2 or 3) per the May 12 2026 user directive — recurrence evidence is the threshold, not first-pattern speculation.
- No-active-plan gate (v3.11): no plan currently exists for this cluster. Verify both:
- Grep cluster ID (e.g.,
W7.c) across known plan directories:~/Documents/claude-projects/claude-skills/plans/,~/.claude/plans/,~/Documents/claude-projects/Personal/*/plans/,~/Documents/claude-projects/Personal/plan-execution-pipeline/plans/ - Check the cluster's Fix field for an explicit plan-path reference (e.g., "see plan at /path/to/X.md")
- Grep cluster ID (e.g.,
When BOTH gates pass, spawn a child sub-agent with PLAN_DRAFTER_PROMPT (see prompt block alongside CONSOLIDATION_PROMPT). The main wrap-up sub-agent does NOT do the drafting work — child sub-agent extraction keeps the main wrap-up context clean (matches the v3.5 persona-panel architecture).
The child sub-agent receives: cluster ID + cluster header + Fix field + all sub-entries + PEP plan schema. It parses Fix for plan location, drafts the plan with each historical incident as a Success Criteria checkbox, handles ambiguous Fix-field areas via ## Open Questions (blocking) section, writes the file, and reports back.
Plan content schema:
| Plan Field | Source from watch-list cluster |
|---|---|
## Objective |
Cluster's root cause + fix in one paragraph |
## Success Criteria |
Every historical incident reframed as a test case checkbox: "Would this fix have prevented incident W_N.x ([date], [transcript ref])?" Each W_N sub-entry becomes a criterion. The fix must trace through all test cases and demonstrate robustness against all of them. |
## Context |
Aggregated incident notes + transcript references + dates + N-failure count + cognitive/process origins |
## Open Questions (blocking) (v3.11) |
Every plan section that the drafter couldn't fill with high confidence from the Fix field. Blocks transition to ready-for-autonomous until user fills them. The drafter must never fabricate file paths or technical specifics not present in the Fix field. |
YAML status |
draft |
YAML plan_kind |
executable (queues into autonomous pipeline) or pr-spec if scoped narrowly |
YAML priority |
Based on cluster size: ≥10 sub-IDs → high; 5-9 → medium |
YAML priority_rationale |
"Watch-list cluster <ID> matured to N sub-IDs; fix unimplemented as of <date>" |
YAML created |
Today's date |
YAML project_bucket |
Inferred from chosen plan directory |
Plan file location (Fix-field auto-routing, v3.11):
- Fix field mentions
~/.claude/paths →~/.claude/plans/ - Fix field mentions
~/Documents/claude-projects/claude-skills/→~/Documents/claude-projects/claude-skills/plans/ - Fix field mentions
~/Documents/claude-projects/Personal/<X>/→~/Documents/claude-projects/Personal/<X>/plans/ - No file path mentions in Fix → fallback to
~/Documents/claude-projects/claude-skills/plans/(most common case)
Filename: YYYY-MM-DD-<cluster-id>-<short-slug>.md.
The main wrap-up sub-agent surfaces drafted plans in Step 4's Cluster + Watch-List State section as Zone-3-style single-line notifications — NEVER as Zone 1 decisions (would defeat the cognitive-load-reduction goal). Render shape:
✓ Auto-drafted plans (matured clusters, v3.11):
- W7.c → ~/.claude/plans/2026-05-15-w7c-auto-mode-classifier.md (3 Open Qs)
- W37 → ~/Documents/claude-projects/claude-skills/plans/2026-05-15-w37-hook-false-positive.md (0 Open Qs)
Review when ready; promote to `ready-for-autonomous` after answering any Open Questions.
Why v3.4 → v3.11 refinement (May 12 2026): Original v3.4 thresholds (count ≥2 or 3) were tuned aggressively to catch sprawl early. In practice, drafting plans on thin evidence created speculative debt. User directive (May 12): "we want recurrence evidence before adding to the watch-list." Tightening to ≥5 sub-IDs + no-active-plan aligns Mod 5 with the Workstream A recurrence-test philosophy. Fix-field auto-routing + Open Questions handling were also missing — plans landed in inconsistent locations and over-fabricated specifics from vague Fix fields. Child sub-agent extraction matches the v3.5 persona-panel architecture and keeps wrap-up context lean.
STOP and surface if:
- A cluster hits BOTH gates but the PLAN_DRAFTER_PROMPT child sub-agent is not spawned (default action is to draft, not defer)
- The child sub-agent reports back without writing a file (means the drafter failed or refused to run)
- The auto-drafted plan is missing test cases for incidents present in the watch-list cluster (every sub-ID must become a Success Criteria checkbox)
Mod 6 — Watch-vs-Codify Decision Criterion (added v4.0, 2026-05-20 hygiene pass):
Before adding any signal to the watch-list, apply this decision criterion:
| Condition | Action |
|---|---|
| All three present: mechanism named (the WHY of the failure) + canonical destination identifiable (specific file + section) + ≥1 prior incident | CODIFY DIRECTLY. Write the rule into the destination. Log to graduation-log.md. Skip the watch-list entirely. |
| Any one missing: mechanism unclear (multiple competing hypotheses) OR destination unknown OR pattern not yet trusted (need ≥N instances to distinguish from noise) | WATCH. Add to watch-list with threshold-based escalation (Mod 5). |
| Recurrence of already-codified rule: matching graduation-log.md entry exists | INCREMENT incidents_since_codification on the matching graduation entry. If 2+ → re-open trigger (enforcement gap — usually Cluster 1 register-translation pattern). |
Why (2026-05-20): Cluster 2 sat at 8 incidents waiting for "more evidence" when the fix was knowable at incident 1 (mechanism = pre-elicit constraints; destination = pm-partnership.md). Threshold-based escalation makes sense when the pattern is unknown; it becomes waste when the pattern is already named. The codify-now criterion overrides Mod 5's recurrence threshold (≥5 sub-IDs) when all three conditions are met.
Mod 7 — Granularity Ceiling Rule (added v4.0, 2026-05-20 hygiene pass):
Sub-entries within a cluster must not exceed these granularity ceilings:
- Sub-entry sprawl threshold: When ≥3 sub-entries share the same root cause + fix shape (only the surface differs), collapse to 1 entry + "surfaces observed" list/table. Do NOT create per-surface sub-IDs for the same mechanism.
- Mechanism-first naming: Entry header must name the mechanism (WHY) before the surface (WHAT). Surface variants become facets inside the entry, not separate sub-entries.
- ❌ Wrong:
W1.u.i — Visual surface: cover-image misread(surface-first, encourages per-surface proliferation) - ✅ Right:
W1.u — Surface-signal-as-confident-claim+ table of 8 surfaces (mechanism-first, surfaces are facets)
- ❌ Wrong:
- Tabular incident format: Sub-entries with ≥3 incidents use a compact table (Sub-ID | First-seen | Surface | Count | Routing | Status), not prose paragraphs. Full narrative reserved for entries with unique detail (consolidated chronologies, graduation traces, mechanism explanations).
Why (2026-05-20): W1.u accumulated 8 sub-entries (i-viii), W1.k accumulated 4 (parent + .iv with 2 instances), Cluster 1 prose ballooned to ~200 lines. All of W1.u shared the same mechanism + same fix. The granularity decision should happen at capture time (when writing the entry), not at consolidation time (when sprawl is already visible).
Mod 8 — Stalled-Deliverable Separation (added v4.0, 2026-05-20 hygiene pass):
When a watch-list cluster has an associated plan and the plan has been in active-remediation status for >4 weeks without ship:
- Move the plan's status into the watch-list entry's Status field (e.g., "Plan executed 2026-05-19; registration blocked on /update-config from main session").
- Watch-list keeps only the incidents-since-fix counter and the link to the plan file.
- Granular sub-IDs preserved but compressed to tabular form (Mod 7).
- Trigger attention on the plan (deployment target date?), not on the watch-list (which is correctly tracking).
Why (2026-05-20): Cluster 1 had a "5+ weeks active remediation" status, but the actual state was "implementation 80% done, blocked on one main-session command." The watch-list framing made it look like learning-loop hadn't acted; the truth was the plan was executing. The watch-list should reveal that distinction so user action goes to the right surface.
Mod 9 — Graduation Ledger Requirement (added v4.0, 2026-05-20 hygiene pass):
Companion file: ~/.claude/learning-captures/graduation-log.md (created 2026-05-20).
Every codification action MUST atomically:
- Update the canonical destination file with the new rule
- Write a graduation-log.md entry with: mechanism, destination, incident count at codification, re-open trigger
- Update watch-list entry status to GRADUATED (with link to graduation-log.md entry)
A codification that doesn't write to graduation-log.md is incomplete. The codification action is the atomic unit; partial codifications are the failure mode this rule prevents.
Per-wrap-up monitoring (also fires at Step 4c): After eval data capture, scan that session's incidents against graduation-log.md. If any incident matches a graduated rule's surface, increment incidents_since_codification on the matching graduation entry. ≥2 post-fix incidents = re-open trigger (usually Cluster 1 enforcement-gap pattern — rule exists, doesn't fire under task momentum, needs discrete hook).
Why (2026-05-20): Zero rules graduated from watch-list to graduation-log in 5 weeks despite multiple Cluster 1 + Cluster 2 fixes shipping at the source (CLAUDE.md, reference docs). The fix shipped; the watch-list never updated. Without a ledger, "did the fix work?" is unanswerable; entries accumulate as a one-way archive.
Mod 10 — Path-Drift Detection at Cluster Audit (added v4.0, 2026-05-20 hygiene pass):
During Step 4b's cluster audit, verify referenced paths exist:
- For each cluster with a Fix-field path or plan-path reference, run a one-shot existence check (
test -for equivalent). - If the path doesn't resolve, surface as a STOP item: the reference is broken and the actual file location should be hunted with
findbefore the audit proceeds.
Why (2026-05-20): Watch-list Cluster 1 referenced the W4 plan at ~/Documents/claude-projects/claude-skills/plans/2026-04-18-w4-discrete-trigger-retrofit.md, but the actual file lived at ~/.claude/plans/2026-04-18-w4-discrete-trigger-retrofit-plan.md. Path drift had been invisible for 5+ weeks. Anyone following the reference would fail.
Step 4c: Capture Phase 1 Eval Data (added v3.5 Apr 28 2026)
Skip this step entirely if ~/.claude/learning-captures/[session-id]/persona-review.json does not exist (Phase 1 not active, REVERT in effect, or persona run failed).
Otherwise, after user verification completes:
-
For each conclusion the personas reviewed, classify the user's actual choice in Step 4:
accepted_consolidation— user kept consolidation's original framing/destinationaccepted_persona_counter— user accepted the persona's challenge counter-proposalwrote_own— user wrote a third version (counts as a correction the persona did not match)no_correction_needed— consolidation was right, no challenge issued, no correction made
-
Compute match classification per persona challenge:
full_match— persona's counter-proposal matches user's actual final decisionpartial_match— persona challenged the right conclusion but with different specifics from user's correctionmismatch— persona challenged but user's correction went a different directionno_challenge_user_corrected— persona issued no challenge but user corrected anyway (counts toward coverage miss)
-
Write
~/.claude/learning-captures/[session-id]/persona-eval.mdin this exact YAML schema:--- session_id: <session-id> eval_date: <YYYY-MM-DD> phase: 1-shadow consolidation_proposals: <int> persona_challenges_issued: <int> # sum across both personas, deduped per conclusion user_corrections_made_in_step4: <int> --- ## Per-Challenge Records - challenge_id: 1 persona: trigger-moment-auditor conclusion_id: C1 consolidation_proposed: "..." persona_counter_proposed: "..." user_final_decision: "..." match_class: full_match | partial_match | mismatch | no_challenge_user_corrected failure_category_observed: a | c | d | g | other # which class the user's correction targeted ## Aggregate Metrics match_rate: <float, 0.0-1.0> coverage_rate: <float, 0.0-1.0> noise_rate: <float, 0.0-1.0> match_rate_calc: "<numerator>/<denominator>" coverage_rate_calc: "<numerator>/<denominator>" noise_rate_calc: "<numerator>/<denominator>" -
Append a one-line entry to
~/.claude/learning-captures/persona-eval-runs.txtwith the format:<YYYY-MM-DD> <session-id> challenges=<N> matches=<N> noise=<N>If the file does not exist, create it with a one-line header:
# Phase 1 persona-panel shadow run log (created <YYYY-MM-DD>)followed by the entry. -
Bootstrap-on-first-run note: if this is the first Phase
Truncated - read the full file at https://github.com/Duds/llm-toolkit/blob/dabd681bd04486f7243ef881bfa8fd45074127b5/skills/learning-loop/SKILL.md.