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
plugins/disk-hygiene v0.20.21. Split out of the audit umbrella. F13, medium-high. Cheapest high-value fix in that report: a message change, no behavior change.
Problem
The plugin has two Bash-denying surfaces with opposite scopes:
The always-on engine gate — registered in hooks/hooks.json on PreToolUse matcher Bash|PowerShell with no invocation predicate. Active in every session whether or not /disk-hygiene:clean was ever invoked.
They emit identical denial text. A user who has never invoked the skill triggers the always-on gate and is told their Bash lane is restricted to the skill's scan/preview/handoff-verify/apply shapes — describing a lockout they did not opt into, in the words of a different guard.
Evidence
This misled the audit itself. A Bash denial was initially attributed to the session belt and written up as such. A two-cell control isolated it to the always-on gate, and the finding was withdrawn (F9.1/F9.2). If an audit reading the plugin's own source got this wrong from the message text, an ordinary user has no chance.
The withdrawal also corrected a related claim: the belt does not reach subagents. That non-inheritance is undocumented and build-specific, so it should not be documented as a recovery lane without that caveat.
Suggested fix
Branch the denial message on resolve_mode() so each guard explains itself:
Always-on gate: say that this specific engine invocation is what is gated, that the rest of the Bash lane is unaffected, and that the skill need not have been invoked for this to fire.
Session belt: say that /disk-hygiene:clean was invoked in this session, that the belt persists until the session ends, and name the recovery lanes — including that a subagent does not inherit it, caveated as undocumented.
No behavior change, no scope change. The two guards keep doing exactly what they do; they stop claiming to be each other.
Related
Umbrella: #3347. F9.3/F9.4 in that issue cover the belt's missing escape hatch and its over-broad scope, which are separate and larger.
plugins/disk-hygienev0.20.21. Split out of the audit umbrella. F13, medium-high. Cheapest high-value fix in that report: a message change, no behavior change.Problem
The plugin has two Bash-denying surfaces with opposite scopes:
hooks/hooks.jsononPreToolUsematcherBash|PowerShellwith no invocation predicate. Active in every session whether or not/disk-hygiene:cleanwas ever invoked.disk-hygiene:clean: frontmatter Bash belt is session-lifetime, not skill-scoped (+6 findings from a post-use audit) #2618).They emit identical denial text. A user who has never invoked the skill triggers the always-on gate and is told their Bash lane is restricted to the skill's scan/preview/handoff-verify/apply shapes — describing a lockout they did not opt into, in the words of a different guard.
Evidence
This misled the audit itself. A Bash denial was initially attributed to the session belt and written up as such. A two-cell control isolated it to the always-on gate, and the finding was withdrawn (F9.1/F9.2). If an audit reading the plugin's own source got this wrong from the message text, an ordinary user has no chance.
The withdrawal also corrected a related claim: the belt does not reach subagents. That non-inheritance is undocumented and build-specific, so it should not be documented as a recovery lane without that caveat.
Suggested fix
Branch the denial message on
resolve_mode()so each guard explains itself:/disk-hygiene:cleanwas invoked in this session, that the belt persists until the session ends, and name the recovery lanes — including that a subagent does not inherit it, caveated as undocumented.No behavior change, no scope change. The two guards keep doing exactly what they do; they stop claiming to be each other.
Related
Umbrella: #3347.
F9.3/F9.4in that issue cover the belt's missing escape hatch and its over-broad scope, which are separate and larger.🤖 Generated with Claude Code