# Bot Capability Model — 스키마 / 사용 가이드

**도입일**: 2026-05-02
**근거**: `memory/meetings/2026-05-02-bot-anu-automation-safety.md`
**관련 task**: task-2364 (P0 본 task)

---

## 1. 목적

봇 자율 판단 오작동(task-2360 codegraph cron 사고)을 시스템 레벨에서 차단한다.
모든 task 파일에 명시적 `allowed_resources` capability를 선언하고,
dispatch (사전) + finish-task (사후) 이중 게이트로 강제한다.

## 2. 스키마

### 2.1 위치

task 파일(`memory/tasks/{task_id}.md`) 본문 어딘가에 fenced code block (yaml) 형태로 인라인.

```markdown
## allowed_resources (본 task의 capability)

\`\`\`yaml
allowed_resources:
  paths:
    - "scripts/finish-task.sh"
    - "memory/plans/bot-capability-system/**"
  forbidden_paths:
    - "memory/events/*.cron-*"
    - ".github/**"
  commands:
    - "pytest"
    - "python3 -m py_compile"
  merge_policy: "tiered"
  ttl_hours: 48
\`\`\`
```

### 2.2 필드 정의

| 필드 | 타입 | 필수 | 의미 |
|------|------|------|------|
| `paths` | `list[str]` (glob) | ✅ | 작업 가능 파일 화이트리스트. recursive glob `**` 허용. |
| `forbidden_paths` | `list[str]` (glob) | ⚠️ 권장 | 보호 경로 블랙리스트. paths에 일치해도 차단. |
| `commands` | `list[str]` | ⚠️ 권장 | 실행 가능 명령. **P0: 정보 표시 + audit log만**, P1+ shell wrapper로 enforce 예정. (Codex high 지적 반영: P0는 paths-only PoC) |
| `merge_policy` | `"auto"` / `"tiered"` / `"manual"` | ✅ | 머지 정책. P0 시점에서는 표시만, P1+ Tiered Auto-Merge에서 enforce |
| `ttl_hours` | `int` | ⚠️ 권장 | capability 만료 시간 (긴 task 안전판). 미지정 시 24h 기본. |

### 2.3 글로브 매칭 규칙

- `*`: 단일 디렉토리 내 와일드카드 (예: `scripts/cron_*.py`)
- `**`: 모든 하위 디렉토리 재귀 (예: `memory/plans/foo/**`)
- 절대 경로 금지. 모두 workspace root(`/home/jay/workspace`) 상대 경로.
- forbidden_paths가 paths보다 우선 (블랙리스트 우선 원칙)

### 2.4 시스템 자동 파일 무시 (scope-guard 적용 제외)

다음은 봇 의도와 무관한 시스템 자동 변경이므로 scope-guard에서 무시한다 (finish-task git-gate와 동일):

```
memory/heartbeats/
memory/events/
memory/daily/
memory/logs/
memory/reports/
memory/tasks/{본 task}.md
logs/
whisper/
bot-activity.json
token-ledger.json
memory/pipeline-status.json
memory/preview-state.json
memory/merge-log.json
memory/bot_settings_sync.json
memory/memory-check-log.json
memory/task-timers.json
memory/canary-status.json
.heartbeat
memory/.task-counter
config/constants.json
scripts/gemini_rate_tracker.json
tests/coverage-report.txt
```

## 3. 게이트 동작

### 3.1 dispatch.py 사전 검증 + Immutable Snapshot

- task 파일 파싱 시 `allowed_resources` YAML 추출 (fenced yaml block 안의 `allowed_resources:` 키)
- 미명시 시:
  - `--allow-no-scope` 플래그 없으면 거부 (exit 1) + 명확한 에러 메시지
  - `--allow-no-scope` 플래그 있으면 통과 + `memory/events/{task_id}.allow-no-scope.log` 이벤트 생성 (audit trail)
- capability **immutable snapshot**을 `memory/capabilities/{task_id}.json`에 저장:
  ```json
  {
    "task_id": "task-XXXX",
    "captured_at": "2026-05-02T17:30:00+09:00",
    "source": "memory/tasks/task-XXXX.md",
    "source_sha256": "abc123...",
    "allowed_resources": { "paths": [...], "forbidden_paths": [...], ... }
  }
  ```
- snapshot은 자동으로 forbidden_paths에 `memory/capabilities/**`가 추가되어 봇이 변조 불가
- task-scope-guard.sh는 task 파일이 아니라 **snapshot 파일만 읽음** (Codex critical 지적 반영)

### 3.2 task-scope-guard.sh 런타임 검증

```bash
bash scripts/task-scope-guard.sh <task_id> <git_diff_files_path>
```

- **`memory/capabilities/{task_id}.json` snapshot에서 `allowed_resources` 로드** (task 파일 직접 읽지 않음)
- snapshot 미존재 → 명시적 안내 메시지 + exit 1 (`--allow-no-scope`로 dispatch된 task는 별도 처리: legacy 마커 확인 후 통과)
- 입력 파일은 git diff --name-only 결과 (한 줄 한 파일)
- 시스템 자동 파일 무시 후 위반 파일 식별 (4.4 무시 목록 참조)
- 위반 1건 이상 시 exit 1 + `memory/events/{task_id}.scope-violation.json`
- 위반 0건 시 exit 0

### 3.3 finish-task.sh 사전 검증 (머지 *직전*)

위치: **QC 통과 직후 + 머지 직전 (Step 1.6 신규)**. 머지 후 검증은 이미 main 오염이라 의미 없음 (Codex high 지적 반영).

- 워크트리 브랜치에서 `git diff --name-only main..HEAD` 추출 (병합 전 diff)
- `task-scope-guard.sh` 호출
- 위반 시:
  - **머지 차단** (worktree_manager.py finish 호출 전 exit 1)
  - `memory/events/{task_id}.escalate` 마커 생성
  - `memory/events/{task_id}.scope-violation.json` 기록
  - 봇→아누 알림 cron 발사
- non-code task → 검증 스킵 (`## 레벨` 섹션의 "코드 수정 없음/문서만" 키워드)
- PROJECT_PATH 미지정인 시스템 task (예: `dispatch.py`, `scripts/finish-task.sh` 변경) → **workspace root 자체를 PROJECT_PATH로 사용**. 시스템 인프라 task가 가장 위험하므로 절대 스킵 금지 (Codex high 지적 반영).

### 3.4 위반 이벤트 파일 포맷

`memory/events/{task_id}.scope-violation.json`:
```json
{
  "task_id": "task-XXXX",
  "violations": [
    {"path": "scripts/cron_settings.json", "matched_forbidden": "memory/events/*.cron-*"},
    {"path": "config/secrets.json", "not_in_paths": true}
  ],
  "timestamp": "2026-05-02T17:30:00+09:00",
  "reason": "scope_guard_violation"
}
```

## 4. 작성 가이드

### 4.1 paths 좁게 유지

```yaml
# ❌ 너무 광범위 — scope guard 무력화
paths:
  - "**/*.py"
  - "**"

# ✅ 명시적 + 좁은 디렉토리
paths:
  - "scripts/task-scope-guard.sh"
  - "scripts/finish-task.sh"
  - "memory/plans/bot-capability-system/**"
```

### 4.2 forbidden_paths로 보호 경로 명시

```yaml
forbidden_paths:
  - "memory/events/*.cron-*"            # 다른 task의 cron 보호
  - "memory/events/task-*.completion.txt"  # 다른 task 완료 보고 보호
  - ".github/**"                          # GitHub Actions 변경 금지
  - "secrets/**"                          # 비밀 키 보호
  - "config/constants.json"               # 시스템 상수 보호
```

### 4.3 merge_policy 선택 기준 (P1+ enforce)

- `auto`: Lv.0-1, scope 명확, 빌드 PASS 보장 가능 → 자동 머지
- `tiered`: Lv.2, 다중 파일, 의존성 → 1-tap 승인
- `manual`: Lv.3+, 인프라, 외부 키 → 회장 명시 승인

## 5. 점진적 마이그레이션 (P0)

1. **신규 dispatch부터 강제**: 신규 task 파일은 capability 필수
2. **진행 중 task grace**: 본 P0 머지 시점에 진행 중인 task는 `--allow-no-scope`로 우회 허용 (1주)
3. **legacy task 일괄 업데이트**: P1 진입 전 마이그레이션 task 별도 위임

## 6. 테스트 시나리오

| 시나리오 | 입력 | 기대 결과 |
|----------|------|-----------|
| codegraph cron 사고 재현 | task `paths: ["scripts/finish-task.sh"]` + 봇이 `memory/events/cron-CC712188.json` 수정 | exit 1 + `.scope-violation.json` |
| 정상 흐름 | scope 내 변경만 | exit 0 |
| forbidden 우선 | paths matches but forbidden_paths matches | exit 1 (forbidden 우선) |
| legacy 호환 | capability 없는 task + `--allow-no-scope` | exit 0 + 경고 |
| 시스템 자동 파일 | `memory/heartbeats/foo.json` 변경만 | exit 0 (무시) |
| dispatch 거부 | 신규 task capability 미명시 | dispatch.py exit 1 |

## 7. 관련 파일

- 구현: `scripts/task-scope-guard.sh`, `dispatch.py`, `scripts/finish-task.sh`
- 시스템 3문서: `memory/plans/bot-capability-system/`
- 위임 완결성 5대 규칙: `CLAUDE.md` (P0 추가)
- 미팅 합의: `memory/meetings/2026-05-02-bot-anu-automation-safety.md`
