# task-2718 — ci_gemini_watcher 단일 멱등 cycle runner 결선

## 회장 인가 (2026-05-31)
ci_gemini_watcher 결선 1단계. OS-level 주기실행/Phase2 전체가 아니라 **"단일 멱등 cycle runner"까지만**.
기존 anu_v2 빌딩블록을 **import/call 로 결선**하는 얇은 runner. 신규 로직/복제 최소.
이후 OS-level driver 가 호출할 수 있는 deterministic 1회 cycle entrypoint 를 만드는 것이 목표.

## 단일소스 작업안 (반드시 먼저 읽을 것)
`memory/plans/ci_gemini_watcher_wiring/wiring_plan_260531.md`
sha256 = `c510148ee02bd1f93849c8462e37e496a1d37d3773f904b75d3871a809650ee5`
→ §1 기존 entrypoint / §2 gap / §9 구현순서 / §10 regression / §11 성공기준 준수.

## expected_files (정확히 2개 — 그 외 어떤 파일도 수정 금지)
- `anu_v2/ci_gemini_watcher_runner.py` (신규)
- `tests/regression/test_ci_gemini_watcher_runner_2718.py` (신규)

## 허용 기능 (회장 verbatim, 1~10)
1. current PR/head 조회 input 처리
2. expected_head 와 actual_head 비교
3. CI rollup 확인
4. Gemini fresh/stale 판정
5. stale 이면 owner_gemini_trigger decision 호출
6. OWNER proof + dedupe 조건 만족 시 trigger decision = `ALLOW_OWNER_TRIGGER` 반환
7. Gemini finding 수집 결과를 auto_gemini_triage entrypoint 로 넘기는 결선
8. terminal enum 출력: `MERGE_READY_CANDIDATE` / `LOOP_BOUNDARY` / `BLOCKED_BY_CAPABILITY` /
   `GEMINI_EXTERNAL_TRIGGER_REQUIRED` / `CI_FAILED_NON_REMEDIABLE` / `HOLD_STALE_HEAD` / `HOLD_SCOPE_UNCLEAN`
9. decision JSON 출력
10. 중복 실행 대비 idempotent dry-run mode

## 구현 방식 (필수)
- 기존 entrypoint 를 **복제하지 말고 import/call 로 결선**:
  - `anu_v2.gemini_evidence_freshness_checker.check_gemini_evidence_fresh`
  - `anu_v2.owner_trigger_decision.validate_decision`
  - `anu_v2.owner_trigger_entry` (run_single / decision 경로)
  - `anu_v2.auto_gemini_triage.AutoGeminiTriage`
  - `anu_v2.executor_scheduler` (`_has_active_trigger_for_head` dedupe)
- runner = **"1회 실행 → terminal enum 1개 반환"**. session-bound sleep/polling 절대 금지.
- gh/git/clock 등 부수효과는 **주입형(runner 인자)** 으로 — 테스트에서 mock 가능하게.
- 모든 GitHub write / 실 `/gemini review` comment 발사 = **mock/dry-run/decision only. 실 write 0.**
- 코드 존재 ≠ 결선: implemented/verified/wired/active 4축 구분 인지.

## 금지 (회장 verbatim)
OS-level crontab/systemd/inotify **설치 금지** · hook 구현 금지 · ANU key 봉인 구현 금지 ·
completion_contract 자동주입 금지 · PR #163 수정 금지 · PR #162 접촉 금지 ·
merge/force/rebase/admin 금지 · 새 PR 생성 금지 · **push 금지** · 실 GitHub write 금지 ·
ANU key literal 노출 금지.

## regression 검증 (필수 — 전부 fixture/mock, 네트워크 0)
- stale Gemini + OWNER proof OK + dedupe OK → `ALLOW_OWNER_TRIGGER` decision
- OWNER proof 없음 → `GEMINI_EXTERNAL_TRIGGER_REQUIRED`
- expected_head ≠ actual_head → `HOLD_STALE_HEAD`
- scope 불량(expected_files 밖 diff) → `HOLD_SCOPE_UNCLEAN`
- CI 실패 non-remediable → `CI_FAILED_NON_REMEDIABLE`
- unresolved 0 + CI PASS + scope clean → `MERGE_READY_CANDIDATE`
- unresolved 반복 / triage loop boundary → `LOOP_BOUNDARY`
- `auto_gemini_triage` 호출 여부 mock 검증 (실제 결선 입증)
- `owner_gemini_trigger` decision 호출 여부 mock 검증
- GitHub write 0 검증 (mock 호출 카운트)
- idempotent: 동일 head 2회 실행 → 중복 trigger 0 (dedupe)

## finalize (로컬 commit 까지만 — push/PR 금지)
1. 새 worktree(task-2718) 또는 origin/main base 에서 작업. PR #163 worktree 와 격리.
2. 전 regression PASS 확인 (`python3 -m pytest tests/regression/test_ci_gemini_watcher_runner_2718.py -q`).
3. expected_files 2개만 변경 확인 (git diff --name-only).
4. **로컬 commit only. push/PR/merge 일체 금지.**
5. 완료 시 `memory/events/task-2718.done` 생성 + `memory/reports/task-2718.md` 보고서
   (terminal enum 7종 fixture 결과 / triage·owner_trigger mock 호출 입증 / GitHub write 0 / commit sha).
6. ANU normal completion callback 은 **ANU key `c119085addb0f8b7`** 로 발사 (executor self-key 금지).
   callback prompt envelope-only, UTF-8 ≤3900 bytes.

## allowed_resources (본 task의 capability)

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

## ANU 후속 (봇 아님)
ANU 가 로컬 commit 을 독립 재검증 → capability delta(auto_gemini_triage/owner_gemini_trigger/
ci_gemini_watcher 구현 전후) + PR 진입 가능 여부만 보고. push/PR 은 별도 회장 승인 전까지 금지.

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