feat: add PR-only queue cleanup mode with per-PR dispatch gates (Closes #390)
Adds canonical pr-queue-cleanup workflow, report verifier, reviewer-only task routing, and runbook guidance so operators can drain open PRs one canonical review at a time with fail-closed boundaries on batching and unauthorized merges. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -22,6 +22,7 @@ workflow file.
|
||||
| Reconcile already-landed open PRs | [`workflows/reconcile-landed-pr.md`](workflows/reconcile-landed-pr.md) | [`schemas/reconcile-landed-final-report.md`](schemas/reconcile-landed-final-report.md) |
|
||||
| Create or update Gitea issues | [`workflows/create-issue.md`](workflows/create-issue.md) | [`schemas/create-issue-final-report.md`](schemas/create-issue-final-report.md) |
|
||||
| Work on an assigned issue / author code | [`workflows/work-issue.md`](workflows/work-issue.md) | [`schemas/work-issue-final-report.md`](schemas/work-issue-final-report.md) |
|
||||
| PR-only queue cleanup (one canonical review per PR) | [`workflows/pr-queue-cleanup.md`](workflows/pr-queue-cleanup.md) | [`schemas/pr-queue-cleanup-final-report.md`](schemas/pr-queue-cleanup-final-report.md) |
|
||||
|
||||
## Universal rules
|
||||
|
||||
@@ -50,6 +51,10 @@ changes, merge, implement fixes, create branches, commit, push, or create PRs.
|
||||
A run that starts in `work-issue` mode may not review, approve, request changes,
|
||||
merge, close PRs, or act as reviewer.
|
||||
|
||||
A run that starts in `pr-queue-cleanup` mode may not claim issues, create
|
||||
branches, edit implementation files, file new issues, or review a second PR
|
||||
after any terminal review mutation.
|
||||
|
||||
If the task requires a different mode, stop and produce a handoff for the
|
||||
correct workflow.
|
||||
|
||||
@@ -156,6 +161,7 @@ Ready-to-copy task prompts live in [`templates/`](templates/):
|
||||
|
||||
- [`start-issue.md`](templates/start-issue.md) — author work (loads `work-issue.md`)
|
||||
- [`review-pr.md`](templates/review-pr.md) — review (loads `review-merge-pr.md`)
|
||||
- [`pr-queue-cleanup.md`](templates/pr-queue-cleanup.md) — one PR per cleanup run
|
||||
- [`merge-pr.md`](templates/merge-pr.md) — merge (loads `review-merge-pr.md`)
|
||||
- [`recover-bad-state.md`](templates/recover-bad-state.md)
|
||||
- [`reconcile-closed-not-merged-pr.md`](templates/reconcile-closed-not-merged-pr.md)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# PR-queue-cleanup final report schema
|
||||
|
||||
One report per cleanup run (one run = one PR). Fields must all be present;
|
||||
use `none` where nothing occurred. Validated by
|
||||
`pr_queue_cleanup.assess_pr_queue_cleanup_report` (fail closed).
|
||||
|
||||
* Task: pr-queue-cleanup
|
||||
* Workflow source: workflows/pr-queue-cleanup.md (+ version/commit/hash)
|
||||
* Repo:
|
||||
* Role/profile:
|
||||
* Identity:
|
||||
* PR inventory pagination proof: (inventory_complete / final page / total_count)
|
||||
* Queue ordering proof:
|
||||
* Earlier PRs skipped: (with live per-PR proof)
|
||||
* Selected PR: (exactly one)
|
||||
* Pinned head SHA:
|
||||
* Review decision: (single terminal decision)
|
||||
* Merge authorized for PR: true/false (explicit per-PR operator authorization)
|
||||
* Merge gates result:
|
||||
* Merge result: (none / not attempted / merged SHA / blocker)
|
||||
* Run stop point: (which §4 chain rule ended the run)
|
||||
* Next suggested PR: (named, not continued to)
|
||||
* File edits by reviewer:
|
||||
* Worktree/index mutations:
|
||||
* Git ref mutations:
|
||||
* MCP/Gitea mutations:
|
||||
* Issue mutations: none (required — forbidden in cleanup mode)
|
||||
* Branch mutations: none (required — forbidden in cleanup mode)
|
||||
* Read-only diagnostics:
|
||||
* Blockers:
|
||||
* Safe next action: (fresh run for the next PR)
|
||||
@@ -0,0 +1,25 @@
|
||||
# Template: PR-only queue cleanup (one PR per run)
|
||||
|
||||
Copy, fill the `<...>` fields, and paste as the task prompt.
|
||||
|
||||
```text
|
||||
Task: PR-only queue cleanup for <repo>.
|
||||
|
||||
Load workflows/pr-queue-cleanup.md and workflows/review-merge-pr.md before any
|
||||
mutation. Route pr_queue_cleanup through gitea_route_task_session (reviewer
|
||||
profile required).
|
||||
|
||||
Rules:
|
||||
- One run = exactly one selected PR = one terminal review decision.
|
||||
- Build full open-PR inventory with pagination proof before selection.
|
||||
- Forbidden: issue claiming, branch creation, implementation edits, issue filing,
|
||||
reviewing a second PR after a terminal mutation in this run.
|
||||
- After REQUEST_CHANGES: stop. After APPROVED: merge only this PR and only if
|
||||
operator explicitly authorized merge for this PR in this run.
|
||||
- Report Next suggested PR without continuing to it.
|
||||
|
||||
Operator PR list (optional): <pr numbers or "oldest eligible from inventory">
|
||||
Merge authorized for selected PR in this run: <true|false>
|
||||
|
||||
End with the pr-queue-cleanup final report schema.
|
||||
```
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
task_mode: pr-queue-cleanup
|
||||
canonical: true
|
||||
final_report_schema: ../schemas/pr-queue-cleanup-final-report.md
|
||||
---
|
||||
|
||||
# PR-only queue cleanup workflow (canonical)
|
||||
|
||||
**Task mode:** `pr-queue-cleanup`
|
||||
|
||||
Reviewer-role mode for cleanup periods when the queue holds many open PRs.
|
||||
Each run dispatches **exactly one** canonical review for **exactly one** PR,
|
||||
then stops after any terminal review mutation. The next PR always requires a
|
||||
new run with fresh identity, capability, and inventory proof.
|
||||
|
||||
This mode composes with the canonical review workflow: for the selected PR,
|
||||
load and follow [`workflows/review-merge-pr.md`](review-merge-pr.md) in full.
|
||||
This file adds the cleanup-mode boundaries around that per-PR run; it does
|
||||
not replace the review workflow.
|
||||
|
||||
## 0. Load the canonical workflow first
|
||||
|
||||
Load this file and `workflows/review-merge-pr.md` before any mutation and
|
||||
report source, version/commit/hash, and any conflict with the operator
|
||||
prompt. If either cannot be loaded, stop and produce a recovery handoff.
|
||||
|
||||
## 1. Mode isolation — forbidden actions
|
||||
|
||||
PR-only cleanup mode forbids, with no exceptions:
|
||||
|
||||
* issue claiming (`claim_issue`, `mark_issue`, `lock_issue`)
|
||||
* branch creation or push (`create_branch`, `push_branch`)
|
||||
* implementation edits of any kind
|
||||
* new issue filing (`create_issue`)
|
||||
* PR creation (`create_pr`) and commit tools (`commit_files`)
|
||||
* reviewing a second PR after any terminal review mutation
|
||||
|
||||
`pr_queue_cleanup.check_cleanup_task_allowed` fails closed on these tasks.
|
||||
If author-side work is needed, stop and hand off to `work-issue` mode in a
|
||||
separate session.
|
||||
|
||||
## 2. Identity, capability, and routing
|
||||
|
||||
Route `pr_queue_cleanup` through `gitea_route_task_session` — reviewer role
|
||||
required; author sessions receive `wrong_role_stop`. Prove `gitea.pr.review`
|
||||
capability before selection. Merge additionally requires `gitea.pr.merge`
|
||||
plus the explicit per-PR authorization in §4.
|
||||
|
||||
## 3. Inventory and selection
|
||||
|
||||
Build the complete open-PR inventory with pagination proof
|
||||
(`inventory_complete`, final page, `total_count`) before any selection
|
||||
claim. Select exactly one PR according to project queue ordering rules
|
||||
(oldest-first unless the operator queue says otherwise), skipping earlier
|
||||
PRs only with live per-PR proof. No multi-PR validation and no batch report
|
||||
may substitute for per-PR proof.
|
||||
|
||||
## 4. Terminal mutation chain
|
||||
|
||||
`pr_queue_cleanup.resolve_cleanup_run_state` is the authority:
|
||||
|
||||
* After `REQUEST_CHANGES` → the run stops.
|
||||
* After `COMMENT` or a proof-backed skip → the run stops.
|
||||
* After `APPROVED` → the run may continue **only** to same-PR merge, and only
|
||||
when the operator explicitly authorized merge for that specific PR in this
|
||||
run (`Merge authorized: true`) and every merge gate passes.
|
||||
* After merge, or on any merge blocker → the run stops.
|
||||
* Any terminal mutation targeting a PR other than the selected PR is a hard
|
||||
stop and must be reported as a violation.
|
||||
|
||||
## 5. Fresh run per PR
|
||||
|
||||
The next PR requires a new run with fresh identity, capability, inventory,
|
||||
and ordering proof. Do not carry pinned SHAs, eligibility classes, or
|
||||
validation results across runs.
|
||||
|
||||
## 6. Final report
|
||||
|
||||
Use the schema in
|
||||
[`schemas/pr-queue-cleanup-final-report.md`](../schemas/pr-queue-cleanup-final-report.md).
|
||||
The report must include the **Next suggested PR** (from the proven ordering)
|
||||
without continuing to it, exactly one **Selected PR**, the single terminal
|
||||
decision, pagination proof, and `Issue mutations: none` / `Branch mutations:
|
||||
none`. `pr_queue_cleanup.assess_pr_queue_cleanup_report` validates these
|
||||
fields and fails closed on batch reviews, missing pagination proof, missing
|
||||
next-suggested-PR, unauthorized merges, or any issue/branch mutation.
|
||||
Reference in New Issue
Block a user