---
task_id: task-2370
type: context
scope: task
created: 2026-05-02
updated: 2026-05-02
status: completed
---

# 맥락 노트: task-2370

**task**: task-2370

---

## 결정 근거

### 결정 1 — 별도 webhook(`anu-confirm-bot`) vs 기존 cokacdir 확장
- 채택: 별도 webhook (Flask 단일 파일)
- 이유: cokacdir는 단일 채널·단일 봇 단순성 핵심. inline button callback은 Telegram bot API 별도 webhook이 표준. 다빈치 미팅에서 "cokacdir 단순성 유지" 명시.
- 기각: cokacdir 확장 → 단일 책임 위반 + 본 작업 후 P3 대시보드와 결합도 ↑

### 결정 2 — HMAC-SHA256 + 5분 TTL + 1회 사용 마커 (Codex G1 critical 반영)
- 채택: `callback_data = <action>:<task_num>:<pr_num>:<expiry_unix>:<sig8>` (Telegram 64B 한도)
  - `action` ∈ {a=approve, r=reject, d=diff}
  - `task_num` = 2370 (숫자만)
  - `expiry_unix` = `int(time.time()) + 300`
  - `sig8` = base64url(HMAC-SHA256(SECRET, f"{action}:{task_num}:{pr_num}:{expiry_unix}"))[:8]
- Replay 차단: `memory/events/anu-confirm/processed-{task_num}-{pr_num}-{action}` 마커 파일 — 동일 callback 재클릭 시 거부.
- 이유: Codex G1 critical 지적 — 서명 입력에 expiry 포함되지 않으면 TTL/replay 재구성 불가. nonce DB 대신 file marker로 단순성 유지.

### 결정 6 — Approve action 직접 머지 금지 (Codex G1 high 3 반영)
- 채택: Approve callback → `gh pr merge {pr_num} --merge --delete-branch` 호출 + audit log append
- 이유: GitHub API가 측면에서 직렬화. auto_merge.py의 `.done.merging` lock과 race 회피.
- 기각: 직접 git merge → race condition + auto_merge.py와 중복 처리 위험.

### 결정 3 — 트리거 마커 환경변수 추상화
- 채택: `ANU_CONFIRM_TRIGGER` / `DIGEST_TRIGGER` 환경변수, 기본 `.merge-done`
- 이유: task-2368(`.done` 시맨틱 재설계 미팅) 진행 중. 결과(`.done`/`.merge-done`/`.merged`/`.fully-done` 분리)에 따라 1줄 변경으로 적용 가능.
- 기각: 하드코딩 → task-2368 결과 반영 시 추가 PR 필요.

### 결정 4 — Scope violation 별도 채널 prefix 방식 (Codex G1 medium 1 반영)
- 채택: 환경변수 `SCOPE_VIOLATION_CHAT_ID` 미설정 시 동일 chat에 `⚠️ SCOPE VIOLATION` 이모지 prefix + bold HTML
- 이유: 비너스 UX — "드물게 울리는 알림이 진짜 알림". Telegram은 일반 텍스트 색상 미지원이라 색상 강조는 포기하고 이모지+bold+별도 chat_id로 강조.
- 기각: 별도 봇 토큰 분리 → 운영 부담 + 본 task 범위 외(P3 대시보드 빨간 배너에서 시각화).

### 결정 5 — 랜덤 10% 샘플링
- 채택: `random.sample(merged, max(1, ceil(len*0.1)))` 단순 균일 무작위
- 이유: 마아트 합의안 — Netflix Chaos 차용. 1건 미만이면 0건 처리 → 매일 검토 0~2건 자연스러운 분포.
- 기각: 샘플링 가중(diff_loc, 봇별 violation 이력) → P3 이후 정교화 여지.

## 3 Step Why 자문

- **1st Why — 왜 이 설계가 필요한가?**
  A: 회장 인지 부담을 최소화하기 위해 Lv.0-1 자동 머지는 즉시 알림 0, 일일 다이제스트로만, Lv.2는 5분 TTL의 1-tap inline button, 보안 위반은 별도 채널로 분리 알림.
- **2nd Why — 왜 A가 최선의 접근인가?**
  B: 대안 (모든 머지 즉시 알림 / 단일 채널 / Telegram 스레드만 사용 / 24h delay 자동 머지) 중에서, 즉시 알림은 미팅 합의 4번 위반·인지 폭주, 단일 채널은 scope violation이 묻힘(비너스 UX 지적), 스레드만은 5분 1-tap 불가, 24h delay는 핫픽스 차단. **별도 webhook + 채널 분리 + 다이제스트 묶음**이 cokacdir 단순성과 인지 부담 최소화를 동시 달성.
- **3rd Why — 왜 B가 다른 대안보다 나은가?**
  C: 미팅 cycle 2 합의 4번(UX) + 비너스 UX 권고 + 다빈치 3-Tier 아키텍처 + 마아트 10% 샘플링 — **8명 미팅 합의의 직접 실행**. 별도 webhook은 cokacdir 단일 봇 단순성을 깨지 않고, HMAC+TTL은 모코시(보안)의 replay attack 방어 요구를 충족. 다른 대안은 합의 4번을 위반하거나 보안/UX 한 축을 희생함.
- **A-B-C 일관성**: ✅ (회장 인지 부담 최소화 → 채널 분리 + 1-tap 인지 → 별도 webhook 필요)

## 참조 자료

- 미팅: `memory/meetings/2026-05-02-bot-anu-automation-safety.md` (cycle 2 합의 4)
- 의존 P0: `memory/reports/task-2364.md` (Capability Matrix)
- 의존 P1: `memory/reports/task-2367.md` (Tiered Auto-Merge + Audit JSONL)
- task-2368 미팅: `memory/meetings/2026-05-02-done-semantics-redesign.md` (트리거 마커 변경 가능성)
- audit log 포맷: `scripts/auto_merge.py:1005 _append_audit` (JSONL append-only)
- classify_tier: `scripts/auto_merge.py:967` (tier1/tier2/tier3 분류)

## 주의사항

- `scripts/auto_merge.py` 수정은 **Tier 2 hook 1점 + scope violation hook 1점**만 허용. 다른 로직 절대 변경 금지(P1 회귀).
- 트리거 마커 추상화 범위: anu_confirm_bot/ + daily_digest.py만. auto_merge.py의 `.done` glob은 보호 경로(P1)이므로 본 task에서 미수정. task-2368 결과 확정 시 별도 task로 흡수(보고서에 명시).
- Daily digest는 audit log 미존재 시 "Tier 1 자동 머지 0건" 카드 또는 skip — graceful fallback.
- `scripts/post_merge_probe.py`, `scripts/auto_revert.py`, `scripts/task-scope-guard.sh`, `scripts/finish-task.sh` 변경 절대 금지.
- `memory/audit/auto-merge.log`는 read-only(append만). daily_digest.py는 readonly로만 접근.
- 본 task는 자기-분류 시 tier3로 분류되어야 함 (auto_merge.py 변경 → 보호 경로 + Lv.3) → 자동 머지 차단되어 회장 명시 승인.
- Telegram bot token / chat_id는 환경변수 사용. 하드코딩 금지.
- Sanitize 게이트: 외부 AI 호출 시 ANU_KEY/CHAT_ID/Bot Token 마스킹 필수.
