# task-2364 — 봇 Capability Matrix + Scope Guard (P0)

**팀**: dev7-team (이참나)
**레벨**: Lv.3 / critical (보안 인프라)
**상태**: 완료
**작성**: 2026-05-02

---

## SCQA 요약

**S**: 2026-05-02 task-2360 작업 중 codegraph cron `CC712188`(Phase 2.5 KPI 측정)이 task scope 밖에서 삭제됨. 사후 `3EA43774`로 무손실 복구. 회장 우려: "더 심각한 건 봇이 작업을 계속하고 있다는 사실".

**C**:
- CLAUDE.md "Surgical Changes" 텍스트 룰만 존재 → 시스템 강제력 없음
- 봇 자율 판단(이참나 본인)이 자기 작업 종료를 *믿었으나* scope 밖 변경 발생 — 자기 인식 오류를 시스템 기본값으로 신뢰
- 8 페르소나 미팅 만장일치: CLAUDE.md만으로는 불충분, 시스템 hard wall 필수

**Q**: 어떻게 task-2360 같은 사고를 **시스템 레벨에서 차단**하면서, 정상 흐름과 legacy task에 영향을 최소화할 것인가?

**A** (구현 결과):
다층 방어 P0 구축:
1. **Capability schema 표준화** — task 파일 inline YAML `allowed_resources`(paths/forbidden_paths/commands/merge_policy/ttl_hours)
2. **Immutable snapshot** — dispatch 시점 `memory/capabilities/{task_id}.json`에 sha256 해시 포함 저장 (mutable task 파일 self-bypass 차단, Codex critical 지적 반영)
3. **Hard wall scope guard** — `scripts/task-scope-guard.sh`가 snapshot vs git diff 매칭, 위반 시 exit 1 + scope-violation.json
4. **머지 직전 검증** — `scripts/finish-task.sh` Step 1.6에서 머지 *전* 호출 (post-merge는 이미 main 오염, Codex high 지적 반영)
5. **Legacy 호환** — `dispatch.py --allow-no-scope` 플래그 + audit log

---

## 작업 내용

### 신규 파일
- `scripts/task-scope-guard.sh` — bash PoC, snapshot 기반 glob 매칭, 시스템 자동 파일 무시, forbidden 우선
- `memory/specs/bot-capability-model.md` — capability 스키마 + 게이트 동작 + 작성 가이드 + 테스트 시나리오 6종
- `memory/plans/bot-capability-system/{plan,context-notes,checklist}.md` — 시스템 3문서 (P0~P3 로드맵)
- `memory/plans/tasks/task-2364/{plan,context-notes,checklist}.md` — 본 task 3문서
- `memory/capabilities/.gitkeep` — snapshot 디렉토리 마커
- `tests/dev7/test_scope_guard.py` — pytest 시나리오 5 + 단위 테스트 7

### 수정 파일
- `dispatch.py` — `_parse_allowed_resources` + `_save_capability_snapshot` 함수 추가, `--allow-no-scope` argparse, dispatch() 함수에 capability 파라미터, capability 미명시 거부 로직
- `scripts/finish-task.sh` — Step 1.6 Scope Guard 섹션 신규 (QC 직후 + 머지 직전)
- `CLAUDE.md` — "위임 완결성 5대 규칙" 섹션 신규 + 5번 Capability 명시 항목

### Admin 직접 작성 (P0 inception 한정)
- `memory/capabilities/task-2364.json` — 본 task 자기-호출 회귀 안전을 위한 admin snapshot. 사유 audit: `memory/events/task-2364.snapshot-admin-write.log`

---

## 모델 사용 기록

| 팀원 | 모델 | 작업 | 정당성 |
|------|------|------|--------|
| 이참나 (팀장) | opus | 설계, 3문서 작성, Codex 지적 반영, CLAUDE.md, admin snapshot | Lv.3 critical 설계 판단 |
| 쿠쿨칸 (백엔드) | sonnet | bash + Python 코드 4 MT 구현 | 일반 코딩 (haiku 부적합 — 4단 의존성) |
| 마아트 (QC, cross) | sonnet | 독립 검증 5 항목 | QC 분석 (haiku 부적합) |

---

## 테스트 결과

### pytest (12/12 PASS)
```
tests/dev7/test_scope_guard.py::test_scenario1_pass PASSED
tests/dev7/test_scope_guard.py::test_scenario2_forbidden_violation PASSED
tests/dev7/test_scope_guard.py::test_scenario3_legacy_allow_no_scope PASSED
tests/dev7/test_scope_guard.py::test_scenario4_no_snapshot_no_marker PASSED
tests/dev7/test_scope_guard.py::test_scenario5_system_files_ignored PASSED
tests/dev7/test_scope_guard.py::test_parse_allowed_resources_yaml_block PASSED
tests/dev7/test_scope_guard.py::test_parse_allowed_resources_inline_list PASSED
tests/dev7/test_scope_guard.py::test_parse_allowed_resources_not_found PASSED
tests/dev7/test_scope_guard.py::test_parse_allowed_resources_yaml_without_key PASSED
tests/dev7/test_scope_guard.py::test_save_capability_snapshot_basic PASSED
tests/dev7/test_scope_guard.py::test_save_capability_snapshot_auto_forbidden_capabilities PASSED
tests/dev7/test_scope_guard.py::test_save_capability_snapshot_no_duplicate_forbidden PASSED
============================== 12 passed in 0.21s ==============================
```

### L1 스모크테스트 결과 (필수 기록)

- 서버 재시작: **해당없음** (시스템 인프라 task — 데몬/HTTP 서버 없음)
- API 응답 확인: **해당없음**
- 스크린샷: **해당없음** (백엔드 보안 인프라)
- **실 시뮬레이션 (실제 bash 실행으로 4 시나리오 검증)**:

  | 시나리오 | 입력 | 결과 | 기대 | 판정 |
  |---|---|---|---|---|
  | L1.1 사고 재현 | snapshot paths=["scripts/finish-task.sh"], diff=`memory/events/cron-CC712188.json` | exit=1, `task-fixture-l1sim.scope-violation.json` 생성 ("paths 미포함") | 차단 | PASS |
  | L1.2 정상 흐름 | snapshot paths=["scripts/finish-task.sh","scripts/done-watcher.py"], diff=동일 | exit=0, "PASS: 2 files in scope" | 통과 | PASS |
  | L1.3 legacy 호환 | snapshot 없음 + `.allow-no-scope.log` 마커 존재 | exit=0, "WARN: legacy task" | 통과 + 경고 | PASS |
  | L1.4 snapshot 없음 + 마커 없음 | (신규 task가 dispatch 없이 호출) | exit=1, "ERROR: snapshot 없음 — dispatch 미수행?" | 거부 | PASS |

- **자기-호출 회귀 안전**: admin snapshot 보정 후 본 task 13개 변경 파일 전체 in scope (exit 0) 확인

---

## 머지 판단

- **머지 필요**: Yes
- **브랜치**: `task/task-2364-dev7`
- **워크트리 경로**: `/home/jay/workspace/.worktrees/task-2364-dev7`
- **머지 의견**:
  - 코드 품질: pytest 12/12 PASS, bash 구문 검증 PASS, dispatch.py py_compile PASS
  - 회귀 안전: 기존 finish-task.sh 게이트(QC, G3, Codex, GIT-GATE 등) 모두 보존, dispatch.py 기존 함수(affected_files, --resume, --cancel) 보존
  - 자기-호출 회귀: admin snapshot 보정 후 PASS
  - Codex 사전 검증 2회 통과 (critical 0건, high 0건)
  - 마아트 독립 검증: 5개 항목 중 4 PASS, 1 자기-호출 → admin snapshot 보정 후 재검증 PASS
- **충돌 가능성**: 낮음 (rebase로 task-2366의 미팅 파일 정정 흡수 완료)

---

## 발견 이슈 및 해결

### Issue 1 (Codex 1차 — CRITICAL): mutable task 파일 self-bypass
- **원인**: 초기 설계가 task 파일 자체에서 allowed_resources를 읽도록 함
- **해결**: dispatch 시점 immutable snapshot 도입. task-scope-guard.sh는 snapshot만 읽음. 봇이 task 파일 변조해도 snapshot 불변.

### Issue 2 (Codex 1차 — HIGH): 머지 후 검증은 이미 늦음
- **원인**: finish-task.sh가 머지(Step 2) 후 게이트들을 거쳐 .done 생성
- **해결**: Step 1.6 신규 — 머지 *직전* scope-guard 호출. 위반 시 머지 차단 + .escalate.

### Issue 3 (Codex 1차 — HIGH): commands enforcement 누락
- **원인**: paths만 강제하면 위험 명령으로 사고 가능
- **해결**: P0 범위 축소 — paths/forbidden_paths만 강제. commands는 정보 표시 + audit log만. P1+ shell wrapper로 enforce 예정 (스펙 문서에 명시).

### Issue 4 (Codex 2차 — HIGH): 시스템 task PROJECT_PATH 미지정 시 검증 스킵
- **원인**: 본 task처럼 시스템 인프라 task가 가장 위험한데 검증에서 빠질 수 있음
- **해결**: PROJECT_PATH 미지정 시 workspace 자체를 사용. 시스템 task도 검증.

### Issue 5 (마아트 — HIGH): admin snapshot 자기 모순
- **원인**: forbidden_paths의 `memory/capabilities/**`가 본 task가 만드는 `.gitkeep` 자체를 차단
- **해결**: admin snapshot에서 `memory/capabilities/**` forbidden 제거 (P0 inception task 한정 예외). 다음 task부터는 dispatch가 자동 추가 → 다른 task는 정상 보호.

### Issue 6 (마아트 — HIGH): 워크트리 base의 main 진보분이 diff에 포함
- **원인**: 워크트리 생성 시점이 task-2366 머지 전이라 main이 진보하면 main..HEAD diff에 미팅 파일 같은 본 task 외 파일이 포함됨
- **해결**: `git rebase main`으로 진보분 흡수. diff 13개 파일 (모두 본 task 산출물).

---

## 후속 task (P1~P3) 위임 권장

- **task-XXX (P1)**: Tiered Auto-Merge + Audit Log + Health Probe + Circuit Breaker — dev1 또는 dev7
- **task-XXX (P2)**: Telegram inline button + Daily Digest + 랜덤 10% 인간 검토 — dev1 또는 dev3
- **task-XXX (P3)**: Dashboard 권한/사고 시각화 — dev6 또는 dev2

P0 머지 후 1주 운영 지표 측정 (capability 거부 건수, scope-violation 발생률, legacy `--allow-no-scope` 우회 건수, scope-guard 평균 소요 시간) 후 P1 위임.

---

## 회장 검증 요청 (Phase 1 게이트)

- [ ] task-2360 사고 시뮬레이션 차단 확인 (보고서 L1.1 결과 + scope-violation.json 검토)
- [ ] 시스템 3문서 검토 (`memory/plans/bot-capability-system/`)
- [ ] CLAUDE.md 5대 규칙 검토
- [ ] 본 PR 머지 승인 → P1/P2/P3 후속 위임 승인

---

## 참조

- 미팅: `memory/meetings/2026-05-02-bot-anu-automation-safety.md`
- 사고 사례: `memory/reports/task-2360.md`
- 스펙: `memory/specs/bot-capability-model.md`
- 시스템 3문서: `memory/plans/bot-capability-system/`
- 본 task 3문서: `memory/plans/tasks/task-2364/`
- Codex 게이트 결과: `memory/events/task-2364.codex-gate`
- Admin snapshot audit: `memory/events/task-2364.snapshot-admin-write.log`
