# task-2563 — Checklist

## 구현 (3 hardening 1:1)

### Fix 1 — FIRST_TRIGGER_PENDING 상태 분리
- [x] `STATE_FIRST_TRIGGER_PENDING = "FIRST_TRIGGER_PENDING"` 상수 추가 (`anu_v2/idle_pr_diagnoser.py`)
- [x] `FIRST_TRIGGER_PENDING_WINDOW_SECONDS = 5 * 60` 신규 (default 300s)
- [x] `ALL_STATES` 에 새 상태 포함
- [x] `OWNER_TRIGGER_INVOKING_STATES` 에 새 상태 미포함 (PENDING 은 fast_path=true 시에만 dispatch)
- [x] `GRACE_PERIOD_SECONDS = FIRST_TIMEOUT_SECONDS = 1800` 1:1 정합
- [x] state machine 9-state 분기 update (`IdlePRDiagnoser.diagnose`)
- [x] `__all__` 갱신

### Fix 1 — scheduler 분기
- [x] `ACTION_FIRST_TRIGGER_PENDING_SKIP = "FIRST_TRIGGER_PENDING_SKIP"` (`anu_v2/executor_scheduler.py`)
- [x] `DISPATCH_DECISION_FAST_PATH_KEY = "owner_trigger_fast_path"`
- [x] `_load_fast_path_flag(diag)` helper — decision JSON 에서 fast_path 읽기, 없으면 False (fail-closed)
- [x] `_handle_single_diagnosis` 에서 PENDING 분기: fast_path=true → dispatch / 그 외 → SKIP
- [x] `SchedulerPRAction.__post_init__` 허용 set 에 신규 action 추가
- [x] `__all__` 갱신

### Fix 2 — http_post signature 회귀
- [x] `OwnerTriggerOnly._http_post: Callable[[str, str, dict, dict], dict]` 유지 (변경 0)
- [x] direct call test (`test_8_direct_call_invokes_http_post_with_4_positional_args`)
- [x] scheduler invoke test (`test_9_scheduler_invoke_uses_same_4_arg_signature`)
- [x] wrapper/DI mock test (`test_10_wrapper_di_mock_propagates_same_4_arg_signature`)
- [x] signature mismatch fails test (`test_11_signature_mismatch_breaks_owner_trigger_call`)

### Fix 3 — FUC-3 logger.exception + secret masking
- [x] `import logging` + module-level `logger = logging.getLogger(__name__)` (`anu_v2/owner_trigger_only.py`)
- [x] `_redact_diagnostics(...)` 헬퍼 — dict / list / tuple / str 재귀 마스킹
- [x] `_collect_http_diagnostics(...)` 헬퍼 — status / x-github-request-id / x-accepted-github-permissions / documentation_url 수집
- [x] http_post 예외 경로 `logger.exception(...)` 호출 (BEFORE txn.record(FAILED))
- [x] token 원문 노출 0 (sentinel 검증)
- [x] audit FAILED + token_value_logged=False + token_hash_prefix 보존
- [x] HTTP POST side-effect 0 (mock 1 call 만)

## 테스트

- [x] 신규 `anu_v2/tests/test_owner_trigger_invocation_hardening_2563.py` — 20 testcase PASS
- [x] 기존 `test_owner_trigger_only_2554.py` — 10 PASS (변경 0)
- [x] 기존 `test_executor_first_gemini_trigger_missing.py` — 9 PASS (semantic 변경 반영)
- [x] 기존 `test_executor_scheduler_per_pr_isolation.py` — 9 PASS (변경 0)
- [x] 전체 anu_v2/tests/ suite — 480 passed, 1 skipped

## 정적 검사

- [x] `python3 -m py_compile anu_v2/owner_trigger_only.py anu_v2/idle_pr_diagnoser.py anu_v2/executor_scheduler.py` PASS
- [x] module source 에 raw token 패턴 0 (`ghp_` literal 0)

## fixture (3건)

- [x] `anu_v2/fixtures/first_trigger_pending_window.json` (Fix 1)
- [x] `anu_v2/fixtures/owner_trigger_signature_mismatch_repro.json` (Fix 2)
- [x] `anu_v2/fixtures/owner_trigger_failure_path_logger_exception.json` (Fix 3)

## 봇 직접 행동 8 (cron 발사 후)

- [ ] cokacdir 시작
- [x] worktree (`/home/jay/workspace/.worktrees/task-2563-dev6`)
- [ ] PR 생성 (BOT_GITHUB_TOKEN)
- [ ] CI 11 checks SUCCESS
- [ ] Gemini fresh + unresolved 0 (capability N번째 활용 가능)
- [ ] BOT squash merge (admin override 0)
- [ ] smoke + reconcile evidence
- [ ] lifecycle markers + 보고서

## 금지 9건 어셀션

- [x] task-2562 G4 영역 재수정 0
- [x] task-2558 auto_gemini_triage 재수정 0
- [x] scripts/finish-task.sh 수정 0
- [x] task-2560/2561 영역 섞기 0
- [x] 회장 수동 `/gemini review` 0 (코드만)
- [x] BOT `/gemini review` 0 (코드만)
- [x] token 원문 출력 0 (logger.exception 에서도 strict assertion)
- [x] long polling 0 (single-shot run_one_cycle)
- [ ] force push / rebase / admin override 0 (PR 단계 어셀션)

## 완료 조건 11건 (회장 §명시)

- [x] FIRST_TRIGGER_PENDING / FIRST_GEMINI_TRIGGER_MISSING 상태 구분 테스트 PASS (test 1~5)
- [x] owner_trigger_fast_path=false 일 때 조기 trigger 차단 (test 6)
- [x] owner_trigger_fast_path=true 일 때 조기 trigger 허용 (test 7)
- [x] http_post signature mismatch 회귀 테스트 PASS (test 8~11)
- [x] logger.exception 보강 후 secret masking 테스트 PASS (test 12~14, 16, 20)
- [x] fail-closed 속성 유지 (test 15)
- [x] expected_files strict (dispatch_decision.json authoritative, 12 files)
- [x] forbidden path 0
- [ ] CI/Gemini/CLEAN (PR 단계)
- [ ] BOT squash merge (PR 단계)
- [ ] post-merge smoke + reconcile evidence (PR 단계)
