---
task_id: task-43.0
type: context
scope: system
project: anu-guide-system
created: 2026-03-02
updated: 2026-05-05
status: active
---

# 맥락 노트: 아누 가이드 시스템 구축

**task**: task-43.0

---

## 결정 근거

### Phase 7 — 신호등 sync 정정 + auto_merge.py 폐기 (2026-05-05 task-2452)

**왜 신호등 단일 책임 = `finish-task.sh` 끝부분인가?**
- 회장 직접 진단 (2026-05-05): "오토 머지까지 다 되어야 작업이 정말 완성된 거고, 그 이후 finish-task.sh가 진행되니, 마지막에 신호등이 꺼지는 로직이어야 정상."
- 변경 전: `member-status.json`은 finish-task.sh Step 2.7에서 머지 직후, `bot-activity.json`은 done-watcher.py cron이 .done 감지 시 → 다른 트리거·다른 시점 mismatch.
- 대안 기각: (A) done-watcher가 두 source 모두 책임 → 외부 cron이 신호등 만짐. (B) 중간 Step 2.7 유지 + bot-activity 끝부분 추가 → 시점 또 다름.
- 채택: Step 2.7 통째로 .done 직전 마지막 Step (Step 2.99)으로 이동 + bot-activity 통합. 단일 트리거.

**왜 auto_merge.py 공식 폐기인가?**
- 회장 직접 진단: "실제 workflow 따라가보면 merge는 git을 통해 하는 걸로 되어있다."
- raw 증거: `logs/auto_merge.log` 24MB 최근 1000줄 = 227건 모두 `[BLOCKED]`. 머지 0건.
- 머지의 진짜 경로 3개 (auto_merge 거치지 않음): A) finish-task.sh → worktree_manager finish, B) taskctl.py merge → gh pr merge, C) GitHub merge_group + Ruleset.
- 30일 유예 사유: tests/test_auto_merge.py 등 의존 테스트 다수 + lock_in_verify.py가 First-line guard 추적. 즉시 삭제 시 회귀 위험.

**왜 done-watcher fallback only로 강등인가?**
- 변경 전 즉시 idle은 finish-task.sh가 도는 중에도 cron이 30초마다 신호등 만짐 → 단일 책임 깨짐.
- 30분 grace + `.merge-done` 부재 조건: 정상 흐름은 finish-task.sh가 처리, 비정상 흐름(봇 크래시)만 fallback.
- 30분 산정: finish-task.sh 평균 실행 << 5분. 30분이면 안전 마진 충분.

### 왜 hooks가 최우선인가?
- Agent 미팅 6명 전원 동의: hooks가 모든 자동화의 뿌리
- 아누 가이드 Section 1 전체가 hooks 의존
- hooks 없이는 매뉴얼 자동 주입, Audit Trail, 셀프체크 리마인더 모두 불가

### 왜 보안을 즉시 조치하는가?
- 로키 발견: dispatch.py 34-39행에 BOT_KEYS 평문 하드코딩 (폴백)
- 환경변수 미설정 시 키가 코드에 노출 → 보안 위반
- 파일 권한 664 → 그룹 내 누구나 변조 가능

### 왜 1팀에 Phase 0, 2팀에 Phase 1?
- Phase 0(hooks)는 실행 중심 → 헤르메스(빠른 판단)에 적합
- Phase 1(skills)은 설계 중심 → 오딘(아키텍처 관점)에 적합

### 비너스 경고 반영
- 동시 구현 금지 → 순차 실행 (즉시→Phase 0→Phase 1)
- 각 Phase 완료 확인 후 다음 진행
- 인터페이스 단순하게 유지

## 참조 자료
- 아누 가이드: `memory/specs/anu-guide.md`
- Agent 미팅: `memory/meetings/2026-03-02-anu-guide-gap-analysis.md`
- Claude Code hooks 스펙: 1팀이 리서치 필요
- 조직도: `memory/organization-structure.json`

## 주의사항
- hooks는 전역 공유 (야누스 경고) → detect-bot.sh로 봇별 분기 필수
- hooks 실패 시 전체 블로킹 위험 (헤르메스 경고) → try/except + fallback
- QC 트리거는 Phase 2로 미룸 → hooks에 QC 로직 넣지 말 것

---

## Phase 4 결정 근거 (2026-04-24 추가)

### 3대 루트 원인 분석

**RC-1: 영향 범위 전수조사 누락**
- 사례: task-2142 — FeatureGate.tsx L41 수정했으나 use-feature-access.ts에 동일 로직 누락
- 원인: affected_files를 아누가 수동 기재하는 구조. 아누가 빠뜨리면 전체 무력화
- 기존 방어: dispatch.py `_enrich_affected_files_with_ast()`는 Python만 지원, TS/TSX는 범위 밖

**RC-2: 연쇄 이슈 직렬 발견**
- 사례: task-2143(Vitest supabaseUrl) → task-2144(pytest doc_parser) — 같은 CI인데 2건 분리
- 원인: finish-task.sh의 test_runner가 `--check-files` 기반 부분 테스트만 실행
- 기존 방어: 없음 (멀티 러너 CI 게이트 부재)

**RC-3: 실동작 미검증**
- 사례: task-2140 — "인증 필요 환경으로 UI 직접 확인 불가"인데 완료 처리
- 원인: l1_smoketest_check가 "해당없음" 패턴을 허용
- 기존 방어: browser_verify는 스크린샷 파일 존재만 확인 (캡처 자동화 없음)

### 핵심 설계 판단

**왜 post-flight(finish-task.sh) 중심인가?**
- 로키 제안: pre-flight(dispatch.py)는 아누 의존 → 아누가 빠뜨리면 무력화
- post-flight는 봇이 작업 완료 후 자동 실행 → 아누 의존도 제거
- 합의: pre-flight + post-flight 양면 방어, post-flight에 무게

**왜 Phase 1A/1B 분리인가?**
- 로키 경고: grep 기반 false positive 폭발 위험 + CI 타임아웃 → 정당한 작업 차단
- 합의: 명백한 위반(l1_smoketest, goal_assertions)만 즉시 FAIL, 나머지는 WARN 모드 2주 데이터 수집
- 전환 기준: false positive < 10% 시 WARN → FAIL 승격

**왜 grep 기반이고 AST/LSP가 아닌가?**
- 헤르메스: Python은 AST 가능하지만 TypeScript는 tsc 파서 의존성 과다
- 합의: Python=AST, TypeScript=regex 기반 (`export function/class/type/interface`)
- 로키 반론 반영: 백틱 코드 토큰만 추출 + COMMON_FILTER 20단어로 정밀도 확보

**Goal Assertions 패턴 채택 이유**
- 오딘 제안: task 파일에 실행 가능한 shell command로 완료 기준 명시
- 코딩 4원칙 "Goal-Driven Execution"과 완벽 합치
- dispatch.py가 task 파일의 검증 시나리오에서 자동 생성 가능

### 기각된 대안
- **Shadow Run (라 제안)**: Haiku 세션 추가 spawn으로 독립 검증 → 세션 관리 복잡도 + 완료 지연 위험으로 기각
- **affected_files 전면 AST 분석 (헤르메스 초안)**: TypeScript AST 파서 의존성 과다, grep + regex로 충분
- **CI 전체 실행 (엔키 초안)**: InsuRo 4000+ TS 파일 → tsc 3분 소요 → 타임아웃 위험. 러너당 120초 제한으로 타협
- **미해결 이슈 전면 차단 (쿠쿨칸 초안)**: "범위 외" 정당한 미해결도 차단 → "범위 내" 미해결만 카운트로 수정

## 참조 자료 (Phase 4)
- Agent 미팅: `memory/meetings/2026-04-24-dispatch-quality-automation.md` (13명 5사이클)
- dispatch.py 기존 함수: `_parse_affected_files()`(766행), `_enrich_affected_files_with_ast()`(812행)
- finish-task.sh 기존 게이트: Step 0~2.10 (부록 참조)
- qc_verify.py verifier 21개: l1_smoketest_check, scope_check, browser_verify 등

## 주의사항 (Phase 4)
- 신규 게이트는 subshell 격리 실행 (C-FINAL-9) — 한 게이트 실패가 다른 게이트 차단 방지
- gate-config.json이 단일 소스 — 코드에 임계치 하드코딩 금지
- impact_scanner의 grep 타임아웃: 심볼당 3초, 전체 15초 (무한 대기 방지)
- ci_preflight의 러너 타임아웃: 120초/러너, 전체 300초 (봇 세션 보호)
- "확인 불가" 차단의 EXEMPT 조건: task 키워드에 UI/컴포넌트/화면 없으면 스크린샷 면제

## Phase 5 결정 근거 (2026-04-26)

### 왜 봇별 key fallback이 필요한가?
- dispatch.py가 아누 key로만 cron을 보내면 cokacdir 재시작 후 다른 봇에 전달 안 됨
- 2026-04-26 사고: task-2200~2204에서 5회 연속 봇 미수신
- 봇별 고유 key로 직접 전송하면 해당 봇에 확실하게 전달됨

### 왜 빌드+배포를 워크플로우에 명시해야 하는가?
- InsuRo는 dist 폴더를 서빙 → PR 머지만으로는 프로덕션 미반영
- jszip npm install 누락으로 빌드 실패 경험

### 왜 L1 SKIP을 금지해야 하는가?
- task-2201 보고서에서 10개 시나리오 중 8개 SKIP → 실제 이미지 업로드 시 크래시 발견 못 함
- "build 성공 = 동작" 착각이 근본 원인
- SKIP = 미검증 = .done 자격 없음

## Phase 6 결정 근거 (2026-05-04~05)

### 왜 server-side enforcement까지 가야 했는가?
- task-2439까지 코드/스크립트 차원에서는 9단계 + Lock-in + 침투/Race/CI 모두 PASS
- 그러나 회장 진단: "GitHub 보호 규칙 차원에서 강제되지 않으면 cancelled 작업이 main에 들어가는 것을 영구적으로 보장할 수 없다"
- 클라이언트 측 hook + CI 검증만으로는 다음이 모두 가능했음:
  - PR이 `qc-check=failure` 상태인데 머지됨 (PR #14 raw 증거: merged_at < qc-check completed_at)
  - `gh pr merge --admin` 우회
  - direct push to main (free private repo는 protection 자체를 등록할 수 없었음)

### 왜 task-2440 봇 작업으로는 4/7만 PASS였는가?
- 저장소 `JonghyukJeon/dev_workspace`가 **GitHub free private repo**
- raw API 응답:
  - `branches/main/protection PUT` → HTTP 403 "Upgrade to GitHub Pro or make this repository public"
  - `rulesets API` → HTTP 403 동일
  - `enableRepositoryMergeQueue` GraphQL mutation → "Field doesn't exist"
- 결론: A(required checks enforced), B(Gemini failure → merge 불가), E(merge queue 강제) 항목은 봇 권한으로 물리적 불가능 → 회장 직접 처리 필요로 보고
- 봇 권한 내 PASS: C(cancel 차단 3중), D(direct push 차단), F(race 0건), G(MD 삭제 후 동작) = 4/7

### 왜 회장이 free → org 전환을 선택했는가? (2026-05-04 09:18)
- 옵션 1: public 전환 → 무료지만 코드 공개 부담
- 옵션 2: GitHub Pro 개인 plan
- **선택: Organization(team plan)** → `Jeon-Jonghyuk` org 신설, 저장소 이전, team plan 가입
- 결과: Ruleset id=15896715 (enforcement=active) 등록 완료. 7개 required checks를 server-side에서 강제

### 왜 task-2449 침투 테스트 9 케이스를 추가했는가?
- task-2440이 server-side enforcement 활성화 후, 실제로 빠져나갈 길이 모두 막혔는지를 raw 로그로 증명할 필요
- 회장 절대 기준 7항목 + 9 침투 = 코드/CI/server-side 3중 차단의 직접 증거
- 결과: 9건 모두 차단 또는 evidence 강제 기록 동작

### 왜 V1 외부 조언자 문서가 잘못된 그림을 줬는가?
- V1 작성 시 task-2440/2449/2451 enforcement 정보를 누락
- "merge_policy=manual 기본"이라는 표현만 보고 외부 조언자가 "이 시스템은 server-side enforcement 없음"으로 오판할 위험 있었음
- 실제로는 `merge_policy`는 task 메타 라벨일 뿐이고 게이트는 다층(merge_needed → Tier 분류 → Ruleset + CI 7-step → taskctl 상태)
- V2에서 §0 정정 요약 + §9.1 사례 + 부록 A/B 갱신으로 해소
- 교훈: "코드만 grep하지 말고 최근 task 보고서까지 사례로 읽어야 시스템 현재 상태가 보인다"
