# task-2699 — OWNER_GEMINI_TRIGGER_CAPABILITY_WIRING (production http_post + entry point 실 wiring · 회장 verbatim 2026-05-27)

- Level: Lv.3 (보안 · OWNER PAT/token capability · OWNER_TRIGGER_ONLY_CAPABILITY doctrine 엄격)
- 담당: **dev1-team Hermes 헤르메스** (★ 회장 verbatim 2026-05-27 지정 · bot key c38fb9955616e24d · dev7 제외 · self-key/quarantine 봇 제외)
- chair_authorization_id: **`CHAIR-AUTH-TASK-2699-OWNER-GEMINI-TRIGGER-CAPABILITY-WIRING-20260527-JJONGS-IMPLEMENT-001`** (★ 회장 verbatim 2026-05-27 발급 확정)
- 완료 목표: **`OWNER_GEMINI_TRIGGER_CAPABILITY_WIRING_COMPLETE`**

## ★ 배경 (task-2698+1 capability gap 실증)

PR #157 GEMINI_HEAD_DRIFT unblock 시도 중 발견: `owner_trigger_only` 코어(검증/dedupe/redaction/decision schema v1 8조건)는 origin/main 반영됐으나 —
- **실제 production http_post 구현체 0건** (test mock 만 존재)
- **scheduler/daemon/runner entry point 부재** (executor_scheduler.py L4-5 주석 자인: "idle PR 자동감지 runner 호출 daemon/scheduler entry point 부재")
- **owner_gemini_trigger_router.py origin/main 미tracked** (pyc 잔존 · .py 는 .worktrees/* 에만)

→ ANU 단발 트리거 시 http_post 신규 작성 필요 = ad-hoc = 금지. 정식 자동 trigger 경로 불완전.
박제: `memory/events/task-2698-pr157-owner-trigger-capability-incomplete-260527.json`

## ★ 목표 (★ 회장 verbatim 10)

1. **production GitHub comment http_post 구현체 추가** (실제 POST `/repos/{owner}/{repo}/issues/{pr}/comments`)
2. **OWNER_GEMINI_TRIGGER_TOKEN 안전 주입** (token_provider · BOT_GITHUB_TOKEN fallback 0)
3. **redaction 검증** (`_redact_diagnostics` 재사용 · token/PII 마스킹)
4. **endpoint 제한** (FORBIDDEN_ENDPOINT_PATTERNS — merge/push/PR/admin 차단)
5. **dedupe 검증** (audit JSONL + fcntl flock · (pr, head) 1회)
6. **decision.json 8조건 검증** (`owner_trigger_decision.validate_decision` v1)
7. **scheduler/daemon/runner entry point 연결** (OwnerTriggerOnly 생성 + http_post 주입 + 구동 진입점 — 단발 CLI + scheduler 자동 둘 다)
8. **owner_gemini_trigger_router main 반영 여부 정리** (.worktrees/* 의 router.py 가 정본인지 / main 반영 누락인지 규명 후 단일화)
9. **"/gemini review" body 단일 허용** (COMMENT_BODY 상수 · 외부 입력 변조 차단)
10. **token/stdout/stderr/log/marker 누출 0** + **regression + dry-run + mock HTTP test 포함**

## ★ 기존 자산 (보존·재사용 — 신규 재작성 금지)

- `anu_v2/owner_trigger_only.py` (코어 — OwnerTriggerOnly/invoke_from_scheduler/COMMENT_BODY/TOKEN_ENV_NAME/FORBIDDEN_ENDPOINT_PATTERNS/redaction) — **보존, http_post 주입 구조 유지**
- `anu_v2/owner_trigger_decision.py` (decision v1 8조건 validator) — 재사용
- `anu_v2/owner_trigger_audit.py` (dedupe JSONL + flock) — 재사용
- `anu_v2/executor_scheduler.py` (ExecutorScheduler — owner_trigger 주입받음) — entry point 연결 대상
- `anu_v2/merge_queue_executor.py` (orchestrate_owner_trigger_for_stale_pr) — 연결 대상
- spec: `memory/specs/system_owner_trigger_only_capability_spec_260511.md` + `memory/specs/system_owner_gemini_trigger_router_spec_260523.md` (★ 1:1 준수)

## ★ 핵심 설계 원칙 (★ OWNER_TRIGGER_ONLY_CAPABILITY doctrine)

- OWNER token = `/gemini review` 1회 작성 외 **모든 action 코드 차단** (single endpoint hard-block)
- production http_post = urllib 기반 단일 endpoint POST only. merge/push/PR-merge/admin endpoint 호출 시 ForbiddenEndpointError raise
- token 직접 노출 0 (token_provider 경유 · 로그/marker/stdout/stderr redaction)
- dedupe atomic (audit JSONL + flock · 동일 (pr,head) 재트리거 DEDUPED)
- decision.json 8조건 fail-closed (불충족 시 POST 0)

## ★ 검증 시나리오 (★ "이게 되면 성공")

1. mock HTTP test: decision 8조건 충족 → POST 1회 호출 (body=="/gemini review", endpoint==issues/{pr}/comments)
2. dry-run: 실제 POST 0 · decision 검증 path 통과
3. dedupe: 동일 (pr,head) 2회 호출 → 2번째 DEDUPED · POST 0
4. forbidden endpoint: merge/pulls endpoint 주입 시 ForbiddenEndpointError
5. token unavailable: OWNER_GEMINI_TRIGGER_TOKEN 부재 → fail-closed (POST 0)
6. redaction: 로그/marker/exception 에 token 문자열 0 (grep 검증)
7. entry point: CLI/scheduler 단발 호출 → runner 생성 + http_post 주입 + decision → (mock) POST
8. regression: 기존 owner_trigger_only test 전부 PASS (코어 무훼손)

## ★ 금지

- owner_trigger_only 코어 로직 재작성 (★ http_post wiring + entry point 만 추가)
- BOT_GITHUB_TOKEN / 다른 token fallback
- COMMENT_BODY 외 body 허용 / 외부 입력 body
- merge/push/PR/admin endpoint 호출 경로 추가
- token/credential 평문 로그·marker·stdout·stderr 노출
- 실제 OWNER PAT 로 live POST in test (★ mock/dry-run 만)
- artifact/memory PR head commit (runtime code only)

## ★ 보안 게이트 (Lv.3 security)

- Codex 사전 검증 PASS + sanitize 게이트 (token/PII 마스킹)
- 마아트 독립 검증 (OWNER_TRIGGER_ONLY 13 구현 원칙 대조)
- 실제 token 값 test/코드/로그 하드코딩 0 (owasp-security 스캔)

## allowed_resources

```yaml
allowed_resources:
  paths:
    - "anu_v2/owner_trigger_only.py (★ http_post 구조 보존 · 코어 무훼손)"
    - "anu_v2/owner_gemini_trigger_router.py (★ main 반영 단일화)"
    - "anu_v2/executor_scheduler.py (★ entry point 연결)"
    - "anu_v2/merge_queue_executor.py (★ orchestrate 연결)"
    - "anu_v2/owner_trigger_http_post*.py (★ 신규 production http_post 구현체 — urllib single endpoint)"
    - "anu_v2/tests/** (★ mock HTTP + dry-run + dedupe + forbidden endpoint + redaction test)"
  forbidden_paths:
    - "settings.json · hooks/** · Axis/** · .github/** · dispatch.py · dispatch/__init__.py"
    - "**/.env* · **/credentials* (★ token 값 미접촉)"
    - "PR #157 / task-2698 branch (★ 별개 task)"
  commands:
    - "git fetch/log/diff/show/worktree/commit/push (fresh branch task/task-2699-*)"
    - "gh pr create / gh pr view / gh api (read)"
    - "python3 -m pytest (mock/dry-run only · live POST 0)"
  merge_policy: "no_merge_chair_approval_required"
  ttl_hours: 8
```

## ★ 완료 보고 필드

1. production http_post 구현체 (endpoint/method/urllib)
2. entry point 연결 (CLI + scheduler)
3. owner_gemini_trigger_router main 반영 정리 결과
4. 검증 8 시나리오 결과
5. token 누출 0 evidence (grep)
6. 기존 owner_trigger_only regression PASS
7. PR 번호 + head SHA
8. forbidden_action_count

## 종결

성공: **`OWNER_GEMINI_TRIGGER_CAPABILITY_WIRING_COMPLETE`** (★ merge 회장 결재)

★ 회장 verbatim 2026-05-27 A+B 병행 — B(capability 실 wiring). 정식 경로 production-ready 화. ad-hoc POST 영구 제거.

끝