---
name: watch-pr
description: PR push 直後 / PR 作成後の auto chain (`/create-pr` のフェーズ 6.2 から発動) / CI 監視 / レビュー対応 / merge 前確認 の文脈で発動。`gh pr checks` を一度 polling し green / red / pending を集計、 red なら失敗 job のログを fetch して「format drift / test fail / build error / flake / contract drift」に分類。 同時に unresolved review thread (人間 / Copilot) も集計し、 安全カテゴリ (stale / Copilot style ノイズ) は `/reply-review --auto-safe` を auto chain で起動して reply + resolve まで自動完了。 人間 reviewer / blocker 候補は user 判断のため提示のみ。 `/loop /watch-pr <PR>` で継続監視に使える。
argument-hint: "[pr-number]"
disable-model-invocation: false
allowed-tools: Bash(gh pr checks *) Bash(gh pr view *) Bash(gh run view *) Bash(gh api *) Bash(git rev-parse *) Bash(git branch *) Read Grep Skill
---

# PR CI Status Watcher

PR の CI checks を 1 回ポーリングして状態を集計する skill。継続監視は `/loop` と組み合わせる:

```text
/loop /watch-pr 489       # 5 分間隔で polling、red/green/timeout で通知
/watch-pr                 # 引数省略時は現在ブランチに紐づく PR を自動検出
```

## 引数

- `$1` (任意): PR 番号 (例: `489`)。省略時は `gh pr view --json number` で現在ブランチから自動取得

## 実行前の確認

- ブランチ: !`git rev-parse --abbrev-ref HEAD`
- 引数: $ARGUMENTS

## 手順

### フェーズ 1: PR 番号の確定

引数 `$1` がない場合、現在ブランチに紐づく PR を取得:

```bash
PR_NUM=$(gh pr view --json number --jq '.number' 2>/dev/null)
```

該当 PR がない場合 (= まだ push していない / PR 未作成) は、その旨をユーザーに報告して停止。

### フェーズ 2: CI checks の一括取得

```bash
gh pr checks "$PR_NUM" --json name,state,conclusion,link --jq '.[]'
```

各 check は以下の状態のいずれか:

- **state**: `QUEUED` / `IN_PROGRESS` / `COMPLETED`
- **conclusion** (COMPLETED 時のみ): `SUCCESS` / `FAILURE` / `CANCELLED` / `SKIPPED` / `NEUTRAL` / `TIMED_OUT` / `ACTION_REQUIRED`

### フェーズ 3: 集計とサマリ

以下のテーブルでサマリを表示 (件数は実際の集計値):

```text
## PR #<N> CI Status (<HH:MM:SS>)

| State        | Count |
|--------------|-------|
| ✅ Success   | <n>   |
| ❌ Failure   | <n>   |
| 🔁 Pending   | <n>   |
| ⏭️ Skipped   | <n>   |
| ⚠️ Cancelled | <n>   |

Total: <total> checks
```

判定ルール:

- **All green** (failure=0, pending=0, cancelled=0): 「全 N checks green、merge 可能状態」
- **Red** (failure ≥ 1): フェーズ 4 へ
- **Pending** (queued/in_progress ≥ 1): 「N checks がまだ走行中、再度 polling を推奨」
- **Suspicious skip** (cancelled+skipped が 3 件以上連続): silent skip の可能性を警告 (PR #419 事例)

### フェーズ 4: 失敗 job の分析 (failure ≥ 1 時のみ)

各失敗 job について:

1. job 名と link を表示
2. `gh run view <run-id> --log-failed` で失敗 step のログを fetch (最大 100 行)
3. ログを以下の pattern で分類:
   - **Format drift**: `ruff` `cargo fmt` `gofmt` `dotnet format` `clippy` 系のエラー → ローカル `pre-commit run --all-files` で修復可能
   - **Test fail**: `FAILED` `assert` `panicked` `expected` 系 → どのテストかを抽出
   - **Build error**: `error[E0` `cannot find` `undefined reference` 系 → コンパイルエラー
   - **Flake**: `timeout` `network` `connection reset` `rate limit` 系 → 一過性、retry 推奨
   - **Contract drift**: `MISMATCH` `OUT OF SYNC` `byte-for-byte` 系 → 該当 `check-*` skill を案内
4. 分類別に推奨アクションを提示

### フェーズ 5: Unresolved review thread の集計

CI status とは独立で、 review コメント / Copilot 指摘が未解決のまま残っていないか
を毎回チェック。 `/check-review-backlog --pr <PR>` 相当の GraphQL を呼ぶ:

```bash
gh api graphql -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 50) {
        nodes {
          isResolved
          isOutdated
          comments(first: 1) {
            nodes {
              author { login }
              path
              body
              createdAt
            }
          }
        }
      }
    }
  }
}' -F owner=ayutaz -F name=piper-plus -F number="$PR_NUM" --jq \
'.data.repository.pullRequest.reviewThreads.nodes
 | map(select(.isResolved == false))
 | length, map(select(.isResolved == false))[]'
```

集計:

- **Unresolved 0 件**: review 障害なし、 next phase へ
- **Unresolved ≥ 1 件**:
  - reviewer 別 (human / Copilot bot) に分類
  - **stale check**: 該当 file がそのコメント以降に修正済みか (memory `feedback_copilot_stale_review`)
  - 提案テーブル形式で表示:

    ```text
    ## Unresolved Review Threads (#<PR>)

    | # | Reviewer | Path | Stale? | 提案 |
    |---|----------|------|--------|------|
    | 1 | Copilot  | src/foo.py:42 | ✓ stale (b7e71c8 以降に更新済) | dismiss / reply |
    | 2 | yousan   | src/bar.rs:88 | new | 修正 → `/reply-review <PR>` |
    ```

### フェーズ 5.5: 安全カテゴリの自動 reply + resolve (auto-chain)

Unresolved review thread が 1 件以上ある場合、 **必ず**`/reply-review <PR> --auto-safe`
を Skill tool で chain 起動する。 これにより以下が自動処理される (フェーズ 1.9
参照、 SAFE-stale / SAFE-copilot-style の 2 カテゴリ):

- **SAFE-stale**: コメント以降に該当 file が更新済 → 「修正済 (commit `<hash>`)」 reply + resolve
- **SAFE-copilot-style**: Copilot bot の style noise (`^Consider (using|renaming)\b` 等) → 「style 提案は本 PR の scope 外」 reply + resolve

`--auto-safe` は SAFE 系のみ実行、 **REVIEW-human / REVIEW-copilot-blocker** は
内部で dry-run 扱いとなり提示のみ。 これにより:

- ユーザの介入なく Copilot のノイズコメントと stale 指摘を片付ける
- 人間 reviewer の本質的な指摘と Copilot の logic / security 指摘は user 判断に残す
- memory `feedback_pr_body_over_comments` (PR body 改変ルール) は review thread reply には適用外、 `feedback_merge_caution` (merge 前確認) も merge ≠ resolve のため抵触しない

skill 呼び出し:

```text
Skill({skill: "reply-review", args: "<PR_NUM> --auto-safe"})
```

戻り値の reply / resolve カウントを次フェーズの判定材料にする。

### フェーズ 6: 次のアクション提案

| 状態 | 推奨アクション |
|------|-------------|
| All green + Unresolved 0 (自動 resolve 後含む) | `/check-pr-ready` で最終確認、 user 確認後に merge (`gh pr merge --auto` 禁止) |
| All green + REVIEW 残 ≥ 1 (自動処理外) | user に judge を促し、 修正コミット後再度 `/loop /watch-pr <PR>` |
| Red (format drift) | `pre-commit run --all-files` をローカル実行、修正後 `/commit` |
| Red (test fail) | 該当テストファイル名を提示、`/run-tests <scope>` で再現 |
| Red (build error) | エラーログを示してユーザーに方針確認 |
| Red (flake) | `gh run rerun <run-id> --failed` を提示 (ユーザー確認後実行) |
| Red (contract drift) | `/check-pua` `/check-loanword` 等の該当 skill を提示 |
| Pending | `/loop /watch-pr <PR>` で継続監視 (auto-safe は次回 iteration でも走る) |

## 継続監視モード

ユーザーが「green になるまで監視して」と希望する場合:

```text
/loop /watch-pr <PR>
```

`/loop` skill が `/watch-pr <PR>` を再帰的に呼び出す。 各 iteration で本 skill が
CI + review thread を両方確認。 終了条件:

| iteration の結果 | アクション |
|------------------|-----------|
| All green + Unresolved 0 | ユーザーに完了通知して `/loop` を終了 |
| All green + Unresolved ≥ 1 | フェーズ 5.5 で `/reply-review --auto-safe` を chain 起動。 SAFE 系は自動 reply + resolve、 残った REVIEW 系を user に提示して `/loop` を終了 |
| Red (本物) | 失敗分析を表示して `/loop` を終了 (人間判断が必要) |
| Red (flake のみ) | `gh run rerun --failed` を提案 (確認後実行)、 ループは継続 |
| Pending | 次の polling 間隔まで sleep (自動 pace は CI 状況で 4-20 分、 cache TTL の都合で IN_PROGRESS 多い時は `delaySeconds=270`、 落ち着いた状態なら `1200`+)。 各 iteration でも review thread の auto-safe chain は走る |

SAFE 系 review thread の自動 reply + resolve は本 skill のフェーズ 5.5 で行う。
REVIEW-human / REVIEW-copilot-blocker は memory `feedback_pr_body_over_comments` /
`feedback_merge_caution` 遵守のため user 判断に委ね、 修正後にユーザが明示的に
`/reply-review <PR>` を起動する形。

## 注意事項

- **無限ループ防止**: 4 時間以上 pending が続くケースは `/loop` を終了して人間に確認を促す
- **rate limit**: GitHub API は 5000 req/hour、 ポーリング間隔を 1 分未満にしない
- **silent skip**: cancelled+skipped が連続 3 以上は path filter による意図的 skip かもしれないが、 PR #419 事例のように baseline が silent に skip されることがあるので警告
- **失敗ログ取得失敗時**: `gh run view` が 404 を返す場合 (job がまだ完了していない等) はスキップ
- **merge は user-only**: 本 skill から `gh pr merge` を実行することは禁止 (memory `feedback_merge_caution` に従う)
- **review reply は SAFE 系のみ自動**: フェーズ 5.5 で `/reply-review --auto-safe` を chain 起動。 SAFE-stale / SAFE-copilot-style だけ自動 reply + resolve。 REVIEW-human / REVIEW-copilot-blocker は user 判断のため `/reply-review <PR>` 明示起動を待つ
- **自動コード修正は行わない**: review 指摘で「コードを直す」 必要があるものは user 判断。 stale (既に修正済) / Copilot ノイズ (style 提案) のみ自動 reply で完結
- **Copilot stale 検出**: review コメント以降に同 file が更新済なら `stale` フラグ付き提示 (memory `feedback_copilot_stale_review`)。 自動 reply の core ロジック

## 使用例

```text
# 現在ブランチの PR を 1 回チェック
/watch-pr

# PR #489 を 1 回チェック
/watch-pr 489

# 5 分間隔で継続監視 (loop skill が pace 決定)
/loop /watch-pr 489

# 固定 5 分間隔
/loop 5m /watch-pr 489
```

## 期待効果

- ユーザーが 7 ランタイム × ~94 jobs の CI を手動で `gh pr checks` ポーリングする手間を削減
- red 時に「どの分類の失敗か」即座に分類することで対応時間を短縮
- silent skip (PR #419 type) の早期検出
