# task-2729 Phase 1 — progress watcher dispatch gate (자동화 hardening, 회장 인가)

## 회장 인가 (2026-06-03, task-2729 실행 — 실행 가능 자동화 구현, 문서 정리 아님)
PR #171/#172 수렴에서 확인된 자동화 결함을 코드/러너/가드/회귀로 보강. **"code exists"를 "automation works"로 과장 금지 — IMPLEMENTED/VERIFIED/WIRED/ACTIVE 분리.** production ACTIVE 전환은 별도 회장 승인.

## ANU audit-first 결과 (read-only 확정)
- `dispatch/__init__.py`: `dispatch()` (line 3407), `cron_response` 반환부 다수, `spawn_callback_contract_validator` import(line 218) 존재 = 봇 spawn 직전 contract 검증 지점. **progress_watcher 등록 검증 결선 0**.
- CI_WATCH_HANDOFF 전용 watcher 러너 **부재**(scripts/activity-watcher.py·done-watcher.py·utils/pr_watcher_terminal_state_classifier.py 만 존재). → 신규 러너 필요.
- 결함 대상(Phase 1): DISPATCH_WITHOUT_PROGRESS_WATCHER · WATCHER_TERMINAL_CALLBACK_NOT_WIRED · REVIEW_SETTLE_MISSING(러너에 quiet-window 골격).

## 목표 (회장 6 — Phase 1)
1. **모든 dev dispatch 직후 `progress_watcher_registered=true` 필수화** (dispatch gate).
2. **watcher 없이 fallback 만 있으면 `DISPATCH_INCOMPLETE`**.
3. watcher 가 최소 **head change · non-force push · CI · finish-task .done · normal callback · fallback prune** 상태 추적.
4. watcher terminal 시 **ANU normal callback 반드시 등록·발사**(collector_role=ANU, ANU_KEY sealed).
5. watcher terminal callback 누락 시 **WATCHER_TERMINAL_CALLBACK_NOT_WIRED** 기록.
6. **fallback 은 dead-man safety-net 일 뿐 progress trigger 로 쓰지 않기**(분리).

## expected_files (audit 후 확정 — lock, ≤5)
1. `dispatch/progress_watcher_gate.py` (신규) — dispatch 후 watcher 등록 검증, DISPATCH_INCOMPLETE 판정, progress_watcher_registered 필드.
2. `dispatch/__init__.py` (최소 결선 — dispatch() 반환부에 progress_watcher_gate 호출 1~3줄. 광범위 수정 금지).
3. `scripts/ci_watch_handoff_runner.py` (신규) — watcher 러너: 6상태 추적 + review-settle quiet-window 골격 + terminal 시 ANU normal callback 발사. utils/pr_watcher_terminal_state_classifier.py 재사용.
4. `tests/regression/test_progress_watcher_gate_2729.py` (신규) — 회귀.
5. `memory/state/automation_capability_matrix.json` (progress_watcher capability 4축).
- ★ 5파일 초과·forbidden 필요 시 CHAIR_REQUIRED.

## Phase 1 완료 조건 (회장 7)
1. progress_watcher_registered gate regression PASS.
2. fallback-only dispatch → DISPATCH_INCOMPLETE regression PASS.
3. watcher terminal callback required regression PASS.
4. WATCHER_TERMINAL_CALLBACK_NOT_WIRED regression PASS.
5. 기존 callback/fallback behavior 무손상(dispatch/normal_fallback_callback_helper·spawn_callback_contract_validator 회귀 유지).
6. capability matrix 에 `progress_watcher` IMPLEMENTED/VERIFIED/WIRED/ACTIVE 분리 기록.
7. **ACTIVE=false 유지**.

## 금지 (회장 verbatim 11)
admin override · force push · rebase · production ACTIVE=true 전환 · credential/ANU key raw 노출 · unrelated cleanup · finish-task.sh 수정 · critical_gap.py 수정 · terminal_callback.py 수정 · systemd/.github/deploy 수정 · 회장 승인 없는 merge.
- expected_files 5파일 밖 수정 시 CHAIR_REQUIRED. Gemini/Codex non-Critical = validity/scope/repetition 자동 triage + 같은 Phase expected_files 내 bounded fix.

## doctrine
- 새 commit→new head→non-force push로 PR 생성. bot `/gemini review` 무효(ANU owner_gemini_trigger request-only). long polling 금지(watcher 위임). ★ ANU 가 dispatch 직후 이 progress_watcher gate 를 dogfood(자신도 watcher 등록).

## finalize (PR 생성 → MERGE_APPROVAL_CANDIDATE — merge 금지)
1. fix → 7 완료조건 PASS → commit → non-force push → PR 생성(fresh origin/main 9ba3cfbb).
2. `memory/reports/task-2729.md`(Phase 1 + L1). 3. `memory/events/task-2729-p1.done`.
4. ANU normal callback cron 강제 등록(collector_role=ANU, ANU_KEY=c119085addb0f8b7 sealed, self-key 금지) + **progress_watcher 등록(dogfood)**.
5. ★ merge 금지 — 새 head owner_gemini_trigger 자동 발사 → review-settle watcher → CI 11/11 + fresh HIGH/CRITICAL 0 + diff 5파일 내 + forbidden 0 + ANU key 0 + ACTIVE=false 시 MERGE_APPROVAL_CANDIDATE 보고. ★ Phase 1 PASS 시 회장 재확인 없이 Phase 2 진행.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "dispatch/progress_watcher_gate.py"
    - "dispatch/__init__.py"
    - "scripts/ci_watch_handoff_runner.py"
    - "tests/regression/test_progress_watcher_gate_2729.py"
    - "memory/state/automation_capability_matrix.json"
    - "memory/reports/task-2729.md"
    - "memory/events/task-2729-p1.done"
  forbidden_paths:
    - "scripts/finish-task.sh"
    - "teams/shared/verifiers/critical_gap.py"
    - "scripts/harness/v36/terminal_state_callback.py"
    - "deploy/systemd/**"
    - ".github/**"
  commands: ["pytest","python3 -m pytest","python3 -m py_compile","bash -n"]
  merge_policy: "none"
  ttl_hours: 48
```

## goal_assertions (auto)
- `python3 -m pytest tests/regression/test_progress_watcher_gate_2729.py -q`
- `python3 -c "import sys; s=open('dispatch/progress_watcher_gate.py').read(); req=['DISPATCH_INCOMPLETE','progress_watcher_registered','WATCHER_TERMINAL_CALLBACK_NOT_WIRED']; sys.exit(0 if all(r in s for r in req) else 1)"`
- `python3 -c "import sys; import glob; bad=[f for f in ['dispatch/progress_watcher_gate.py','scripts/ci_watch_handoff_runner.py'] if 'c119085addb0f8b7' in open(f).read()]; sys.exit(1 if bad else 0)"`
- `python3 -c "import json; d=json.load(open('memory/state/automation_capability_matrix.json'))['capabilities']['progress_watcher']; sys.exit(0 if d['ACTIVE'] is False else 1)" `

## 상태
CHAIR_APPROVED_TASK2729_PHASE1 — dev 위임. Phase 1 PASS → 회장 재확인 없이 Phase 2. production ACTIVE 전환 별도 승인. expected_files/forbidden/ACTIVE=false/no admin·force·rebase lock.
