Summary
disk-hygiene's destructive-operation guard has been silently unenforced for the entire measured
window. Both registered variants fail before any guard logic runs, and both fail non-blockingly —
so the tool call proceeds and nothing surfaces to the operator.
This was found incidentally while diagnosing guardrails PreToolUse latency: the disk-hygiene guard
was being used as the fast "control" in that comparison, and it turned out never to have executed.
Evidence
Measured from hook attachments in ~/.claude/projects/*/*.jsonl.
Variant 1 — destructive_guard.py --mode engine-gate. All 16 recorded runs are
hook_non_blocking_error with exitCode: 1:
Failed to run: Plugin option "disk_hygiene_enabled" isn't set. Open /plugin manage to configure it, or check that the plugin's userConfig schema declares "disk_hygiene_enabled".
The recorded durationMs is 2 ms — that is Claude Code refusing to launch the hook during config
validation, before any process is spawned. python3 -c 'pass' costs ~396 ms on this host, so 2 ms
was never physically achievable for a real run.
An earlier variant of the same registration shows a second, distinct registration bug:
Failed to run: Hook command references ${CLAUDE_PLUGIN_DATA} but only ${CLAUDE_PLUGIN_ROOT} is available for skill hooks (${CLAUDE_PLUGIN_DATA} is plugin-only).
Variant 2 — destructive-guard.sh. All 57 recorded runs are hook_non_blocking_error with
exitCode: 1:
Failed with non-blocking status code: <3>WSL (2444932 - Relay) ERROR: CreateProcessCommon:818: execvpe(/bin/bash) failed: No such file or directory
The command resolved to the Windows WSL bash.exe relay, which has no /bin/bash. Its 878 ms is the
cost of failing, not of guarding.
Impact
- The destructive-operation guard provided zero protection over the whole measured window.
- Both failure modes are non-blocking, so there is no operator-visible signal — the guard's absence
is indistinguishable from the guard allowing the operation.
- Invoked directly, bypassing the broken registration, the guard does run and is genuinely fast:
destructive_guard.py --mode engine-gate against a real payload measured 181 ms, 1 process, 0
external spawns. The logic is fine; only the registration is broken.
Sequencing note
The registration carries a Bash|PowerShell matcher, so repairing it will add this guard to every
Bash tool call. On Windows that adds load to an already-contended process-spawn path. Land the
guardrails spawn-count reduction (see the linked issue) before or alongside the repair.
Not fixed here
Deliberately out of scope for the guardrails latency work — filed so it is not lost. Needs an owner
for the disk_hygiene_enabled userConfig declaration and the bash-resolution path.
Related
Summary
disk-hygiene's destructive-operation guard has been silently unenforced for the entire measuredwindow. Both registered variants fail before any guard logic runs, and both fail non-blockingly —
so the tool call proceeds and nothing surfaces to the operator.
This was found incidentally while diagnosing guardrails PreToolUse latency: the disk-hygiene guard
was being used as the fast "control" in that comparison, and it turned out never to have executed.
Evidence
Measured from hook attachments in
~/.claude/projects/*/*.jsonl.Variant 1 —
destructive_guard.py --mode engine-gate. All 16 recorded runs arehook_non_blocking_errorwithexitCode: 1:The recorded
durationMsis 2 ms — that is Claude Code refusing to launch the hook during configvalidation, before any process is spawned.
python3 -c 'pass'costs ~396 ms on this host, so 2 mswas never physically achievable for a real run.
An earlier variant of the same registration shows a second, distinct registration bug:
Variant 2 —
destructive-guard.sh. All 57 recorded runs arehook_non_blocking_errorwithexitCode: 1:The command resolved to the Windows WSL
bash.exerelay, which has no/bin/bash. Its 878 ms is thecost of failing, not of guarding.
Impact
is indistinguishable from the guard allowing the operation.
destructive_guard.py --mode engine-gateagainst a real payload measured 181 ms, 1 process, 0external spawns. The logic is fine; only the registration is broken.
Sequencing note
The registration carries a
Bash|PowerShellmatcher, so repairing it will add this guard to everyBash tool call. On Windows that adds load to an already-contended process-spawn path. Land the
guardrails spawn-count reduction (see the linked issue) before or alongside the repair.
Not fixed here
Deliberately out of scope for the guardrails latency work — filed so it is not lost. Needs an owner
for the
disk_hygiene_enableduserConfig declaration and the bash-resolution path.Related
repo-hygiene: destructive-guard PreToolUse hook inert on Windows — bash resolves to WSL relay, fail-open. Same WSL-relay failure mode; independently corroborates variant 2.