# 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 `. 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 ` → 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 "` 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 ` 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)