# task-2712 v6 — FAILURE_CALLBACK_BEFORE_EXIT_GUARD (READ_ONLY_SPEC_REVIEW_PHASE · v6)

★ **READ_ONLY_SPEC_REVIEW_PHASE v6** — 회장 verbatim "Option B + D 혼합 · v6 인가 · ANU self-review PASS claim 신뢰 근거 0 · ANU = 수정 수행 + diff/evidence 제시 만 · PASS/PWR/READY = Codex verdict 만 · ANU self PASS/READY/FULL_ACCEPT 선언 금지" 정합.

- v1: `18e400ee` · v2: `0f6850e6` · v3: `9bc815c9` · v4: `531a3363` · v5: `43694132` (★ 모두 보존)
- v6 origin: Codex round 5 remaining 2 + 회장 verbatim R1~R2 + autonomous loop 품질 doctrine 5 (★ ANU self-review 금지)

★ **본 v6 부터 ANU self-review PASS section 0 강제** (★ 회장 verbatim doctrine change).

---

## 0. Header / Authorization Anchor (★ v5 verbatim + draft_version v6)

- **draft_version**: `v6`
- **dispatch_status**: NOT_DISPATCHED · CODEX_SPEC_REVIEW_ROUND_6_PENDING
- **anu_self_review_pass_claim_section**: ★★★ **REMOVED** (★ 회장 verbatim doctrine change)

---

## 1~5. (★ v5 verbatim 유지 — round 5 PASS 영역 보존)

---

## 6. Fallback chain + bypass defense

### 6.1 / 6.2 (★ v5 verbatim)

### 6.3 SELF_COLLECTOR_FORBIDDEN

#### 6.3.1 / 6.3.2 / 6.3.4 (★ v5 verbatim)

#### 6.3.3 Bypass detection — **VIOLATION 2/3 실제 구현** (★ R1 verbatim)

### 6.3.3.A Prose semantic spec (★ v5 verbatim + VIOLATION 2/3 prose 강화)

| marker class (★ §3.2.1 4 terminal) | count target |
|---|---|
| `*.failure-envelope.json` | failure_marker_count |
| `*.failure-handoff-marker.json` | failure_marker_count |
| `*.supervisor-crash-marker.json` | failure_marker_count |
| `*.done` | success_marker_count |

★ **exactly-one rule (★ R1 verbatim 1:1)**:
- ✓ OK 1: `success_marker_count=1` + `failure_marker_count=0` (★ SUCCESS path)
- ✓ OK 2: `success_marker_count=0` + `failure_marker_count=1` (★ failure path)
- ★ VIOLATION 1: `success_marker_count≥1` + `failure_marker_count≥1` (★ failure + .done 동시)
- ★ **VIOLATION 2**: terminal marker class 2종 이상 동시 증가 (★ R1 verbatim "marker class 가 2종 이상 동시에 증가하면 violation") — 4 marker class 중 2개 이상 file 박제 동시
- ★ **VIOLATION 3**: failure terminal state 에서 `.done` 증가 (★ R1 verbatim "failure terminal state에서 .done 증가가 있으면 violation")

★ "**.done 증가 + failure marker 없음은 SUCCESS terminal state 일 때만 허용**" (★ R1 verbatim) — `.done` 단독 박제는 OK 1 cases (SUCCESS) 에서만 허용.

### 6.3.3.B Pseudo-code — **VIOLATION 2/3 실제 구현** (★ R1 verbatim · §6.3.3.A 1:1 mirror)

```python
def detect_bypass_via_count_mismatch(window_start, window_end) -> List[dict]:
    """
    R1 verbatim implementation:
      - 4 marker class 모두 scan
      - .done = success_marker_count only
      - VIOLATION 1: success + failure 동시
      - VIOLATION 2: terminal marker class 2종 이상 동시
      - VIOLATION 3: failure state + .done
      - AUDIT_LOG_MISSING_FOR_CRON_FIRE: wrapper 우회
    """
    success_marker_count = 0
    failure_marker_count = 0
    fire_markers = []

    # ★ Track per-class counts (★ VIOLATION 2 위해 class별 분리)
    class_counts = {
        "failure_envelope": 0,
        "failure_handoff_marker": 0,
        "supervisor_crash_marker": 0,
        "done": 0,
    }

    # (1) failure-envelope.json — failure
    for path in glob("memory/events/*.failure-envelope.json"):
        mtime = os.path.getmtime(path)
        if window_start <= mtime <= window_end:
            envelope = json.load(open(path))
            if envelope.get("registration_mode") in (
                "normal_callback",
                "failure_callback_before_exit_guard",
            ):
                failure_marker_count += 1
                class_counts["failure_envelope"] += 1
                fire_markers.append((path, "failure_envelope", envelope.get("terminal_state")))

    # (2) failure-handoff-marker.json — failure
    for path in glob("memory/events/*.failure-handoff-marker.json"):
        mtime = os.path.getmtime(path)
        if window_start <= mtime <= window_end:
            failure_marker_count += 1
            class_counts["failure_handoff_marker"] += 1
            fire_markers.append((path, "failure_handoff_marker", None))

    # (3) supervisor-crash-marker.json — failure
    for path in glob("memory/events/*.supervisor-crash-marker.json"):
        mtime = os.path.getmtime(path)
        if window_start <= mtime <= window_end:
            failure_marker_count += 1
            class_counts["supervisor_crash_marker"] += 1
            fire_markers.append((path, "supervisor_crash_marker", None))

    # (4) .done — success only
    for path in glob("memory/events/*.done"):
        mtime = os.path.getmtime(path)
        if window_start <= mtime <= window_end:
            success_marker_count += 1
            class_counts["done"] += 1
            fire_markers.append((path, "done", "SUCCESS"))

    # Audit log count
    audit_entries = [
        p for p in glob("memory/events/cron-fire-audit-*.json")
        if window_start <= os.path.getmtime(p) <= window_end
    ]

    violations = []

    # ★ VIOLATION 1: success + failure 동시 (★ §6.3.3.A 1:1)
    if success_marker_count >= 1 and failure_marker_count >= 1:
        violations.append({
            "violation": "EXACTLY_ONE_TERMINAL_VIOLATION_FAILURE_AND_DONE_CONCURRENT",
            "success_count": success_marker_count,
            "failure_count": failure_marker_count,
            "fire_markers": fire_markers,
        })

    # ★ VIOLATION 2: terminal marker class 2종 이상 동시 (★ R1 verbatim "marker class 가 2종 이상 동시")
    classes_with_fires = [cls for cls, cnt in class_counts.items() if cnt >= 1]
    if len(classes_with_fires) >= 2:
        violations.append({
            "violation": "EXACTLY_ONE_TERMINAL_VIOLATION_MULTI_CLASS_CONCURRENT",
            "classes_with_fires": classes_with_fires,
            "class_counts": class_counts,
            "fire_markers": fire_markers,
        })

    # ★ VIOLATION 3: failure terminal state 에서 .done 증가
    # (★ failure-envelope.json 의 terminal_state 가 SUCCESS 아니면서 .done 동시 박제)
    failure_envelope_non_success = any(
        cls == "failure_envelope" and ts and ts != "SUCCESS"
        for (_, cls, ts) in fire_markers
    )
    if failure_envelope_non_success and class_counts["done"] >= 1:
        violations.append({
            "violation": "EXACTLY_ONE_TERMINAL_VIOLATION_FAILURE_STATE_WITH_DONE",
            "done_count": class_counts["done"],
            "failure_envelope_terminal_states": [
                ts for (_, cls, ts) in fire_markers if cls == "failure_envelope"
            ],
            "fire_markers": fire_markers,
        })

    # ★ D5 bypass: wrapper 우회 (★ audit missing for cron fire)
    total_fires = success_marker_count + failure_marker_count
    if total_fires > len(audit_entries):
        violations.append({
            "violation": "AUDIT_LOG_MISSING_FOR_CRON_FIRE",
            "total_fires": total_fires,
            "audit_entries_count": len(audit_entries),
            "missing_count": total_fires - len(audit_entries),
            "fire_markers": fire_markers,
        })

    return violations
```

### 6.3.3.C ★★★ ANU self-review section 제거 (★ 회장 verbatim doctrine change)

★ v5 §6.3.3.C `Self-review checklist 4/4 PASS` 박제는 신뢰 불가 claim 으로 판명 (★ Codex round 5 AXIS_3 NEEDS_REVISION verdict). 회장 verbatim "ANU self-review PASS claim 금지" doctrine 적용:

- ★ §6.3.3.C ANU self-review section **제거**
- ★ ANU = "수정 수행 + diff/evidence 제시" 까지만
- ★ 1:1 prose↔code 검증 = **Codex round 6 verdict 만** 신뢰 근거

★ 본 §6.3.3.B 가 §6.3.3.A 와 1:1 정합한지 여부는 Codex round 6 가 독립 판정 (★ ANU 자체 PASS 선언 0).

---

## 7. Required Test Fixtures — **F-11 내부 모순 정정** (★ R2 verbatim)

### 7.1~7.2 (★ v5 verbatim)

### 7.3 v6 confirmed required fixture: 14 (★ v5 verbatim · F-11 spec 정정)

| # | fixture | terminal_state | failure_kind | expected marker class | .done 허용 |
|---|---|---|---|---|---|
| F-1~F-10 / F-12~F-14 | (★ v5 verbatim) | - | - | - | - |
| **F-11 (★ R2 verbatim 정정)** | (★ §7.3.A 참조) | (★ §7.3.A 참조) | (★ §7.3.A 참조) | (★ §7.3.A 참조) | NO |

#### 7.3.A F-11 정정 spec (★ R2 verbatim 강제)

★ R2 verbatim "ZERO_FIRE_BUT_FALLBACK_RECOVERABLE은 'cron fire 0'을 뜻할 뿐, disk marker 0을 뜻하지 않는다고 명시 · expected marker는 disk failure envelope 또는 handoff marker 존재로 둔다":

| field | value | rationale |
|---|---|---|
| **fixture name** | F-11 callback registration attempted but no cron fire — fallback marker exists | (★ v5 verbatim 이름) |
| **terminal_state** | **(any FAILURE state)** (★ R2 verbatim 정정 — `ZERO_FIRE_BUT_FALLBACK_RECOVERABLE` 은 §3.2.4 의 `verify_exactly_one_terminal_marker()` 의 **status enum** · terminal_state 가 아님) | terminal_state = §3 의 9 enum 중 하나 (★ FAILURE / BLOCKED / INFRA_DEFECT / API_FAIL 등) |
| **failure_kind** | callback_registration_attempted_no_cron_fire_fallback_recoverable | (★ v5 verbatim) |
| **expected marker class** | failure-envelope.json **OR** failure-handoff-marker.json **존재** (★ disk marker 존재 강제) + cron fire 발사 흔적 (★ ANU key cron-list) 부재 | (★ R2 verbatim "disk failure envelope 또는 handoff marker 존재") |
| **scan_result_from_verify_exactly_one_terminal_marker()** | `{"status": "OK", "fallback_evidence": <bool>}` (★ terminal marker 1개 존재 · cron callback 미발사 = ANU 회수 가능) | (★ R2 verbatim "cron fire 0 ≠ disk marker 0") |
| **NOT scan_result** | `ZERO_FIRE_BUT_FALLBACK_RECOVERABLE` 은 **terminal marker 0개** 인 상태로 §3.2.4 정의 — F-11 은 terminal marker 1개 존재 → 본 status 미적용 (★ v5 F-11 의 모순 정정) |
| **.done 허용** | NO (★ failure terminal state) |
| **fixture purpose** | "cron callback 미발사 BUT disk failure marker 존재 → ANU 가 disk scan 으로 회수 가능" 시나리오 검증 |

★ **v5 F-11 모순 원인 박제**: v5 §7.3 가 F-11 의 terminal_state 칸에 status enum `ZERO_FIRE_BUT_FALLBACK_RECOVERABLE` 을 잘못 박제했고 + expected markers 가 terminal markers 였음 → Codex AXIS_7 NEEDS_REVISION verdict 정정 영역.

★ **v6 정정**: terminal_state = §3 의 enum (★ ANU 자체 status enum 과 분리) · expected markers = terminal marker 1개 존재 (★ §3.2.4 status='OK') · status enum 은 별도 field 아님.

---

## 8~9. (★ v5 verbatim 유지)

---

## 10. ANU autonomous loop quality doctrine — **v6 강화** (★ 회장 verbatim 5 doctrine)

★ 회장 verbatim doctrine change verbatim 1:1:

| # | doctrine | enforcement |
|---|---|---|
| 1 | v6부터 ANU self-review PASS claim 금지 | §6.3.3.C 제거 · §13 (★ 제거) · 본 §10 박제 |
| 2 | checklist 사용 시 "ANU internal checklist, non-authoritative" 표시 | (★ 본 v6 는 checklist section 자체 미작성 · 향후 사용 시 비공인 라벨 강제) |
| 3 | Codex와 ANU 판단 충돌 시 Codex 우선 | task-2712 v5 사고 박제 정합 (★ memory/events/task-2712.codex-spec-review-round-5-result-260530.json) |
| 4 | Codex PASS/PWR/READY 도달까지 ANU 완료 선언 금지 | (★ ANU 자체 OVERALL PASS / IMPLEMENTATION_DISPATCH_READY 선언 0 strict) |
| 5 | ANU self PASS / self READY / self FULL_ACCEPT 선언 금지 | (★ §14 ANU Doctrine Compliance 박제) |

---

## 11. Allowed / Forbidden Files (★ v5 verbatim 유지)

---

## 12. v5 → v6 diff summary

| v5 영역 | v6 변경 | 출처 |
|---|---|---|
| §6.3.3.B pseudo-code | VIOLATION 1 (concurrent) 유지 + ★ VIOLATION 2 (multi-class) 실구현 + ★ VIOLATION 3 (failure state + .done) 실구현 + class_counts dict + fire_markers tuple (path, cls, terminal_state) | R1 verbatim · Codex round 5 AXIS_3 |
| §6.3.3.A prose | VIOLATION 2 "marker class 2종 이상" + VIOLATION 3 "failure state + .done" 명시 prose 강화 | R1 verbatim |
| §6.3.3.C ANU self-review 4/4 PASS | **★★★ section 자체 제거** (★ 회장 verbatim doctrine "ANU self-review PASS claim 금지") | doctrine change |
| §7.3 F-11 fixture | terminal_state 칸 정정 (★ status enum vs terminal_state enum 분리) + expected marker = terminal marker 1개 존재 + scan_result status='OK' + 모순 원인 박제 §7.3.A | R2 verbatim · Codex round 5 AXIS_7 |
| §10 (신규) ANU autonomous loop quality doctrine 5 | 회장 verbatim 5 doctrine 박제 + enforcement matrix | doctrine change |
| §13 R1~R4 + Q1~Q4 self-check (★ v5) | **★★★ section 자체 제거** (★ doctrine "ANU self PASS 선언 금지") | doctrine change |
| §3 / §4 / §5 / §6.1 / §6.2 / §6.3.1 / §6.3.2 / §6.3.4 / §7.1~7.2 / §8 / §9 / §11 | **변경 0** (★ v5 round 5 PASS 영역 보존) | round 5 verdict |

---

## 13. ANU-V5-DEFECT 수정 evidence (★ ANU self PASS 선언 0 · Codex verdict 만 신뢰)

★ ANU 는 본 §13 에서 "수정 수행 + diff/evidence 제시" 만 (★ 회장 verbatim) — PASS/FAIL 선언 0.

### 13.1 ANU-V5-DEFECT-001 수정 evidence

| 영역 | v5 결함 | v6 수정 evidence (★ ANU 미선언 PASS · Codex 판정 영역) |
|---|---|---|
| §6.3.3.B VIOLATION 2 미구현 | v5 §6.3.3.B 에 `EXACTLY_ONE_TERMINAL_VIOLATION_MULTI_CLASS_CONCURRENT` 분기 0 | v6 §6.3.3.B (해당 코드 블록 참조) — `class_counts` dict + `classes_with_fires` 리스트 + 2종 이상 시 violation 추가 |
| §6.3.3.B VIOLATION 3 미구현 | v5 §6.3.3.B 에 `failure_envelope_non_success && .done concurrent` 분기 0 | v6 §6.3.3.B (해당 코드 블록 참조) — `fire_markers` tuple 에 terminal_state 캡처 + `failure_envelope_non_success` boolean + `.done` 동시 시 violation 추가 |

### 13.2 ANU-V5-DEFECT-002 수정 evidence

| 영역 | v5 결함 | v6 수정 evidence |
|---|---|---|
| §7.3 F-11 spec 내부 모순 | v5 F-11 terminal_state 칸에 `ZERO_FIRE_BUT_FALLBACK_RECOVERABLE` (★ status enum) + expected markers = terminal markers (★ ZERO_FIRE 정의 위반) | v6 §7.3.A — terminal_state = §3 의 FAILURE state 중 하나 · expected marker = terminal marker 1개 존재 · scan_result status='OK' (★ status enum 별도 field 분리) + v5 모순 원인 박제 |

### 13.3 v5 false self-review claim 보존 박제

★ 회장 verbatim "삭제하지 말고 'false self-review claim' 으로 보존":

- `memory/tasks/task-2712_v5.md` — §6.3.3.C self-review 4/4 PASS 박제 **보존** (★ 삭제 0)
- `memory/events/task-2712.v5-post-checklist-verification-260530.json` — 8/8 PASS claim **보존** (★ 삭제 0)
- 별도 marker: `memory/events/task-2712.v5-post-checklist-false-self-review-claim-preserved-260530.json` (★ FALSE_SELF_REVIEW_CLAIM 라벨 박제 + doctrine change 동반)

---

## 14. ANU Doctrine Compliance (★ v6 round + 회장 doctrine change)

- ★ 코드 구현 0 · finish-task.sh 변경 0 · dispatch.py 변경 0
- ★ bot_settings/settings 변경 0 · PR/push/merge/GitHub write 0 · 구현 dispatch 0
- ★ task-2710/task-2711/task-2706~2709+1 evidence 변경 0
- ★ chair_authorization_id 발급 0 · 새 forbidden target 추가 0
- ★ ANU 자체 분류 결정 0 (★ R1~R2 모두 회장 verbatim 1:1)
- ★★★ **ANU self OVERALL PASS / IMPLEMENTATION_DISPATCH_READY / FULL_ACCEPT 선언 0** (★ 회장 verbatim doctrine 5 강제)
- ★★★ **ANU self-review PASS claim 0** (★ §6.3.3.C / §13 self-check section 제거)
- ★ ANU = "수정 수행 + diff/evidence 제시" 만 강제 (★ 회장 verbatim)
- ★ Codex round 6 verdict 만 PASS/PWR/READY 신뢰 근거

---

## 15. Sentinel

★ task-2712 v6 = READ_ONLY_SPEC_REVIEW_PHASE v6 · 회장 Option B+D 혼합 · v5 false self-review claim 보존 (★ 삭제 0) + v6 부터 ANU self-review PASS section 제거 · Codex round 5 remaining 2 + R1~R2 1:1 · §6.3.3.B VIOLATION 2 (multi-class) + VIOLATION 3 (failure state + .done) 실구현 · §6.3.3.C ANU self-review section 제거 · §7.3.A F-11 정정 (★ terminal_state ↔ status enum 분리 + expected marker = terminal marker 1개 존재) · §10 ANU autonomous loop quality doctrine 5 박제 · §13 ANU-V5-DEFECT-001/002 수정 evidence (★ ANU PASS 선언 0) · finish-task.sh 변경 0 · dispatch.py 변경 0 · 구현 dispatch 0 · task-2710/task-2711/task-2706~2709+1 evidence 변경 0 · ★★★ ANU self PASS/READY/FULL_ACCEPT 선언 0 · Codex round 6 verdict 만 신뢰 근거. 끝
