fix(disk-hygiene): make the confirmation gate answerable and the alias probe reachable - #2016
Conversation
Four stranded post-merge review findings, three of them the same bug class: a condition keyed on a surface being *absent* when the real trigger is present-but-unusable. - The confirmation gate held every question to one bar -- an affirmative naming exactly the tier and path list just shown -- including the no-target prompt and the large-scan confirmation, neither of which has shown a tier or a path list. The surface rule and the answer floor stay common to all four questions; what an answer must name is now stated per question, and the two cross-references that asserted the deletion bar applies unchanged now name their row. - The gate fell back to an inline question only when AskUserQuestion was absent. Permission mode dontAsk denies the tool even when an allow rule names it, leaving it visible while every call fails; only a bare-name deny rule removes it from context. The fallback now triggers on absent or denied. - setup step 1(b) routed to the PowerShell signal only when no alternate interpreter existed at all. A real-but-incompatible launcher -- Python 3.6, which the same section already names as unable to run a future-import -- is not absent, so the check had no path to a verdict. The fallback now also covers a chosen interpreter that emits no verdict. - _discard_stream re-closed the descriptor it had just repaired: os.open returns the lowest free fd, so a target fd closed outright comes back on its own number, dup2 is a no-op, and the unconditional close in the finally undoes the repair. The module's os._exit tail means no exit-status regression rode on this, so this is defense in depth; a new test asserts fd 2 is writable after the repair rather than the exit code that survives either way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nded-review-threads
Drop the `_discard_stream` change and its test. The review thread that prompted them is already discharged on main: the module tail is `os._exit(_exit_code)`, so the exit-status leak the thread reported no longer reproduces regardless of what the fallback does. The remaining descriptor defect is real but unrelated to any finding this branch carries, and belongs in its own change. Close two enumerations that a literal reader could fall out of: - The question-surface rule listed absence and denial as the only two unusable states. It now reads absent, denied, or otherwise unusable, including a denial discovered only by calling the tool. - The per-question table said what an answer must name but never obliged the question to show it, which is the exact shape of the defect the table was written to fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Claude finished @kyle-sexton's task in 1m 56s —— View job Security review — PR #2016
Scope confirmed: all four changed files are prose/manifest — No security issues found. This PR's two substantive edits both touch security-relevant logic (the destructive-action
No injection surface, credential handling, permission-widening, or supply-chain change is present in |
|
Claude finished @kyle-sexton's task in 4m 50s —— View job Review complete
This is a prose-only fix to three stranded review findings against Verified independently:
Not independently verified (sandboxed environment blocked script execution/approval for Finding (Suggestion — consistency gap in the refactor itself): The PR's whole point is that a call site should point at the confirmation gate's per-question row rather than claude-code-plugins/plugins/disk-hygiene/skills/clean/SKILL.md Lines 237 to 240 in 4739892 Compare to the new §6 wording a few lines later ( No other correctness, design, or maintainability issues found in the diff. The markdown table renders |
|
Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
…very site The handoff gate's §6 row requires an answer naming exactly one tier, but the manual-handoff step asked only for an exact path list against a report that is multi-tier by construction. States the single-tier presentation there, so the rule holds at every question it governs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 35s —— View job Security review — PR #2016 (re-run at
|
|
Claude finished @kyle-sexton's task in 3m 8s —— View job Review complete
Scope: prose/manifest only ( Independently verified (not just author-claimed):
Not independently verified ( Finding — carried over from an earlier review pass on this same PR, still unaddressed (Suggestion, not a bug): The PR's stated goal is that a call site should point at the confirmation gate's per-question row rather than restate the "what must be named" bar inline — that's exactly what §1 (line 131) and §6 (line 268) were migrated to do here, including in the latest commit ( claude-code-plugins/plugins/disk-hygiene/skills/clean/SKILL.md Lines 238 to 241 in ea12ae6 This isn't a functional gap — §5's plan is single-tier by construction (§4: "never mix tiers"), and it already shows the table before asking, so it satisfies the rule in substance. It's the one remaining textual inconsistency across the three call sites the table's intro paragraph describes ( No other correctness, design, or maintainability issues found. The table renders correctly, all |
…2255) ## Summary Mirror the #2016 `disk-hygiene` confirmation-gate prose fix in `repo-hygiene`: the inline-question fallback must trigger when `AskUserQuestion` is absent, denied, or otherwise unusable — not only when it is absent. ## Fix - Update `plugins/repo-hygiene/skills/clean/SKILL.md` confirmation gate question-surface rule to match the corrected `dontAsk` / deny / disallowed-tools wording. - Bump plugin to 0.10.1 with CHANGELOG entry. ## Verification Prose-only change; no shell/python suites map to this file. Reviewed against the live permissions docs claim cited in #2088 and the merged `disk-hygiene` sibling wording. ## Related Fixes #2088 (completes the three-item sweep alongside #2252 and #2254). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Three stranded review findings against
disk-hygiene, all in normative prose. No behavior change toany script; the diff is four files and the plugin manifest bump.
What was wrong
The confirmation gate applied one acceptance bar to four different questions. The bar demanded an
answer "naming exactly the tier and path list just shown". Two of the four questions it governs have
shown neither at the point they are asked — the no-target prompt asks the user to supply a
directory, and §1's large-scan confirmation is asked before the walk that would produce a tier or a
path list. Neither could be cleared by any reply a human could give, and one of them gates an
unbounded whole-volume walk. The surface rule and the answer floor are genuinely common to all four,
so they stay shared; what an answer must name is now stated per question in a table. The gate also
now states the obligation that produced the defect in the first place: ask each question so it shows
what its row requires the answer to name.
The gate fell back to an inline question only when
AskUserQuestionwas absent. Perpermissions (fetched 2026-08-08), a bare tool name in
permissions.deny"removes the tool from Claude's context entirely", whiledontAskmode deniesAskUserQuestion"even if you've allowed them" — the tool stays visible and every call fails.Absence and denial are distinct states, and the skill named
dontAskas a cause while keying thetrigger on the one state it does not produce. An agent that checks its tool list would see the tool,
skip the inline branch, call it, be denied, and find no recovery in the text. The fallback now
triggers on absent, denied, or otherwise unusable, including a denial discovered only by calling it.
The
python3alias probe was routed through an interpreter that may be unable to run it.setupstep 1(b) launches the bundled inspect-only probe with "any interpreter already proven real" and
gates the PowerShell escape hatch on no such interpreter existing. But the probe carries
from __future__ import annotations(optional release 3.7.0b1) and PEP 604 unions, and CPythonraises
SyntaxErrorat compile time for a future feature it does not define — so on Python 3.6 theprobe dies before emitting any JSON. The same section already names 3.6 as an interpreter that
rejects guard-shaped code, then routed an identically-shaped probe through it. A 3.6 interpreter is
not absent, so the literal reading never reached PowerShell and the check failed closed with no
detailto remediate from. The fallback now also covers a chosen interpreter that emits no verdict.Scope
A fourth finding on this branch (
_discard_streamre-closing the descriptor it just repaired) wasalready discharged on
mainbefore this branch was reopened: the module tail isos._exit(_exit_code), so the exit-status leak the thread reported no longer reproduces regardlessof what the fallback does. The commit that had added a fix and a test for it is reverted here rather
than carried — the residual descriptor defect is real but maps to no finding this branch owns.
The
dontAskdefect has an exact twin atplugins/repo-hygiene/skills/clean/SKILL.md:85, from thesame original PR. It is deliberately not fixed here: changelog parity is per-plugin, and folding
a second plugin in would require its own bump and entry. Reported separately for its own change.
Verification
live interpreter (
__future__.annotations.getOptionalRelease()), not asserted.check-changelog-parity.sh--check/--check-order/--check-bump,check-changed-skills.sh,check-shell-portability.sh, andmarkdownlint-cli2all pass locally.test_hygiene.py242 pass,python3_alias_probe.test.sh10 pass — unchanged, as expected for aprose-only diff.
0.15.0steps over0.14.0, which is claimed by open PR fix(disk-hygiene): qualify unknown and non-reclaimable byte counts #1870 against the same manifest.Related
Addresses review threads on #1124, #1738.
No linked issue