# task-2511 — auto_gemini_triage: Gemini review thread 자동 분류/resolve

- 작업 유형: **자동화 코드 구현 + 회귀 테스트** (정책 문서 X)
- 작업 레벨: **Lv.3**
- 우선순위: **★★**
- Track: **auto_gemini_triage / review_thread_state_machine / required_review_thread_resolution_auto_clear / 5 모듈 #3**
- parallel_policy: **serial_only**
- 일시: 2026-05-09
- 회장 결정: 2026-05-09 직접 발행 (PR #61 required_review_thread_resolution blocker 학습 후)

## ⚠️ 본 task의 본질 — 회장 명시

> 본 task의 본질은 "Gemini comment 읽기"가 아니라 **review thread state machine 자동화**다.
> Gemini unresolved thread → auto triage → auto resolve → CLEAN → auto merge까지
> **사람 개입 없이 연결 가능한 상태**를 만드는 것이 목표다.
> 산출물 = 코드 + 회귀 테스트. 문서는 부속.

## PR #61 학습 (회장 직접 박제)

PR #61 (task-2510)은 다음과 같은 사고를 일으켰다:
- CI 11/11 SUCCESS, mergeable=MERGEABLE, mergeStateStatus=BLOCKED
- 원인: Repository ruleset `required_review_thread_resolution=true` + 5건 unresolved Gemini thread
- 4건 outdated, 1건 코드 반영 후 PR comment dismiss
- **봇이 자동으로 resolveReviewThread GraphQL 호출을 못 해서 stuck**
- 회장 운영 원칙(2026-05-08) "Critical 7종 0건 + 자동 머지 10조건 충족 = 회장 승인 없이 자동 머지"에 위배

본 task가 해소해야 할 capability gap:
1. **review thread state classifier** 부재
2. **resolveReviewThread GraphQL mutation 자동 호출** 부재
3. **unresolved_count / auto_resolved_count / blocking_thread_count 계산기** 부재
4. **scope expansion vs in-scope minor fix 분리** 부재

## dependency (모두 충족)

- ✅ task-2509.merged (PR #58)
- ✅ task-2509+1.merged (PR #59)
- ✅ task-2509+2.merged (PR #60, automation_contracts.py freeze)
- ✅ task-2510.merged (PR #61, replacement_pr_runner)

## Merge Topology Gate metadata

```yaml
expected_files:
  - "utils/auto_gemini_triage.py"
  - "tests/regression/test_auto_gemini_triage_2511.py"

risk_area: "auto_gemini_triage / review_thread_state_machine / required_review_thread_resolution / scope_expansion_detection"

dependency:
  - "task-2509.merged"
  - "task-2509+1.merged"
  - "task-2509+2.merged"
  - "task-2510.merged"

parallel_policy: "serial_only"

merge_queue_position: 8

stale_recheck_required: true

cherry_pick_allowed: false
```

## 실전 replay fixture (회장 명시 — 반드시 replay)

- **PR #55** (task-2507): style-only / fixed-after-review thread
- **PR #56** (task-2506): outdated thread + hardcoded path dismiss
- **PR #57** (task-2503+1): regex grep false-positive + wrapper/helper pattern false-positive
- **PR #61** (task-2510): **5건 unresolved → CLEAN 전환 자동화** (★ 핵심 회귀)
  - 4 outdated thread auto-resolve
  - 1 코드반영 후 dismiss-by-comment thread auto-resolve
  - mergeStateStatus BLOCKED → CLEAN 검증

본 fixture를 회귀 테스트 입력으로 사용 — 동일 결과 재현 필수.

## 필수 구현 6건 (회장 §1~6)

### 1. Gemini thread classifier

다음 7 상태 자동 분류:

```python
class TriageVerdict(str, Enum):
    FALSE_POSITIVE          # 정적 분석/grep 오탐 (예: regex false-positive, wrapper/helper pattern)
    STYLE_ONLY              # 코드 스타일 의견 (semantic 동등)
    OUTDATED                # PR head 변경 후 outdated 처리됨
    CODE_ALREADY_FIXED      # 이미 후속 commit으로 반영됨 (commit 본문/diff 매칭)
    MINOR_FIX_ALLOWED       # expected_files 안 + 작은 수정 (bool flag, 변수명 등)
    REAL_BUG_IN_SCOPE       # 실제 버그 + expected_files 안 (자동 수정 가능)
    REAL_BUG_SCOPE_EXPANSION  # ★ Critical #3 GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION
```

분류 입력:
- thread metadata (isOutdated, isResolved)
- comment body (정규식 매칭: hardcoded path / regex / wrapper pattern / style hint)
- 후속 commit diff (CODE_ALREADY_FIXED 검증)
- expected_files 비교 (SCOPE_EXPANSION 검증)
- forbidden path 비교 (Critical #1 FORBIDDEN_PATH_INTRUSION)

### 2. 자동 dismiss / resolve

자동 처리 대상 (5종):
- FALSE_POSITIVE
- STYLE_ONLY
- OUTDATED
- CODE_ALREADY_FIXED
- MINOR_FIX_ALLOWED

자동 수행:
- **dismiss comment 생성** (분류 사유 + 증거 evidence 명시, 1~3 문장)
- **resolveReviewThread GraphQL mutation 호출** (subprocess `gh api graphql -f query=...`)
- **thread state refresh** (post-resolve 재조회로 isResolved=true 검증)

### 3. scope expansion 감지

다음 4 경우만 Critical escalation:
- expected_files 밖 수정 필요 → `GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION` (Critical #3)
- forbidden path 수정 요구 → `FORBIDDEN_PATH_INTRUSION` (Critical #1)
- architecture/scope expansion 요구 → `GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION` (Critical #3)
- dependency cycle 유발 수정 → `DEPENDENCY_CYCLE_OR_SERIAL_ONLY_COLLISION` (Critical #5)

나머지는 모두 자동 처리 (회장 §자동 처리 7항목 #1, #2).

### 4. automation_contracts 사용 (task-2509+2 freeze 결과)

import 대상:
- `GeminiTriageResult` (verdict / thread_id / auto_resolved / dismiss_comment / escalation_type / evidence)
- `ReviewGateStatus` (gemini_status / unresolved_count / auto_resolved_count / blocking_thread_count / review_gate_passed)
- `AutomationDecision`
- `CriticalEscalationType`
- `EscalationPacket`

### 5. merge_queue_executor 연동 준비 (실제 wiring은 task-2514)

다음 카운터 + readiness 반환:
- `unresolved_count` (정수)
- `auto_resolved_count` (정수)
- `blocking_thread_count` (정수, REAL_BUG_SCOPE_EXPANSION/FORBIDDEN_PATH_INTRUSION 등)
- `merge_readiness` (bool: blocking_thread_count == 0)
- `ReviewGateStatus` 인스턴스 반환

본 task에서는 호출 인터페이스만 제공. 실제 merge_queue_executor wiring은 task-2514 영역.

### 6. 실전 replay fixture (회장 §6)

`tests/regression/test_auto_gemini_triage_2511.py` 안에 4 PR fixture replay 회귀:
- PR #55 fixture: style-only/fixed-after-review thread → STYLE_ONLY/CODE_ALREADY_FIXED
- PR #56 fixture: outdated thread + hardcoded path dismiss → OUTDATED/FALSE_POSITIVE
- PR #57 fixture: regex grep false-positive + wrapper/helper false-positive → FALSE_POSITIVE × 2
- **PR #61 fixture: 5 unresolved → 5 auto-resolved → mergeStateStatus 가상 CLEAN 전환** (★ 핵심)

## 필수 회귀 테스트 16건 (회장 §1~16)

`tests/regression/test_auto_gemini_triage_2511.py`:

1. outdated thread auto-resolve (verdict=OUTDATED, auto_resolved=true)
2. code-fixed thread auto-resolve (commit body/diff 매칭으로 CODE_ALREADY_FIXED 판정)
3. false-positive dismiss (regex false-positive 패턴)
4. style-only dismiss (semantic 동등 판정)
5. allowed minor fix auto-pass (expected_files 안)
6. expected_files 밖 수정 요구 → Critical `GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION`
7. forbidden path 요구 → Critical `FORBIDDEN_PATH_INTRUSION`
8. resolveReviewThread payload 생성 검증 (subprocess args에 mutation + threadId 포함)
9. unresolved_count 계산 (입력: 5 thread, 정답: 5)
10. ReviewGateStatus JSON serialization (round-trip 무결성)
11. **★ replay: PR #61 unresolved 5건 → CLEAN 전환** (가상 fixture 합성)
12. replay: PR #56 hardcoded path dismiss
13. replay: PR #57 regex grep false-positive
14. replay: PR #57 wrapper/helper false-positive
15. replay: PR #56 outdated commit review
16. replay: PR #55 style-only medium thread

## CLI entrypoint

`python3 utils/auto_gemini_triage.py --pr <N> --dry-run`
- 출력: `ReviewGateStatus` JSON
- `--apply` 옵션: 실제 GraphQL resolveReviewThread 호출
- `--task-file <path>` 옵션: expected_files / forbidden path 로드
- dry-run = subprocess 시뮬레이션만, 실제 호출 X

## 금지 행위 (회장 명시 — 절대 준수)

- **merge_queue_executor 대규모 수정 금지** (import 가능성만 확인)
- **dispatch.py wiring 금지**
- **replacement_pr_runner 수정 금지** (task-2510 영역)
- **post_merge_smoke_runner 구현 금지** (task-2512 영역)
- **critical_escalation_reporter 구현 금지** (task-2513 영역)
- **force push 금지**
- **rebase 금지**
- **admin override 금지** (`gh pr merge --admin`)
- **manual .done 금지**
- **required CI bypass 금지**
- **PR #52/#49/#50/#51 수정 금지**
- **expected_files 외 수정 금지**
- **자동 cherry-pick 구현 금지**
- **정책 md만 작성하고 종료 금지**
- **Critical 7종 외 회장 보고 금지**
- **amendment 무시 / mid-dispatch correction 무시 금지**

## allowed_resources

```yaml
allowed_resources:
  read_only_paths:
    - "memory/tasks/task-2509*"
    - "memory/tasks/task-2510*"
    - "memory/tasks/task-2511*"
    - "memory/feedback/feedback_critical_escalation_only_260508.md"
    - "memory/feedback/feedback_merge_topology_gate_260508.md"
    - "utils/automation_contracts.py"  # task-2509+2 freeze
    - "utils/merge_queue_executor.py"
    - "utils/replacement_pr_runner.py"
    - "utils/merge_topology_gate.py"
    - "memory/orchestration-audit/merge-queue.jsonl"
    - "memory/task-timers.json"
    - ".env.keys"
  paths:
    - "memory/tasks/task-2511*"
    - "memory/reports/task-2511*"
    - "memory/events/task-2511*"
    - "utils/auto_gemini_triage.py"
    - "tests/regression/test_auto_gemini_triage_2511.py"
  forbidden_actions:
    - "merge_queue_executor 대규모 수정"
    - "dispatch.py wiring"
    - "replacement_pr_runner 수정"
    - "post_merge_smoke_runner 구현"
    - "critical_escalation_reporter 구현"
    - "force push"
    - "rebase"
    - "admin override (gh pr merge --admin)"
    - "manual .done 생성"
    - "required CI bypass"
    - "PR #52/#49/#50/#51 수정"
    - "expected_files 외 수정"
    - "자동 cherry-pick 구현"
    - "정책 md만 작성하고 종료"
    - "Critical 7종 외 회장 보고"
    - "amendment 무시 / mid-dispatch correction 무시"
```

## 완료 조건 (회장 명시)

1. ✅ 실행 가능한 Python 코드 (`utils/auto_gemini_triage.py`)
2. ✅ replay fixture 기반 회귀 PASS (16/16)
3. ✅ 실제 resolveReviewThread payload 생성 가능 (subprocess args 검증)
4. ✅ ReviewGateStatus 반환 가능 (`automation_contracts` import)
5. ✅ **required_review_thread_resolution blocker 자동 해소 가능** (PR #61 fixture 회귀 #11)
6. ✅ Critical 7종 외 회장 보고 0건
7. ✅ Merge Topology Gate 자기참조 PASS (effective diff = 정확히 2 파일)
8. ✅ CI 11/11 SUCCESS
9. ✅ forbidden path 0
10. ✅ amendment 보호 의무 명시 + 적용 evidence

## 시스템 3문서 참조

- 정책 본체: `memory/feedback/feedback_critical_escalation_only_260508.md`
- 공통 계약: `utils/automation_contracts.py` (task-2509+2 freeze)
- merge_queue_executor: `utils/merge_queue_executor.py` (task-2509 + task-2509+1)
- replacement_pr_runner: `utils/replacement_pr_runner.py` (task-2510)
- 실전 fixture: PR #55 / #56 / #57 / #61 (★ #61 = 본 task 핵심 회귀)

## 후행 task

본 task가 5 모듈 #3. 머지 후:
- task-2512 — post_merge_smoke_runner
- task-2513 — critical_escalation_reporter
- task-2514 — wiring (★ 마지막 단일 serial task: merge_queue_executor에 4 모듈 실제 연결)

## affected_files (auto-detected)
- utils/auto_gemini_triage.py (NEW)
- tests/regression/test_auto_gemini_triage_2511.py (NEW)

## goal_assertions (auto-generated)
- `python3 utils/auto_gemini_triage.py --pr 61 --dry-run`
- `pytest tests/regression/test_auto_gemini_triage_2511.py -q` → 16/16 PASS