# watch-pr-review

설정한 GitHub 저장소의 PR을 주기적으로 감시(폴링)하여, 신규 PR이거나 기존 PR의 커밋이 변경된 경우 `/review` 파이프라인을 재사용해 자동 코드 리뷰를 수행하고, 결과를 마크다운 파일로 저장한 뒤 해당 PR에 댓글로 등록하는 기능이다.

## 명령어

| 명령 | 설명 |
| --- | --- |
| `/watch-pr-review` | PR 감시 폴링 루프를 시작한다. `Ctrl+C`로 종료한다. |
| `/watch-pr-review-config` | 감시 대상 저장소 설정 파일(`repos.json`)을 에디터로 연다. |

## 사전 조건

- `gh` CLI가 설치되어 있고 인증(`gh auth login`)되어 있어야 한다.
- 시작 시 `gh auth status`로 사용 가능 여부를 검사하며, 실패하면 안내 후 종료한다.

## 저장 위치

모든 산출물은 `.ju-hong-e/watch-pr-review/` 하위에 보관한다.

| 파일/경로 | 역할 |
| --- | --- |
| `repos.json` | 감시 대상 저장소 목록 + 폴링 주기 설정 |
| `history.json` | 리뷰 완료 PR 이력 (PR URL + 커밋 OID 목록 + 리뷰 시각) |
| `reports/watch-pr-review-YYYY-MM-DD-HH-MM-SS-pr<번호>.md` | 리뷰 결과 마크다운 (PR 댓글과 동일 내용) |
| `reports/watch-pr-review-YYYY-MM-DD-HH-MM-SS-pr<번호>-diff.md` | PR diff 원문 (변수 적재 없이 파일로 스트리밍 저장) |

### repos.json 예시

```json
{
  "pollIntervalMs": 10000,
  "concurrency": 3,
  "repos": [
    { "repo": "minhyupp/poc-dsp-dct-fe", "enabled": true },
    { "repo": "owner/another-repo", "enabled": false }
  ]
}
```

- `pollIntervalMs`: 폴링 주기(ms). 최소 3000ms. 기본 10000ms.
- `concurrency`: 큐에서 동시에 꺼내 리뷰하는 워커(스레드) 수. 범위 1~8, 기본 2.
- `repos[].repo`: `owner/repository` 형식.
- `repos[].enabled`: `false`면 감시에서 제외. 자리표시자 `owner/repository`도 무시된다.

## 동작 흐름 (생산자 + 워커 풀)

`/watch-pr-review`는 **생산자(폴링→큐 적재)** 와 **워커 풀(동시 N건 소비)** 로 동작한다.

### 생산자 (poll loop)

1. `gh auth status`로 gh CLI 가용성 확인.
2. `pollIntervalMs` 주기로 아래를 반복한다.
3. 각 활성 저장소의 열린 PR 목록을 `gh pr list`로 조회.
4. PR별 커밋 OID(`gh pr view --json commits`)를 조회해 `history.json`과 비교.
   - 신규 PR이거나 커밋 집합이 달라진 경우에만 **큐에 적재**.
   - 이미 큐에 있거나 처리 중인 PR(URL 기준)은 중복 적재하지 않는다.

### 워커 (concurrency 만큼 동시 실행)

5. 큐에서 작업을 꺼내(동시에 최대 `concurrency`건) 처리한다.
6. `gh pr diff` 출력을 변수에 담지 않고 `reports/...-diff.md` 파일로 직접 스트리밍 저장. 빈 diff면 건너뜀.
7. 변경 파일 목록은 diff 파싱이 아니라 `gh pr view --json files`로 획득(조건부 리뷰 규칙 선택용).
8. 저장된 diff 파일을 참조해 `/review` 규칙·지시 자산을 그대로 적용한 헤드리스 AI 리뷰 수행.
9. 결과를 `reports/`에 마크다운으로 저장하고, 그 파일을 `gh pr comment --body-file`로 PR에 댓글 등록.
10. `history.json`에 PR URL·커밋 OID·리뷰 시각을 갱신.

### 중복 리뷰 방어 (2단계)

`history.json`은 `.ju-hong-e/` 아래 로컬·gitignore 파일이라 다른 PC에서 실행하면 비어 있다. 이로 인한 중복 댓글을 막기 위해 2단계로 방어한다.

1. **로컬 이력**: `history.json`에 동일 커밋 집합으로 리뷰한 기록이 있으면 건너뛴다(API 비용 0).
2. **원격 댓글 서명**: 로컬 이력에 없더라도, 리뷰 댓글에 심긴 **커밋 서명**(`buildReviewSignature` — 커밋 OID 집합의 안정적 해시)을 PR 기존 댓글(`gh pr view --json comments`)에서 찾아 동일 서명이 있으면 건너뛴다. 발견 시 로컬 이력에도 기록해 다음 사이클부터는 1단계로 커버한다.

> 코드/커밋이 바뀌면 커밋 OID가 바뀌어 서명도 달라지므로, **변경이 있는 PR은 정상적으로 재리뷰**된다. "이미 리뷰됨 + 변경 없음"일 때만 건너뛴다.

### 동시성 안전 / 진행 표시

- **중복 차단**: 큐가 PR URL 기준으로 대기·진행 중인 작업을 추적(`ReviewQueue`)해, 같은 PR이 동시에 두 번 리뷰되지 않는다.
- **이력 레이스 방지**: 여러 워커가 `history.json`을 동시에 갱신하지 않도록 in-process mutex(`createMutex`)로 읽기-갱신-쓰기를 직렬화한다.
- **진행 표시**: 동시 처리 중에는 in-place 스피너 대신 `[W{워커}·PR #{번호}]` 접두사 라인 로그로 단계(1/4~4/4)를 출력하고, 8초마다 진행 중 건수·대기 건수·PR별 경과시간 하트비트를 출력한다.

> 대용량 산출물(diff, 리뷰 본문)은 base-rule 규칙에 따라 문자열 변수가 아닌 파일로 저장·전달한다.

## 진행 표시 (UI) 예시

동시 처리 시 워커별 단계 로그가 인터리브되며, 8초 하트비트가 진행 중 현황을 알려준다.

```
➕ 리뷰 대기열 추가: PR #1053 test pr
➕ 리뷰 대기열 추가: PR #1054 fix login
[W1·PR #1053] 리뷰 시작: test pr
[W2·PR #1054] 리뷰 시작: fix login
[W1·PR #1053] 1/4 diff 수집 완료 (12.3KB)
[W1·PR #1053] 2/4 변경 파일 5개 · a.ts, b.tsx, c.scss 외 2개
[W1·PR #1053] 3/4 AI 리뷰 요청...
[W2·PR #1054] 1/4 diff 수집 완료 (3.1KB)
⏳ 진행 중 2건 · 대기 0건 — PR #1053(8s), PR #1054(5s)
[W1·PR #1053] 4/4 리포트 저장 · PR 댓글 등록 중
[W1·PR #1053] ✅ 리뷰 완료 · 댓글 등록 — .ju-hong-e/watch-pr-review/reports/...md
```

## 파일 구성

```
features/watch-pr-review/
  domain/
    types.ts             # WatchConfig, WatchHistory, PullRequestInfo, ReviewTask 타입
    review-marker.ts     # 커밋 서명·리뷰 댓글 마커 (cross-machine 중복 방어)
  infrastructure/
    gh.ts                # gh CLI 래퍼 (PR 목록/커밋/변경파일/diff 스트리밍, 댓글)
    store.ts             # repos.json / history.json 읽기·쓰기, 이력 비교, 설정 정규화
    system.ts            # 에디터 열기, SIGINT 중단 제어, 지연 대기, mutex
  application/
    context.ts           # 생산자·워커 공유 실행 문맥 타입
    review-queue.ts      # URL 기준 dedup 동시성 큐 (적재/소비/진행추적)
    producer.ts          # 폴링 → 리뷰 대상 큐 적재
    worker.ts            # 큐 소비 → diff 저장 → AI 리뷰 → 저장·댓글·이력
    review-runner.ts     # PR diff 파일 → 헤드리스 /review 호출 → 리뷰 마크다운
    action.ts            # 생산자 루프 + 워커 풀 + 하트비트 / 설정 파일 열기
```

## 재사용 관계

- AI 리뷰는 `/review`의 `buildReviewPrompt` + `runAIService`를 그대로 사용한다.
- 리뷰 규칙/지시/폼 자산은 `features/review/assets`를 재사용하며, `/watch-pr-review` 명령 정의를 통해 `promptAssets`로 주입된다.
- FE/BE 프로필에 따라 `reviewFePromptRules` / `reviewBePromptRules`가 선택된다.
