# normal callback registration enforcement spec (Core hardening · read-only · 위임/구현 0) — 260523

회장 결정(2026-05-23): task-2634 dev6 페룬 NORMAL_CALLBACK_NOT_REGISTERED 사고를 별도 사고로 분리. PR #137 과 섞지 않는다. **본 spec 은 read-only — 코드/구현 없음. 회장 결정 후 별도 task 발행.**

기반: `feedback_callback_self_key_helper_not_wired_260521.md`(self-key 변종 원형) + `feedback_callback_must_spawn_independent_anu_not_executor_self_260518.md` + `feedback_dispatch_must_register_fallback_safetynet_260520.md` + `project_callback_lifecycle_2axis_schema_260522.md` + `feedback_executor_completion_callback_mandatory_260518.md`.

---

## 1. 사고 분류 (task-2634 dev6 페룬 · 2026-05-23 01:16~01:17 KST)

| 항목 | 값 |
|---|---|
| 사고 분류 | **NORMAL_CALLBACK_NOT_REGISTERED** (CALLBACK_ENFORCEMENT_GAP) |
| Critical7 해당 | **❌ 아님** (forbidden path 0 / scope expansion 0 / replacement_pr fail 0 / smoke fail 0 / dep_cycle 0 / serial 0 / admin override 0) |
| 산출물 정상성 | ✅ 정상 (50 files · regression 264/264 · 안전 불변식 100%) |
| self-key 변종? | ❌ self-key 사고 아님 (envelope 에 ANU key `c119085addb0f8b7` + `collector_role=ANU` 정확히 명기) |
| 거버넌스 영향 | ⚠️ 회장 수동 텔레그램 relay 의존 — 자동 ANU collector spawn 0 → 본 spec 의 hardening 동기 |

---

## 2. 원인 후보 분리 (회장 5 항목 verbatim)

### 2.1 executor prompt 에 ANU key cron 지시 있었는가?
✅ **있었음.**
- `task-2634.md` §5 finalize: "ANU normal completion callback — **반드시 독립 ANU key `c119085addb0f8b7`** · collector_role=ANU"
- dispatch cron prompt 본문: "ANU normal completion callback: 반드시 독립 ANU key c119085addb0f8b7 · collector_role=ANU. envelope UTF-8 ≤3900 bytes."
- → prompt 차원 doctrine 인가 ✅

### 2.2 dev6 helper/tooling 에 ANU callback registrar 가 실제 코드로 결선되어 있는가?
❌ **결선 0.**
- `feedback_callback_self_key_helper_not_wired_260521.md` 명시: "근본 원인: `build_anu_owned_callback_request` 는 ANU fail-closed 정확하나 `dispatch/__init__.py` import 0 · 봇 발사 경로 결선 0 → 봇이 task md §X 텍스트 지시만 받고 자기 key 로 자율 발사."
- task-2634 는 발사 안 함 (자기 key 도 아니고 ANU key 도 아니고 **아예 cron 등록 0**) → 결선 부재의 다른 변종
- 즉 task md prompt 텍스트만 doctrine 이고 코드 enforce 부재라는 근본 원인은 동일

### 2.3 result.json 에 normal_callback_registration_status 가 있는가?
❌ **필드 부재.**
- `task-2634.anu-callback.json` keys: `task_id · collector_role · anu_key · status · delivery_outcome · classification · executor_*_ts_kst · local_commit_sha · base_sha · branch · worktree · spec_sha256 · spec_path · result_path · report_path · fixture_summary · regression_summary · safety_invariants · scope_compliance · chair_escalation_triggers · loop_boundary_status · notes`
- `normal_callback_registration_status` / `callback_cron_schedule_id` / `delivery_method` 전부 부재
- → schema 에 enforce 없음

### 2.4 Telegram sendfile 이 callback 대체로 오인된 것인가?
✅ **그렇게 오인됨.**
- schedule_history `866B71C4.log` response 영역에 `📎 task-2634.anu-callback.json` sendfile 흔적만 존재
- `cokacdir --cron ... --key c119085addb0f8b7` 호출 흔적 0
- 봇 해석: "envelope 파일 sendfile = callback 전달"
- 실제 enforcement: callback = ANU 세션 spawn 트리거 (별도 cron 필수), sendfile = 회장 가시화 보조 (대체 아님)
- → 두 채널 의미 분리가 코드/검증 단에서 결선되지 않음

### 2.5 fallback cancel-on-success 가 정상 동작 가능한 구조였는가?
⚠️ **부분 — 동작 가능했으나 source-of-truth 미정의.**
- ANU fallback id `512A122D` 02:28:58 KST 등록됨 (90분 후)
- cancel-on-success 의 success signal 정의 부재 — normal callback cron 등록 자체가 success signal 인지, ANU collector durable-success 마커 생성이 success signal 인지 미정의
- 본 사고는 fallback 도착 전 회장이 수동 relay 했기에 cancel-on-success 트리거 시점 미관측
- → success signal source 모호 → fallback 의 NO-OP 오판 위험

---

## 3. 사고 패턴 박제 (NORMAL_CALLBACK_NOT_REGISTERED)

- **self-key 변종과의 차이**: self-key = executor 가 자기 key 로 cron 발사(별도 ANU spawn 0) / **본 변종 = executor 가 cron 자체 발사 0, envelope 파일 sendfile 만**
- **공통 근본**: callback registrar 코드 결선 부재. prompt 텍스트 doctrine 만 있고 봇 발사 경로에 hardcoded enforcement 0
- **위험**: 회장 복붙 수동 relay 의존 → 거버넌스 자동화 break · ANU 자동 collector spawn 0 · 시스템 idle gap

---

## 4. 후속 hardening task 목표 (회장 6 항목 verbatim)

| # | 목표 | enforcement layer |
|---|---|---|
| 1 | executor 완료 시 ANU key normal callback 강제 등록 | helper code (registrar hardcoded) |
| 2 | sendfile/report 전송 ≠ callback (코드/검증 분리) | schema + regression |
| 3 | result.json `normal_callback_registration_status` 필수화 | schema enforcement |
| 4 | callback 미등록 시 task 완료 불가 또는 ANU fallback 즉시 감지 | fail-closed + fallback detector |
| 5 | ANU fallback 이 callback miss 를 NO-OP 오판 금지 | fallback success-signal source 명시 |
| 6 | 회장 수동 전달 없이 ANU collector spawn 검증 fixture/regression | fixture + test |

### 4.1 구체 enforcement points

- **helper 코드**: `utils/anu_callback_registrar.py`(가칭) — `register_normal_callback(envelope) -> {schedule_id, anu_key, registered_at_ts}` 순수함수. `cokacdir --cron --key c119085addb0f8b7` subprocess 호출 또는 동등 API. ANU key hardcoded, self-key 차단.
- **dispatch wiring**: dev 봇 task lifecycle 의 "executor done" hook 에 `register_normal_callback` mandatory call. 호출 0 시 task 종료 reject (start_task_guard 와 동급의 finish_task_guard).
- **schema**: envelope `normal_callback_registration_status: REGISTERED|NOT_REGISTERED|REGISTRATION_FAILED` enum 필수. `callback_cron_schedule_id: str` 필수. `delivery_method` enum 추가 (`anu_cron_callback` / `sendfile_only` / `both`). sendfile_only 단독은 callback 으로 미인정.
- **regression**:
  - `test_anu_callback_registrar.py` — registrar 호출 시 ANU key 정확/cron 등록 흔적 검증
  - `test_callback_registration_enforcement.py` — `NOT_REGISTERED` 시 task fail-closed 단언
  - `test_callback_vs_sendfile_separation.py` — sendfile 만으로는 callback 충족 안 됨 단언
- **fallback 정합**: ANU fallback prompt 에 "cancel-on-success = ANU collector durable-success 마커 생성 시점" 명시. callback registrar 호출 단순 등록만으로는 cancel 안 함 (false cancel 방지).

---

## 5. 회장 결정 대기 항목

1. 본 hardening task 발행 여부 (회장 명시 없이 임의 dispatch 금지)
2. 위임 봇 (dev6 페룬 본인 vs. 다른 봇 — `feedback_resolver_reinjection_limit_doctrine_260513` 적용 여부)
3. task ID 부여 (next available · 회장 결정)
4. PR #137 머지 전/후 진행 순서 (회장 결정 — 본 spec 권장: PR #137 머지 완료 후 별도 진행)
5. callback runtime enforcement 기존 production-verified 와의 관계 명시 (확대해석 금지 doctrine 유지)

---

## 6. 본 단계 금지 (회장 verbatim)

- PR #137 에 callback hardening 을 섞지 말 것
- PR #137 expected_files 밖 수정 금지
- callback 재발사 실험 금지
- foreign dirty 정리 금지
- replacement_pr_runner.py 수정 금지
- finish-task.sh 수정 금지
- production enforcement 완료 판정 금지 (본 spec = 사고 분리 + hardening 목표 정의까지만)
- 본 spec 권고를 spec 작성 외 실행 금지

---

## 7. frozen anchor (D-SPEC-EXACTNESS)

- ANCHOR-1: "task-2634 사고 = NORMAL_CALLBACK_NOT_REGISTERED · Critical7 아님 · 산출물 정상 · 거버넌스 운영 결함"
- ANCHOR-2: "원인 = callback registrar 코드 결선 0 (prompt doctrine 만 · 봇 코드 enforce 부재)"
- ANCHOR-3: "sendfile/report ≠ callback — 두 채널 의미 코드/스키마 단에서 분리"
- ANCHOR-4: "PR #137 머지 진행과 callback hardening 은 별도 — 섞지 말 것"
- ANCHOR-5: "본 spec read-only — 회장 결정 후 별도 task 발행 시에만 구현 진행"
