|
1 | 1 | --- |
2 | 2 | name: pr-sweep |
3 | | -description: "Drive open PRs toward zero across one or many repos by risk-ranking every open PR, auto-merging the low-risk mergeable ones, and surfacing the rest with the exact reason each is held. Use when open PRs have piled up and you want them triaged and cleared in one pass. Batches over the existing /merge-pr and /finalize-pr per PR — it decides which PRs are safe to merge and delegates the merge, it does not reimplement merging." |
| 3 | +description: "Use when open pull requests have piled up in one repo or across an owner's repos and you want the pile triaged and driven toward zero in one pass — including when most of them are bot- or teammate-authored. Also use when a sweep must run many repos in parallel without racing approvals or flooding CI." |
4 | 4 | --- |
5 | 5 |
|
6 | 6 | # PR Sweep |
7 | 7 |
|
8 | | -Take a pile of open PRs and drive it to zero: merge what is safe, surface what is |
9 | | -not with a specific reason. This is triage-and-clear, distinct from |
10 | | -`/prune-branches --sweep` (which deletes dead branches and worktrees). This |
11 | | -skill acts on **open PRs**; that one acts on **repo/worktree state**. |
| 8 | +Drive a pile of open PRs toward zero: merge what is safe, repair what is |
| 9 | +cheaply repairable, and surface the rest with a concrete reason each. This is |
| 10 | +triage-and-clear on **open PRs**; `/prune-branches --sweep` acts on |
| 11 | +**repo/worktree state** and is a different job. |
12 | 12 |
|
13 | | -It does not reimplement merging. It **risk-ranks**, then hands each merge to |
14 | | -`/merge-pr` (which itself runs the readiness gate and calls `/finalize-pr`). |
15 | | -Merges use `/merge-pr`'s default (merge commit) — this sweep never passes |
16 | | -`--squash`. |
| 13 | +This skill decides **which** PRs move and in **what order**. It never |
| 14 | +reimplements merging: each merge is delegated to `/merge-pr`, each repair to |
| 15 | +`/finalize-pr`. |
17 | 16 |
|
18 | | -> **State warning**: PR status, CI, and mergeability change between invocations. |
19 | | -> Re-list and re-check every PR in this run; never act on a cached list. |
| 17 | +## Invariants |
20 | 18 |
|
21 | | -## Scope |
22 | | - |
23 | | -- `/pr-sweep` — open PRs in the current repo. |
24 | | -- `/pr-sweep --org <owner>` — open PRs authored by you across the owner's repos |
25 | | - (`gh search prs --owner <owner> --author @me --state open`). |
| 19 | +These four hold in every mode. They are the difference between a sweep and a |
| 20 | +stampede. |
26 | 21 |
|
27 | | -Always list first, act second. State the count before touching anything. |
| 22 | +1. **Triage is read-only and confers no merge authority.** Classifying a PR |
| 23 | + never merges it. |
| 24 | +2. **A merge happens only against an execution order that pins the head |
| 25 | + commit.** If the head moved since triage, the order is void — re-triage. |
| 26 | + This is what makes an approval round impossible to race. |
| 27 | +3. **Serialize within a repo; parallelize across repos.** Merge ordering, |
| 28 | + broken-base diagnosis, and repo-wide gates are all repo-scoped. |
| 29 | +4. **Cap concurrent merges globally** (default 2–3). Every merge triggers CI, |
| 30 | + and CI capacity is finite and shared. |
28 | 31 |
|
29 | | -## Step 1: List and gather signal |
| 32 | +Never pass `--admin`. Never merge a draft. Never bypass a failing check — |
| 33 | +repair it or hold the PR. |
30 | 34 |
|
31 | | -For every open PR, collect the merge-decision signals in one pass: |
| 35 | +> **State warning**: PR status, CI, and mergeability change constantly, and |
| 36 | +> `mergeable`/`mergeStateStatus` are computed lazily — a first query often |
| 37 | +> returns `UNKNOWN`. Re-query before classifying, and never act on a list |
| 38 | +> gathered earlier in the session. |
32 | 39 |
|
33 | | -```bash |
34 | | -gh pr view <N> --json number,title,url,isDraft,mergeable,mergeStateStatus,\ |
35 | | -reviewDecision,additions,deletions,changedFiles,labels,baseRefName,headRefName |
36 | | -``` |
37 | | - |
38 | | -Also resolve whether the repo is git-flow (default branch `develop`) — a |
39 | | -`develop → main` promotion PR is never swept (see Hold reasons). |
| 40 | +## Merge method is not this skill's business |
40 | 41 |
|
41 | | -## Step 2: Risk-rank each PR |
| 42 | +`/merge-pr` resolves the merge method from the repo's capabilities and the |
| 43 | +branching model — see **git-flow-next** (git-workflows) for which method each |
| 44 | +target branch requires. This skill passes no method flag and states no |
| 45 | +default. A promotion PR into a production branch is never swept: hold it and |
| 46 | +point at `/promote-release`. |
42 | 47 |
|
43 | | -Rank by blast radius and confidence, low to high: |
| 48 | +## Scope |
44 | 49 |
|
45 | | -| Risk | Signals | |
| 50 | +- `/pr-sweep` — open PRs in the current repo. |
| 51 | +- `/pr-sweep --org <owner>` — open PRs across the owner's repos, **all |
| 52 | + authors**. Bot and teammate PRs are usually the bulk of a real pile. |
| 53 | +- `--author <login>` — optional filter. Do not default to "mine": some token |
| 54 | + types (app installation tokens) carry no user identity, so a self-filter |
| 55 | + silently returns nothing. |
| 56 | + |
| 57 | +Command shapes live in **gh-cli-patterns**. List first, act second, and state |
| 58 | +the count before touching anything. |
| 59 | + |
| 60 | +## Phases |
| 61 | + |
| 62 | +Run all five in order. Phases 1 and 3 fan out; 0, 2, and 4 are the lead's. |
| 63 | + |
| 64 | +- **Phase 0 — Manifest (lead).** Enumerate repos × open PRs in one pass. |
| 65 | + Report the count. Spawn one worker per repo, capped (default 4 concurrent). |
| 66 | +- **Phase 1 — Triage (workers, parallel, read-only).** Each worker classifies |
| 67 | + every PR in its repo and detects repo-level conditions (broken base, |
| 68 | + repo-wide gate). Output: one report block per repo. No writes. |
| 69 | +- **Phase 2 — Approval (lead, one round).** Batch **all** escalations into a |
| 70 | + single round — one short paragraph per PR: identity, diffstat, state, and |
| 71 | + the specific yes/no question. No diffs. Then issue per-repo execution |
| 72 | + orders: `(PR number, head OID)` plus any ordering constraints. |
| 73 | +- **Phase 3 — Execute (workers).** Continue the *same* worker by message so it |
| 74 | + keeps its triage context. Per repo, serially: take a merge-budget slot, |
| 75 | + assert the head OID still matches, delegate to `/merge-pr`, wait on |
| 76 | + merge-triggered CI with an event-driven monitor, release the slot. `FIX` |
| 77 | + items go to `/finalize-pr`, then back through triage. |
| 78 | +- **Phase 4 — Verify and report (lead).** Wait for merge-triggered CI to |
| 79 | + settle, then attribute every red by timestamp against merge time before |
| 80 | + claiming a clean sweep. |
| 81 | + |
| 82 | +The lead does exactly two blocking things: the Phase 2 round and the Phase 4 |
| 83 | +aggregation. It never re-derives repo state itself. |
| 84 | + |
| 85 | +## Classification |
| 86 | + |
| 87 | +Every PR gets exactly one verdict. |
| 88 | + |
| 89 | +| Verdict | Meaning | |
46 | 90 | | --- | --- | |
47 | | -| **Low** (auto-merge candidate) | `mergeable == MERGEABLE`, CI clean (`mergeStateStatus` CLEAN), not draft, no unresolved threads, small diff, docs/config/test-only or a bot dependency bump from a trusted source | |
48 | | -| **Medium** (surface, do not auto-merge) | app/library code, larger diff, passing CI but no review, or any label like `needs-review`/`blocked` | |
49 | | -| **High** (surface, flag loudly) | touches auth/secrets/migrations/infra, failing or pending CI, conflicts, or a `develop → main` promotion | |
50 | | - |
51 | | -The bar for **auto-merge** is deliberately conservative: low risk **and** nothing |
52 | | -held. When unsure, rank up — a surfaced PR costs a glance; a wrongly-merged one |
53 | | -costs a revert. |
| 91 | +| **MERGE** | Mergeable, checks green, not draft, no unresolved threads, and either low blast radius or an approved escalation. | |
| 92 | +| **FIX** | One delegated `/finalize-pr` away from mergeable — unresolved review threads, a stale rollup, a repairable check. Re-triage after. | |
| 93 | +| **HOLD** | Cannot proceed without a decision or new work. Always carries a reason. | |
| 94 | +| **ESCALATE** | Mergeable but the *judgment* is not the sweep's to make. Goes to Phase 2 as a question, never as an assumption. | |
54 | 95 |
|
55 | | -## Step 3: Auto-merge the low-risk set |
| 96 | +Rank up when unsure. A surfaced PR costs a glance; a wrongly-merged one costs |
| 97 | +a revert. |
56 | 98 |
|
57 | | -For each low-risk PR, delegate — do not merge by hand: |
| 99 | +## Hold reasons (never auto-merge) |
58 | 100 |
|
59 | | -- Invoke **`/merge-pr <N>`** (no `--squash`). It re-runs the readiness gate, calls |
60 | | - `/finalize-pr` for soft blocks, and aborts on hard stops. Trust its refusal: if |
61 | | - it declines, the PR moves to the surfaced list with that reason. |
62 | | -- Never pass `--admin`, never bypass a failing check, never merge a draft. |
| 101 | +- Draft, merge conflicts, or checks failing for a real (non-infrastructure) |
| 102 | + reason. |
| 103 | +- A promotion PR into a production branch — use `/promote-release`. |
| 104 | +- Changes touching auth, secrets, migrations, permissions, or live infra — a |
| 105 | + human decides. |
| 106 | +- An explicit human "do not merge", or a review-gate label. A prior human |
| 107 | + refusal outranks the sweep. |
| 108 | +- `/merge-pr` refused — carry its reason forward verbatim. |
| 109 | +- A PR another session is actively working (recently pushed, in flight). |
63 | 110 |
|
64 | | -## Step 4: Report |
| 111 | +## Report |
65 | 112 |
|
66 | 113 | ```text |
67 | 114 | PR Sweep — <scope> |
68 | | - Swept (merged): <N> — <title> (× each) |
69 | | - Held: <N> — <reason: draft | CI red | conflicts | needs review | promotion | high-risk> |
| 115 | + Merged: <repo#N> — <title> |
| 116 | + Fixed+merged: <repo#N> — <what was repaired> |
| 117 | + Held: <repo#N> — <reason> |
| 118 | + Escalated: <repo#N> — <question> → <decision> |
| 119 | + Repo findings: <broken base | repo-wide gate | infra failure> |
70 | 120 | Open before → after: <b> → <a> |
71 | 121 | ``` |
72 | 122 |
|
73 | | -Every PR is either merged or listed with a concrete reason — never silently |
74 | | -skipped. If nothing is low-risk, say so; a sweep that merges nothing is a valid |
75 | | -outcome, not a failure. |
| 123 | +Every PR is merged or listed with a concrete reason — never silently skipped. |
| 124 | +A sweep that merges nothing is a valid outcome. File follow-ups per the |
| 125 | +project's issue-routing convention, and end a run that is blocked on a human |
| 126 | +decision by naming that decision. |
76 | 127 |
|
77 | | -## Hold reasons (never auto-merge) |
| 128 | +## Mechanics |
78 | 129 |
|
79 | | -- Draft, failing/pending CI, merge conflicts, unresolved review threads. |
80 | | -- `develop → main` promotion PRs — use `/promote-release`. |
81 | | -- Anything touching auth, secrets, DB migrations, or live infra — a human decides. |
82 | | -- `/merge-pr` refused — carry its reason forward verbatim. |
| 130 | +Diagnosis and parallel-protocol detail — lazy state, `UNSTABLE` vs `BLOCKED`, |
| 131 | +broken-base proof, repo-wide gates, infrastructure-failure signatures, worker |
| 132 | +and order schemas: see [references/sweep-mechanics.md](references/sweep-mechanics.md). |
83 | 133 |
|
84 | 134 | ## Related Skills |
85 | 135 |
|
86 | | -- **merge-pr** (github-workflows) — performs each merge; this skill decides which. |
87 | | -- **finalize-pr** (github-workflows) — PR metadata/soft-block handling, via merge-pr. |
88 | | -- **prune-branches** (github-workflows) — the repo/worktree sweep; complementary, not this. |
89 | | -- **promote-release** (github-workflows) — the correct path for held promotion PRs. |
| 136 | +- **merge-pr** (github-workflows) — performs each merge and owns method resolution. |
| 137 | +- **finalize-pr** (github-workflows) — drives one PR to mergeable; the `FIX` delegate. |
| 138 | +- **resolve-pr-threads** (github-workflows) — review-thread resolution. |
| 139 | +- **gh-cli-patterns** (github-workflows) — canonical command shapes and queries. |
| 140 | +- **promote-release** (github-workflows) — the held-promotion path. |
| 141 | +- **git-flow-next** (git-workflows) — the branching model that decides merge method. |
| 142 | +- **prune-branches**, **refresh-repo** (github-workflows) — complementary cleanup. |
0 commit comments