Catalogskills.sh · pinguapps

finish-pr

Finish the GitHub pull request attached to the current branch; resolve merge conflicts, diagnose and fix failed CI checks, action review feedback from every source without duplicating replies that are awaiting a reviewer response, push focused commits, and continue until current-head CI and any running PR Agent review succeed and all actionable feedback is addressed. Use whenever the user asks to finish, complete, ready, resolve, fix, or address feedback/CI/conflicts on the current PR.

Review advisedVerified hub552 installs

Savant verdict: Review advised

Security analysis or source-hub review identified patterns requiring attention.

Live evaluation

Not evaluated yet. Workspaces can request a live evaluation.

Security assessment

Scan pending.

Structure

  • 1 referenced file isn't in the package<feedback-permalink>. They may be binary, too large to catalog, or missing upstream.
  • Ships 5 executable scriptsscripts/get-unresolved-pr-threads.ps1, scripts/reply-to-review-thread.ps1, scripts/wait-for-pr-review.ps1, tests/reply-to-review-thread.tests.ps1, tests/wait-for-pr-review.tests.ps1. Review what they do before enabling the skill for agents with tool access.
  • No license declaredConfirm you may reuse this skill before importing it into your repository.
  • The source hub's security checks flagged this skillSnyk: warn (Risk: MEDIUM · 1 issue)

SKILL.md

---
name: finish-pr
description: Finish the GitHub pull request attached to the current branch; resolve merge conflicts, diagnose and fix failed CI checks, action review feedback from every source without duplicating replies that are awaiting a reviewer response, push focused commits, and continue until current-head CI and any running PR Agent review succeed and all actionable feedback is addressed. Use whenever the user asks to finish, complete, ready, resolve, fix, or address feedback/CI/conflicts on the current PR.
---

# Finish PR

Bring the pull request attached to the current branch to a genuinely ready state.

Requires Git 2.38+, GitHub CLI (`gh`) authenticated for the repository, and PowerShell 7 (`pwsh`) for bundled helpers.

## Definition of done

Finish only when all of these are true for the current PR HEAD:

- GitHub and a local merge probe show no merge conflicts.
- No CI check is failing. Pending checks may still be running, but never describe the PR as fully ready while a required check is pending.
- Every unresolved review thread is in one of these states:
  - its latest unaddressed feedback has been actioned and the agent has replied with the result; or
  - the latest relevant comment is the agent's response and no reviewer has replied afterwards, so the thread is awaiting review and needs no duplicate work.
- No reply created by this run remains in a pending GitHub review.
- No review thread's resolution state was changed by this run.
- If PR Agent is running for this repository, the exact current HEAD carries a successful completed `PR Agent` check run or a `PR Agent` commit status with state `success`, with no active PR Agent review signal. See the PR Agent section below for detection and state semantics.

An unresolved thread is not automatically unfinished. Reviewers own resolution state; the conversation order determines whether the agent currently owes action.

## PR Agent

PR Agent is a self-hosted reviewer that may or may not be running. Detect its check run named `PR Agent` or its legacy commit status with context `PR Agent` (configurable via its `CHECK_NAME`), posted on every PR head it reviews.

- **Detection**: PR Agent is considered running for this PR when a `PR Agent` check run or commit status exists on the current HEAD or on any earlier commit of the pull request. If neither exists anywhere on the PR, it is not running — never wait for it, never post anything to trigger it, and skip every PR Agent rule below.
- **Status semantics**: a check run not yet `completed`, or a legacy status of `pending`, means a review is running or about to run. A completed check with conclusion `failure`, or a legacy status of `failure`, means its inline findings are action-required; a completed successful check or legacy `success` means PR Agent has approved this exact HEAD. PR Agent picks up new PRs and pushes automatically; inspect its check output or status description for details.
- **Feedback identification**: PR Agent posts inline review comments and replies through the repository owner's own login. Identify them by the hidden `<!-- pr-agent:v1 -->` marker (and the "PR Agent" shields badge) in the body — never by author login. Its messages are reviewer feedback, not agent responses, even though the login matches yours. The bundled watcher already includes them in new feedback.
- **Thread handling**: apply exactly the same logic as every other reviewer — agree and fix (one focused commit, then reply on the thread with the commit SHA and verification), or push back with concrete evidence. Never resolve PR Agent threads: it owns their resolution and resolves a thread automatically once it verifies a fix against the pushed HEAD or accepts a justified decline.
- **Memory of declined findings**: when PR Agent accepts a push-back and resolves a thread, it remembers the declined finding and will not re-report it on later reviews of the same PR. If it pushes back again, only continue the debate when you have new evidence; otherwise leave the thread awaiting its response.
- **Superseded reviews**: PR Agent reviews the entire pull request on every push. A push during its review cancels that run and starts again on the new HEAD. Preserve the running review by following the automated-review gate below.

## Operating rules

- Use the conversation history as first-class task context. The skill is often invoked after implementation, so recover the user's intent, earlier decisions, tradeoffs, verification, known limitations, and reasons for the current design before judging PR feedback.
- Read every applicable `AGENTS.md` plus repository-native requirements and design documents implicated by the PR. Discover these from the repository and PR; never assume a particular task directory, branch naming scheme, language, build system, or hosting provider.
- Treat unresolved review threads as the authoritative inline-feedback list. Also inspect PR-level reviews and issue comments for standalone actionable feedback.
- Preserve unrelated worktree changes. Commit only changes made during this run.
- Resolve conflicts before failed checks, and failed checks before review feedback. Later evidence may require revisiting an earlier phase.
- Prefer the smallest correct change. Add focused tests for behavioural or regression-prone fixes.
- Use exactly one focused, unsquashed commit per action-required PR feedback unit whose disposition produces a change: one review thread or one standalone PR-level feedback item. Never combine multiple units into one commit, even when they are related. A justified disagreement requires a reply but no commit.
- Never rebase, force-push, merge the pull request on GitHub, close, approve, or mark the PR ready for review unless the user explicitly requested that separate action. The conflict-resolution workflow may merge the latest base commit into the PR branch.
- Never resolve or unresolve a review thread. Do not call `resolveReviewThread`, `unresolveReviewThread`, or an equivalent.
- Reply directly to review threads, one at a time. Never create replies concurrently.
- Apply the automated-review gate below before every push or PR comment, including thread replies, disagreements, acknowledgements, reminders, and deferred replies after a push.
- Continue autonomously through new feedback from PR Agent and every other source after pushes, within the convergence bounds below.
- Let PR automation initiate reviews. Do not ping any reviewer, automated or human, to request a review or response by default. For reviewers other than PR Agent and Copilot, only send one concise reminder when a reply is essential to finish the PR, no review is active, and the reviewer has been silent for at least 25 minutes for automation or one business day for a person. Measure a person's wait from PR creation or the latest agent reply across resumed runs of this skill; otherwise report the wait as a blocker. Never ping Copilot or manually request or trigger a Copilot review or re-review through GitHub controls, reviewer assignment or reassignment, comments, CLI commands, API calls, or any equivalent mechanism. `pinguapps-pr-agent` adopts every Copilot thread on creation; action its feedback and reply once with the fix or reasoned decline, then leave verification and further follow-up to that bot.
- Never post trigger comments or fallbacks for PR Agent. It discovers PRs and pushes automatically when running; use its check run or legacy commit status and inline threads as terminal signals.

### Automated-review gate

This gate covers only PR Agent. Other reviewers and unrelated CI checks do not block pushes or comments through this gate; the existing CI and feedback requirements still apply.

Immediately before each push or PR comment, refresh the published PR head and its `PR Agent` check runs plus any legacy `PR Agent` commit status. Inspect all checks, including optional ones, using `gh pr checks`; use paginated check-run and commit-status API results when needed to establish the exact head, provider, or latest status. Skip the gate only when PR Agent is not running for this PR. When detected, a missing current-head signal is not proof of completion; wait for its automatic review.

- PR Agent is active while any of its latest current-head review check runs is not `completed`, including queued or in-progress runs, or its latest current-head legacy status is `pending`.
- While PR Agent is active, keep all fixes, commits, and reply drafts local. Never push or post any PR comment, regardless of its recipient or whether it cites a commit. Work on available feedback from other reviewers whose reviews have completed; leave PR Agent feedback queued until its review finishes.
- When PR Agent has completed, fetch feedback again, action the newly completed feedback, and repeat the feedback audit before publishing the batch. Completion can include findings or failure; this gate requires a finished review, not approval. The definition of done still requires clean terminal results.
- Recheck the gate before the push and before each serial comment. A previous idle snapshot, captured baseline, watcher result, or successful push does not authorize the next mutation. A push may start a new review immediately; retain deferred replies until PR Agent finishes, then re-read their threads to avoid duplicate or superseded responses.
- If completion cannot be established within the existing 25-minute wait or overall convergence bound, stop with the local commits and queued replies intact and report the blocker. A timeout never permits bypassing the gate.

## 1. Establish state and intent

1. Locate the repository root and read applicable instructions.
2. Inspect:

   ```powershell
   git status --short
   git rev-parse --abbrev-ref HEAD
   git rev-parse HEAD
   gh --version
   gh auth status
   gh pr view --json number,title,url,body,author,headRefName,headRefOid,headRepository,headRepositoryOwner,isCrossRepository,baseRefName,baseRefOid,mergeable,mergeStateStatus,reviews,comments
   ```

3. Record the starting SHA and every existing changed path, separating staged, unstaged, and untracked changes. Never include pre-existing changes in this run's commits.
   A feedback or CI fix must not touch a path that had any pre-existing staged, unstaged, or untracked change. Stop and ask the user before editing that path; partial staging plus `git commit --only` does not preserve same-file hunk isolation.
4. If the current branch has no PR, inspect `gh pr status`. Switch or check out a PR only when the mapping is unambiguous and local changes are safe; otherwise ask the user.
5. Reconstruct the intended change from, in priority order:
   - explicit user instructions and this conversation;
   - applicable repository instructions;
   - PR title, body, commits, and diff;
   - linked issue/spec/design documents;
   - surrounding code, tests, and conventions.
6. Inspect the complete PR diff before evaluating conflicts, CI, or feedback.
7. Detect PR Agent from current and earlier PR commits using the rules above. Treat its exact-HEAD check run or legacy status as the processing/completion boundary and read its findings from review threads.
8. Resolve the authenticated GitHub viewer login. Treat comments from that login, or another agent login established unambiguously by the conversation/PR history, as agent responses.
9. Resolve the base and head repositories independently from PR metadata:
   - derive the base repository from the PR URL;
   - use `headRepository.nameWithOwner` for the head repository;
   - prefer existing configured remotes that match those exact repositories;
   - otherwise use GitHub-provided clone URLs and configure Git to use the authenticated `gh` credential helper;
   - retain the exact `headRefName`.

   ```powershell
   $pr = gh pr view --json number,url,headRefName,headRefOid,headRepository,headRepositoryOwner |
     ConvertFrom-Json
   $prNumber = [int]$pr.number
   $prUri = [uri]$pr.url
   $pathSegments = $prUri.AbsolutePath.Trim("/").Split("/")
   $githubHostname = $prUri.Authority
   $baseRepositoryName = "$($pathSegments[0])/$($pathSegments[1])"
   $baseRepository = "$githubHostname/$baseRepositoryName"
   $baseMetadata = gh api --hostname $githubHostname "repos/$baseRepositoryName" |
     ConvertFrom-Json
   $headMetadata = gh api --hostname $githubHostname "repos/$($pr.headRepository.nameWithOwner)" |
     ConvertFrom-Json
   gh auth setup-git --hostname $githubHostname
   $baseFetchUrl = [string]$baseMetadata.clone_url
   $headPushUrl = [string]$headMetadata.clone_url
   ```

   GitHub's `clone_url` preserves the server authority, including non-default ports, while `gh auth setup-git` makes HTTPS Git operations use the authenticated CLI identity. A verified matching SSH/configured remote may be used instead. Stop if authentication, repository identity, or the head repository is unavailable or ambiguous. Never assume `origin` points to either side of a fork-based PR.
10. Align the checkout with the exact PR head before making any changes:

   ```powershell
   git fetch $headPushUrl $pr.headRefName
   $remoteHeadSha = (git rev-parse FETCH_HEAD).Trim()
   $lastObservedPrHeadSha = $remoteHeadSha
   $localHeadSha = (git rev-parse HEAD).Trim()
   git merge-base --is-ancestor $remoteHeadSha $localHeadSha
   $localContainsRemoteHead = $LASTEXITCODE -eq 0

   if ($localContainsRemoteHead -and $localHeadSha -ne $remoteHeadSha) {
     $initialLocalAheadCommits = git log --oneline "$remoteHeadSha..$localHeadSha"
     # Validate and record every commit against the recovered user intent and full PR diff.
     # Stop for confirmation if any commit is unrelated, unfinished, or ambiguous.
   }

   if (-not $localContainsRemoteHead) {
     git merge-base --is-ancestor $localHeadSha $remoteHeadSha
     $canFastForward = $LASTEXITCODE -eq 0 -and -not (git status --porcelain)
     if (-not $canFastForward) {
       throw "Local HEAD is stale or diverged from the PR head; stop before mutation."
     }

     git merge --ff-only $remoteHeadSha
   }
   ```

   Continue only when local `HEAD` matches the fetched PR head, is safely fast-forwarded to it, or every initially local-ahead commit was explicitly validated as intended PR work from conversation and repository evidence. Record those commits as pre-existing push scope; stop for confirmation on any uncertainty. Never silently publish local-ahead commits.
11. Create one unique state directory outside the repository and retain it for the full run:

   ```powershell
   $runStateDirectory = Join-Path ([IO.Path]::GetTempPath()) (
     "finish-pr-{0}-{1}" -f $prNumber, [guid]::NewGuid().ToString("N")
   )
   New-Item -ItemType Directory -Path $runStateDirectory | Out-Null
   ```

   Store every baseline, snapshot, and watcher-state file for this run inside this directory so concurrent runs cannot overwrite one another.

## 2. Resolve merge conflicts

Run this before CI or feedback:

1. Refresh PR/base metadata and perform a non-mutating local probe:

   ```powershell
   $pr = gh pr view $prNumber --repo $baseRepository --json number,url,baseRefName,baseRefOid,headRefName,headRefOid,headRepository,headRepositoryOwner,mergeable,mergeStateStatus |
     ConvertFrom-Json
   git fetch $baseFetchUrl $pr.baseRefName
   $baseCommit = (git rev-parse FETCH_HEAD).Trim()
   git merge-tree --write-tree --messages HEAD $baseCommit
   ```

2. Investigate locally when GitHub reports `CONFLICTING`, `DIRTY`, or `UNKNOWN`, or when the probe reports conflicts.
3. If conflicts exist, check the initial worktree baseline before merging. A normal merge requires a clean index: if any pre-existing staged change remains, stop before mutation and tell the user to commit or stash it, or request explicit permission to isolate and restore the index. Do not use `--autostash` on user work without that permission.

   If the index is clean and unrelated local changes are safe, merge the latest base into the PR branch:

   ```powershell
   git merge --no-ff $baseCommit
   ```

4. Resolve each conflict using the recovered task intent, repository requirements, adjacent code, and tests. Do not mechanically prefer either side.
5. Run focused verification, stage only the resolution, and commit it. Record the conflict summary, commit SHA, and checks run.
6. If the merge is clean, keep any Git-created merge commit but do not create an extra empty commit.

## 3. Fix failed CI

1. Inspect all checks:

   ```powershell
   gh pr checks $prNumber --repo $baseRepository --json bucket,completedAt,description,event,link,name,startedAt,state,workflow
   gh pr checks $prNumber --repo $baseRepository --required --json bucket,completedAt,description,event,link,name,startedAt,state,workflow
   ```

   Use the second query to distinguish required checks from optional checks. Treat “no required checks reported” as an empty required set, not a failure.

2. For each failure, retrieve the actual logs before editing:

   ```powershell
   gh run list --repo $baseRepository --branch $pr.headRefName --commit $pr.headRefOid --json databaseId,name,workflowName,status,conclusion,url,headSha,event,createdAt -L 50
   gh run view <run-id> --repo $baseRepository --json name,status,conclusion,jobs,url
   gh run view <run-id> --repo $baseRepository --log-failed
   ```

3. For non-Actions checks, inspect the provider link or available check details.
4. Fix the root cause, not merely the symptom. Work from the clearest upstream failure outward because one failure may cascade into others.
5. Run the closest local equivalent, inspect the initial worktree baseline, and stage only that fix. Commit with an exact pathspec so pre-existing staged changes remain outside the CI commit:

   ```powershell
   git commit --only -m "fix(ci): address <failed check>" -- <exact-ci-fix-paths>
   ```

   If a CI fix path had pre-existing staged, unstaged, or untracked changes, stop before editing it. Record the check, cause, SHA, and verification.
6. If a failure is external, flaky, permission-related, or not repository-fixable, capture evidence. Retry only when safe and supported; do not change code to appease an unrelated failure.

## 4. Fetch and classify feedback

Resolve the loaded skill's directory, then use its bundled helpers by absolute path; do not assume the skill lives inside the target repository.

Capture every thread's read-only resolution baseline outside the repository:

```powershell
$threadBaseline = Join-Path $runStateDirectory "thread-resolution.json"
$threadSnapshot = Join-Path $runStateDirectory "unresolved-threads.json"
pwsh <skill-directory>/scripts/get-unresolved-pr-threads.ps1 -PrNumber $prNumber -Repository $baseRepository -Hostname $githubHostname -All |
  Set-Content -Encoding utf8 $threadBaseline

pwsh <skill-directory>/scripts/get-unresolved-pr-threads.ps1 -PrNumber $prNumber -Repository $baseRepository -Hostname $githubHostname |
  Set-Content -Encoding utf8 $threadSnapshot
```

For each unresolved thread, read all paginated comments in chronological order and classify it. First identify comment authorship: PR Agent posts through the repository owner's own login, so classify every comment carrying the hidden `<!-- pr-agent:v1 -->` marker (or the "PR Agent" badge) as a PR Agent reviewer message — never as an agent response. Then classify the thread:

- **Copilot handoff:** if Copilot created the thread, action its feedback and reply once with the fix or reasoned decline. `pinguapps-pr-agent` verifies the reply and handles further follow-up. Never request a Copilot review or send it a reminder.
- **Awaiting reviewer:** the latest relevant comment is an agent response in a submitted review (`pullRequestReview.state != PENDING` with non-null `submittedAt`) and nobody has replied later. Do nothing. Do not post a reminder, repeat the fix, or duplicate the response. PR Agent messages count as reviewer messages for this rule: when PR Agent replies (verification result, push-back, or resolution note), the thread is awaiting your action or is already resolved by it.
- **Action required:** there is reviewer feedback after the agent's latest submitted response, the agent has never responded, or its latest response exists only in a pending review. PR Agent inline findings are always action-required when the thread is unresolved: agree and fix with a focused commit, or push back with evidence and let PR Agent re-evaluate.
- **Superseded/non-actionable:** the later conversation explicitly withdraws, answers, or supersedes the point. Reply only if the thread still needs an agent acknowledgement; avoid duplicating an existing agent response. A PR Agent resolution note ("verified ... resolving this thread") on a thread it has just resolved needs no reply.

Within action-required threads, identify each distinct feedback item. Judge it against the user's intent, conversation history, repository rules, linked requirements, PR scope, current code, conventions, and tests. The thread is the commit boundary: group all work required by one thread into that thread's single commit, but never include another thread's work.

Classify actionable PR-level review bodies and issue comments with the same rules. Each standalone feedback item is its own commit boundary; never combine it with a review thread or another standalone item. Track it by feedback ID and permalink because it has no review-thread ID.

- Agree when it identifies a real bug, missed requirement, broken invariant, missing test, misleading behaviour, or scoped maintainability problem.
- Disagree when it conflicts with requirements, established intent, repository invariants, or would produce a worse/out-of-scope design.
- When uncertain, make a small scoped correctness fix if evidence supports it. Otherwise explain the uncertainty and why no change was made.

Do not skip outdated unresolved threads; determine whether their feedback still applies to current code.

## 5. Fix and reply

For each action-required review thread or standalone feedback item eligible under the automated-review gate:

1. Make the smallest complete fix for every actionable item in that thread, with focused tests.
2. Run the narrowest meaningful verification.
3. Inspect and stage only files for that item:

   ```powershell
   git status --short
   git diff
   git add <paths>
   git diff --cached
   ```

   Keep unrelated staged changes in other paths staged. Stop before editing any fix path that had a pre-existing staged, unstaged, or untracked change; never rely on partial staging followed by `git commit --only` for same-file isolation.

4. If the disposition produces a change, create exactly one commit for the feedback unit before moving to the next unit:

   ```powershell
   git commit --only -m "fix(pr): address <thread summary>" -- <exact-thread-fix-paths>
   ```

   Do not amend, squash, or combine feedback commits. If an earlier unit's change completely satisfies a later agreed unit and no distinct file change remains, create an explicit traceability commit with `--allow-empty` for that later unit rather than merging their commit history. Do not create a commit for a justified disagreement.

5. For review-thread feedback, reply directly to the thread after evaluating it and creating any relevant commit, subject to the automated-review gate and commit deferral below. Draft and queue the reply locally whenever either blocks posting:

   ```powershell
   $body = @"
   Agreed. I fixed this in commit <sha> by <specific change>.

   Verification: <command and result>.
   "@
   pwsh <skill-directory>/scripts/reply-to-review-thread.ps1 -ThreadId "<thread-id>" -Hostname $githubHostname -Body $body
   ```

   For standalone feedback, post a PR-level reply that links the exact feedback permalink:

   ```powershell
   $body = @"
   Regarding [this feedback](<feedback-permalink>): agreed. I fixed this in commit <sha> by <specific change>.

   Verification: <command and result>.
   "@
   gh pr comment $prNumber --repo $baseRepository --body $body
   ```

   Use the same PR-level path for a standalone justified disagreement, retaining the feedback permalink and the disagreement wording below.

   For a justified disagreement:

   ```text
   I don't think this change is correct for this PR.

   Reason: <specific reason grounded in requirements, conversation, or code>.

   No code change made.
   ```

   If any PR Agent feedback disposition created a commit that has not been pushed yet, defer its thread or PR-level reply until after the batch push and the automated-review gate clears. PR Agent cannot verify a local-only SHA; replying before it can see the commit may cause a misleading follow-up. A disagreement has no commit dependency but still requires the gate to clear. Keep all replies serial.

6. Record the one-to-one feedback-unit ID → commit SHA mapping for changed dispositions, plus every disposition, verification, and returned comment ID. Use the thread ID for review threads and the feedback ID for standalone items. Record `no commit — disagreement` for justified disagreements.

The reply helper uses GitHub's single-comment reply endpoint so it never submits or modifies a shared pending review. It then verifies `state != PENDING` plus a non-null `submittedAt`. A helper failure is blocking; a returned comment URL alone is not proof of submission.

After each feedback batch, including when replies remain queued:

1. Re-fetch all threads with `-All`, plus PR-level reviews and issue comments.
2. Verify every reply created in this run belongs to a submitted review.
3. Verify the authenticated user has no pending review on the PR, including reviews created before this run.
4. For every thread ID present in the baseline, compare its `isResolved` value with the current value. Baseline resolution states must be unchanged; report external changes and never mutate them back. New thread IDs are expected during review convergence: classify them as additional feedback rather than treating their existence as a resolution mutation.
5. If new action-required review threads or standalone feedback items appeared during the batch, action each eligible item in its own commit and repeat the audit. Push only once the automated-review gate clears and the refreshed feedback set has been fully actioned or is awaiting reviewer response. Items with completed local dispositions and queued replies count as actioned for this pre-push audit, but their replies remain mandatory once the commit deferral and gate clear; they are not awaiting reviewer response until posted.

## 6. Push and converge with review

1. Confirm the worktree contains no uncommitted changes created by this run. Do not push individual thread commits as they are created; batch-push all unsquashed thread commits only after any running PR Agent review has completed and the refreshed feedback audit is clear.
2. Review commits after the starting SHA and every validated commit that was already local-ahead at invocation, then fetch the exact PR head before pushing:

   ```powershell
   git log --oneline <starting-sha>..HEAD
   git fetch $headPushUrl $pr.headRefName
   $remoteHeadSha = (git rev-parse FETCH_HEAD).Trim()
   $localHeadSha = (git rev-parse HEAD).Trim()
   $currentPrHeadSha = (gh pr view $prNumber --repo $baseRepository --json headRefOid --jq .headRefOid).Trim()
   $pushRequired = $localHeadSha -ne $remoteHeadSha
   git status --short --branch
   ```

   Stop if `$remoteHeadSha` and `$currentPrHeadSha` differ, or if either differs from `$lastObservedPrHeadSha`. Never overwrite `$lastObservedPrHeadSha` with an unexpected remote value. Use `$pushRequired`, not the starting-SHA commit range, to decide whether the PR head needs a push; the range is reporting context only.

3. If `$pushRequired`, increment `$reviewRound` and capture a review baseline immediately before pushing:

   ```powershell
   $reviewRound++
   $reviewState = Join-Path $runStateDirectory ("review-round-{0}.json" -f $reviewRound)
   pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
     -CaptureBaseline `
     -StatePath $reviewState `
     -PrNumber $prNumber `
     -Repository $baseRepository `
     -Hostname $githubHostname `
     -PrAgentContext "PR Agent"
   ```

4. Recheck the automated-review gate against the published head immediately before pushing. If blocked, keep the batch local, wait for completion, and repeat the feedback audit and head checks before recapturing the baseline. Once clear, push without force and record the exact HEAD:

   ```powershell
   $reviewRequestedAt = [DateTimeOffset]::UtcNow
   git push $headPushUrl "HEAD:refs/heads/$($pr.headRefName)"
   $expectedHeadSha = git rev-parse HEAD
   $lastObservedPrHeadSha = $expectedHeadSha
   ```

   Retain queued replies after the push. Recheck the automated-review gate before each reply; if the push has started a PR Agent review, wait for it to finish. Then re-read feedback and post only still-needed replies serially with the now-visible commit SHA and verification result. Verify thread replies are submitted and refresh feedback. Apply the same gate to disagreements and replies to any other reviewer.

5. After pushing, wait for the exact-HEAD `PR Agent` check run or legacy commit status when PR Agent is running. Select the wait path from its detected signal type:

   - **PR Agent check runs:** use the environment's PR watcher when available; inspect exact-HEAD checks and refreshed feedback on each wake. Otherwise poll these read-only signals through `gh pr checks` and the paginated check-run API every 20 seconds, bounded to 25 minutes. Apply the gate and definition of done directly. The bundled watcher reads legacy statuses only, so skip its `-Wait` invocation on this path; a successful check-run-only review with no new feedback can finish through the final audit without waiting for a helper timeout.
   - **Legacy-status PR Agent:** use the environment's PR watcher when available; otherwise use the bundled `-Wait` command below. If PR Agent check runs appear later, switch to the check-run path. A missing legacy status or absence from the helper's result never overrides check-run detection.
   - **PR Agent not running:** refresh checks and feedback, then proceed to the final audit. Do not wait for an absent integration.

   ```powershell
   pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
     -Wait `
     -StatePath $reviewState `
     -ExpectedHeadSha $expectedHeadSha `
     -ReviewRequestedAt $reviewRequestedAt `
     -TimeoutMinutes 25 `
     -PollSeconds 20
   ```

   Run it as a long-lived tool call. While it runs, use only the environment's wait mechanism and remain silent unless the user interrupts. The watcher keeps repeated polling out of model context.

6. Handle the selected wait path's result using the outcomes below. The bundled watcher delivers PR Agent's inline findings through `newFeedback` like every other reviewer's; on the check-run path, refresh and classify feedback using step 4. Feedback may arrive while another review is still active; use the automated-review gate to determine which feedback is eligible and whether publishing is allowed:
   - `feedback`: fetch all feedback for context, but action only newly owed feedback (`newFeedback` IDs when using the bundled watcher). This may include inline threads (from PR Agent, Copilot, or other reviewers), PR-level feedback from any reviewer, and a synthetic `pragent_status` item when PR Agent reported `failure` or `error` without captured comments. If a new comment extends an old unresolved thread, read the full thread and handle only feedback after the last agent response. PR Agent findings follow the same agree-and-fix / push-back rules, and it will re-verify pushed fixes and resolve its threads automatically. For Copilot threads, reply once with the disposition so `pinguapps-pr-agent` can follow up; never request Copilot re-review.
   - `approved`: the exact-HEAD `PR Agent` legacy status succeeded. Verify PR Agent check runs separately as above. Re-fetch checks, PR-level feedback, and threads once; finish only if the full definition of done still holds.
   - `timeout`: inspect whether a required automated reviewer has remained silent for the full 25 minutes with no review active. For a person, require one business day since PR creation or the latest agent reply, including across resumed runs. Only when the reply is essential to finish the PR, consider the single-reminder exception for eligible reviewers in the operating rules; it excludes PR Agent and Copilot. Otherwise report the wait as a blocker and do not claim readiness.
   - `head_changed`: fetch and inspect the new state. Stop when another actor's push makes continued mutation unsafe.
   - `pr_closed`: stop and report the PR state.

7. For new feedback, repeat eligible fix → verify → commit → queue or gated serial reply → completed reviews and refreshed audit → baseline → gated push → wait. Flush still-needed queued replies only when the gate and commit deferral clear; finish only after the reply audit passes.

If no push is needed, use the same wait-path selection in step 5. A successful `PR Agent` check or legacy status on the exact current HEAD is sufficient once the gate clears and the remaining definition of done holds. When PR Agent is absent, proceed directly to the final audit. Otherwise capture the current state, wait read-only for its automatic review, and apply the same timeout rule without posting a default trigger.

```powershell
$expectedHeadSha = (git rev-parse HEAD).Trim()
$reviewRound++
$reviewState = Join-Path $runStateDirectory ("review-round-{0}.json" -f $reviewRound)
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
  -CaptureBaseline `
  -StatePath $reviewState `
  -PrNumber $prNumber `
  -Repository $baseRepository `
  -Hostname $githubHostname
```

Run the following wait command only on the legacy-status PR Agent path when the environment has no PR watcher:

```powershell
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
  -Wait `
  -StatePath $reviewState `
  -ExpectedHeadSha $expectedHeadSha `
  -ReviewRequestedAt ([DateTimeOffset]::MinValue) `
  -TimeoutMinutes 25 `
  -PollSeconds 20
```

The watcher verifies the PR head matches the expected SHA and waits for its `PR Agent` legacy status to reach `success`, `failure`, or `error` before reporting `approved` or `feedback`, unless new feedback arrives first. Check runs must be verified separately using the check-run path above.

Bound convergence to five pushed review rounds or two hours overall. Stop earlier for a clean result, timeout, closure, unexpected head movement, or a genuine blocker.

## Final audit and response

Re-fetch rather than relying on cached state:

- PR head, mergeability, and base;
- latest base commit and a fresh local `git merge-tree --write-tree --messages HEAD <base-commit>` conflict probe;
- all checks;
- required checks queried separately with `gh pr checks --required`;
- the exact-HEAD `PR Agent` check-run status/conclusion and any legacy commit status (when PR Agent is running for this repository);
- PR-level reviews/comments;
- all review threads and reply submission states;
- local/remote branch state and worktree.

Report concisely:

- PR number and URL;
- conflict and CI outcome, with commits;
- thread counts: actioned, awaiting reviewer, and disagreed;
- fixes, focused verification, and commit SHAs;
- push result and review rounds;
- terminal `PR Agent` result for current HEAD: completed successful check or legacy `success` (or `not running` when neither signal exists on the pull request);
- pending review replies: `0`;
- review-thread resolution mutations: `0`, with baseline audit result;
- any blocker or required check still pending.
finish-pr · Skill catalog | Savant