You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for the actionable half of the PreToolUse guard audit, under the contract locked in
that topic's PLAN.md. The topic's contract slice (docs/topics/claude-pretool-validation-hooks-84d7ka/,
carrying PLAN.md and the 484-line FINDINGS.md) was pruned before merge per the topic-docs
convention. Best-effort retrieval while GitHub retains the object — pre-prune commit 19318ff1ba9c5af12a93f34332f0468004c12c27:
gh api "repos/melodic-software/claude-code-plugins/contents/docs/topics/claude-pretool-validation-hooks-84d7ka/FINDINGS.md?ref=19318ff1ba9c5af12a93f34332f0468004c12c27" --jq .content | base64 -d
The locked Brief is reproduced verbatim in the body of #3727.
The 17 PreToolUse guards had never been audited against the current model generation or the current
hooks reference. The audit's ablation verdicts turned out to be its least actionable part; what it
found that was actionable is below.
Every guard's kill switch is read after the library it costs. All 17 read <name>_enabled
through hook::check_enabled, which only exists once the 2,684-line hook-utils.sh is sourced,
so a DISABLED guard parses the whole library before finding out it has nothing to do. scripts/sync-hook-utils.sh covers the vendored library copies but not the entry scripts, so
nothing would notice the ordering drifting back.
Two one-line visibility fields are missing. Both disk-hygiene PreToolUse rows lack a statusMessage while its Stop row has one; and all 20 plugins/*/hooks/hooks.json omit the
documented optional top-level description.
The content guards have an MCP blind spot.secret-pattern-detection and hardcoded-path-check match Write|Edit|NotebookEdit only, so a session can be cleared by both
and still push the same secret to a repository through mcp__github__push_files or mcp__github__create_or_update_file — a route with no local file to fix afterwards and no pre-commit content-invariants layer on it.
Two policy questions have no written home, and were being re-litigated: whether a plugin's
hooks may be split out of it, and whether a PreToolUse hook may silently rewrite a tool call.
Out of scope
Recorded here so the boundary is explicit rather than implied:
The PostToolUse half of the kill-switch hoist, owned by the sibling lane on claude/posttool-hooks-review-ji6rl5 under an agreed split.
Any change to docs/conventions/hook-budget/.
The remaining ablation verdicts. Ten KEEP, three TRIM, two EVIDENCE-GATE and one DELETE rest on
class reasoning with no firing data; FINDINGS.md frames them as triage and they need per-guard
evidence before any of them moves.
Tracking issue for the actionable half of the PreToolUse guard audit, under the contract locked in
that topic's
PLAN.md. The topic's contract slice (docs/topics/claude-pretool-validation-hooks-84d7ka/,carrying
PLAN.mdand the 484-lineFINDINGS.md) was pruned before merge per the topic-docsconvention. Best-effort retrieval while GitHub retains the object — pre-prune commit
19318ff1ba9c5af12a93f34332f0468004c12c27:The locked Brief is reproduced verbatim in the body of #3727.
The 17 PreToolUse guards had never been audited against the current model generation or the current
hooks reference. The audit's ablation verdicts turned out to be its least actionable part; what it
found that was actionable is below.
Scope
block-hook-bypassfires with zero true positives on write targets it should never haveblocked.
block_hook_bypass_scratch_rootsshipped empty, so the harness's own per-sessionscratchpad blocked. Measured at five blocks in one day across four sessions with no true positive.
Per ADR 0003 clause 4 this is a wrong SCOPE rather than a wrong oracle, so the remedy is rescoping,
not deletion. (The memory tier
.work/was originally in this scope and was withdrawn in reviewon fix(hooks): PreToolUse guard remediation — scratch-root default, kill-switch hoist, MCP coverage, two conventions #3727: exempting it reopened a content-guard bypass. See session-flow prescribes a write command guardrails blocks #3720 and secret-pattern-detection scans the memory tier, which the topic-docs convention designates for raw credentials #3730.)
Every guard's kill switch is read after the library it costs. All 17 read
<name>_enabledthrough
hook::check_enabled, which only exists once the 2,684-linehook-utils.shis sourced,so a DISABLED guard parses the whole library before finding out it has nothing to do.
scripts/sync-hook-utils.shcovers the vendored library copies but not the entry scripts, sonothing would notice the ordering drifting back.
Two one-line visibility fields are missing. Both
disk-hygienePreToolUse rows lack astatusMessagewhile its Stop row has one; and all 20plugins/*/hooks/hooks.jsonomit thedocumented optional top-level
description.The content guards have an MCP blind spot.
secret-pattern-detectionandhardcoded-path-checkmatchWrite|Edit|NotebookEditonly, so a session can be cleared by bothand still push the same secret to a repository through
mcp__github__push_filesormcp__github__create_or_update_file— a route with no local file to fix afterwards and nopre-commitcontent-invariants layer on it.Two policy questions have no written home, and were being re-litigated: whether a plugin's
hooks may be split out of it, and whether a PreToolUse hook may silently rewrite a tool call.
Out of scope
Recorded here so the boundary is explicit rather than implied:
filed separately (Evaluate splitting session-flow's SessionStart hook from its 14 skills #3722 through Evaluate splitting context-budget's settings-write-ask hook from its two skills #3726).
block-hook-bypass(Run the ADR 0003 corpus sweep on block-hook-bypass's remaining default-on scope #3721). The scratch-root default narrows scopewith a known root cause, which ADR 0003 treats as rescoping; the broader default-on question needs
its own evidence table.
claude/posttool-hooks-review-ji6rl5under an agreed split.docs/conventions/hook-budget/.class reasoning with no firing data;
FINDINGS.mdframes them as triage and they need per-guardevidence before any of them moves.