deadeye-sweep ยท diff
git:20260804.af65d3d to git:20260911.b6d782c
280 added, 43 removed. Audit A to A.
---
name: deadeye-sweep
- description: Whole-repo over-engineering audit, ranked by biggest cut first.
+ description: Applies the findings from /deadeye-review, /deadeye-pr, and /deadeye-guard, verifies the build, and re-scans on a loop until nothing (critical/high, or every severity with --all) survives. In --pr mode also answers the PR's own open review comments, replying and resolving.
license: MIT
+ argument-hint: "[--repo|--pr [<PR>]] [<max-passes>] [--commit] [--all]"
---
# Deadeye Sweep
- Scan the whole repository for over-engineering and report a ranked
- list โ biggest cut first. Same five tags as /deadeye-review
- (`delete:` `stdlib:` `native:` `yagni:` `shrink:`), one line each:
+ `/deadeye-review`, `/deadeye-pr`, and `/deadeye-guard` all end the same way:
+ "Findings are a LIST. Do not apply them unless asked." Typing `/deadeye-sweep`
+ IS that ask. It runs the review, audits each finding's premise, applies the
+ ones that are ๐ด/๐ **and** in reach, proves the tree still builds, then
+ re-scans the changed code and repeats until a pass comes back clean.
- `<tag> <what to cut>. <replacement>. [path]`
+ Sweep does not reimplement scanning โ it invokes the existing skills and
+ consumes their printed findings. Coder mode stays active throughout: the
+ fixes it writes follow the lean-first ladder, not a patch bolted at the line
+ the finding named.
- End with `net: -<N> lines, -<M> deps possible.`
+ ## Scope
- ## How โ scope cheaply, this plugin's whole point is token thrift
+ - **default** โ the working diff. Scan: `/deadeye-review`, then `/deadeye-guard`.
+ - **`--pr [<PR>]`** โ that PR, or the current branch's PR with none given.
+ Scan: `/deadeye-pr <PR>`, then `/deadeye-guard`, then the PR's own open
+ review comment threads (see "PR review comments" below). If the current
+ branch isn't the PR's head branch, ask before `gh pr checkout <PR>` โ
+ before pass 1 does anything, since every fix that follows is applied
+ locally to that branch.
+ - **`--repo`** โ the whole repository. Scan: `/deadeye-review --repo` only โ
+ `/deadeye-guard` has no whole-repo mode, and `--repo` already runs the
+ security lens plus native dependency auditors.
+ - A bare integer lowers the pass cap (default: loop until clean, hard cap
+ **5**) โ e.g. `/deadeye-sweep --repo 2`. The integer right after `--pr` is
+ the PR number; any other bare integer is the cap.
+ - `--commit` โ commit each pass that verifies green. Off by default. Never
+ pushes on its own; see "PR handoff" below.
+ - `--all` โ lowers the severity floor to include ๐ก medium and โช nits (see
+ "What gets fixed"). Off by default โ the unattended default stays ๐ด/๐
+ only. The reach gate still applies either way; `--all` widens which
+ severities qualify, not how far a fix is allowed to reach.
- 1. Enumerate with `git ls-files` (or `find` with `-maxdepth` if not a
- git repo) โ never by reading directories of files whole.
- 2. Grep-first for candidates before opening ANY file body: duplicate
- deps (`go.mod`/`package.json` vs stdlib), `interface` declarations
- (then `grep -c` their implementers), one-export files, config keys
- (then grep for readers), wrapper-shaped names (`*Wrapper`, `*Manager`,
- `*Factory`, `*Helper`).
- 3. Read full file contents ONLY for the top candidates you intend to
- list โ a sweep that reads the whole repo into context is the exact
- waste this plugin exists to prevent.
+ Empty diff (nothing changed or staged): say so plainly and stop โ do not
+ substitute a different scope. Not a git repo: stop, sweep needs a restore
+ point it can't build without one.
- ## Verify before reporting
+ **The scan's verdict is step 2 of 6, not the end.** `/deadeye-review` and
+ `/deadeye-pr` close with something that reads like a finish line
+ (`Ship it.`). When you invoke them here, that verdict is not the end of the
+ turn โ carry the findings straight into the premise audit below.
- Before listing a finding, confirm it: grep for ALL implementers/callers
- across the repo (including test files and other packages) โ "interface
- with one implementation" must mean one implementer exists, not one you
- happened to find. A finding that's wrong on second look erodes trust in
- every other finding. Report only what you confirmed.
+ ## The loop
- ## What to hunt
+ One pass:
- - Dependencies that duplicate what the stdlib ships
- - Interfaces with a single implementation
- - Factories that only ever build one product
- - Wrappers that purely delegate
- - Files exporting one small thing that belongs next to its caller
- - Feature flags and config keys nothing reads
- - Abstractions with exactly one call site
+ 1. **Scan.** Pass 1 invokes the review skill for the scope above, then (diff
+ and PR modes only) `/deadeye-guard` โ sequentially, never both loaded at
+ once. Pass 2+ does **not** re-invoke the Skill tool: the rubric is already
+ in context, and re-running the scan procedure directly against the current
+ diff is the whole point of the loop. Pass 2+ scope:
+ - default / `--pr`: full re-scan โ `git diff` (default) or
+ `git diff <baseRefName>...HEAD` locally for `--pr` (not `gh pr diff`,
+ which reads the *remote* branch and would just re-report what pass 1
+ already fixed locally).
+ - `--repo`: run the diff rubric (not `--repo` again) over the accumulated
+ working diff, plus an explicit grep for callers of anything the previous
+ pass deleted or renamed. Reuse the diff scan, don't hand-roll a third
+ scan mode.
- ## Output discipline
+ In `--pr` mode only, pass 1 additionally pulls every open review comment
+ thread on the PR and folds each into this same pass's triage โ see "PR
+ review comments" below for the fetch, the (absent) floor, and how they get
+ answered.
+ 2. **Audit the premise.** A finding is a claim, not a work order โ re-grep
+ what it asserts (callers, implementers, existing guards, the absence it
+ claims) before touching anything. Disproved โ drop it, print the one-line
+ evidence, and move on. Fixing fewer findings than the scan printed is
+ correct behavior here, not a shortfall. Do not record a disproved finding
+ as `review-false-positive` โ that record means a *human* disputed it
+ (see Learning loop); auto-recording it here would let sweep desensitize
+ its own scanner with nobody in the loop.
+ 3. **Triage.** Split survivors by both gates in "What gets fixed."
+ 4. **Apply.** You write every fix yourself, in the main session, coder mode
+ active โ no subagent fan-out. The severity floor already bounds a pass to
+ a handful of findings; splitting them across subagents would separate a
+ finding from the cross-file context that made it real (an interface named
+ in one file, its one implementer in another), make a red build
+ unattributable to one edit, and lose coder mode's session-level persona,
+ which a fanned-out agent does not inherit.
+ 5. **Verify.** Run the check command (see gate below). Green โ pass recorded.
+ Red from formatting alone โ run the formatter, re-check, no repair budget
+ spent. Red from anything else โ one repair attempt, then restore the
+ snapshot and stop.
+ 6. **Re-scan.** Loop back to step 1 for the next pass.
- - Rank by lines removable, not by how easy the fix is.
- - Cap at 20 findings. Fewer exist โ stop; never pad with weak ones.
- More exist โ keep the 20 biggest and say how many were omitted.
- - Nothing found: exactly `Lean already. Nothing to cut.`
- - If a replacement is itself a deliberate simplification with a known
- ceiling (not a straight deletion), include the marker line to plant:
- `# deadeye: <shortcut>. ceiling: <limit>. upgrade: <trigger>.`
+ **Confirm once, before pass 1, then run unattended.** Print the triaged list
+ โ what will be fixed, what's deferred and why, what's below the active floor
+ (and that `--all` is on, if it is), which check command will run, whether
+ `--commit` is on and on which branch (flag it if it's the default branch),
+ and (in `--pr` mode) how many open review comment threads were found and how
+ many are in scope โ and wait for a go-ahead. Say plainly that
+ passes 2+ will **not** stop again, bounded only by the gates below โ except:
+ if any later pass's fix list is more than 2ร pass 1's, stop and re-confirm.
+ An unattended writer suddenly going wide is exactly what that check catches.
+ ## What gets fixed
+
+ Both gates must pass:
+
+ - **Severity floor: ๐ด critical and ๐ high by default.** ๐ก medium and โช nits
+ are printed in the final report, never applied โ churn, not consequence, in
+ an unattended run. With `--all`, all four severities clear this gate; state
+ that explicitly at the confirmation step, since it changes what an
+ unattended pass is allowed to touch.
+ - **Reach: the fix is contained in the files the finding names.** Unaffected
+ by `--all` โ a nit still doesn't buy a signature change into untouched
+ callers.
+
+ Deferred โ reported, not touched:
+
+ - a fix that changes an exported signature and ripples into call sites this
+ work never entered
+ - a design decision with more than one defensible answer
+ - vendored code, generated code, lockfiles
+
+ Coder mode's own rule, applied to someone else's finding list: fix what's in
+ reach, name the rest.
+
+ Dependency findings from the guard pass are in reach when the fix is a bump
+ to a fixed version โ edit the manifest and regenerate the lockfile with the
+ native tool (`go get`, `npm install`), never hand-edit a lockfile. A
+ major-version bump, or a CVE with no fixed version, is a design decision โ
+ defer.
+
+ Never delete the one runnable check coder mode leaves behind, or the one log
+ breadcrumb at a real failure boundary โ both are load-bearing, same as in
+ `/deadeye-review`.
+
+ ## The verify gate
+
+ First check command that applies, in order: `make check` (or `make test` if
+ that's what the Makefile defines) โ Go: `go build ./... && go test ./...` โ
+ Node: the `package.json` test script, plus `tsc --noEmit` if a tsconfig
+ exists โ `pytest` / `cargo test`. None found โ ask once, at the confirmation
+ step; declined โ build only, and say so in the output. Never print a green
+ verdict for a check that didn't run.
+
+ Restore point, taken before applying, every pass:
+
+ ```bash
+ git add -N <untracked paths in scope> # so they're visible to the scan and the stash
+ git stash create
+ git rev-parse HEAD # fallback โ stash create prints nothing on a clean tree
+ ```
+
+ A red verify after the one repair attempt: `git checkout <sha> -- .`, stop,
+ print the failure output.
+
+ ```
+ deadeye: snapshot restores tracked files only. ceiling: files a pass newly
+ creates survive the revert. upgrade: when sweep starts creating files.
+ ```
+
+ With `--commit`: stage only the paths this pass edited โ
+ `git add <paths>` then `git commit -m "sweep: pass <n> โ <k> fixes"`. Never
+ `git commit -a`: in the default scope, the user's own uncommitted work *is*
+ the scope, and `-a` would fold it into a commit labeled as sweep's. Never
+ `git push`.
+
+ ## Stop conditions
+
+ First one that fires wins:
+
+ 1. A scan returns nothing at or above the active floor (๐ด/๐ , or all four
+ under `--all`) โ converged
+ 2. Pass cap reached (the user's N, else 5)
+ 3. Verify red after the one repair attempt โ restore, stop
+ 4. A pass applies zero fixes (everything dropped or deferred) โ no progress, stop
+ 5. Oscillation โ a finding at the same `path + tag + normalized description`
+ (never line number, which shifts every edit) reappears after being fixed โ
+ stop and report it
+ 6. A pass's fix list exceeds 2ร pass 1's โ stop and re-confirm
+
+ ## Learning loop
+
+ Same mechanism as `/deadeye-review`, same best-effort contract (retry once
+ with `~/.deadeye/bin/deadeye`, else continue regardless). For every finding
+ you actually **applied** this run:
+
+ ```bash
+ deadeye lessons record coder-miss <lens>:<tag>
+ ```
+
+ Diff and PR scope only โ `--repo` sweeps pre-existing code nothing wrote this
+ session, so it never attributes to coder mode. Never call
+ `lessons record review-false-positive` from here โ that record means a human
+ disputed the finding; a premise-audit drop is sweep's own judgment, not
+ theirs, and auto-recording it would quietly desensitize the next scan.
+
+ ## Output
+
+ ```
+ pass 1 โ 11 findings ยท 2 dropped (premise) ยท 4 ๐ด/๐ in reach ยท 4 fixed ยท check: green
+ pass 2 โ 3 findings ยท 1 fixed ยท check: green
+ pass 3 โ clean
+
+ Converged in 3 passes. 5 fixes, +11/-84. Tree is dirty โ review with `git diff`.
+ Dropped (2): internal/x.go:41 โ authz: guard exists one call down at y.go:88.
+ Deferred (1): internal/x.go:12 โ yagni: exported, 6 call sites outside this change.
+ Below floor: 3 ๐ก, 1 โช.
+ Say the word and I'll take the deferred one and the mediums.
+ ```
+
+ (Under `--all` there's no "Below floor" line โ every severity already cleared
+ the gate, so what's left is only "Dropped" and "Deferred".)
+
+ Terminal strings: `Converged โ nothing left to cut.` when a pass finds
+ nothing left; `Nothing to sweep โ the scan came back clean.` when pass 1
+ itself finds nothing (distinct from convergence โ say plainly there was no
+ work to do). No `DEADEYE-SWEEP.md`, no state file between runs โ leftovers
+ are printed and closed with the one follow-up line, same as `/deadeye-debt`'s
+ report-only convention.
+
+ ## PR review comments and handoff (`--pr` mode)
+
+ Pass 1 pulls the PR's own review threads and treats each **unresolved** one
+ as an additional finding, fed through the same pipeline a scanner finding
+ gets from here on. REST alone can't tell resolved from open โ only the
+ GraphQL thread carries `isResolved` โ so fetch via:
+
+ ```bash
+ gh api graphql -f query='
+ query($owner:String!,$repo:String!,$pr:Int!) {
+ repository(owner:$owner,name:$repo) {
+ pullRequest(number:$pr) {
+ reviewThreads(first:100) {
+ nodes { id isResolved
+ comments(first:100) { nodes { databaseId body path line author { login } } }
+ }
+ }
+ }
+ }
+ }' -F owner=<owner> -F repo=<repo> -F pr=<PR>
+ ```
+
+ - **No severity floor** โ a person asking is already in scope, `--all` or
+ not.
+ - **The reach gate still applies** โ a comment asking for a change that
+ ripples into untouched callers is deferred exactly like a scanner finding.
+ - **The premise audit still applies** โ "a review comment is a claim, not a
+ work order" governs these the same as a scanner finding. A comment can be
+ stale (the code moved since it was written) or already handled by an
+ earlier pass in this same run; re-grep before treating it as work.
+ - It enters the normal apply โ verify โ (revert on red) pipeline, so a
+ reverted pass takes its comment-driven fixes down with it too.
+
+ **When the loop ends**, resolve every thread that got a real answer this run,
+ and offer the two outward actions below โ each its own explicit
+ confirmation, all presented together, none implied by the original
+ invocation:
+
+ 1. **Reply and resolve, per thread:**
+ - *Fixed* โ reply describing what changed, then
+ `POST /repos/<owner>/<repo>/pulls/comments/<databaseId>/replies` with the
+ reply body, then resolve:
+ `gh api graphql -f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' -F id=<thread node id>`.
+ - *Premise disproved* (stale, already handled) โ reply with the evidence.
+ **Leave it open** โ closing someone else's thread on your own say-so
+ isn't sweep's call.
+ - *Deferred* (out of reach, a design decision) โ reply saying so and why.
+ **Leave it open.**
+ 2. **Push the fixes** to the PR branch.
+ 3. **Post one comment** summarizing what was auto-fixed and what was left โ
+ same opt-in shape as `/deadeye-pr --post`, not a new authorization path.
+
+ Print exactly what each action would do โ the reply text included โ before
+ asking.
+
+ **Write every reply like the person who made the fix, not a report
+ generator.** Say what you actually did, plainly, the way you'd tell a
+ teammate over their shoulder: "Good catch โ moved this into gitutil since
+ both files already had a copy" reads like a person; "Fixed. lens: reuse.
+ tag: dup. proof: codemap.go:349, sessionmem.go:38." reads like a scanner
+ dump pasted into a conversation. Keep the `Fix:`/`proof:`/tag glyph shape for
+ sweep's own local report only โ never in a reply a human will read. Address
+ what the reviewer actually wrote, keep it to a sentence or two, and let the
+ phrasing vary thread to thread the way a person's actually does โ five
+ replies that all open "Fixed:" read like a bot even if every fix is real.
+
## Boundaries
- - Report only. Apply nothing unless asked.
- - Skip vendored code, generated code, and lockfiles.
- - The one runnable check per non-trivial change stays โ never list
- smoke tests as bloat.
+ - Never push, reply, or resolve a thread without the confirmation above.
+ - Never resolve a thread whose premise was disproved or whose fix was
+ deferred โ only one that was actually fixed.
+ - Never commit without `--commit`.
+ - Never substitute a different scope than the one requested.
+ - Leave the tree dirty for the user to review with `git diff` (or committed,
+ under `--commit`) โ sweep never claims done on your behalf.
+ - `/deadeye-review` and `/deadeye-pr` stay the report-only versions of this;
+ `/deadeye-guard` stays the dedicated security-only pass.