---
task_id: task-2364
type: context
scope: task
created: 2026-05-02
updated: 2026-05-02
status: in-progress
---

# 맥락 노트: task-2364

**task**: task-2364

---

## 결정 근거

### 결정 1: capability 작성 = inline YAML / enforcement 원본 = dispatch snapshot (계층 분리)
- **작성 (작성자 책임)**: task 파일 inline YAML — 미팅 [HOUR 1] 결정. 단순성 우선, 작성자는 한 곳만 관리.
- **Enforcement 원본 (시스템 책임)**: dispatch.py가 inline YAML을 파싱해서 `memory/capabilities/{task_id}.json`에 immutable snapshot 저장. scope-guard는 snapshot만 읽음.
- **이유**: 작성 단순성 + enforcement immutability 동시 만족 (Codex critical "mutable task 파일 self-bypass" 차단)
- **대안 1 (작성자가 별도 JSON 직접 유지)**: 동기화 비용 → 기각
- **대안 2 (환경변수)**: glob/TTL 표현 한계 → 기각
- **대안 3 (mutable task 파일 그대로 사용)**: 봇 self-scope-extension 가능 → Codex critical → 기각
- **하위 호환**: 신규 dispatch부터 강제. 진행 중인 legacy task는 `--allow-no-scope` grace period.

### 결정 2: capability paths 표현 = glob (regex 미채택)
- **근거**: 미팅 [HOUR 2-3] OPEN → 본 task에서 결정. 대다수 운영자가 glob에 익숙. `**`/`*`로 directory tree 표현 충분.
- **대안 (regex)**: 표현력은 강하나 오작성 위험 + 봇/사람 가독성 저하. 기각.
- **구현**: Python `pathlib.PurePath.match` + `fnmatch` 조합. recursive glob `**`은 `pathlib.Path.glob`로 처리.

### 결정 3: 위반 검출 시점 = dispatch (사전) + finish-task (사후) 이중
- **근거**: 미팅 [HOUR 2-3] RESOLVED. 사전만은 우회 가능, 사후만은 작업 낭비.
- **사전 (dispatch.py)**: capability 미명시 → 작업 자체 거부. 위반 작업을 시작조차 안 시킴.
- **사후 (finish-task.sh)**: git diff vs allowed glob → 실제 변경 파일이 scope 일치하는지 검증.

### 결정 4: 위반 시 처리 = exit 1 + `.scope-violation.json` + .escalate
- **exit 1**: finish-task가 .done 생성 차단 (기존 게이트 패턴과 동일)
- **`.scope-violation.json`**: `memory/events/{task_id}.scope-violation.json` (audit trail)
- **.escalate**: `memory/events/{task_id}.escalate` (회장 알림 트리거 — 별도 cron이 감지)
- **근거**: 미팅 합의 5(다층 방어). 기존 .failed/.cancelled 패턴 재사용으로 인지 부담 최소화.

### 결정 5: CLAUDE.md 업데이트 = root CLAUDE.md에 5대 규칙 섹션 신규 추가
- **근거**: task 본문 affected_files에 `CLAUDE.md`만 명시. `memory/specs/anu-guide.md` 위임 완결성 4대 규칙 업데이트는 본 task scope 밖 (별도 후속 task).
- **이유**: scope guard 자체 통과를 위해 자기 task의 allowed_resources 위반 금지.
- **추가 위치**: CLAUDE.md 끝에 "## 위임 완결성 5대 규칙 (2026-05-02)" 섹션 신규.

## 참조 자료

- 미팅: `memory/meetings/2026-05-02-bot-anu-automation-safety.md`
- 사고 사례: `memory/reports/task-2360.md` (codegraph cron 복구)
- 위임 완결성 4대 규칙: `memory/specs/anu-guide.md` 3.9
- 회장 결정: 2026-05-02 옵션 A
- finish-task 패턴: `scripts/finish-task.sh` 0-cancelled / 0-stopmarker / G3-GATE 섹션

## 주의사항

- **자기 호출 회귀 위험**: 본 task가 finish-task.sh 자체를 수정하므로, finish-task 실행 시 scope-guard 훅이 본 task에 적용됨. 본 task의 allowed_resources에 `scripts/finish-task.sh`가 포함되어 있어 통과해야 함.
- **dispatch.py 호환**: 기존 dispatch 호출은 `--allow-no-scope` 명시적 opt-in 없이 거부되면 안 됨 → 점진적 마이그레이션. 신규 task 파일에 `allowed_resources` 섹션이 있을 때만 검증, 없으면 경고+통과.
- **glob 매칭 위양성**: `**/*.py` 같은 광범위 glob 허용은 사실상 무효화. 미팅 합의대로 paths는 명시적 파일 경로 또는 좁은 디렉토리 한정 권장 (스펙 문서에 가이드 작성).
- **시스템 자동 파일 무시**: `memory/heartbeats/`, `memory/events/`, `memory/task-timers.json` 등 시스템 자동 파일은 finish-task.sh git-gate에서 이미 무시 중 — scope-guard도 동일 무시 필요.
- **본 task allowed_resources 자체 검증**: 본 task가 `allowed_resources` 자체를 정의하는 작업이므로, 자기 자신의 allowed_resources를 위반하지 않도록 작업 파일 읽기/쓰기 신중.

## Codex 1차 지적 반영 (2026-05-02 17:28)

Codex critical 1건 + high 2건 + medium 3건 지적을 다음과 같이 반영:

### 반영 1 (CRITICAL): scope 원본 = immutable snapshot
- **지적**: task 파일 자체가 mutable이면 봇이 자기 scope를 넓혀 우회 가능
- **반영**:
  - dispatch.py는 task 파일 파싱 직후 `memory/capabilities/{task_id}.json`에 capability snapshot을 저장 (한 번만, immutable)
  - task-scope-guard.sh는 **snapshot 파일만 읽음** (task 파일 직접 읽기 금지)
  - snapshot은 자동으로 forbidden_paths에 추가되어 봇이 변조 불가
  - snapshot 파일 sha256 hash 기록 (변조 감지)

### 반영 2 (HIGH): scope 검증 시점 = 머지 *직전*
- **지적**: finish-task가 머지 후 .done 생성 흐름이라 post-merge diff 검증은 이미 늦음
- **반영**: finish-task.sh 흐름 재배치
  - 현재: QC (Step 1) → 머지 (Step 2) → 게이트들 → .done (Step 3)
  - **변경**: QC (Step 1) → **scope-guard 검증 (Step 1.5 신규)** → 머지 (Step 2) → 게이트들 → .done
  - diff 계산: `git diff --name-only main..HEAD` (worktree 브랜치 기준, 머지 *전*)
  - 위반 시 머지 차단 + .escalate + exit 1

### 반영 3 (HIGH): commands enforcement = P0 범위 제외
- **지적**: paths만 강제하고 commands enforce 안 하면 위험 명령으로 사고 가능
- **반영**: P0 범위는 **paths + forbidden_paths 강제만**. commands는 스키마 표시 + audit log만 (P1+ enforce). 스펙 문서에 명시.

### 반영 4 (MEDIUM): `--allow-no-scope` 명시 정의
- dispatch.py에 명시적 argparse 추가
- 사용 시 `memory/events/{task_id}.allow-no-scope.log` 이벤트 파일 생성 (audit trail)

### 반영 5 (MEDIUM): inline YAML + affected_files 파서 분리
- dispatch.py의 affected_files 자동 주입 로직과 `allowed_resources` fenced yaml block은 **독립 파서**
- `allowed_resources` 파싱은 ```yaml ... ``` 블록 안의 `allowed_resources:` 키 검색
- affected_files 섹션과 충돌 없도록 별도 함수 `parse_allowed_resources(task_text) -> dict | None`

## 3 Step Why 결과

- **1st Why**: 왜 capability matrix가 필요한가? → CLAUDE.md 텍스트 룰만으로는 봇 자율 판단 오작동(task-2360)을 막을 수 없음. 시스템 hard wall 필요.
- **2nd Why**: 왜 이 접근(immutable snapshot + 머지 직전 검증 + paths-only PoC)이 최선인가?
  - immutable snapshot: task 파일은 mutable이라 self-scope-extension 가능. dispatch 시점 snapshot이 진실의 원본.
  - 머지 직전 검증: 머지 후 검증은 이미 main 오염. worktree 브랜치 기준 diff가 정확.
  - paths-only PoC: commands enforcement는 shell wrapper 필요 → 별도 시간 소모. P0는 가장 큰 위협(파일 수정)부터 막음. P1에서 commands 추가.
- **3rd Why**: 왜 이 접근이 다른 대안보다 나은가?
  - vs. mutable task 파일 검증: self-bypass 가능 → 보안 무력화
  - vs. post-merge 검증: 이미 main 오염 → revert 비용 큼 (P1 auto-revert는 다음 단계)
  - vs. commands까지 P0에 포함: 일정/복잡도 증가 → P0 미머지 → 사고 재발 위험. 점진적 도입이 안전.

A→B→C 정합성: 텍스트 룰 한계 → snapshot+머지전 검증+범위 축소 → 보안+속도+점진성 (정합성 OK)
