# task-2729 Phase 1 round-1 — AUTO_REPAIR: record-only gate 방어적 hardening (PR #173 fresh HIGH 2건)

## 회장 인가 (2026-06-03, AUTO_REPAIR_CONTINUE 재분류 — STOP 아님)
PR #173(head `751d8393`, task-2729 Phase 1) fresh OWNER /gemini **fresh unresolved HIGH 2건 유효**(둘 다 outdated=False, 코드 직접대조 PASS, FALSE_POSITIVE 아님). 회장: **STOP 아니라 AUTO_REPAIR_CONTINUE.** task-2729 범위 내 자동 수정 → Gemini 재검증 → 수렴까지 계속. **동일 계열 반복 임계치 초과 전까지 회장 승인 대기 금지.**

## fresh HIGH 2건 (코드 직접대조 확인)
1. **HIGH-1** `dispatch/__init__.py:~4017-4018`: `annotate_dispatch_result` 호출부가 try-except 미보호 → 게이트(record-only, ACTIVE=false)에서 예외 발생 시 dispatch() 전체 흐름 중단 위험. **기존 behavior 무손상 원칙 정면 위배**(Phase 1은 record-only 여야 함).
2. **HIGH-2** `dispatch/progress_watcher_gate.py:~110`: `result[PROGRESS_WATCHER_REGISTERED_KEY] = bool(...)` 직전 type guard 부재 → `result` 가 dict 아니거나 None 일 때 TypeError → dispatch 중단.

## worktree
- `/home/jay/workspace/.worktrees/task-2729-dev6` (branch `task/task-2729-dev6`, head `751d8393`)에서 **이어서**. new head → **non-force push**(PR #173 갱신, amend 금지).

## 허용 파일 (expected_files 2개 — Phase 1 expected_files 부분집합. 그 외 수정 금지)
1. `dispatch/__init__.py` ← 게이트 호출부 try-except 방어
2. `dispatch/progress_watcher_gate.py` ← `annotate_dispatch_result` 시작부 `isinstance(result, dict)` guard
- 회귀 보강 필요 시 `tests/regression/test_progress_watcher_gate_2729.py` 1파일 추가 허용(Phase 1 expected_files 내부). 총 ≤3파일.

## 수정 방향 (gemini 제안 + 무손상 원칙)
1. **HIGH-1**: 게이트 호출부를 try-except 로 감싸 예외 시 `logger.warning` 만 남기고 원래 `_result` 정상 반환. import 도 try 내부로(모듈 부재여도 dispatch 무중단).
2. **HIGH-2**: `annotate_dispatch_result` 함수 시작부에 `if not isinstance(result, dict): return result` (또는 동등 방어). 기존 record 로직은 dict 일 때만.
3. **ACTIVE=false 유지** — record-only. `result["status"]` 변경 금지(active=False 경로 불변).
4. 기존 회귀 무손상. ANU key literal 0.

## 필수 회귀
1. 게이트 호출부 예외 주입 → dispatch() 무중단 + `_result` 정상 반환(신규 회귀).
2. `annotate_dispatch_result(None,...)` / non-dict → 원본 그대로 반환, 예외 없음(신규 회귀).
3. 기존 progress_watcher_gate 회귀 전체 유지 또는 증가.
4. `git diff --name-only $(git merge-base origin/main HEAD)..HEAD` = expected_files 내(≤3파일).
5. forbidden 0. ANU key literal(`c119085addb0f8b7`) 0.
- smoke: `python3 -m pytest tests/regression/test_progress_watcher_gate_2729.py -q` + `python3 -m py_compile dispatch/__init__.py dispatch/progress_watcher_gate.py`.

## 금지 (회장 verbatim)
- expected_files 밖 수정 금지 · merge 금지 · ACTIVE=true 금지 · admin override·force push·rebase 금지 · finish-task.sh/critical_gap.py/terminal_callback.py/systemd/.github/deploy 수정 금지 · task-2727/2725 혼입 금지.
- ★ 또 같은 "방어적 hardening/exception-guard" 계열 fresh HIGH 가 round-2 후에도 재발(동일 계열 3회차) → **LOOP_BOUNDARY 보고**(replacement 검토). 새 결함 계열 → CHAIR_REQUIRED. 그 전까지 회장 대기 금지·자동 수렴.

## doctrine
- repair = 새 commit→new head→non-force push(PR #173 갱신). bot `/gemini review` 무효(ANU owner_gemini_trigger request-only 1회). long polling 금지(watcher 위임 — review-settle quiet-window).

## finalize (PR #173 갱신 → 자동 재검증 → 수렴)
1. fix → 회귀 PASS → `git add` → commit → **non-force push**.
2. `memory/reports/task-2729.md` 갱신(round-1 + L1). 3. `memory/events/task-2729-p1-r1.done` 생성.
4. ANU normal callback cron 강제 등록 — collector_role=ANU, ANU_KEY=c119085addb0f8b7(sealed, literal 노출 금지). self-key 금지.
5. ★ merge 금지 — ANU 가 새 head owner_gemini_trigger 자동 발사 → review-settle watcher → fresh HIGH/CRITICAL 0 + CI PASS + diff expected_files 내 + forbidden 0 + ANU key 0 + ACTIVE=false 시 수렴 → Phase 1 PASS → Phase 2 자동 연속(회장 재확인 없이).

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "dispatch/__init__.py"
    - "dispatch/progress_watcher_gate.py"
    - "tests/regression/test_progress_watcher_gate_2729.py"
    - "memory/reports/task-2729.md"
    - "memory/events/task-2729-p1-r1.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(); sys.exit(0 if 'isinstance(result, dict)' in s else 1)"`
- `python3 -c "import sys; s=open('dispatch/__init__.py').read(); i=s.find('annotate_dispatch_result'); seg=s[max(0,i-300):i]; sys.exit(0 if 'try:' in seg else 1)"`
- `python3 -c "import sys; bad=[f for f in ['dispatch/__init__.py','dispatch/progress_watcher_gate.py'] if 'c119085addb0f8b7' in open(f).read()]; sys.exit(1 if bad else 0)"`

## 상태
CHAIR_APPROVED_AUTO_REPAIR_ROUND1 (PR #173 fresh HIGH 2건) — dev6 재위임(head 751d8393 이어서). merge 회장 승인 전 금지. 동일 계열 3회차 재발 → LOOP_BOUNDARY. 그 전까지 자동 수렴.
