Closes #334 - Add workflows/review-merge-pr.md with reviewer-only gates and steps - Add schemas/review-merge-final-report.md with mutation ledger fields - Turn SKILL.md into task-mode router; replace inlined §F/§G with links - Point review/merge templates at extracted workflow - Add doc-contract tests for split structure Part of #333. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
243 lines
7.8 KiB
Markdown
243 lines
7.8 KiB
Markdown
# Review and merge PR workflow
|
|
|
|
**Task mode:** `review-merge-pr`
|
|
|
|
Load this file before any PR review or merge mutation. Parent router:
|
|
[`../SKILL.md`](../SKILL.md). Final report schema:
|
|
[`../schemas/review-merge-final-report.md`](../schemas/review-merge-final-report.md).
|
|
|
|
## Mode isolation (hard walls)
|
|
|
|
Review mode **must not**:
|
|
|
|
- create issues or edit issue bodies
|
|
- edit repository files, run formatting, or fix code
|
|
- claim issues, create branches, commit, push, or open PRs
|
|
- use author MCP namespace (`gitea-tools` / `prgs-author`) for mutations
|
|
- improvise raw MCP repair, shell fallbacks, or background task tools
|
|
|
|
Review mode **must**:
|
|
|
|
- use reviewer MCP namespace (`gitea-reviewer` / `prgs-reviewer`)
|
|
- prove identity, profile, runtime context, and exact capabilities before mutation
|
|
- validate only in a session-owned worktree under `branches/`
|
|
- keep the main checkout on `master`/`main`/`dev` for orchestration only
|
|
|
|
If the authenticated user equals the PR author → **stop** (no self-review, no self-merge).
|
|
|
|
---
|
|
|
|
## Global worktree rule (reviewer)
|
|
|
|
The main project checkout is orchestration only. All review validation happens
|
|
under `branches/` — typically a detached review worktree from
|
|
`scripts/worktree-review <pr-head-branch>`.
|
|
|
|
Before validation, prove:
|
|
|
|
1. project root
|
|
2. working directory (must be under `branches/`)
|
|
3. worktree path
|
|
4. worktree clean status
|
|
5. pinned PR head SHA == `git rev-parse HEAD`
|
|
|
|
Never run `git stash`, `git checkout --`, `git reset`, or `git clean` on
|
|
another session's dirty files. If the shared worktree is dirty, create a scratch
|
|
review worktree instead.
|
|
|
|
Merge simulation (`git merge --no-commit`, `git merge --abort`) is a
|
|
**worktree/index mutation**, not read-only diagnostics (#317).
|
|
|
|
---
|
|
|
|
## 1. Pre-flight gates
|
|
|
|
Run before any PR mutation:
|
|
|
|
1. `gitea_whoami` — prove reviewer identity (not PR author)
|
|
2. `gitea_get_profile` / `gitea_get_runtime_context`
|
|
3. `gitea_resolve_task_capability` for `review_pr`, `approve_pr`, `merge_pr`
|
|
4. `gitea_check_pr_eligibility` for the intended action on the selected PR
|
|
|
|
Capability claims must cite exact resolver output (#179); bare "checks passed" is
|
|
downgraded.
|
|
|
|
Stay in the reviewer namespace. Any author-namespace call requires explicit
|
|
justification in the final report.
|
|
|
|
---
|
|
|
|
## 2. PR inventory and queue selection
|
|
|
|
### Repo disambiguation
|
|
|
|
- `Gitea-Tools` / `gitea tool` / `MCP Gitea tool` → `Scaled-Tech-Consulting/Gitea-Tools`
|
|
- `mcp-control-plane` → `Scaled-Tech-Consulting/mcp-control-plane`
|
|
- Ambiguous requests → inventory **both** configured repos
|
|
|
|
Report must state exactly which repo(s) were checked. A single-repo zero must not
|
|
be reported as a global empty queue if the other repo was not inventoried.
|
|
|
|
### Pagination proof (#330)
|
|
|
|
PR inventory completeness requires explicit final-page/no-next-page evidence,
|
|
total-count evidence, or traversal until an empty/final page. Do not prove
|
|
completeness by assuming the default Gitea API page size.
|
|
|
|
### Trust gate (#196, #198)
|
|
|
|
Before reporting "no open PRs" or "queue empty":
|
|
|
|
- run `pr_inventory_trust_gate` (or `review_proofs.assess_reviewer_queue_inventory`)
|
|
- only `trusted_empty` allows a clean empty-queue stop
|
|
- a bare `[]` from `gitea_list_prs` is never sufficient
|
|
|
|
Empty-queue reports must include `pr_inventory_trust_gate.status`, reasons,
|
|
corroboration, remote/owner/repo/state filter, and inventory MCP profile.
|
|
|
|
### Queue ordering (#321, #318)
|
|
|
|
Select the lowest eligible open PR unless a documented blocker requires skipping.
|
|
Skipping requires live proof the blocker still applies — not stale handoff text.
|
|
|
|
### Already-landed gate (#292, #294, #295)
|
|
|
|
If the PR head is already on the target branch, stop review/approve/merge.
|
|
Redirect to reconciliation workflow; do not treat as review-eligible.
|
|
|
|
---
|
|
|
|
## 3. Review worktree and pinned head
|
|
|
|
1. `scripts/worktree-review <pr-head-branch>` → detached under `branches/review-*`
|
|
2. Prove checkout (#173):
|
|
- pinned PR head SHA from Gitea
|
|
- local `git rev-parse HEAD`
|
|
- `HEAD ==` pinned head
|
|
- diff base == PR base branch
|
|
3. If head moved → re-pin and restart review
|
|
4. Confirm worktree clean; inspect full diff; confirm scope matches linked issue
|
|
|
|
Linked issue consistency (#314): fetch/verify the linked issue live. Report the
|
|
same issue number in all sections. If not verified:
|
|
`Linked issue status: not verified in this session`.
|
|
|
|
Secret/provenance sweep (#179): state exact command/script/pattern and scope.
|
|
|
|
---
|
|
|
|
## 4. Validation
|
|
|
|
Run tests from the review worktree. Report must include (#311):
|
|
|
|
- exact command as executed
|
|
- working directory
|
|
- exact result (pass/fail counts)
|
|
- executable path proof for bare commands like `pytest` (`which`, `--version`)
|
|
|
|
If full suite fails, default action is `REQUEST_CHANGES` (#323). Approval with
|
|
failures requires baseline worktree proof under `branches/`, not main checkout.
|
|
|
|
During validation, use `gitea_dry_run_pr_review` — never live APPROVE/REQUEST_CHANGES
|
|
to probe tool paths.
|
|
|
|
---
|
|
|
|
## 5. Review mutation (terminal)
|
|
|
|
After validation completes:
|
|
|
|
1. Re-fetch PR; verify head SHA unchanged
|
|
2. `gitea_mark_final_review_decision` with pinned head
|
|
3. `gitea_submit_pr_review(..., final_review_decision_ready=True)` — exactly one live review
|
|
4. `gitea_get_pr_review_feedback` — confirm visible verdict (`approval_visible` for APPROVE; PENDING drafts do not count — #244)
|
|
|
|
Final reports must list exactly one review mutation
|
|
(`review_proofs.assess_review_mutation_final_report`).
|
|
|
|
Hard-stop after terminal review mutation (#332): do not perform additional review
|
|
mutations in the same session unless operator-approved correction.
|
|
|
|
---
|
|
|
|
## 6. Merge preflight and execution
|
|
|
|
Merge only when:
|
|
|
|
- eligible non-author reviewer
|
|
- visible APPROVED review at pinned head
|
|
- no undismissed REQUEST_CHANGES
|
|
- PR open and mergeable
|
|
- live head == pinned reviewed head (re-fetch immediately before merge)
|
|
|
|
Use `gitea_merge_pr` with `confirmation="MERGE PR <n>"` and `expected_head_sha`.
|
|
|
|
Gated merge refuses moved heads and widened diffs when `expected_changed_files` is set.
|
|
|
|
---
|
|
|
|
## 7. Post-merge cleanup
|
|
|
|
After confirmed merge on remote `master`:
|
|
|
|
1. Post-merge file-presence verification on `master`
|
|
2. Close/release linked issue; remove `status:in-progress`
|
|
3. Delete remote branch (when safe)
|
|
4. `scripts/worktree-clean --delete-branch <branch>`
|
|
5. Fetch/prune; confirm main checkout clean and `0 0` vs remote
|
|
|
|
Never run cleanup before merge is confirmed on remote `master`.
|
|
|
|
See also [`../templates/worktree-cleanup.md`](../templates/worktree-cleanup.md).
|
|
|
|
---
|
|
|
|
## 8. Fail-closed stops
|
|
|
|
Stop and report (no mutating action) when:
|
|
|
|
- identity/capability cannot be proven
|
|
- self-author detected
|
|
- worktree state unclear
|
|
- pinned head mismatch
|
|
- inventory incomplete or untrusted
|
|
- tests fail without baseline proof
|
|
- PR closed-not-merged (`merged=false`) — run reconciliation instead
|
|
- infra_stop or MCP transport failure — recovery handoff only
|
|
|
|
When blocked, emit recovery handoff per
|
|
[`../templates/recover-bad-state.md`](../templates/recover-bad-state.md).
|
|
|
|
---
|
|
|
|
## 9. Role-boundary proof (#175)
|
|
|
|
A reviewer queue task must not silently become author implementation. If no
|
|
eligible PR exists, stop with the queue report. Do not claim issues, branch,
|
|
commit, push, or open PRs unless the operator explicitly retasks as author work.
|
|
|
|
Use `review_proofs.assess_role_boundary`; downgrade or stop if not clean.
|
|
|
|
---
|
|
|
|
## 10. A-bar proofs (#179)
|
|
|
|
All required before A-grade report or merge:
|
|
|
|
- `assess_capability_evidence`
|
|
- `assess_sweep_evidence`
|
|
- `assess_live_state_recheck` (immediately before review submit and merge)
|
|
- `assess_role_boundary`
|
|
- `assess_review_mutation_final_report`
|
|
- `build_final_report`
|
|
|
|
Missing proof → downgrade or block merge.
|
|
|
|
---
|
|
|
|
## Prompt templates
|
|
|
|
Short triggers still work via templates that reference this workflow:
|
|
|
|
- [`../templates/review-pr.md`](../templates/review-pr.md)
|
|
- [`../templates/merge-pr.md`](../templates/merge-pr.md) |