Backlog item G. The `coverage:` line under-reported a skill chosen in a PRIOR turn:
enforce-coverage-verify credited channel=skill only if the Skill tool ran in the
CURRENT turn, so an honest `skill:X` continuation line was BLOCKED -> the controller
learned to under-report as direct/chain. Two-sided systemic fix, no weakening:
- enforce-coverage-verify: decide() also accepts skill:X when X was invoked anywhere
earlier in THIS session (new priorSkillNames param; main() collects them via
sessionToolUses). Still unforgeable -- a real Skill tool_use must exist in the
transcript. The only residual is possibly-stale attribution, far better than the
forced dishonest direct-reporting it replaces.
- enforce-prompt-injection: the §17 reminder now lists active skills carried over
from earlier turns (read from the transcript) and tells the controller to report
`coverage: skill:<name>` when work continues under one -- the proactive half, so
the correct line is not merely allowed but prompted.
TDD: RED -> GREEN per behavior. tools-vitest 2032 passed / 2 skipped.
Plan docs/superpowers/plans/2026-05-31-discipline-guard-backlog.md (item G).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the TDD-gate cross-actor gap: when a subagent (spawned by a Task in the
controller's current turn) writes the failing test and confirms RED, the
controller's subsequent production edit was falsely blocked because the gate only
scanned the controller's own turn. Net strengthening, no discipline weakened.
- Part 1 (enforce-runtime-write-deny): block the Write tool from any
~/.claude/projects/**/*.jsonl (session/subagent transcripts). Memory *.md there
stays writable (never matches .jsonl$). Resolving normalizer defeats ./.. evasion.
This makes the agent-<id>.jsonl that Part 2 trusts unforgeable (it was the last
ungated write channel; Bash/PowerShell/Read gates already covered it).
- Part 2 (enforce-tdd-gate): decide() also credits a subagent's matching test edit
+ RED via a new subagentEntriesList. turnTaskAgentIds() reads the hex agentId from
the harness-written Task tool_result (the controller cannot forge its own
tool_result; hex-only match blocks "agentId: ../../x" path traversal).
subagentTranscriptPaths() derives <dir>/<controller-session>/subagents/agent-<id>.jsonl.
main() reads them best-effort (missing/unreadable -> no extra credit = stricter).
No new weakening: a delegated subagent doing real TDD is legitimate; the only
forgery vector (overwriting the agent jsonl) is closed by Part 1. Existing
controller-turn behaviour is preserved (empty subagent list == old logic).
OWNER (settings.json, Claude can't edit it): enforce-tdd-gate is already a
registered PreToolUse hook -> Part 2 goes live on merge. enforce-runtime-write-deny
must be registered on PreToolUse(Edit|Write|MultiEdit|NotebookEdit) for Part 1 to be live.
TDD: RED -> GREEN per behavior. tools-vitest 2027 passed / 2 skipped.
Backlog item C (=Z); plan docs/superpowers/plans/2026-05-31-discipline-guard-backlog.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the remaining parallel-session-lock remarks on top of the keying fix
(7a469dc9), with NO weakening of same-worktree serialization:
- D: the block message now identifies the holder by its STABLE session_id and
marks the recorded pid as transient ("may change between attempts"). Chasing
the pid is what led to closing the wrong session. Decision logic is unchanged
(text only) — existing /pid N/ triage assertion still holds.
- B: pruneStaleLocks() best-effort deletes leaked lock files that are ALREADY
stale by the shared isStale() definition (now exported from the pure module —
single source of truth). Active within-TTL locks are never touched, so the
serialization guarantee is not weakened. Wired into the PreToolUse branch of
main(), wrapped so hygiene can never break the gate (fail-open).
- C (no code): release-on-SessionEnd needs only a settings.json registration
(owner action) — the existing !tool_name branch already releases. Documented
in the plan. Until then, leaked locks self-heal via B + the 5-min TTL takeover.
TDD: RED -> GREEN per behavior. tools-vitest 2014 passed / 2 skipped.
Backlog items B/C/D; plan docs/superpowers/plans/2026-05-31-discipline-guard-backlog.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
enforce-parallel-session-lock keyed the lock on the hook's process.cwd(),
which collapses to the main repo dir after a session resume — so sessions in
DIFFERENT git worktrees shared one lock and false-blocked each other (observed:
a brainrepo-worktree session blocked launching agents by a discipline-guard
session). New resolveWorkspacePath() keys on the session's stable cwd
(event.cwd) resolved to the git work-tree root (git -C <cwd> rev-parse
--show-toplevel), with fallback to process.cwd() so behaviour never regresses
when event.cwd is absent. Same-worktree concurrency stays serialized
(unchanged) — discipline not weakened; only cross-worktree false-blocks fixed.
TDD: RED (5 resolveWorkspacePath cases) -> GREEN -> tools-vitest 2003 passed /
2 skipped. Backlog item F; plan
docs/superpowers/plans/2026-05-31-discipline-guard-backlog.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`npm ci` does a clean install strictly from the committed lockfile
(deterministic, no version drift) — needed to restore junction node_modules
in a fresh worktree. Distinct from `npm install`/`npm i`, which stay
hard-blacklisted because they can pull new/updated versions; the blacklist
runs before the whitelist, so they remain blocked. Word boundary after `ci`
prevents `npm cider`-style prefix matches; chain semantics still block
`npm ci && <mutating>`.
TDD: RED (3 allow-cases failed default-deny) -> GREEN (/^npm\s+ci\b/) ->
tools-vitest 1998 passed / 2 skipped (2000). Backlog item A; plan
docs/superpowers/plans/2026-05-31-discipline-guard-backlog.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sibling Claude session 2026-05-30 found that lastTurnEntries treats
harness-injected skill bodies as spurious turn boundaries, breaking both
enforce-memory-coverage (can't find user's coverage line) AND
enforce-normative-content-rules::detectLegitSkillActive (can't find the
Skill tool_use that lives in the assistant message BEFORE the body).
Refinement applied here: this session inspected 29 isMeta:true entries
across the live transcript (8f4ba767-...jsonl) via a debug helper and
found isMeta:true is ALSO used for "Continue from where you left off"
auto-resume, Stop hook feedback strings, and <local-command-caveat>
wrappers — those are real user-equivalent boundaries that must remain
visible. Sibling's blanket "skip isMeta" proposal would have broken them.
Discriminator: skip ONLY when isMeta === true AND typeof sourceToolUseID
=== 'string' (tool-spawned content). Skill bodies have the linking field;
the other isMeta sources do not. The sourceToolUseID field is harness-
controlled and not writable by controller from inside a tool call —
cannot be spoofed.
Behaviour after fix:
* Skill body injection → skipped → walk continues back to find user's
real prompt (with coverage line).
* The assistant message containing the Skill tool_use is now inside the
turn → detectLegitSkillActive finds it → normative writes pass when
invoked under an active claude-md-management skill.
* "Continue from where you left off." → still treated as turn boundary.
* Stop hook feedback strings → still treated as turn boundary.
TDD:
* 3 new tests in tools/enforce-hook-helpers.test.mjs under the
"lastTurnEntries / lastUserPromptText / lastAssistantText / turnToolUses"
describe block:
- lastTurnEntries skips skill body injections (isMeta + sourceToolUseID)
- lastTurnEntries does NOT skip "Continue from where you left off"
(isMeta but no sourceToolUseID)
- turnToolUses includes Skill tool_use spawned in same turn as the
injected skill body
* 2/3 RED→GREEN (the "Continue" negative test passed on baseline already
since its string content satisfies the existing string-content branch).
Scope:
* Fixes 2 of the 5 structural quirks documented in the Stream H
completion log (enforce-memory-coverage gap, enforce-normative-
content-rules detectLegitSkillActive gap).
* Does NOT fix: enforce-read-path-deny LEGIT_SKILLS exemption gap
(separate hook, no lastTurnEntries dependency); TDD-gate cross-actor
blindness (different mechanism — actor session boundaries);
detectFullTestRun regex narrowness (command-pattern matching).
Regression: vitest tools 1788/1788 GREEN (was 1785; +3 new tests).
Plan: docs/superpowers/plans/2026-05-30-lastturnentries-skill-body-skip.md
Code-quality reviewer flagged 2 IMPORTANT factual inaccuracies in
recovery-procedures.md (commit 3ce73a68):
1. Section 6 RECOMMENDED code example imported resolvePathNormalize from
the wrong module path (tools/shell-content-rules.mjs). Actual exporter
is tools/enforce-router-gate.mjs (verified via Grep at line 174).
shell-content-rules.mjs only exports defaultPathNormalize. A future
reader copying the RECOMMENDED pattern would get an import error.
Also corrected the call signature: resolvePathNormalize() takes no
arguments and is async — returns the normalize function directly.
2. Section 4 (Stale-process) cited tools/enforce-bash-content-gate.mjs —
no such file exists in tools/ (verified via Glob). Correct hook
filenames are enforce-router-gate.mjs (Bash) and
enforce-powershell-gate.mjs (PowerShell).
Fix: replace both module references with the verified correct filenames
(Grep'd against tools/ exports + Glob'd file existence). Also includes
the lefthook MD032 blank-lines-around-lists auto-format diff carried
over from the previous commit's post-commit hook.
Surgical edit — no new content, no restructuring.
Adds first-time recovery runbook with:
- 3 self-recovery levels (Level 1 ≤5min sentinel reset, Level 2 ≤15min VS Code
restart, Level 3 destructive workspace rebuild)
- Stale-process / hook reload trap (Smoke 5 chistaa-session hypothesis +
refutation method); key takeaway: live restart-test is the only way to
confirm a hook-modifying fix landed
- Self-fabrication patterns — 7 cases enumerated from Smokes 3/4/5/7 with
pattern signature, detection signal, mitigation for each
- Test methodology lesson — Smoke 5 root cause showed unit tests with inline
mocks can give false-green if they bypass the live resolver function; debug
scripts have the same trap
- Smoke methodology — statusline-setup system prompt overrides user tasks
(Smoke 9 Run 1); use semgrep-scanner for echo-probes, statusline-setup OK
for gate-inheritance smokes
Docs-only change; verified via docs-only short-circuit in enforce-verify-
before-push (§5 п.13 CLAUDE.md).
Stream H Task 1 of 11. Plan: docs/superpowers/plans/2026-05-30-router-gate-v4-stream-H.md
Opt-in live smoke (ROUTER_LLM_LIVE_TEST=1 + ROUTER_LLM_KEY); auto-skips otherwise
so it never pollutes the unit regression in worktrees where undici is unresolved.
Checkpoint-1 live result on owner machine: PASS (2/2) — single Sonnet judge + 3-judge
consensus (Sonnet 4.6 + Haiku 4.5 + Opus 4.7) reach all models with real verdicts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8 TDD tasks (~день кода): extract shared AuditChainConfig, refactor VerifyAuditChains (regression-safe), failing tests для multi-tenant/BYPASSRLS/single-row, rewrite AuditRebuildChain через LAG OVER (partition_clause ORDER BY id) симметрично verify, активация ADR-018 enforcement rules, Pint/Larastan/Pest --parallel smoke, handoff для прод-cleanup activity_log_y2026_m05 через gh workflow run artisan-run.yml. Self-review GREEN на spec coverage / placeholders / типы. Execution mode: subagent-driven.
Task 4 уточнён: нет миграций (только PHP), fast-fail активируется сразу после
деплоя. Добавлены конкретные gh workflow run команды для cleanup (Steps 3-4 из
sql-runner.yml) и верификации шторма + incidents алерта. Галочки [ ] оставлены
(задача контроллера, не агента).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdownlint added blank line before list in TL;DR v3.5 Changes section. Cosmetic, no semantic change. Captured to keep working tree clean for session handoff.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dedicated brainstorm на S8 (последний acceptable residual после v3.4) — controller-writable markers BRANCH-SWITCH-CONFIRMED / RECOVERY-INTENT: заменены на AskUserQuestion-gate через расширение §4.5 answer parser. Тот же class fix что S5 v3.4 — перенос сигнала в side-channel который controller не контролирует.
V3.5 architectural shift:
- Old: controller wants git rebase → hook видит блокировку → controller пишет BRANCH-SWITCH-CONFIRMED в response → hook читает, allows. Самоодобрение через controller-written text.
- New: controller wants git rebase → hook блокирует → controller обязан AskUserQuestion('Выполнить git rebase main?') с 3 опциями → user picks → §4.5 parser распознаёт git-pattern, пишет approve_git_operation запись в askuser-decisions.jsonl с approved_action_pattern exact → controller retries → hook читает askuser-decisions, exact-match approval, consumes one-shot, allows.
Anti-forgery 4 защиты:
- askuser-decisions.jsonl в protected paths (~/.claude/runtime/*)
- Пишется только §4.5 parser при реальном AskUser-ответе
- Strict exact-match approved_action_pattern против tool_input.command
- 5-min time window + one-shot consumption (consumed flag)
Adversarial pre-check v4.3 — 6 attack-векторов проверены, все заблокированы.
5 spec edits:
- §3 preserved hooks таблица — enforce-branch-switch row переписан (no longer reads response markers, instead reads askuser-decisions)
- §4.5 — новый row + новое enum gate_interpretation: approve_git_operation
- §9 — S8 убран из acceptable residual list. Список residual теперь ПУСТ.
- §10.2 — askuser-decisions schema +consumed/consumed_at/consumed_by_tool_use_id + полный schema приведён
- §11 v3.5 history entry
Implementation budget: 21.5-31h (v3.4) → 22.5-32h (v3.5). +1.1h за: rewrite hook, extend parser, one-shot consumption, schema, spec edits.
Главный урок: класс controller-writable signals закрыт архитектурно через обе v3.4 (file side-channel) и v3.5 (askuser-decisions side-channel). Формула generalisable — любой controller-writable signal закрывается переносом write-канала в protected file который пишет отдельный gate-процесс при harness-driven событии.
Hard wall теперь полный hard. Acceptable residual list пуст.
Verify-sentinel: 1179/1179 vitest tools-only GREEN.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Handoff document for transition to new session. Contains:
- TL;DR of where we left off (spec v3.1 ready, impl not started)
- 4-step instructions for next session (read spec, writing-plans,
subagent-driven impl, post-impl tasks)
- Context (brain-retro #10 trigger, self-retrospect #2 confirmation,
user choice of Level 4)
- 7 design principles from spec section 2
- Architecture TL;DR (gate, 4 behaviors, baseline, deletes, preserved)
- All 4 spec versions in git with commits
- Cross-refs to L1+L2 plan, brain-retro, self-retrospect
- 5 open questions for writing-plans phase
Cannot write to memory/ path in this turn (memory-coverage hook
requires direct:memory-sync coverage, current turn has different
coverage). Memory entry can be added in next session via Skill or
manual annotation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comprehensive analysis of v3 found ~24 minor issues (no critical bypasses).
V3.1 closes most via clarifications to prepare for writing-plans skill in
next session.
Additions:
- TL;DR at top — fast orientation for implementer
- 10.1 Function and registry references (nodeMatches source,
registry source docs/registry/nodes.yaml, SDD-skill impact,
coverage-hint to recovery resolution)
- 10.2 State file schemas (8 files: router-state, chain-state,
askuser-decisions, router-gate-decisions, subagent-inheritance,
coverage-hint, gate-errors, gate-config)
- 10.3 Test strategy: ~150 unit + 10-15 integration + 10-15 golden
snapshot + 5-7 smoke
- 10.4 Success metrics: quantitative (override drops to 0,
gate-decisions growing) + qualitative (lockout < 5/100,
correct% > 60%) + acceptance criteria
- 10.5 Rollback plan (3 levels: hook off / revert commits / v2 baseline)
- 10.6 Stages and parallelism: 6-9h wall-clock with SDD parallelism
vs 13.5-20h sequential
No architectural changes — v3.1 only clarifies what implementer needs
to know without making implicit decisions.
Spec versions in git:
- v1: 7a43c175
- v2: b510a758
- v3: b632bcba
- v3.1: this commit
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>