Skip to content

fix(disk-hygiene): flag the parent-folder send-to-Recycle-Bin spelling - #2860

Merged
kyle-sexton merged 3 commits into
mainfrom
fix/2850-recycle-bin-send-form
Aug 16, 2026
Merged

kyle-sexton merged 3 commits into
mainfrom
fix/2850-recycle-bin-send-form

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The Shell.Application Recycle Bin rule shipped for issue 2595 required the literal bin folder id
(NameSpace(10) / NameSpace(0xa)) and a MoveHere/InvokeVerb action. The ordinary way to
send a named item to the bin addresses the item through its parent folder and never mentions
the bin at all:

$sh.NameSpace('C:\some\parent').ParseName('victim').InvokeVerb('delete')

That spelling returned no verdict, so the belt raised no prompt — and because the gate keyed on the
presence of a literal token rather than on the deletion, the same command could be made to prompt by
adding an inert NameSpace(10).Items().Count call.

This keys that shape on the delete verb instead of on the folder id. The bin-id branch is still
evaluated first and keeps its verdict text, so commands satisfying both are unaffected; its action
pattern gains only the InvokeVerbEx suffix described below.

What it now catches

  • InvokeVerb / InvokeVerbEx whose literal verb argument names the delete verb, in single or
    double quotes, with or without a menu accelerator ('&Delete', 'De&lete'), from any namespace —
    the match is context-free, like every other spelling in this pattern set. Requiring a
    Shell.Application context would be a second, trivially-defeated way of doing the same test.
  • InvokeVerbEx specifically: a word boundary closed immediately after InvokeVerb never matched
    the suffixed spelling, which is the stem-vs-suffixed-relative gap this repo has been bitten by
    before. InvokeVerbEx is "similar to InvokeVerb, but it allows you to specify arguments to the
    command as well as the command itself"
    (ShellFolderItem.InvokeVerbEx,
    fetched 2026-08-16).

What it deliberately still does NOT catch

Each of these still defers, and each is now locked by a fixture:

  • MoveHere into an ordinary (non-bin) folder — a MOVE, not a deletion. The existing
    assertIsNone fixture is untouched.
  • CopyHere into an ordinary folder — copies; the original is untouched. CopyHere into the
    bin namespace also defers, exactly as it did before this PR; it is left alone rather than widened
    because no primary source establishes what it does there.
  • Non-delete verbs (InvokeVerb('open')) and the omitted verb (the default, "typically open").
  • An opaque verb argument (InvokeVerb($verb)) — unknowable from the command text. Widening to
    it is its own change, as is widening _POWERSHELL_MUTATION_WORDS.

The delete-verb set is enumerated, not identity-checked, and the pattern set now says so with
its source: the verb argument "must be one of the values returned by the item's
FolderItemVerb.Name property. If no verb is specified, the default verb will be invoked"
(FolderItem.InvokeVerb,
fetched 2026-08-16), and FolderItemVerb.Name merely "Contains the verb's name"
(reference, fetched
2026-08-16). There is no canonical-token identity test available for a COM shell verb, so a verb
named anything else (a localized name) is not covered and completeness is not implied.

The test note claiming Move-Item is the catch-all for these COM spellings is corrected:
_POWERSHELL_MUTATION_WORDS matches neither MoveHere (the move entry's trailing (?![\w-])
rejects the here) nor InvokeVerb — verified by execution, printed below, not by reading.

Verified by execution

powershell_decision(command, enabled=True) driven directly against the pre-fix module (the
origin/main blob 042b7051, copied out and hash-verified) and against the patched module:

probe before after
$sh.NameSpace('C:\some\parent').ParseName('victim').InvokeVerb('delete') (send form) DEFER ask
(New-Object -ComObject Shell.Application).NameSpace(10).MoveHere($path) ask ask
$shell = New-Object -ComObject Shell.Application; $shell.NameSpace(10).MoveHere($path) ask ask
$shell.NameSpace(0xa).ParseName($path).InvokeVerb('delete') ask ask
(New-Object -ComObject Shell.Application).NameSpace('C:\tmp').MoveHere($path) (move) DEFER DEFER
...ParseName('victim').InvokeVerbEx('delete') DEFER ask
...ParseName('victim').InvokeVerb('&Delete') DEFER ask
...ParseName('victim').InvokeVerb('open') DEFER DEFER
...ParseName('victim').InvokeVerb() DEFER DEFER
NameSpace('C:\tmp').CopyHere($path) DEFER DEFER
NameSpace(10).Items() DEFER DEFER
...ParseName('victim').Verbs() DEFER DEFER

_POWERSHELL_MUTATION_WORDS.search(...) returns None for both the folder-path MoveHere and the
InvokeVerb('delete') command, before and after.

The three new fixture sets were run against the pre-fix guard module and fail there
(test_powershell_deletion_spellings_force_final_prompt,
test_powershell_deletion_spellings_denied_in_audit_only_mode, and the new
test_powershell_shell_app_send_to_bin_via_parent_folder_prompts); the deferral test passes both
before and after, so its added cases lock existing behavior rather than change it.

Deliberate over-coverage

A fresh-context reviewer flagged that the leading (?<![\w]) lets a hyphen-prefixed relative
through: My-InvokeVerb('delete') (a wrapper function) returns ask. That is kept on purpose and
the reason is now recorded in the pattern comment — tightening it to the cmdlet list's
(?<![\w./\\-]) would buy precision by making a deleting wrapper go silent, which is the exact
failure this rule exists to close. Prompting once on a wrapper is the cheaper error. Text that
merely mentions the spelling (Select-String "InvokeVerb('delete')") likewise prompts, which is the
same behavior every other spelling in this file already has for a mention of Remove-Item.

Gates run locally

check-changelog-parity.sh --check, --check-order, --check-bump origin/main,
--check-preserved origin/main, validate-plugins.sh, markdownlint-cli2 on the CHANGELOG,
run-ruff.sh check/format --diff on both touched Python files (no new findings; the only
pre-existing ones are untouched regions), and the plugin's Python suites. Six failures in the local
Windows run (test_stash_must_exist_in_an_independent_checkout,
test_preview_allows_root_children_os_managed_snapshot, two in test_guard_launch_monitor, two in
test_hook_telemetry) reproduce identically on a pristine origin/main worktree and are unrelated
to this change.

Related

The Shell.Application rule shipped for issue 2595 required the literal Recycle
Bin folder id (NameSpace(10) / NameSpace(0xa)) AND a MoveHere/InvokeVerb
action, so the ordinary way to send a named item to the bin --
$sh.NameSpace('<parent folder>').ParseName('victim').InvokeVerb('delete'),
which addresses the item through its containing folder and never mentions the
bin -- returned no verdict at all. The belt raised no prompt, and because the
gate keyed on a literal token rather than on the deletion, the same command
could be made to prompt by adding an inert NameSpace(10) call.

The widened rule keys that shape on the delete VERB instead of on the folder
id: an InvokeVerb / InvokeVerbEx call whose literal verb argument names the
delete verb now returns "ask" (and "deny" in audit-only mode), whatever
namespace the FolderItem was obtained from -- consistent with every other
spelling in this set, which are all context-free token matches. InvokeVerbEx
is covered by the same token because a word boundary closed immediately after
InvokeVerb never matched the suffixed spelling.

What the rule deliberately still does NOT catch, each still deferring:

- MoveHere into an ordinary (non-bin) folder: that is a MOVE, not a deletion.
  Its fixture still asserts assertIsNone, and now carries CopyHere beside it.
- Non-delete verbs (InvokeVerb('open')) and the omitted default verb
  ("typically open" per the FolderItem.InvokeVerb reference).
- An opaque verb argument (InvokeVerb($verb)) -- the verb is unknowable from
  the command text. Widening to it, like widening _POWERSHELL_MUTATION_WORDS,
  is its own change.

The delete-verb set is enumerated, not identity-checked, and the pattern set
now says so: the verb argument "must be one of the values returned by the
item's FolderItemVerb.Name property" (Microsoft's FolderItem.InvokeVerb
reference, fetched 2026-08-16), i.e. a name out of the item's own verb
collection, not a stable canonical token -- so a verb named anything else (a
localized name) is not covered and completeness is not implied.

The test note claiming Move-Item is the catch-all for these COM spellings is
corrected: _POWERSHELL_MUTATION_WORDS matches neither MoveHere (the "move"
entry's trailing boundary rejects the "here") nor InvokeVerb, verified by
execution rather than by reading.

Closes #2850

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPRAvSLuRmR6rPQeCvdok6
@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown

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

claude Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 52s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Determine security-relevant surface (skip gate check)
  • Review destructive_guard.py changes for logic/injection issues
  • Review test_hygiene.py, plugin.json, CHANGELOG for anything security-relevant
  • Report findings

Scope: plugins/disk-hygiene/skills/clean/scripts/destructive_guard.py and its test file, plus a version bump and changelog entry.

No security issues found.

The change is a purely additive heuristic fix to a PowerShell-command classifier used by disk-hygiene's guard hook: it adds a second, independent detection path (_shell_application_recycle_bin_delete_reason, L1387-L1445) that keys detection on the InvokeVerb/InvokeVerbEx delete-verb argument, alongside the original bin-folder-id branch, which is checked first and left byte-for-byte equivalent. Specifically checked:

  • No regression vs. origin/main. The original NameSpace(10/0xa) + MoveHere/InvokeVerb bin-id branch is preserved unchanged and still evaluated first (L1420-L1428); the new verb-keyed branch only adds coverage, it doesn't narrow or replace an existing check. powershell_decision's call site and downstream _powershell_mutation_verdict gating (kill-switch → deny in audit-only mode, ask otherwise) are untouched.
  • No ReDoS. The new patterns (_POWERSHELL_SHELL_APP_INVOKE_VERB_ARG, L1394-L1396) use a bounded [^"']* capture with no nested/overlapping quantifiers — no catastrophic-backtracking shape.
  • Accelerator/case handling is sound. _shell_verb_name_deletes (L1399-L1405) strips all & accelerators and casefolds before comparing against the enumerated verb set — correct for '&Delete'/'De&lete' and locale-agnostic ASCII case variants.
  • This is a heuristic guard, not an auth/trust boundary. The classifier's inherent limitation — an enumerated, non-identity verb match that a sufficiently obfuscated command string (e.g. string concatenation building the verb) could still evade — is pre-existing to this pattern-matching design (shared by every other spelling in the file) and is explicitly disclosed in the PR body ("ENUMERATED, NOT IDENTITY-CHECKED... completeness is not implied"), not a new gap introduced here. Not flagging as a finding since it's a disclosed, unchanged design tradeoff rather than a regression.
  • plugin.json/CHANGELOG.md changes are version/metadata only; test_hygiene.py changes are additive test fixtures only — no security-relevant surface in either.

No pull_request_target/workflow_run usage, secrets handling, injection surfaces, or Actions permission changes are present in this diff.

@github-actions

github-actions Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Last security-reviewed head: 54b1f89e13b273712fbcfb589c2125dd6424dfb4. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@claude

claude Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 14s —— View job


Claude's PR review

Todo list

  • Gather context (PR body, changed files diff)
  • Read destructive_guard.py diff in full
  • Read test_hygiene.py diff in full
  • Check CHANGELOG / plugin.json version bump
  • Verify regex logic against claimed test matrix
  • Post inline findings (none warranted — see below)
  • Post final summary

Summary

I reviewed the diff (git diff origin/main...HEAD) against the four changed files. The fix is narrowly scoped, well-reasoned, and matches its own description precisely. I traced the two new/changed regexes by hand against the fixture matrix rather than by executing pytest (see note below), and every claim checks out:

  • _POWERSHELL_SHELL_APP_BIN_ACTION — adding (?:Ex)? before the trailing \b correctly extends the bin-id branch to InvokeVerbEx without falsely matching an unrelated identifier like InvokeVerbExtra( (the \s*\( after the optional group forces backtrack-and-fail there).
  • _POWERSHELL_SHELL_APP_INVOKE_VERB_ARG — the quote backreference ((?P<quote>["'])...(?P=quote)) correctly rejects mismatched-quote pairs, and the (?<![\w]) lookbehind before InvokeVerb correctly excludes a dotted/bracket-prefixed access (.InvokeVerb() is still matched since . isn't a word char, while a bare identifier suffix (myInvokeVerb() is correctly excluded.
  • _shell_verb_name_deletes — stripping & before casefold-equality (not substring) correctly matches '&Delete'/'De&lete' accelerators while correctly rejecting a verb merely containing "delete" as a substring (e.g. a hypothetical "undelete"), consistent with the "enumerated, not identity-checked" design the comment block documents.
  • The bin-id branch is checked first in _shell_application_recycle_bin_delete_reason, so a command satisfying both branches keeps the original NameSpace(10) verdict text, exactly as claimed.
  • Confirmed via grep that the renamed _is_shell_application_recycle_bin_delete → _shell_application_recycle_bin_delete_reason has no stale references left anywhere in the plugin.
  • The _POWERSHELL_MUTATION_WORDS/move claim in the corrected test comment checks out from the pattern itself: move is followed by (?![\w-]), which rejects MoveHere (the H is a word char), so Move-Item genuinely isn't a catch-all for these COM spellings.
  • plugin.json version bump (0.20.10 → 0.20.11) and the CHANGELOG.md entry are consistent with a patch-level fix and describe both what's now caught and what's deliberately still deferred.
  • New fixtures (test_powershell_shell_app_send_to_bin_via_parent_folder_prompts, plus additions to the force-prompt/audit-deny/defers tests) cover the accelerator, double-quote, InvokeVerbEx, non-delete-verb, omitted-verb, and CopyHere cases described in the PR body.

No correctness, security, or maintainability issues found — I have no inline comments to add. One very minor, non-blocking observation: the audit-only-mode denial test (test_powershell_deletion_spellings_denied_in_audit_only_mode) only adds the plain InvokeVerb('delete') parent-folder case, not the accelerator/InvokeVerbEx variants — those are only exercised in enabled mode. Given powershell_decision's enabled/disabled branching is otherwise identical for this rule, this isn't a real gap, just noting it.

Note on verification: the Bash tool in this environment blocked python3/pytest invocations pending approval (only plain shell commands like git/echo were permitted), so I could not execute the test suite myself. I instead manually traced both new regexes against every fixture in the diff (including the ones documented as pre-fix DEFER / post-fix ask in the PR body) and they all resolve as claimed. If test execution is required for sign-off, the plugin's local Python suite is the one to run.

@github-actions

github-actions Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude has reviewed this PR 3 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

…erdict

Fresh-context review of the widened Recycle Bin rule raised three points, all
about the rule describing itself accurately rather than about what it matches:

- The verb-keyed match is context-free by design, so a command that never
  mentions Shell.Application (a FolderItem obtained some other way, or any
  other COM object exposing InvokeVerb) got a reason naming a library absent
  from the command. The reason now says "a COM shell delete verb".
- _shell_verb_name_deletes documented the accelerator strip but not the
  whitespace strip, which is what resolves a padded literal (' delete ') to
  the enumerated verb.
- The CopyHere non-catch is qualified: only CopyHere into an ORDINARY folder
  is stated, since a CopyHere into the bin namespace is untested here and its
  behavior is not established from a primary source.

The leading `(?<![\w])` is left as-is and the reason recorded: a hyphen-
prefixed relative (My-InvokeVerb('delete'), a wrapper) still matches on
purpose. Tightening it to the cmdlet list's `(?<![\w./\-])` would buy
precision by making a deleting wrapper go silent, which is the failure this
rule exists to close.

No verdict changes: the probe set and the plugin's PowerShell-lane tests
return the same decisions as before this commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPRAvSLuRmR6rPQeCvdok6
@claude

claude Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 51s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review
  • Report findings

Skip gate: no security-relevant surface in the new commits.

The only commits since the last successful security review (1929f76, reviewed above) are in 3221e7d — fix(disk-hygiene): name the COM verb, not Shell.Application, in the verdict. That commit only:

  • Rewords the verdict/reason string from "a Shell.Application delete verb" to "a COM shell delete verb" in destructive_guard.py#L1450 — cosmetic, matches no differently.
  • Adds a .strip() call in _shell_verb_name_deletes so a whitespace-padded verb literal (' delete ') still resolves to the enumerated verb — this only widens an advisory heuristic match, it introduces no new injection surface, doesn't touch trust boundaries, and doesn't weaken any check.
  • Expands a code comment explaining the deliberate (?<![\w]) lookbehind choice, and a corresponding CHANGELOG wording fix. No code-behavior change from either.

No pull_request_target/workflow_run usage, secrets handling, permission changes, or injection surfaces are touched by this delta. This module is a local, advisory PreToolUse pattern-matching guard (prompts/denies a command the agent already chose to run) — not an authentication or authorization boundary — consistent with the prior review's assessment of the rest of this PR, which also found no issues.

No security issues found.

@claude

claude Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 1s —— View job


Code review complete

  • Gather context (PR diff, changed files)
  • Read destructive_guard.py and test_hygiene.py diffs in full
  • Review changed regex logic against fixture matrix
  • Check CHANGELOG / plugin.json version bump
  • Post findings (inline + summary)

Scope: destructive_guard.py (regex + verdict logic), its test fixtures, plugin.json, and CHANGELOG.md. This synchronize event added a second commit (3221e7d) that's wording/documentation-only on top of the already-reviewed first commit — no verdict changes, confirmed below.

Findings

One non-blocking doc nit posted inline: _shell_application_recycle_bin_delete_reason's docstring still frames the function as "Shell.Application Recycle Bin deletion" without noting the verb-arg branch is deliberately context-free (matches any COM object's InvokeVerb('delete'), not just one from Shell.Application) — a distinction the second commit's own message draws but doesn't carry into the code comments. Purely documentation; no behavior issue.

Verification

Hand-traced both regexes (_POWERSHELL_SHELL_APP_BIN_ACTION, _POWERSHELL_SHELL_APP_INVOKE_VERB_ARG) and _shell_verb_name_deletes against the full fixture/probe matrix in the PR body, plus a few adversarial cases not in that matrix:

  • Mismatched-quote verb arg (InvokeVerb('delete")) — correctly fails to match (no valid quote pair), defers.
  • String-concatenated verb (InvokeVerb('del'+'ete')) — correctly defers; only the literal first quoted token is read, consistent with the documented "opaque verb" non-goal.
  • Bare mention in a string argument (Select-String "InvokeVerb('delete')") — correctly still flags, consistent with how every other spelling in this file treats a mention.
  • InvokeVerbEx boundary extension, accelerator stripping (&Delete/De&lete), whitespace-padded verb (' delete '), and the hyphen-prefixed-wrapper over-match (My-InvokeVerb('delete')) all resolve exactly as the PR body claims.

Also confirmed:

  • No stale references to the renamed _is_shell_application_recycle_bin_delete remain anywhere in the plugin.
  • The bin-id branch is still checked first in _shell_application_recycle_bin_delete_reason, so a command satisfying both branches keeps the original NameSpace(10) verdict text.
  • Second commit (3221e7d) touches only CHANGELOG.md wording and comments/docstrings/the reason string in destructive_guard.py — no regex or control-flow changes, matching its own "no verdict changes" claim.
  • New/modified test fixtures in test_hygiene.py are correctly scoped to GuardTests, correctly indented, and assert the right decision (ask/deny) and reason substring for each new case.
  • plugin.json version bump (0.20.10 → 0.20.11) and CHANGELOG.md entry are consistent with a patch-level fix.

No correctness, security, or maintainability blockers found. This is a narrowly-scoped, well-documented widening of an existing detection rule with no regressions to the bin-id branch it builds on.

Comment thread plugins/disk-hygiene/skills/clean/scripts/destructive_guard.py
…cation

Review found the docstring still promised a Shell.Application Recycle Bin
spelling while the second branch is deliberately context-free: it matches a
literal delete verb passed to InvokeVerb on any COM object, with no
Shell.Application or NameSpace call required. A reader with only the
docstring — not the commit history — could reasonably infer a context that
is not required.

Behavior is unchanged; the reason string already said "COM shell delete
verb" rather than naming Shell.Application, for this same reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPRAvSLuRmR6rPQeCvdok6
@claude

claude Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 20s —— View job


Security review complete ✅

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Report findings

Note: the review:security-review skill did not load in this run (invocation returned an empty error each time it was called). I performed the equivalent review manually — full diff against the merge base (2d20a27) of destructive_guard.py, test_hygiene.py, plugin.json, and CHANGELOG.md.

No security issues found.

Scope of the delta since the last successful security review (1929f76/3221e7d, both already reviewed above): the head commit 54b1f89 only extends the _shell_application_recycle_bin_delete_reason docstring — it addresses the earlier inline review comment noting the docstring didn't state that the verb-arg branch is context-free (matches InvokeVerb('delete') on any COM object, not just Shell.Application). Pure comment/docstring change, no behavior difference, no new surface.

For completeness, re-verified the full PR diff from a security lens:

  • No injection surface. _POWERSHELL_SHELL_APP_INVOKE_VERB_ARG (L1413-L1415) is a read-only pattern match over a command string the agent already chose to run; nothing here is executed, interpolated, or shells out.
  • No ReDoS. Both new/changed patterns use bounded, non-overlapping quantifiers ([^"']* closed by a backreferenced quote, \s*, (?:Ex)?) — no nested or ambiguous quantifiers that could cause catastrophic backtracking.
  • No regression to the existing bin-id branch. It is checked first and is byte-for-byte unchanged in matching behavior; the new verb-arg branch is purely additive coverage, and downstream _powershell_mutation_verdict gating (kill-switch → deny in audit-only mode, ask otherwise) is untouched.
  • Heuristic guard, not a trust boundary. This module is an advisory PreToolUse classifier that can only prompt/deny a command already selected by the agent — it doesn't authenticate, authorize, or sanitize anything. Its disclosed limitation (enumerated, non-identity verb matching; a concatenated/opaque verb argument evades it) is a pre-existing design property shared by every other spelling in this file, explicitly documented in the new code comments, and not a regression introduced by this PR.
  • plugin.json (version bump) and CHANGELOG.md changes are metadata/documentation only. test_hygiene.py changes are additive fixtures only.

No pull_request_target/workflow_run usage, secrets handling, or Actions permission changes anywhere in this diff.

@claude

claude Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 17s —— View job


Claude's PR review

Todo list

  • Gather context (PR diff vs 2d20a27, prior review comments/threads)
  • Run skip-gate check — new commit since last code-review pass, so proceeding
  • Re-read destructive_guard.py diff in full, focusing on the new commit
  • Hand-trace _POWERSHELL_SHELL_APP_INVOKE_VERB_ARG and _shell_verb_name_deletes against the fixture/probe matrix
  • Confirm the prior inline review comment was addressed
  • Check test_hygiene.py, CHANGELOG.md, plugin.json diffs
  • Post findings

Summary

Per /review:code-review's skip gate, this pass exists because the head moved since the last code-review pass (3221e7d → 54b1f89), so it isn't stale. The new commit, 54b1f89, is doc-only: it adds the paragraph to _shell_application_recycle_bin_delete_reason's docstring stating the verb-arg branch is context-free (matches InvokeVerb('delete') on any COM object, not just Shell.Application). That's exactly the gap flagged in the prior inline review comment on 3221e7d (posted 2026-08-16T10:34:49Z on line 1445 of destructive_guard.py) — it's resolved, and no code/regex/control-flow changed in this commit.

I independently hand-traced (this sandbox blocks python3/pytest execution, as noted in earlier passes on this PR — the same limitation, no change) both regexes against the full probe matrix from the PR body plus the adversarial cases from prior passes (mismatched quotes, InvokeVerbExtra, myInvokeVerb/My-InvokeVerb, string-concatenated verb, whitespace-padded verb, accelerators, opaque $verb, bare mention in a string). Every case resolves exactly as claimed; nothing in this diff changes that.

No correctness, security, or maintainability issues found. No inline comments to add — the diff is clean and the one substantive finding raised on the prior head has already been fixed.

Other checks:

  • plugin.json (0.20.10 → 0.20.11) and the CHANGELOG.md entry are unchanged by this commit and remain consistent with a patch-level fix.
  • test_hygiene.py fixtures are unchanged by this commit.
  • No stale references to the renamed _is_shell_application_recycle_bin_delete remain in the plugin.

Note on verification: as in prior passes on this PR, this environment does not permit executing python3/pytest, so the regex trace above is by hand, not by running the suite. If execution-based sign-off is required, run the plugin's local Python test suite.

@kyle-sexton
kyle-sexton merged commit 22f3b30 into main Aug 16, 2026
46 checks passed
@kyle-sexton
kyle-sexton deleted the fix/2850-recycle-bin-send-form branch August 16, 2026 15:58
kyle-sexton added a commit that referenced this pull request Aug 16, 2026
Resolves CHANGELOG collisions with main's disk-hygiene 0.20.11 (#2860)
and repo-fleet-hygiene 0.23.2 (#2857): this branch's simplification
entries move to 0.20.12 / 0.23.3 and the manifests are re-bumped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant