# task-2712 — FAILURE_CALLBACK_BEFORE_EXIT_GUARD (DRAFT)

★ **DRAFT ONLY** — 회장 verbatim "이번 단계: task-2712 draft만 준비한다 · 실제 코드 구현은 아직 하지 않는다 · finish-task.sh 변경은 아직 하지 않는다 · dispatch / PR / push / merge / GitHub write 금지" 정합. dispatch 0 · 코드 구현 0 · finish-task.sh 변경 0 · 회장 별도 인가 대기.

---

## 0. Header / Authorization Anchor

- **task_id**: `task-2712`
- **task_type**: `system_hook` (★ 향후 finish-task.sh + harness lifecycle 변경 영역 · 본 단계는 read-only design only)
- **chair_authorization_id**: `<CHAIR_TO_ASSIGN>` (★ 회장 별도 결정 영역 · task-2710 / task-2711 chair_authorization_id 재사용 0 strict)
- **dispatch_status**: **NOT_DISPATCHED · DRAFT_ONLY**
- **executor_team_candidate**: `<CHAIR_TO_DECIDE>` (★ 회장 결정 영역)
- **verifier_team_candidate**: `<CHAIR_TO_DECIDE>` (★ task-2712+1 분리 · 회장 결정 영역)
- **anu_collector_key**: `c119085addb0f8b7`
- **callback_envelope_prompt_byte_limit**: UTF-8 ≤ 3900 bytes hard (★ wc -c)

---

## 1. Problem Statement (★ task-2711 사고 박제 + 회장 verbatim)

### 1.1 task-2711 사례 박제

- 봇 = dev1 헤르메스 정상 작업 완료 (★ 4 commits · 15/15 산출물 · 18/18 PASSED · 1,220 bytes ANU envelope 박제)
- `finish-task.sh` 가 scope-guard FAIL 시 **L451 exit 1** 로 종료 → **L1550 callback registration 단계 도달 0**
- 결과: ANU key cron 0 · ANU 가 봇 상태 / callback / 작업 진행을 **session-bound polling 으로 직접 추적** 필요
- 부작용 1: ANU 가 `silent drop 4신호` 만으로 `봇 spawn 0` 오판 (★ task-2711 직전 사고)
- 부작용 2: ANU 가 `callback 대기` 표현 = `ANU 직접 CI/Gemini 대기 금지` doctrine 위반

### 1.2 회장 verbatim 문제 정의

> "현재 finish-task.sh는 scope-guard FAIL 시 exit 1로 종료하면서 ANU callback 등록 단계에 도달하지 못한다. 이로 인해 작업이 실패했는지, 봇이 죽었는지, callback 결선이 끊겼는지 ANU가 다시 추적해야 한다."

### 1.3 새 원칙 (★ 회장 verbatim 1:1)

> "callback은 성공 후 보상이 아니라 모든 terminal state를 ANU에 전달하는 mandatory lifecycle signal이다."

---

## 2. Goal

> 봇이 SUCCESS/FAILURE/BLOCKED/SCOPE_GUARD_FAIL/QC_FAIL/INFRA_DEFECT/PERMISSION_FAIL/API_FAIL/CRITICAL_ESCALATION 어떤 terminal state 로 종료되든 **exit 전에 반드시 failure envelope 또는 handoff marker를 disk 에 남기고**, ANU 가 session-bound polling 없이 회수 가능한 lifecycle 을 설계 + 구현.

---

## 3. Terminal State 9 (★ 회장 verbatim 1:1)

| # | terminal state | 정의 | callback / handoff |
|---|---|---|---|
| 1 | **SUCCESS** | 모든 phase PASS + finish-task.sh callback registration 완료 + `.done` 박제 자격 | normal callback (★ ANU key) + `.done` (★ 회장 verbatim 기존 정책 유지) |
| 2 | **FAILURE** | phase 1 이상 FAIL · 봇 self-judgment 실패 | failure envelope (★ ANU key) · `.done` 0 |
| 3 | **BLOCKED** | 외부 의존성 (★ chair decision / verifier 등) 으로 진행 0 | handoff envelope (★ ANU key) · `.done` 0 |
| 4 | **SCOPE_GUARD_FAIL** | finish-task.sh scope-guard violation | failure envelope (★ ANU key) · `.done` 0 |
| 5 | **QC_FAIL** | qc_verify.py 결과 FAIL (★ severity HIGH/CRITICAL) | failure envelope · `.done` 0 |
| 6 | **INFRA_DEFECT** | shared branch contamination / worktree corruption / capability snapshot null 등 infra | handoff envelope (★ ANU key) + infra defect classifier · `.done` 0 |
| 7 | **PERMISSION_FAIL** | 권한 (★ chair_authorization_id / forbidden_files / allowed_resources) 위반 | failure envelope + permission detail · `.done` 0 |
| 8 | **API_FAIL** | API 500 / 429 / network · 봇 자체 결함 0 | handoff envelope (★ recoverable 분류) · `.done` 0 |
| 9 | **CRITICAL_ESCALATION** | Critical 7 / 권한 확대 시도 / forbidden target 침해 / 기존 evidence 변경 시도 | failure envelope + Critical7 분류 + 즉시 회장 보고 · `.done` 0 |

### 3.1 .done 생성 정책 (★ 회장 verbatim "1. .done 생성은 성공/정상 closeout에서만 허용한다")

- **`.done` = SUCCESS 만** 박제 자격
- 다른 8 terminal state = `.done` 0 강제 · 별도 disk marker 만 박제
- SUCCESS 외 .done 강제 생성 시도 시 → `CRITICAL_ESCALATION` (★ §4.3 trigger 매칭)

---

## 4. Failure Callback Envelope Schema (★ 회장 verbatim 8 핵심 요구)

### 4.1 envelope 필수 field

```json
{
  "task_id": "task-NNNN(+M)",
  "team": "dev1-team",
  "bot": "bot-b (헤르메스)",
  "session": "<session_id>",
  "phase": "scope_guard | qc | finish_task | dispatch_entry | runtime | ...",
  "terminal_state": "SCOPE_GUARD_FAIL | FAILURE | BLOCKED | QC_FAIL | INFRA_DEFECT | PERMISSION_FAIL | API_FAIL | CRITICAL_ESCALATION",
  "exit_code": 1,
  "failure_kind": "scope_violation_count_NN | qc_severity_HIGH | infra_shared_branch_contamination | ...",
  "artifact_paths": [
    "memory/events/task-NNNN.scope-violation.json",
    "memory/events/task-NNNN.qc-result",
    "memory/events/task-NNNN.escalate",
    "..."
  ],
  "critical7_match": false,
  "critical7_classification": "n/a | doctrine_match_<X>",
  "collector_role": "ANU",
  "collector_key": "c119085addb0f8b7",
  "owner_key": "c119085addb0f8b7",
  "self_key_used": false,
  "registration_mode": "failure_callback_before_exit_guard",
  "recorded_at": "2026-MM-DDTHH:MM:SS+09:00",
  "summary_one_line": "<≤200 chars · failure 요약>"
}
```

### 4.2 byte limit (★ 회장 verbatim "7. failure envelope는 UTF-8 3900 bytes 이하로 제한")

- envelope 전체 UTF-8 ≤ 3900 bytes hard limit (`wc -c`)
- 초과 시 → artifact_paths 만 유지 + summary 축소 + 상세는 path 참조

### 4.3 mandatory fields (★ 회장 verbatim "8. task_id, bot/team/session, phase, exit_code, failure_kind, artifact_paths, critical7 여부를 포함")

| field | 필수 | 누락 시 |
|---|---|---|
| `task_id` | ★ YES | envelope 자체 INVALID |
| `team` / `bot` | ★ YES | INVALID |
| `session` | ★ YES (★ session_id 또는 PID) | INVALID |
| `phase` | ★ YES | INVALID |
| `exit_code` | ★ YES | INVALID |
| `failure_kind` | ★ YES (★ 분류 enum 또는 verbatim 사유) | INVALID |
| `artifact_paths` | ★ YES (★ 빈 리스트 허용 · 단 field 자체 존재 필수) | INVALID |
| `critical7_match` | ★ YES (★ boolean) | INVALID |
| `collector_role=ANU` / `collector_key=ANU key` | ★ YES | SELF_COLLECTOR_FORBIDDEN 위반 |

---

## 5. Terminal Failure Path Matrix (★ 회장 verbatim 3 "모든 terminal failure path는 exit 전에 failure envelope 또는 handoff marker를 남긴다")

### 5.1 finish-task.sh exit path matrix

| exit 지점 | 현재 동작 | task-2712 새 동작 |
|---|---|---|
| **L451 scope-guard FAIL exit 1** | ★ 즉시 exit | ★ **failure envelope 박제 (SCOPE_GUARD_FAIL) → ANU cron 발사 시도 → exit 1** |
| qc FAIL exit | 즉시 exit | failure envelope (QC_FAIL) → ANU cron → exit |
| capability snapshot null exit | 즉시 exit | handoff envelope (INFRA_DEFECT · paths_null) → ANU cron → exit |
| permission violation exit | 즉시 exit | failure envelope (PERMISSION_FAIL) → ANU cron → exit |
| forbidden path violation exit | 즉시 exit | failure envelope (CRITICAL_ESCALATION) → ANU cron → exit |
| API 500 timeout exit | 즉시 exit | handoff envelope (API_FAIL · recoverable) → ANU cron → exit |
| L1550 callback registration | normal callback | (★ SUCCESS 만) |
| `.done` 박제 | SUCCESS 시 | (★ SUCCESS 만 · 8 failure path 모두 0) |

### 5.2 dispatch.py entry path

| 지점 | 새 동작 |
|---|---|
| bot 충돌 detect | failure envelope (BLOCKED · bot_collision) + ANU cron → DISPATCH_FALSE_OK 차단 (★ task-2711 사고 박제) |
| capability snapshot 생성 실패 | failure envelope (INFRA_DEFECT) + ANU cron → exit |
| task md 누락 | failure envelope (PERMISSION_FAIL · task_md_missing) → exit |

### 5.3 봇 runtime path

| 지점 | 새 동작 |
|---|---|
| Critical 7 doctrine 매칭 | failure envelope (CRITICAL_ESCALATION) + 즉시 ANU cron → exit |
| forbidden target write 시도 | failure envelope (CRITICAL_ESCALATION) → exit |
| infra defect detect (★ shared branch contamination 등) | handoff envelope (INFRA_DEFECT) → ANU cron → exit |

---

## 6. callback 등록 실패 시 fallback (★ 회장 verbatim 4 "callback 등록 자체가 실패해도 disk marker를 남긴다")

### 6.1 cron 등록 실패 fallback chain

```
Step 1: failure envelope JSON disk 박제 (★ memory/events/task-NNNN.failure-envelope.json)
    ↓ 성공 시 next
Step 2: ANU cron 발사 시도 (★ /usr/local/bin/cokacdir --cron --chat 6937032012 --key c119085addb0f8b7)
    ↓ cron 등록 실패 시
Step 3: disk handoff marker 박제 (★ memory/events/task-NNNN.failure-handoff-marker.json) — failure envelope path + cron 실패 사유 명시
    ↓ disk marker 박제 성공 시
Step 4: exit (★ exit_code 유지)
```

### 6.2 ANU 회수 path (★ 회장 verbatim 6 "ANU가 session-bound polling 없이 회수할 수 있어야 한다")

- ANU 가 `memory/events/task-NNNN.failure-envelope.json` 또는 `memory/events/task-NNNN.failure-handoff-marker.json` 을 **disk scan** 으로 회수
- session-bound polling 0 강제 — 별도 watcher 또는 ANU 시작 시 backlog scan
- 회수 우선순위: cron callback > disk envelope > disk handoff marker

### 6.3 SELF_COLLECTOR_FORBIDDEN 정합 (★ 회장 verbatim 5 "SELF_COLLECTOR_FORBIDDEN을 위반하지 않는다")

- failure envelope 의 `collector_role` = **ANU strict**
- `collector_key` = **`c119085addb0f8b7`** (ANU key) strict
- 봇 self-key (dev1=c38fb9955616e24d 등) 사용 시 → **SELF_COLLECTOR_FORBIDDEN** + `CRITICAL_ESCALATION` 박제
- 봇이 자기 cron 으로 callback 발사 시도 → **SELF_COLLECTOR_VERIFICATION_FORBIDDEN**
- ★ `feedback_callback_must_spawn_independent_anu_not_executor_self_260518.md` doctrine verbatim 정합

---

## 7. task-2711 scope-guard FAIL Fixture (★ 회장 verbatim "task-2711 scope-guard FAIL 사례 fixture")

### 7.1 input fixture

```json
{
  "task_id": "task-2711",
  "team": "dev1-team",
  "bot": "bot-b (헤르메스)",
  "session": "A82719AF",
  "phase": "finish_task.sh scope_guard L451",
  "terminal_state": "SCOPE_GUARD_FAIL",
  "exit_code": 1,
  "failure_kind": "scope_violation_count_61_main_to_HEAD_contamination",
  "artifact_paths": [
    "memory/events/task-2711.scope-violation.json",
    "memory/events/task-2711.escalate",
    "memory/events/task-2711.scope-diff.txt",
    "memory/events/task-2711.formalization-commit-260530.json",
    "memory/events/task-2711.callback-envelope.json",
    "memory/reports/task-2711.md",
    "scripts/anu/codex_review_loop_decider.py",
    "tests/test_codex_review_loop_decider_2711.py"
  ],
  "critical7_match": false,
  "critical7_classification": "n/a (★ task-2711 self-diff 13 files / 1159 insertions / 0 forbidden modifications · scope-guard FAIL 원인 = task-2703 shared branch contamination 66 files · task-2711 자체 결함 0)",
  "collector_role": "ANU",
  "collector_key": "c119085addb0f8b7",
  "owner_key": "c119085addb0f8b7",
  "self_key_used": false,
  "registration_mode": "failure_callback_before_exit_guard",
  "recorded_at": "2026-05-30T06:25:35+09:00",
  "summary_one_line": "task-2711 scope_guard FAIL · 61 violations 중 task-2711 self 0 · contamination 66 = task-2703 shared branch · IMPLEMENTATION_COMPLETE_DIRECT_RECOVERY_READY · ANU 회장 보고 권고"
}
```

### 7.2 byte size

- envelope UTF-8 byte 추정: ~1,400~1,800 bytes (★ ≤ 3,900 정합)

### 7.3 fixture 적용 결과 (★ 가상)

- task-2712 enforce 적용 시: scope-guard FAIL → 본 envelope disk 박제 → ANU cron 발사 → ANU 가 회장 보고 (★ session-bound polling 0)
- ANU 가 "silent drop 4신호" 오판 0 (★ failure envelope 명시적 회수)

---

## 8. Architecture (★ draft level)

### 8.1 새 module 후보

| module | path | 역할 |
|---|---|---|
| `failure_envelope_writer.py` | `scripts/harness/v36/failure_envelope_writer.py` | envelope JSON 박제 + byte limit 강제 + mandatory field check |
| `failure_callback_dispatcher.py` | `scripts/harness/v36/failure_callback_dispatcher.py` | ANU cron 발사 + 실패 시 disk handoff marker fallback |
| `terminal_state_classifier.py` | `scripts/harness/v36/terminal_state_classifier.py` | 9 terminal state enum 분류 + Critical 7 매칭 |
| `before_exit_guard_hook.sh` | `scripts/harness/v36/before_exit_guard_hook.sh` | finish-task.sh / dispatch.py 의 모든 exit path 전 hook |

### 8.2 finish-task.sh 통합 지점 (★ 향후 구현 영역)

- L451 scope-guard FAIL: `before_exit_guard_hook.sh SCOPE_GUARD_FAIL "$task_id" $exit_code` 호출 후 exit
- qc FAIL: 동일 hook + QC_FAIL
- 기타 8 terminal state 동일 패턴

### 8.3 dispatch.py 통합 지점 (★ 향후 구현 영역)

- bot 충돌 detect 후 exit 직전: `before_exit_guard_hook.sh BLOCKED "$task_id" 0` (★ DISPATCH_FALSE_OK 차단)
- capability snapshot null exit 전: `INFRA_DEFECT`

---

## 9. Affected Files (★ 회장 인가 후 작성)

### 9.1 신규 산출물 (★ 향후 dispatch 단계)

1. `scripts/harness/v36/failure_envelope_writer.py`
2. `scripts/harness/v36/failure_callback_dispatcher.py`
3. `scripts/harness/v36/terminal_state_classifier.py`
4. `scripts/harness/v36/before_exit_guard_hook.sh`
5. `tests/test_failure_callback_before_exit_guard_2712.py`
6. `tests/fixtures/failure_callback_2712/task-2711_scope_guard_fail.json` (★ §7.1)
7. `tests/fixtures/failure_callback_2712/qc_fail.json`
8. `tests/fixtures/failure_callback_2712/infra_defect_paths_null.json`
9. `tests/fixtures/failure_callback_2712/permission_fail.json`
10. `tests/fixtures/failure_callback_2712/critical7_match.json`
11. `tests/fixtures/failure_callback_2712/api_fail_recoverable.json`
12. `tests/fixtures/failure_callback_2712/blocked_bot_collision.json`
13. `tests/fixtures/failure_callback_2712/cron_registration_failure_fallback.json`
14. `schemas/failure_envelope_schema.json`
15. `memory/reports/task-2712.md`
16. `memory/events/task-2712.formalization-commit-260530.json`
17. `memory/events/task-2712.callback-envelope.json`

**총 17 expected_files**

### 9.2 변경 대상 (★ 향후 dispatch 단계 · 회장 별도 인가)

- `scripts/finish-task.sh` (★ exit path 마다 before_exit_guard_hook 통합 · 회장 별도 인가)
- `dispatch.py` (★ bot 충돌 + DISPATCH_FALSE_OK 차단 · 회장 별도 인가)

**★ 본 draft 단계는 finish-task.sh / dispatch.py 변경 0**

---

## 10. Allowed / Forbidden Files

### 10.1 expected_files (★ 본 draft 단계)

1. `memory/tasks/task-2712_draft.md` (★ 본 file)

### 10.2 allowed_existing_file_edits (★ 본 draft 단계)

- **NONE** (★ draft only · 코드 변경 0)

### 10.3 forbidden_files (★ 본 draft 단계 + 향후 dispatch 단계 강제)

- `scripts/finish-task.sh` (★ 본 draft 단계는 0 변경 · 향후 dispatch 단계는 회장 별도 인가)
- `dispatch.py` / `dispatch/__init__.py` / `dispatch/normal_fallback_callback_helper.py` (★ 동일)
- `bot_settings.json` / `memory/bot_settings.json`
- `.claude/settings.json` / `/home/jay/.claude/settings.json`
- `scripts/session-watchdog.sh`
- `scripts/task-scope-guard.sh`
- `qc_verify.py`
- `utils/merge_queue_executor.py` / `utils/real_merge_hooks.py`
- `anu_v3/`
- `memory/capabilities/**`
- task-2706~2709+1 모든 산출물 (★ immutable historical evidence)
- `memory/tasks/task-2710.md` / `task-2710_v2~v8.md` (★ final LOCKED)
- task-2710 모든 marker
- task-2711 모든 산출물 (★ task-2711 사례 fixture 박제만 · 산출물 자체 변경 0)

### 10.4 forbidden_actions (★ 회장 verbatim 8 강제 · 본 draft 단계)

1. 실제 코드 구현 0
2. finish-task.sh 변경 0
3. dispatch.py 변경 0
4. settings.json 변경 0
5. bot_settings.json 변경 0
6. PR / push / merge / GitHub write 0
7. dispatch / pilot dispatch 0
8. task-2710 / task-2706~2709+1 evidence 변경 0

### 10.5 chair_authorization_id 분리 강제 (★ 회장 verbatim)

- task-2712 chair_authorization_id = `<CHAIR_TO_ASSIGN>` placeholder (★ 회장 결정 영역)
- task-2710 / task-2711 chair_authorization_id 재사용 0 strict
- 권장 형식: `CHAIR-AUTH-TASK-2712-FAILURE-CALLBACK-BEFORE-EXIT-GUARD-260XXX`

---

## 11. Acceptance Criteria

### 11.1 본 draft 단계 (★ 본 round)

1. ★ task-2712 draft md 1 file 작성 (★ §10.1)
2. ★ 코드 구현 0 / finish-task.sh 변경 0 / dispatch.py 변경 0
3. ★ task-2710 / task-2711 evidence 변경 0
4. ★ task-2706~2709+1 evidence 변경 0
5. ★ chair_authorization_id placeholder 명시 (★ 회장 결정 영역)
6. ★ task-2711 fixture (★ §7.1) 박제

### 11.2 향후 dispatch 단계 (★ 회장 별도 인가 후)

1. §9.1 신규 산출물 17 작성
2. §9.2 finish-task.sh / dispatch.py 변경 (★ 회장 별도 인가)
3. §3 9 terminal state classifier 정합
4. §4 envelope schema 정합 + mandatory field 9 강제
5. §4.2 UTF-8 ≤ 3900 bytes hard limit
6. §5 terminal failure path matrix 정합
7. §6 cron 등록 실패 fallback chain 정합
8. §6.3 SELF_COLLECTOR_FORBIDDEN 위반 0
9. §7 task-2711 fixture 적용 결과 정합 (★ regression test)
10. §12 regression test 8/8 PASS
11. forbidden_files sha256 동일 (★ §10.3)
12. forbidden_actions 8 위반 0

---

## 12. Regression Test 후보 (★ 향후 dispatch 단계)

### 12.1 9 terminal state 각각 1 fixture (★ §9.1 #6~#13)

| test ID | terminal_state | fixture |
|---|---|---|
| T-1 | SCOPE_GUARD_FAIL | task-2711 fixture (§7.1) |
| T-2 | QC_FAIL | qc_fail.json |
| T-3 | INFRA_DEFECT | infra_defect_paths_null.json (★ task-2709 사고 정합) |
| T-4 | PERMISSION_FAIL | permission_fail.json |
| T-5 | CRITICAL_ESCALATION | critical7_match.json |
| T-6 | API_FAIL | api_fail_recoverable.json (★ task-2709+1 API 500 정합) |
| T-7 | BLOCKED | blocked_bot_collision.json (★ task-2711 bot-b busy 정합) |
| T-8 | cron 등록 실패 fallback | cron_registration_failure_fallback.json |

### 12.2 SUCCESS path regression (★ 기존 동작 0 변경 확인)

- SUCCESS 시 normal callback + `.done` 박제 (★ 기존 동작)
- 8 failure path 중 어떤 것도 SUCCESS path 동작 변경 0

### 12.3 SELF_COLLECTOR_FORBIDDEN regression

- envelope `collector_key` 가 ANU key 외일 때 → `CRITICAL_ESCALATION` + reject
- 봇 self-cron callback 시도 → reject

### 12.4 byte limit regression

- envelope > 3900 bytes 시 → reject 또는 자동 압축 (★ artifact_paths 만 유지)

---

## 13. ANU Doctrine Compliance (★ 본 draft 단계)

- ★ ANU 자체 코드 구현 0 (★ 회장 verbatim "실제 코드 구현은 아직 하지 않는다")
- ★ ANU 자체 finish-task.sh 변경 0 (★ 회장 verbatim "finish-task.sh 변경은 아직 하지 않는다")
- ★ ANU 자체 dispatch 0 (★ 회장 verbatim "dispatch / PR / push / merge / GitHub write 금지")
- ★ ANU 자체 chair_authorization_id 발급 0 (★ 회장 결정 영역)
- ★ task-2710 / task-2711 evidence 변경 0
- ★ task-2706~2709+1 evidence 변경 0
- ★ ANU 자체 새 forbidden target 추가 0 (★ §10.3 은 기존 doctrine 정합)
- ★ ANU 자체 새 chair_authorization scope 확장 0
- ★ ANU 자체 lock/pilot 인가 0

---

## 14. Lineage / Precedent Anchor

| precedent | 적용 |
|---|---|
| `feedback_callback_must_spawn_independent_anu_not_executor_self_260518.md` | §6.3 SELF_COLLECTOR_FORBIDDEN 정합 |
| `feedback_normal_callback_not_registered_variant_260523.md` | §3.1 .done 정책 + §5 terminal failure path matrix |
| `feedback_executor_completion_callback_mandatory_260518.md` | §1.3 새 원칙 (callback = mandatory lifecycle signal) |
| `feedback_anu_no_direct_ci_watch_use_handoff_260523.md` | §6.2 ANU session-bound polling 0 강제 |
| `feedback_dispatch_false_ok_and_prompt_limit_misclassification_260524.md` | §5.2 dispatch.py entry path 통합 |
| `feedback_callback_source_attribution_required_260524.md` | §4 envelope mandatory field |
| `feedback_callback_authority_actual_owner_key_260524.md` | §6.3 ANU key strict |
| task-2711 사례 박제 | §7 fixture |
| task-2709+1 API 500 사례 | §3 API_FAIL terminal state |
| task-2705+3 stale 사례 | §3 BLOCKED terminal state |

---

## 15. Sentinel

★ task-2712 = DRAFT_ONLY · FAILURE_CALLBACK_BEFORE_EXIT_GUARD · 9 terminal state (SUCCESS / FAILURE / BLOCKED / SCOPE_GUARD_FAIL / QC_FAIL / INFRA_DEFECT / PERMISSION_FAIL / API_FAIL / CRITICAL_ESCALATION) · failure envelope schema 9 mandatory field + UTF-8 ≤ 3900 bytes · terminal failure path matrix (finish-task.sh 6 exit + dispatch.py 3 entry + runtime 3 path) · cron 등록 실패 fallback 4-step chain · SELF_COLLECTOR_FORBIDDEN 정합 강제 · ANU session-bound polling 0 · .done = SUCCESS only · task-2711 scope-guard FAIL fixture 박제 · 17 expected_files + 8 regression test 후보 · 실제 코드 구현 0 · finish-task.sh 변경 0 · dispatch.py 변경 0 · PR/push/merge/GitHub write 0 · dispatch 0 · task-2710/task-2711/task-2706~2709+1 evidence 변경 0 · chair_authorization_id placeholder (★ 회장 결정 영역). 끝
