# task-2729+1 P0-A — CI_WATCHER lifecycle state machine / terminal callback contract 보강
## 회장 인가 (2026-06-05) — task-2729+1 P0 (audit-first 후 P0 착수)
CI_WATCHER_SESSION_LIFETIME_GAP(P0) 2 Phase 중 **P0-A**. fresh origin/main(d925b873) base. **P0-A PASS 시 회장 재확인 없이 P0-B 자동 연속.** "code exists ≠ automation works" — IMPLEMENTED/VERIFIED/WIRED/ACTIVE 분리. **production ACTIVE 전환 금지(별도 승인).**

## 배경 (audit 근거)
task-2729(PR#173)에서 terminal callback contract·WATCHER_TERMINAL_CALLBACK_NOT_WIRED·quiet-window·5 terminal_states·classifier(utils/pr_watcher_terminal_state_classifier.py 399L)는 IMPLEMENTED+VERIFIED. WIRED=partial_record_only. **P0-A = 그 위에 death-pending 분류 contract 보강(코드/결선 수준), OS 결선은 P0-B.**

## P0-A 목표 (lifecycle state machine / terminal callback contract)
1. **CI_WATCHER_SESSION_LIFETIME_GAP** 진단 분류 추가: watcher 가 사라졌는데(heartbeat/last_poll stale) PR 이 여전히 pending(non-terminal)이면 이 상태로 분류하는 **순수 판정 함수**(OS 감지/재기동은 P0-B, 여기선 classification contract 만).
2. **watcher terminal callback 필수화** 계약 강화: terminal state 도달 시 normal callback 발사가 MANDATORY. 미발사 시 `WATCHER_TERMINAL_CALLBACK_NOT_WIRED`(기존) 유지·강화.
3. **review-settle quiet-window 유지**(기존 is_quiet_window_settled 보존, 회귀 무손상).
4. **fallback = dead-man safety-net only**(final-report trigger 아님 — dual-purpose 금지 doctrine).
5. WatcherState 에 heartbeat/last_poll_ts(또는 동등) 필드 + staleness 판정만 추가(가벼운 lifecycle 보강).
6. ACTIVE=false 유지. record-only. live OS 기동/auto-register 0 (P0-B).

## expected_files (lock, ≤4 — 최소화)
1. `utils/pr_watcher_terminal_state_classifier.py` — CI_WATCHER_SESSION_LIFETIME_GAP 분류 상태/함수 추가(diagnostic, non-terminal-merge 계열). 기존 5 terminal_states·chair-auth 주석 보존.
2. `scripts/ci_watch_handoff_runner.py` — WatcherState heartbeat/last_poll 필드 + is_watcher_stale() 판정 + fire_terminal_callback 필수화 계약 강화 + classify_lifetime_gap 호출부(record-only). 기존 run_once/quiet-window/fallback 보존. **광범위 수정 금지.**
3. `tests/regression/test_ci_watcher_lifecycle_2729p0a.py` (신규) — 회귀: (a) watcher stale+PR pending → CI_WATCHER_SESSION_LIFETIME_GAP (b) terminal 도달 → callback 필수, 미발사 시 NOT_WIRED (c) quiet-window settled 판정 (d) fallback dead-man-only(final-report trigger 아님) (e) 기존 6-state/terminal 회귀 무손상.
4. `memory/state/automation_capability_matrix.json` — progress_watcher capability delta: IMPLEMENTED/VERIFIED/WIRED/ACTIVE 분리 기록. WIRED 갱신(예: `lifecycle_gap_classified_candidate`), ACTIVE=false 유지, P0-A evidence 추가.
- ★ 5파일 초과·forbidden 필요·OS 기동/systemd/.github 수정 필요 시 CHAIR_REQUIRED(그건 P0-B 또는 별도).

## P0-A 완료 조건
1. 신규+기존 regression PASS(P0-A fixture + task-2729 progress_watcher/callback/fallback 회귀 무손상).
2. py_compile PASS.
3. effective diff = expected_files(≤4) 내. ACTIVE=false. forbidden 0. ANU key raw 0.
4. CI_WATCHER_SESSION_LIFETIME_GAP·WATCHER_TERMINAL_CALLBACK_NOT_WIRED 둘 다 fixture 로 실증.

## 금지 (회장 8 — verbatim)
production ACTIVE=true 전환 · credential/ANU key raw 노출 · admin override · force push · rebase · 회장 승인 없는 merge · unrelated cleanup · P0 범위 밖 결함(NORMAL_CALLBACK 구현/live_prune 구현) 혼입. **P1/P2 구현 금지(P1 설계·fixture 후보는 별도 노트만, 본 PR 미포함).** expected_files 밖 → CHAIR_REQUIRED.

## doctrine (필수 준수)
- same-PR Gemini 도착 후 push/commit/amend 금지(위반 시 Option A replacement).
- bot 의 /gemini review 트리거 무효(인간 1회만). long-polling 금지. chain attempt hard-limit.
- finish-task finalize 14단계 + 봇 직접행동 8항목 명시 수행. "wrapper 가 처리" 표현 금지.
- PR open 시 CI_WATCH_HANDOFF 생성(ANU 가 watcher 위임). normal callback = ANU key c119085addb0f8b7 로 발사(executor self-collector 금지).

## PR 생성 전 재확인 → ANU
CI 11/11 · fresh OWNER Gemini HIGH/CRITICAL 0 · diff expected_files(≤4) 내 · forbidden 0 · ANU key 0 · ACTIVE=false. 통과 시 PR → owner_gemini → review-settle → MERGE_APPROVAL_CANDIDATE. merge 회장 승인 전 금지.

## 산출물
1. PR(fresh origin/main base, ≤4 files). 2. `memory/reports/task-2729+1-p0a.md`(capability delta: IMPLEMENTED/VERIFIED/WIRED/ACTIVE 분리). 3. `memory/events/task-2729+1-p0a.done`.
4. P0-A PASS → 회장 재확인 없이 P0-B 자동 연속.

## allowed_resources (본 task의 capability)

```yaml
allowed_resources:
  paths:
    - "utils/pr_watcher_terminal_state_classifier.py"
    - "scripts/ci_watch_handoff_runner.py"
    - "tests/regression/test_ci_watcher_lifecycle_2729p0a.py"
    - "memory/state/automation_capability_matrix.json"
    - "memory/reports/task-2729+1-p0a.md"
    - "memory/events/task-2729+1-p0a.*"
  forbidden_paths:
    - "bot_settings.json"
    - ".env.keys"
    - ".github/**"
    - "scripts/finish-task.sh"
    - "utils/replacement_pr_runner.py"
    - "memory/events/*.cron-*"
  commands:
    - "pytest"
    - "python3 -m py_compile"
  merge_policy: "none"
  ttl_hours: 48
```
