<!-- AUTO-GENERATED by scripts/gen-adapters.js - DO NOT EDIT -->
---
description: "Use when monitoring CI and handling review comments during /ship. Details mandatory wait periods, auto-reviewer handling, and comment resolution."
agent: general
---

> **OpenCode Note**: Invoke agents using `@agent-name` syntax.
> Available agents: task-discoverer, exploration-agent, planning-agent,
> implementation-agent, deslop-agent, delivery-validator, sync-docs-agent, consult-agent
> Example: `@exploration-agent analyze the codebase`


<ci-review-loop>
# Phase 4: CI & Review Monitor Loop - Reference

This file contains detailed implementation for the CI & Review Monitor Loop phase of `/ship`.

**Parent document**: `ship.md`

---

<mandatory-requirements>
## This Phase Is Mandatory

This is not optional. You must:
1. Wait the full 3 minutes for auto-reviewers
2. Run the monitor loop (not just check once)
3. Address all comments before merge
</mandatory-requirements>

---

<pr-auto-review>
## PR Auto-Review Process

PRs receive automatic reviews from configured auto-reviewers (Copilot, Gemini, CodeRabbit, etc.).

**Mandatory workflow:**
1. After PR creation, wait **at least 3 minutes** for first review round
2. Read **all comments** from all reviewers
3. Address **every comment** - no exceptions
4. Iterate until **zero unresolved threads** (typically 2-4 rounds)

**Rules:**
- Always address all comments, including "minor" or "nit" suggestions
- Do not skip a comment unless factually wrong or user-approved
- Treat all feedback as **required changes**, not suggestions
</pr-auto-review>

---

<overview>
## Overview

The monitor loop must wait for:
1. CI to pass
2. All comments resolved (addressed or replied to)
3. No "changes requested" reviews remain

## Why All Comments Matter

**Every comment must be addressed:**
- Critical/High issues: Fix immediately
- Medium issues: Fix (don't defer)
- Minor/Nit issues: Fix (shows attention to quality)
- Style suggestions: Fix (maintains codebase consistency)
- Questions: Answer with explanation
- False positives: Reply explaining why, then resolve
- Not relevant: Reply explaining why, then resolve

Do not ignore comments. Do not leave comments unresolved. A clean PR has zero unresolved conversations.
</overview>

## The Monitor Loop Algorithm

> **Note:** The JavaScript below is **conceptual pseudocode** showing the algorithm flow.
> Implement using bash functions defined in this file.

*(JavaScript reference - not executable in OpenCode)*

## Step 1: Wait for CI

```bash
wait_for_ci() {
  echo "Waiting for CI checks..."

  while true; do
    CHECKS=$(gh pr checks $PR_NUMBER --json name,state 2>/dev/null || echo "[]")

    PENDING=$(echo "$CHECKS" | jq '[.[] | select(.state | IN("PENDING", "QUEUED", "IN_PROGRESS"))] | length')
    FAILED=$(echo "$CHECKS" | jq '[.[] | select(.state | IN("FAILURE", "CANCELLED"))] | length')
    PASSED=$(echo "$CHECKS" | jq '[.[] | select(.state=="SUCCESS")] | length')

    if [ "$FAILED" -gt 0 ]; then
      echo "[ERROR] CI failed ($FAILED checks)"
      gh pr checks $PR_NUMBER
      return 1
    elif [ "$PENDING" -eq 0 ] && [ "$PASSED" -gt 0 ]; then
      echo "[OK] CI passed ($PASSED checks)"
      return 0
    elif [ "$PENDING" -eq 0 ] && [ "$PASSED" -eq 0 ]; then
      echo "[WARN] No CI checks found, proceeding..."
      return 0
    fi

    echo "  Waiting... ($PENDING pending, $PASSED passed)"
    sleep 15
  done
}
```

## Step 2: Check PR Feedback

```bash
check_pr_feedback() {
  local pr_number=$1

  echo "Checking PR feedback..."

  # Extract owner and repo from git remote
  REPO_INFO=$(gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"')
  OWNER=$(echo "$REPO_INFO" | cut -d'/' -f1)
  REPO=$(echo "$REPO_INFO" | cut -d'/' -f2)

  # Get review state
  REVIEWS=$(gh pr view $pr_number --json reviews --jq '.reviews')
  CHANGES_REQUESTED=$(echo "$REVIEWS" | jq '[.[] | select(.state=="CHANGES_REQUESTED")] | length')

  # Get unresolved review threads
  # NOTE: Fetches first 100 threads. For PRs with >100 threads, implement pagination.
  UNRESOLVED_THREADS=$(gh api graphql -f query='
    query($owner: String!, $repo: String!, $pr: Int!) {
      repository(owner: $owner, name: $repo) {
        pullRequest(number: $pr) {
          reviewThreads(first: 100) {
            nodes {
              isResolved
            }
          }
        }
      }
    }
  ' -f owner="$OWNER" -f repo="$REPO" -F pr=$pr_number \
    --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length')

  echo "  Unresolved threads: $UNRESOLVED_THREADS"
  echo "  Changes requested: $CHANGES_REQUESTED"

  echo "{\"unresolvedThreads\": $UNRESOLVED_THREADS, \"changesRequested\": $CHANGES_REQUESTED}"
}
```

### Get Full Thread Details

```bash
get_unresolved_threads() {
  local pr_number=$1

  REPO_INFO=$(gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"')
  OWNER=$(echo "$REPO_INFO" | cut -d'/' -f1)
  REPO=$(echo "$REPO_INFO" | cut -d'/' -f2)

  # NOTE: Fetches first 100 threads. For PRs with >100, implement pagination.
  gh api graphql -f query='
    query($owner: String!, $repo: String!, $pr: Int!) {
      repository(owner: $owner, name: $repo) {
        pullRequest(number: $pr) {
          reviewThreads(first: 100) {
            nodes {
              id
              isResolved
              path
              line
              diffHunk
              comments(first: 1) {
                nodes {
                  id
                  body
                }
              }
            }
          }
        }
      }
    }
  ' -f owner="$OWNER" -f repo="$REPO" -F pr=$pr_number \
    --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)'
}
```

## Step 3: Address ALL Feedback

> **Note:** This is **conceptual pseudocode** showing the algorithm flow.
> Implement using: gh api, Read, Edit, Task (ci-fixer), etc.

*(JavaScript reference - not executable in OpenCode)*

## Comment Analysis Heuristics

> **Note:** Classification heuristics for comment handling.

*(JavaScript reference - not executable in OpenCode)*

## Implementing Fixes

Use the ci-fixer agent for code changes:

*(JavaScript reference - not executable in OpenCode)*

## Resolving Threads

```bash
resolve_thread() {
  local thread_id=$1

  gh api graphql -f query='
    mutation($threadId: ID!) {
      resolveReviewThread(input: {threadId: $threadId}) {
        thread {
          isResolved
        }
      }
    }
  ' -f threadId="$thread_id"
}

reply_to_comment() {
  local pr_number=$1
  local comment_id=$2
  local body=$3

  REPO_INFO=$(gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"')
  OWNER=$(echo "$REPO_INFO" | cut -d'/' -f1)
  REPO=$(echo "$REPO_INFO" | cut -d'/' -f2)

  gh api -X POST "repos/$OWNER/$REPO/pulls/$pr_number/comments" \
    -f body="$body" \
    -F in_reply_to="$comment_id"
}
```

## Step 4: Commit and Push

```bash
commit_and_push_fixes() {
  local message=$1
  local branch=${2:-$(git branch --show-current)}

  if [ -n "$(git status --porcelain)" ]; then
    git add -A
    git commit -m "$message"
    git push origin "$branch"
    echo "[OK] Pushed fixes"
    return 0
  else
    echo "No code changes to commit (only comment replies)"
    return 1
  fi
}
```

## Complete Loop Script

```bash
#!/bin/bash
# Phase 4: CI & Review Monitor Loop

MAX_ITERATIONS=10
INITIAL_WAIT=${SHIP_INITIAL_WAIT:-180}  # Configurable via env var
ITERATION_WAIT=30
iteration=0

while [ $iteration -lt $MAX_ITERATIONS ]; do
  iteration=$((iteration + 1))
  echo "[CI Monitor] Iteration $iteration"

  # Step 1: Wait for CI
  if ! wait_for_ci; then
    echo "CI failed - launching ci-fixer agent..."
    continue
  fi

  # Step 1.5: First iteration - wait for auto-reviews
  if [ $iteration -eq 1 ] && [ "$INITIAL_WAIT" -gt 0 ]; then
    echo "First iteration - waiting ${INITIAL_WAIT}s for auto-reviews..."
    sleep $INITIAL_WAIT
  fi

  # Step 2: Check feedback
  FEEDBACK=$(check_pr_feedback $PR_NUMBER)
  UNRESOLVED=$(echo "$FEEDBACK" | jq -r '.unresolvedThreads')
  CHANGES_REQ=$(echo "$FEEDBACK" | jq -r '.changesRequested')

  if [ "$UNRESOLVED" -eq 0 ] && [ "$CHANGES_REQ" -eq 0 ]; then
    echo "[OK] ALL CHECKS PASSED"
    echo "[OK] ALL COMMENTS RESOLVED"
    echo "Ready to merge!"
    break
  fi

  # Step 3: Address all feedback
  echo "Addressing $UNRESOLVED unresolved threads..."

  # Step 4: Commit and push
  commit_and_push_fixes "fix: address review feedback (iteration $iteration)"

  # Step 5: Wait before next iteration
  echo "Waiting ${ITERATION_WAIT}s..."
  sleep $ITERATION_WAIT
done

if [ $iteration -ge $MAX_ITERATIONS ]; then
  echo "[ERROR] Max iterations reached - manual intervention required"
  exit 1
fi
```

<iteration-summary>
## Iteration Summary Output

```markdown
## Iteration ${iteration} Summary

**CI Status**: [OK] Passed
**Comments Addressed**: ${addressedCount}
  - Code fixes: ${codeFixCount}
  - Answered questions: ${questionCount}
  - Resolved as not applicable: ${notApplicableCount}
**Remaining Unresolved**: ${remainingCount}

${remainingCount > 0 ? 'Continuing...' : 'Ready to merge!'}
```
</iteration-summary>
</ci-review-loop>
