# task-2709 — allowed_resources.paths schema mismatch fix (DRAFT)

★ **DRAFT** — 회장 verbatim "수정 task 초안만 작성한다" 정합. dispatch.py / scripts/task-scope-guard.sh 양 layer schema mismatch root cause 해소. **ANU 자체 dispatch 0** · 코드 수정 0 · 회장 별도 인가 대기.

---

## 0. Header / Authorization Anchor

- **task_id**: `task-2709`
- **task_type**: `system_hook` (★ dispatch.py + scope-guard 양 layer 수정 영역)
- **chair_authorization_id**: `CHAIR-AUTH-TASK-2709-ALLOWED-RESOURCES-PATHS-SCHEMA-FIX-260529` (★ 회장 verbatim 후보)
- **dispatch_status**: **NOT_DISPATCHED** (★ 회장 verbatim '자동 발사 금지')
- **executor_team_candidate**: `dev1-team` (헤르메스 · Hermes) (★ 회장 결정)
- **verifier_team_candidate**: `dev2-team` (오딘 · Odin) (★ task-2709+1 별도)
- **anu_collector_key**: `c119085addb0f8b7`

---

## 1. Problem Statement

`memory/capabilities/task-2707.json` 및 `task-2708.json` 의 `allowed_resources.paths` 값 = `null` · `scripts/task-scope-guard.sh` 가 `paths` key 만 read 하므로 모든 changed file 이 `paths 미포함` false positive 로 flag → scope-guard FAIL → finish-task L451 exit 1 → callback registration 미도달.

---

## 2. Root Cause (★ read-only evidence)

### 2.1 task md schema 차이

| task | task md `allowed_resources` keys | capability snapshot `paths` |
|---|---|---|
| `task-2706` | `paths` / `forbidden_paths` / `commands` / `merge_policy` / `ttl_hours` | **list 박힘** (★ 정상) |
| `task-2707` | `expected_files` / `allowed_existing_file_edits` / `forbidden_paths` | **None** |
| `task-2708` | `expected_files` / `allowed_existing_file_edits` / `forbidden_paths` | **None** |

### 2.2 dispatch.py `_parse_allowed_resources` (L902)

- 동작: task md `allowed_resources:` 아래 dict 전체를 verbatim 박제 (★ task md keys 그대로)
- docstring spec: `paths: [...]` 형식 documented (★ task-2706 패턴)
- bug 아님 (★ spec 따라 동작) · 단 **cross-key normalization 부재**

### 2.3 `scripts/task-scope-guard.sh` (L63-65, L136-140)

- L64: `paths = ar.get("paths", [])`
- L136-140: `if not any(glob_match(p, file_path) for p in paths)` → 미매칭 시 `paths 미포함` violation
- bug 아님 (★ documented schema 정합) · 단 **`expected_files` / `allowed_existing_file_edits` fallback 부재**

### 2.4 root cause 종합

**양 layer cross-key normalization 부재 = BOTH** (★ §3 classification 정합)

- snapshot generator: task md의 `expected_files` / `allowed_existing_file_edits` keys 를 `paths` 로 normalize 미실행
- scope-guard: `paths` 비면 `expected_files` / `allowed_existing_file_edits` fallback 미실행
- 단독 layer 수정도 가능하지만 defense in depth 정합 = 양쪽 cross-key 정합 강제

---

## 3. Classification (★ 회장 verbatim 4 enum)

| enum | 판정 | rationale |
|---|---|---|
| A SNAPSHOT_GENERATOR_SCHEMA_BUG | REJECTED 단독 | snapshot generator 는 spec 따라 동작 · 단독 bug 아님 |
| B SCOPE_GUARD_SCHEMA_BUG | REJECTED 단독 | scope-guard 는 documented schema 정합 · 단독 bug 아님 |
| **C BOTH** | **★ SELECTED** | 양 layer cross-key normalization 부재 = defense in depth 정합 |
| D UNKNOWN | REJECTED | evidence 명확 (★ 3 capability snapshot + 2 source code 위치 verbatim) |

**verdict = C BOTH** (★ ANU 자체 결정 0 · 회장 verbatim 4 enum 매핑만)

---

## 4. Affected Files

| file | 수정 방향 |
|---|---|
| `dispatch/__init__.py` (★ L902 `_parse_allowed_resources` + L937 regex fallback) | task md keys `expected_files` / `allowed_existing_file_edits` → `paths` union normalization 추가 (★ 기존 `paths` key 사용 시 그대로 유지) |
| `scripts/task-scope-guard.sh` (★ L63-65 reader) | `paths` 비면 `expected_files` + `allowed_existing_file_edits` fallback read 추가 (★ cross-key OR) |

★ **양 layer 모두 backward compatible** — 기존 task-2706 (paths key) 정합 유지 + task-2707/2708 신규 keys 자동 정규화.

---

## 5. Allowed / Forbidden Files

### 5.1 expected_files (★ 회장 인가 후 수정)

1. `dispatch/__init__.py` (★ L902 + L937 modification)
2. `scripts/task-scope-guard.sh` (★ L63-65 modification)
3. `memory/reports/task-2709.md` (★ 보고서)
4. `memory/events/task-2709.formalization-commit-260529.json` (★ formalization marker)
5. `memory/events/task-2709.callback-envelope.json` (★ ANU envelope)
6. `tests/test_allowed_resources_paths_normalization.py` (★ 신규 regression test)

### 5.2 allowed_existing_file_edits

- `dispatch/__init__.py` (★ §4 verbatim · 회장 인가 후)
- `scripts/task-scope-guard.sh` (★ §4 verbatim · 회장 인가 후)

### 5.3 forbidden_files (★ 강제 sha256 동일)

- `scripts/finish-task.sh`
- `scripts/session-watchdog.sh`
- `.claude/settings.json` / `/home/jay/.claude/settings.json`
- `scripts/harness/v36/dispatch_marker_writer.py`
- `scripts/harness/v36/callback_preregistration.py` (★ P2-A 산물 보존)
- `dispatch/normal_fallback_callback_helper.py`
- `qc_verify.py`
- `utils/merge_queue_executor.py` / `utils/real_merge_hooks.py`
- `anu_v3/`
- `memory/capabilities/**` (★ 기존 snapshot 보존)

### 5.4 forbidden_actions (★ 회장 verbatim 8 강제)

1. 코드 수정 금지 (★ §5.1/5.2 scope 외)
2. finish-task.sh 수정 금지
3. settings.json 수정 금지
4. `.done` 생성 금지
5. callback cron 수동 생성 금지
6. PR / branch push / merge 금지
7. GitHub write 금지
8. P2-B/C/D / P1-C 구현 / task-2710 자동 발의 금지

### 5.5 Capability Scope YAML (★ paths key explicit · task-2706 패턴 정합)

```yaml
allowed_resources:
  paths:
    - dispatch/__init__.py
    - scripts/task-scope-guard.sh
    - memory/reports/task-2709.md
    - memory/events/task-2709.formalization-commit-260529.json
    - memory/events/task-2709.callback-envelope.json
    - tests/test_allowed_resources_paths_normalization.py
  expected_files:
    - dispatch/__init__.py
    - scripts/task-scope-guard.sh
    - memory/reports/task-2709.md
    - memory/events/task-2709.formalization-commit-260529.json
    - memory/events/task-2709.callback-envelope.json
    - tests/test_allowed_resources_paths_normalization.py
  allowed_existing_file_edits:
    - dispatch/__init__.py
    - scripts/task-scope-guard.sh
  forbidden_paths:
    - scripts/finish-task.sh
    - scripts/session-watchdog.sh
    - .claude/settings.json
    - /home/jay/.claude/settings.json
    - scripts/harness/v36/dispatch_marker_writer.py
    - scripts/harness/v36/callback_preregistration.py
    - dispatch/normal_fallback_callback_helper.py
    - qc_verify.py
    - utils/merge_queue_executor.py
    - utils/real_merge_hooks.py
    - anu_v3/
    - memory/capabilities/**
```

★ `paths` key explicit 포함 = task-2706 baseline schema 정합 + task-2709 자체 dogfooding (★ task-2709 가 fix 하려는 schema 본인부터 정합)

---

## 6. Regression Scenarios

### RS-1 — backward compatibility (task-2706 baseline)

- **setup**: task-2706.json (paths: list 박힘)
- **expected**: scope-guard PASS · 기존 동작 100% 유지 · paths key 그대로 read

### RS-2 — forward compatibility (task-2707/2708 신규 keys)

- **setup**: task md 가 `expected_files` + `allowed_existing_file_edits` 만 사용
- **expected**: snapshot generator → `paths` = `expected_files ∪ allowed_existing_file_edits` 자동 union · scope-guard PASS

### RS-3 — task-2708 replay

- **setup**: task-2708.json paths=null 재현 + 봇 commit b8f9276..HEAD diff
- **expected**: paths normalization 후 봇 8 in-scope files 모두 paths 매칭 → false positive 0

### RS-4 — forbidden_paths 우선순위 정합

- **setup**: forbidden_paths 매칭 파일 + paths fallback 정합
- **expected**: forbidden_paths 우선 (★ L121 verbatim 정합) · paths fallback 적용해도 forbidden 강제 유지

### RS-5 — mixed schema (paths + expected_files)

- **setup**: task md 가 paths + expected_files 둘 다 사용
- **expected**: paths 우선 + expected_files union (★ deterministic merge)

---

## 7. Acceptance Criteria

1. ★ §4 양 layer minimal modification (★ 추정 ≤ 50 lines total)
2. ★ §6 RS-1~5 모두 PASS
3. ★ existing harness regression 0 (★ task-2706/2707/2708 capability snapshot 회귀 0)
4. ★ forbidden_files sha256 동일 (★ §5.3)
5. ★ forbidden_actions 8 위반 0
6. ★ task-2708 case replay 시 scope-guard PASS (★ infra defect 1 해소)
7. ★ GitHub write 0 / PR 0 / branch push 0 / merge 0

---

## 8. Rollback Plan

- **trigger**: regression 5 중 1건 FAIL · OR forbidden_files sha 변화 감지 · OR task-2706 baseline 회귀 발생
- **action**: `git reset --hard` 본 task commits 직전 (★ 봇 자체 commits 만) · `.escalate` marker + 회장 보고
- **forbidden_rollback_actions**: P2-A 산물 (task-2708 commits b8f9276~619db04) revert 0 · task-2707 산물 revert 0 · main..HEAD 재구성 0

---

## 9. P2-A / task-2708 lineage 영향

| lineage | 영향 |
|---|---|
| P2-A accepted with known caveats | ★ 보존 (★ revert 0) · §6 RS-3 가 task-2708 case 회복 가능성 확인 |
| task-2708 IMPLEMENTATION_COMPLETE_BUT_COMPLETION_BLOCKED_BY_INFRASTRUCTURE | ★ 보존 · 본 task 후 finish-task.sh 재실행 → callback registration 정상 회복 가능성 (★ 회장 결정 영역) |
| task-2707 IMPLEMENTATION_PASS_ROUTING_FAIL | ★ 보존 (★ 동일 schema mismatch 영향 가능성) |
| C1 closeout / P1-A / P1-B / P2-A accepted markers | ★ 모두 보존 · revert 0 |
| infra defect 2 (shared branch contamination) | ★ 별도 (★ 본 task 영역 외 · 회장 verbatim '별도 infra defect 후보로 보존') |

---

## 10. Callback Envelope Schema

```json
{
  "task_id": "task-2709",
  "chair_authorization_id": "CHAIR-AUTH-TASK-2709-ALLOWED-RESOURCES-PATHS-SCHEMA-FIX-260529",
  "executor": "dev1-team / 헤르메스",
  "collector_role": "ANU",
  "collector_key": "c119085addb0f8b7",
  "result_path": "memory/events/task-2709.formalization-commit-260529.json",
  "report_path": "memory/reports/task-2709.md",
  "rs_pass_count": "<N>/5",
  "summary_one_line": "allowed_resources.paths schema mismatch fix · BOTH layer cross-key normalization · regression N/5 PASS"
}
```

★ envelope UTF-8 byte ≤ 3900 hard limit.

---

## 11. Safe-Fail Strategy

- 모든 step unexpected error → 즉시 멈춤 + `.escalate`
- forbidden_files sha 변화 감지 → 즉시 멈춤 + `.escalate`
- §6 RS 1건이라도 FAIL → 즉시 멈춤 + `.escalate`
- §4 양 layer modification 라인 수 > 50 감지 → 즉시 멈춤 + 회장 재인가 요청

---

## 12. Out-of-Scope (★ 회장 verbatim 강제)

- ★ infra defect 2 (shared branch contamination / system_hook worktree isolation) 별도 task
- ★ P2-B (all-exit-path callback finalizer) 별도 task
- ★ P2-C (idempotency marker hardening) 별도 task
- ★ P2-D (task_type aware fail-fast routing) 별도 task
- ★ P1-C (actor attribution) 별도 task
- ★ task-2710 자동 발의 0

---

## 13. ANU Doctrine Compliance

- ★ ANU 자체 task-2709 dispatch 0 (★ 회장 verbatim '자동 발사 금지')
- ★ ANU 자체 코드 수정 0 / finish-task.sh 수정 0 / settings.json 수정 0
- ★ ANU 자체 callback cron 수동 등록 0 / `.done` 생성 0
- ★ ANU 자체 PR / branch push / merge / GitHub write 0
- ★ ANU 자체 분류 결정 0 (★ §3 classification 회장 verbatim 4 enum 매핑만)
- ★ ANU 자체 task-2710 자동 발의 0
- ★ lineage rewrite 0

---

## 14. Linked Markers

- `memory/events/p2a_callback_before_failfast_pre_registration_layer_accepted_with_known_caveats_chair_closeout_260529.json` (★ P2-A closeout)
- `memory/events/task-2708.escalate` + `task-2708.escalation-detail-260529.json` + `task-2708.scope-violation.json` (★ infra defect 1 evidence)
- `memory/capabilities/task-2706.json` (★ paths key 정상 박힘 baseline)
- `memory/capabilities/task-2707.json` / `memory/capabilities/task-2708.json` (★ paths=null evidence)
- `dispatch/__init__.py` L902 + L937 (★ snapshot generator source verbatim)
- `scripts/task-scope-guard.sh` L63-65 + L136-140 (★ scope-guard reader source verbatim)
- `memory/tasks/task-2708_v2.md` / `memory/tasks/task-2708.md` (★ task-2708 task md)
- `memory/tasks/task-2706.md` (★ paths key baseline pattern)

---

## 15. Chair Decision Pending (★ 회장 결정 6 영역)

1. ★ 본 초안 승인 여부 (★ §4 BOTH layer cross-key normalization 정합)
2. ★ chair_authorization_id 최종 확정
3. ★ §4 dispatch.py + scripts/task-scope-guard.sh 수정 인가 (★ 회장 별도 인가 필수)
4. ★ executor dev1 헤르메스 dispatch 인가
5. ★ §6 RS-1~5 정합 확인
6. ★ task-2709+1 verifier (dev2 오딘) 발사 인가 — 본 task 종료 후 별도

---

## 16. Sentinel

★ 본 task-2709 = infra defect 1 fix DRAFT. 회장 별도 인가 전 dispatch 0 · 코드 수정 0 · finish-task.sh 수정 0 · settings.json 수정 0 · `.done` 0 · cron 수동 0 · PR/push/merge 0 · GitHub write 0. 끝