# task-2641 — OWNER_GEMINI_TRIGGER_ROUTER (회장 verbatim 12 필수 + 병렬 3 Track + 10 보고)

- Level: Lv.4 (OWNER nudge 자동화 라우터 · UI fallback 최후수단 · 회장 verbatim 12항목 정합)
- 담당: dev6 페룬
- base: origin/main **033dcf8a** (PR #143 task-2640 SELF_COLLECTOR enforcement wiring merge 반영)
- 단일소스 spec: `memory/specs/system_owner_gemini_trigger_router_spec_260523.md`
  - sha256: `4551e899bcda602ae24c3985f556016e80c4464b72e54e92363a01a333fe2596`
  - 정독 전 sha256sum 검증 필수
- 단일소스 event log: `memory/events/owner_gemini_trigger_ui_fallback_misroute_260523.json` (사고 박제)
- 회장 결정 (2026-05-23 PR #143 merge 직후, 18:11 KST): OWNER_GEMINI_TRIGGER_UI_FALLBACK_MISROUTE 재발 방지 + 회장 UI 1차 경로 안내 금지

## 목표
Gemini fresh evidence 필요 시 (gemini-review-gate / phase3-merge-gate FAILURE = stale SHA mismatch), 회장 UI 입력 요구하기 전에 **ANU 가 OWNER 권한으로 PR-backed issue comment body="/gemini review" 자동 발사** 라우팅.

## 회장 verbatim 12 필수 구현 (★ 반드시 반영 · 1:1 박제)
1. PR Review comment와 PR Conversation issue comment를 명확히 구분
2. PR Review comment는 Gemini trigger로 인정하지 않음
3. PR-backed issue comment body="/gemini review"만 trigger로 인정
4. ANU OWNER issue comment 발사를 **1차 nudge 경로**로 사용
5. OWNER_GEMINI_TRIGGER_TOKEN 또는 기존 owner_trigger_only capability 사용
6. raw token 출력 금지 (token_hash_prefix 12char hex 만)
7. gh api 또는 gh pr comment 중 **안전한 경로** 사용 (subprocess 직접 호출 금지)
8. 403 발생 시 `X-Accepted-GitHub-Permissions` 또는 accepted permissions header 기록
9. nudge 횟수 제한 (1회 hard limit per PR/head)
10. fresh review 미도착 시 `GEMINI_EXTERNAL_TRIGGER_STALE` 분류
11. 회장 직접 UI 입력 요청은 OWNER nudge 경로 실패 후 **최후 수단** 으로만 허용 (CHAIR_UI_FALLBACK_REQUIRED)
12. OWNER_GEMINI_TRIGGER_UI_FALLBACK_MISROUTE 재발 방지 fixture 작성 (task-2640 사고 박제: 회장 review id=4350214991 empty body 오인식 패턴)

## 자동수렴 (회장 verbatim)
- expected_files 내부 Gemini medium/style/quality/non-critical HIGH → 자동수렴
- Critical7 / credential/permission expansion / expected_files 밖 / admin override / post-merge smoke failure → 회장 보고

## 금지 (회장 verbatim 10 항목)
- 회장 UI 입력을 1차 경로로 안내 금지
- PR Review comment를 nudge 성공으로 오인 금지
- 무한 nudge 금지
- raw token 출력 금지
- real auto-merge activation 금지
- PR #141 pilot 재시도와 혼합 금지
- foreign dirty 정리 금지
- finish-task.sh 수정 금지
- cokacdir 본체 수정 금지
- replacement_pr_runner 수정 금지

## 병렬 허용 (회장 verbatim)
- Track A: 본 task-2641 OWNER_GEMINI_TRIGGER_ROUTER 구현 (dev6 페룬)
- Track B: PR #141 B1 pilot 재시도 준비안 read-only 업데이트 (ANU 직접 · 분석 spec만)
- Track C: CI_WATCHER_SESSION_LIFETIME_GAP backlog 정리만 (ANU 직접 · 코드 구현 0)
- ★ Track B pilot 실행 + chair_authorization 발급 = **task-2641 merge 후 별도 회장 승인까지 금지**

## 신규 helper 3 (anu_v2/ 상위 layer)
- `anu_v2/owner_gemini_trigger_router.py` (router state machine)
- `anu_v2/gemini_evidence_freshness_checker.py` (PR HEAD SHA vs Gemini review commit_id)
- `anu_v2/owner_gemini_trigger_router_audit.py` (jsonl audit · raw token redaction)

## 기존 stack 무수정 (회장 verbatim)
- `anu_v2/owner_trigger_only.py` (단일 capability 모듈 · 재사용만)
- `anu_v2/owner_trigger_decision.py` (decision JSON v1 · 재사용)
- `anu_v2/owner_trigger_audit.py` (dedupe + redaction · 재사용)
- `anu_v2/owner_trigger_pat.py` (token 관리 · 재사용)
- 본 task = 상위 layer router 신규만. 기존 4종 unfork 0.

## 신규 fixture 6 시나리오 × 3 = 18 files
`tests/fixtures/owner_gemini_trigger_router/<scenario>/{evidence,expected,PROVENANCE}`:
- `pr_review_empty_body_misroute_block` → NOT_GEMINI_TRIGGER (task-2640 사고 박제 · 회장 review id=4350214991)
- `issue_comment_exact_body_trigger_success` → POSTED + fresh review 도착 시뮬
- `permission_403_diagnostics_record` → 403 + X-Accepted-GitHub-Permissions 기록 + CHAIR_UI_FALLBACK_REQUIRED
- `nudge_limit_exceeded_dedupe` → 2회째 DEDUPED + 실 POST 0
- `fresh_review_arrives_within_timeout` → state=FRESH 통과
- `stale_after_nudge_timeout_classify` → GEMINI_EXTERNAL_TRIGGER_STALE

## 신규 regression 4
- `tests/regression/test_owner_gemini_trigger_router.py` (router state machine + return enum)
- `tests/regression/test_gemini_evidence_freshness_checker.py` (PR HEAD vs Gemini commit_id 정합)
- `tests/regression/test_owner_gemini_trigger_router_audit.py` (audit JSONL + redaction)
- `tests/regression/test_owner_gemini_trigger_router_fixture_parametrized.py` (6 fixture parametrized)

## 안전 불변식
- ANU key `c119085addb0f8b7` 단일 출처 유지 (변경 0)
- OWNER_GEMINI_TRIGGER_TOKEN 단일 출처 (BOT_GITHUB_TOKEN 사용 0)
- envelope UTF-8 ≤3900 bytes 유지
- live cokacdir / gh CLI 실호출 0 (regression mock)
- merge/push/PR/admin override 호출 0
- real auto-merge activation 0
- PR #141 pilot 실행 0
- foreign dirty 정리 0
- production service task 혼합 0
- ANU 직접 코드 구현 0 (dev bot 위임)
- expected_files 외부 수정 0
- BLOCKING_SECRET 0
- forbidden 15종 무수정 (task-2640 merge 후 stack 그대로)
- 기존 owner_trigger 4종 무수정

## 필수 regression
- 신규 4 regression PASS
- 기존 baseline (task-2640 merge 후 origin/main 033dcf8a 기준 1440+) 유지
- full new fail 0 (3 pre-existing test_stash_origin_audit_compat 무관)

## 회장 verbatim 완료 보고 10 항목
1. task id / 담당 bot
2. 구현 파일 목록
3. OWNER issue comment 발사 경로
4. PR Review vs issue comment 구분 로직
5. 403 permission header 기록 방식
6. nudge 횟수 제한 정책
7. GEMINI_EXTERNAL_TRIGGER_STALE 분류 조건
8. regression 결과
9. PR open / CI / Gemini / phase3 상태
10. B1 pilot 재시도 가능 여부

## expected_files (task-2641 범위)
신규:
- `anu_v2/owner_gemini_trigger_router.py`
- `anu_v2/gemini_evidence_freshness_checker.py`
- `anu_v2/owner_gemini_trigger_router_audit.py`
- `tests/fixtures/owner_gemini_trigger_router/<6 시나리오>/{evidence,expected,PROVENANCE}` (18 files)
- (선택) `tests/fixtures/owner_gemini_trigger_router/INDEX.md`
- `tests/regression/test_owner_gemini_trigger_router.py`
- `tests/regression/test_gemini_evidence_freshness_checker.py`
- `tests/regression/test_owner_gemini_trigger_router_audit.py`
- `tests/regression/test_owner_gemini_trigger_router_fixture_parametrized.py`

총 ~28 files. **프로덕션 영향**: anu_v2/ 상위 layer 신규 helper 3 + fixture 18 + regression 4 + (선택) INDEX 1. 기존 4 owner_trigger 모듈 무수정.

## finalize 프로토콜 (★ BOT App token 부재 — 로컬 한정)
1. base = origin/main 033dcf8a clean
2. 신규 helper 3 + fixture 18 + regression 4 PASS · 기존 1440+ 유지 · full new fail 0
3. **로컬 commit만** (push/PR/merge 금지)
4. ANU normal callback (★ 본 task 자체가 OWNER trigger router 이므로 자기검증 강제):
   - 신규 `validate_spawn_callback_contract` 호출로 self-check (task-2640 결선 활용)
   - envelope 5축 + canonical_root 명시
   - REGISTERED + schedule_id non-null + DELIVERED + UNCONFIRMED
5. envelope UTF-8 ≤3900 bytes
6. executor 시작/종료 ts + 로컬 commit SHA 명기

## frozen anchor
- ANCHOR-1: "본 task = OWNER_GEMINI_TRIGGER_UI_FALLBACK_MISROUTE 재발 방지 router 신설 · 회장 UI 1차 경로 안내 금지"
- ANCHOR-2: "회장 verbatim 12 필수 구현 1:1 박제 (PR Review vs issue comment 구분 + body 정확 일치 + OWNER nudge 1차 + token 단일 출처 + redaction + endpoint 단일 + 403 header 기록 + nudge 1회 hard limit + STALE 분류 + UI fallback 최후수단 + 재발 방지 fixture)"
- ANCHOR-3: "기존 owner_trigger_only capability stack (PR #98 merge 후 유지) 재사용 · 신규 4종 무수정 (owner_trigger_only/decision/audit/pat)"
- ANCHOR-4: "Gemini evidence freshness = PR current HEAD SHA == Gemini review commit_id · STALE 자동 감지 → 1차 OWNER nudge → fail 시 CHAIR_UI_FALLBACK_REQUIRED"
- ANCHOR-5: "nudge 1회 hard limit per PR/head · dedupe atomic (audit JSONL + fcntl flock) · validate_decision nudge_count_for_pr_head=0 정합"
- ANCHOR-6: "403 발생 시 X-Accepted-GitHub-Permissions / X-Accepted-OAuth-Scopes / X-OAuth-Scopes / X-RateLimit-Remaining 기록 · raw token redact"
- ANCHOR-7: "병렬 Track B (PR #141 B1 pilot 재시도 준비안 read-only) + Track C (CI_WATCHER backlog 정리) 허용 · Track B pilot 실행 / chair_authorization 발급 task-2641 merge 후 별도 승인까지 금지"
- ANCHOR-8: "real auto-merge activation 0 · ACTIVATION_FLAG_DEFAULT=False · admin override 0 · PR #141 pilot 재시도 혼합 0 · finish-task.sh / cokacdir / replacement_pr_runner 무수정"

## callback envelope byte-limit 정책 (★ task-2612+3 박제 강제)
- callback prompt UTF-8 ≤3900 bytes hard limit · 3500+ warning
- envelope 만 포함 (긴 보고 금지) · 상세는 result.json/report.md 위임
- 측정: `printf '%s' "$P" | wc -c` (wc -c · NOT wc -m)
- result.json 에 callback prompt UTF-8 byte 수 기록 강제
