# バッチ設計書 10-close-stale-prs.yml

## 概要

本ドキュメントは、OpenCodeプロジェクトの非アクティブPR自動クローズワークフロー（close-stale-prs.yml）の設計仕様を定義する。このワークフローは60日以上活動のないPRを自動的にクローズする。

### 本バッチの処理概要

このワークフローは、GitHub GraphQL APIを使用して全オープンPRを取得し、60日以上活動のないPRを自動的にクローズする。actions/github-scriptを使用してカスタムロジックを実装し、最後のコミット日、コメント日、レビュー日から活動状況を判定する。

**業務上の目的・背景**：コミュニティからのPRは、レビュー待ちや作業中断により長期間放置されることがある。放置されたPRはマージコンフリクトが蓄積し、コードベースとの乖離が大きくなる。本バッチにより、非アクティブなPRを自動的に整理し、PR一覧を健全に保つ。クローズされたPRは必要に応じて再オープン可能である。

**バッチの実行タイミング**：毎日06:00 UTCにスケジュール実行される。手動でのworkflow_dispatchトリガーも可能（dryRunオプション付き）。

**主要な処理内容**：
1. GraphQL APIで全オープンPRをページネーション取得
2. 各PRの最終活動日を判定（コミット/コメント/レビュー）
3. 60日以上非活動のPRを特定
4. 各対象PRにコメントを投稿
5. PRをクローズ
6. サマリーログを出力

**前後の処理との関連**：独立したバッチとして動作。stale-issues.ymlと同様の目的を持つが、対象がPRで、カスタムロジックで処理する点が異なる。

**影響範囲**：GitHubリポジトリのPRの状態、コメントに影響を与える。

## バッチ種別

PR管理 / 自動クリーンアップ

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次 |
| 実行時刻 | 06:00 UTC |
| 実行曜日 | 毎日 |
| 実行日 | 毎日 |
| トリガー | cron（0 6 * * *）、手動実行 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| contents: read | リポジトリ読み取り権限 |
| issues: write | Issueコメント書き込み権限 |
| pull-requests: write | PRクローズ権限 |
| GITHUB_TOKEN | 自動提供されるトークン |

### 実行可否判定

ワークフローは常に実行される。dryRunオプションがtrueの場合は、ログ出力のみでPRのクローズは行わない。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| dryRun | boolean | No | false | ドライランモード（クローズせずログのみ） |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| GitHub GraphQL API | JSON | オープンPR一覧（ページネーション） |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| PR state | 状態 | オープン→クローズ |
| PR comments | テキスト | クローズ理由メッセージ |
| Actions Log | テキスト | 処理サマリー |

### 出力ファイル仕様

ファイル出力なし。GitHub API操作のみ。

## 処理フロー

### 処理シーケンス

```
1. GraphQL APIでオープンPR取得
   ├─ ページネーション対応（100件/ページ）
   ├─ 各ページ取得間に1秒待機
   └─ リトライ機能付き（最大3回）

2. stale PR判定
   ├─ 作成日、最終コミット日、コメント日、レビュー日を収集
   ├─ 最新の活動日を特定
   └─ 60日以上前なら対象

3. PR処理（stale PRごと）
   ├─ dryRunの場合：ログ出力のみ
   ├─ コメント投稿
   ├─ PRクローズ
   └─ 処理間隔（小バッチ1秒、大バッチ2秒）

4. サマリー出力
   └─ 総PR数、stale数、クローズ数、エラー数、処理時間
```

### フローチャート

```mermaid
flowchart TD
    A[ワークフロー開始] --> B[GraphQL: オープンPR取得]
    B --> C{次ページあり?}
    C -->|Yes| D[1秒待機]
    D --> B
    C -->|No| E[全PR取得完了]
    E --> F[stale PR判定]
    F --> G{stale PRあり?}
    G -->|No| H[サマリー出力]
    G -->|Yes| I[PR処理ループ]
    I --> J{dryRun?}
    J -->|Yes| K[ログ出力]
    J -->|No| L[コメント投稿]
    L --> M[PRクローズ]
    M --> N[待機]
    K --> O{次のPR?}
    N --> O
    O -->|Yes| I
    O -->|No| H
    H --> P[ワークフロー終了]
```

## データベース操作仕様

### 操作別データベース影響一覧

本ワークフローはデータベース操作を行わない。GitHub API操作のみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | レート制限 | GitHub APIセカンダリ制限 | 自動リトライ（指数バックオフ） |
| - | GraphQL失敗 | ネットワークエラー | リトライ後エラー終了 |
| - | PRクローズ失敗 | 権限エラー等 | エラーログ出力、次PRへ続行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 最大3回（MAX_RETRIES） |
| リトライ間隔 | 指数バックオフ（retry-after * 2^attempt） |
| リトライ対象エラー | 403（レート制限）のみ |

### 障害時対応

1. 全体失敗：次回スケジュール実行で再試行
2. 個別PRエラー：エラーログ出力後、残りのPR処理を継続
3. 継続的失敗：dryRunモードで手動実行して調査

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（PR単位で処理） |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし（手動再オープン可能） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | PR数: 全オープンPR |
| 目標処理時間 | 15分以内（timeout-minutes設定） |
| メモリ使用量上限 | 特に制限なし |
| API操作間隔 | 小バッチ: 1秒、大バッチ: 2秒 |

## 排他制御

特になし。PR単位の処理のため並列実行可能だが、API制限に注意。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 設定ログ | 開始時 | "Dry run mode: {value}", "Cutoff date: {date}" |
| ページログ | ページ取得時 | "Fetching page {n}...", "fetched {m} PRs" |
| PR判定ログ | 各PR判定時 | "PR #{n} is fresh/STALE" |
| stale数ログ | 判定完了時 | "Found {n} stale pull requests" |
| クローズログ | クローズ時 | "Closed PR #{n} from {author}" |
| エラーログ | エラー時 | "Failed to close PR #{n}" |
| サマリーログ | 完了時 | 総数、stale数、クローズ数、エラー数、処理時間 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| ワークフロー失敗 | 発生時 | GitHub Actions通知 |
| タイムアウト | 15分 | GitHub Actions通知 |

## 備考

- 非活動日数: 60日（DAYS_INACTIVE）
- バッチサイズ閾値: 10件（SMALL_BATCH_THRESHOLD）
- 小バッチ遅延: 1秒（日次運用、10件以下）
- 大バッチ遅延: 2秒（バックログ処理、10件超）
- GitHub APIレート制限: 80リクエスト/分（余裕を持って約30リクエスト/分で運用）
- GraphQL取得項目:
  - number, title, author.login, createdAt
  - commits.last.commit.committedDate
  - comments.last.createdAt
  - reviews.last.createdAt
- クローズメッセージ:
  ```
  Closing this pull request because it has had no updates for more than 60 days.
  If you plan to continue working on it, feel free to reopen or open a new PR.
  ```
- actions/github-script@v8を使用
- ubuntu-latestランナーで実行
- timeout-minutes: 15で実行時間制限
