# task-2719 — ci_gemini_watcher GET-only gh_runner dry-run 어댑터 (분리 파일)

## 회장 인가 (2026-05-31)
PR #164(`4e080d58`, main 반영) 후속. run_watch_cycle 은 main 에 있으나 실 PR 데이터를 gh op 5종으로
변환하는 read-only production 어댑터가 0 → 실 PR one-shot dry-run BLOCKED. 본 task = **GET-only
gh_runner 어댑터 신규 파일 분리** 구현. runner 무수정.

## 단일소스 작업안 (먼저 읽을 것)
`memory/plans/ci_gemini_watcher_wiring/dry_run_wiring_plan_260531.md`
sha256 = `753d9ad15ac5ff4b54eb43ae9942529403a6f64933f9cb9fdc26253d81394638`

## expected_files (정확히 2개 — 그 외 어떤 파일도 수정 금지)
- `anu_v2/ci_gemini_watcher_gh_adapter.py` (신규)
- `tests/regression/test_ci_gemini_watcher_gh_adapter_2719.py` (신규)
★ `anu_v2/ci_gemini_watcher_runner.py` **무수정** (main 반영분 4e080d58 보존, import 만 함).

## 허용/구현 (회장 verbatim 조건 1~9)
1. runner 무수정 유지. 2. runner 는 순수 decision/cycle logic 유지(본 어댑터에서 import/call 만).
3. 신규 adapter = **GET-only gh_runner 경계**로 한정.
4. op 5종 read-only 매핑:
   - `actual_head` → `gh pr view <pr> --json headRefOid` (또는 gh api GET)
   - `diff_paths`  → `gh pr view <pr> --json files`
   - `ci_rollup`   → `gh pr checks <pr>` / `gh api .../check-runs` (GET)
   - `reviews`     → `gh api .../pulls/<pr>/reviews` (GET, freshness checker 가 method=GET 으로 호출)
   - `findings`    → `gh api .../pulls/<pr>/comments` (GET)
5. owner_trigger = **decision-only**. 실제 `/gemini review` comment 발사 절대 금지.
6. auto_gemini_triage = finding 전달/decision 검증까지만.
7. terminal enum + decision JSON 출력까지 검증.
8. **GitHub write 0 을 regression 으로 고정** (POST/PATCH/PUT/DELETE/comment op 미구현 + 호출 시 reject guard).
9. 성공해도 wired/active 승격 금지 — dry_run_one_shot✅ 까지만 기록.

## 구현 형태 (권고)
- adapter 모듈에: `build_readonly_gh_runner(gh_cli=...) -> Callable` (op 5종 dispatch, GET-only) +
  `run_one_shot_dry_run(pr_number, expected_head, expected_files, *, gh_cli=...) -> WatchResult`
  (어댑터로 gh_runner 구성 → `run_watch_cycle(...)` 호출, dry_run=True).
- gh 호출은 **주입형(gh_cli callable)** 으로 — 테스트에서 mock. 실 호출은 `subprocess`/`gh` GET only.
- write op 요청 시 `RuntimeError`/reject (GET-only hard guard).

## 금지 (회장 verbatim)
runner 파일 수정 금지 · 실 GitHub write 금지 · 실 `/gemini review` comment 금지 ·
OS-level crontab/systemd/inotify 설치 금지 · hook/key봉인/completion_contract 구현 금지 ·
PR #162/#163/#164 수정 금지 · force/rebase/admin/merge 금지 · **push/PR 생성 금지** ·
새 watcher 활성화 금지 · active/wired 과장 금지 · ANU key literal 노출 금지.

## regression 검증 (전부 mock, 네트워크 0)
- mocked gh output 으로 op 5종 매핑 정확성 (actual_head/diff_paths/ci_rollup/reviews/findings)
- **GitHub write 명령 0 검증** (write op 주입/요청 시 reject; mock 호출 카운트 method 전부 GET)
- stale review + OWNER proof OK + dedupe OK → `ALLOW_OWNER_TRIGGER` decision 만 반환, 실 comment 0
- unresolved 0 + CI PASS + scope clean → `MERGE_READY_CANDIDATE`
- expected_head mismatch → `HOLD_STALE_HEAD`
- scope mismatch → `HOLD_SCOPE_UNCLEAN`
- CI fail → `CI_FAILED_NON_REMEDIABLE`
- owner_trigger(validate_decision) · auto_gemini_triage 호출 spy 입증
- real PR one-shot dry-run 은 read-only 1회만 수행 가능하되 **자동 watcher 라 부르지 말 것**(주석/명명 금지)

## finalize (로컬 commit 까지만 — push/PR 금지)
1. 새 worktree(task-2719) 또는 origin/main(`4e080d58`) base. PR #164 worktree 와 격리.
2. `python3 -m pytest tests/regression/test_ci_gemini_watcher_gh_adapter_2719.py -q` 전 PASS.
3. `git diff --name-only origin/main` = expected_files 2개만 (runner 무수정 확인).
4. **로컬 commit only. push/PR/merge 금지.**
5. 완료 시 `memory/events/task-2719.done` + `memory/reports/task-2719.md`
   (op 5종 매핑/GitHub write 0/terminal enum/decision-only/owner_trigger·triage spy 입증/commit sha).
6. ANU normal callback = **ANU key `c119085addb0f8b7`** (executor self-key 금지), envelope-only ≤3900 bytes.

## ★ dispatch 템플릿 G3(PR/머지) 무시
dispatch 템플릿이 G3 자동 PR/머지를 넣어도 **본 task 에 적용 안 됨**. finalize §4(로컬 commit only)가 우선.
finish-task.sh 를 --action pr 로 실행하지 말 것.

## allowed_resources (본 task의 capability)

```yaml
allowed_resources:
  paths:
    - "anu_v2/ci_gemini_watcher_gh_adapter.py"
    - "tests/regression/test_ci_gemini_watcher_gh_adapter_2719.py"
  forbidden_paths:
    - "anu_v2/ci_gemini_watcher_runner.py"
    - "dispatch/**"
    - ".github/**"
    - "anu_v2/merge_queue_executor.py"
    - "memory/events/*.cron-*"
  commands:
    - "pytest"
    - "python3 -m pytest"
    - "python3 -m py_compile"
  merge_policy: "tiered"
  ttl_hours: 48
```

## ANU 후속 (봇 아님)
ANU 가 로컬 commit 독립 재검증 → capability delta + PR 진입 가능 여부만 보고.
기대 상태: ci_gemini_watcher = implemented✅ verified✅ main_reflected✅ dry_run_one_shot✅ wired❌ active❌.
push/PR 은 별도 회장 승인 전까지 금지.

## goal_assertions (auto-generated)
- `python3 -m pytest tests/regression/test_ci_gemini_watcher_gh_adapter_2719.py -q`
