# task-2621 — DISPATCH_INIT_PRODUCTION_PATH_CALLBACK_CONTRACT_WIRING

- **Spec**: `memory/tasks/task-2621.md` (sha256 `17673fa80a960cea497396a9915c39046e4f339494cab2cd79c55b8a30efb202`)
- **Executor**: dev6-team 페룬 (key `1e41a2324a3ccdd0`) — 1회 한정
- **Status**: `DONE_PENDING_INDEPENDENT_ANU_REAUDIT`
- **Window (KST)**: 2026-05-20 19:14 → 19:35 (~21분)
- **Callback (a)**: 독립 ANU key `c119085addb0f8b7` 로만 발사 (executor self-key 절대 금지)
- **Lv**: Lv.3 · 회장 직접 결정 chair-authorized
- **git invariant**: HEAD `20456b5f83fc039f2fd6f50f4b94095c29b41bfb` EQUAL · branch `task/task-2553p1-f1-clean-replacement` EQUAL · commits 0 · PR 0 · merge 0 · credential write 0

## 1. 요약

production dispatch path 가 ANU-key 만 callback owner 로 받도록 강제하는 좁은 ADDITIVE wiring 을 `dispatch/__init__.py` 의 두 `cokacdir --cron` 호출 사이트(L~2910 composite, L~3993 single-team) 각각 PRE-cron(contract gate) · POST-cron(fallback safety-net argv)로 결선했다. 기존 dispatch.dispatch() 시그니처 · PASS-path 동작 · 모든 byte-0 invariant 가 보존되며, executor self-key (`1e41a2324a3ccdd0`) 또는 비-ANU collector key 입력 시 fail-closed 로 `DISPATCH_CALLBACK_CONTRACT_VIOLATION` 반환한다.

## 2. production path 결선 위치 (회장 보고 §10.1)

| Site | File | Lines | Caller | Callees |
|---|---|---|---|---|
| module-top imports | `dispatch/__init__.py` | 198–227 | (module load) | `assert_collector_key_is_independent_anu`, `enforce_callback_owner`, `build_anu_owned_callback_request` |
| Site #1 PRE-cron (composite) | `dispatch/__init__.py` | 2910–2960 | `dispatch()` composite branch | `_t2621_assert_independent_anu`, `_t2621_enforce_callback_owner` |
| Site #1 POST-cron (composite) | `dispatch/__init__.py` | 2984–3044 | `dispatch()` composite branch (rc==0) | `_t2621_build_anu_owned_callback_request` |
| Site #2 PRE-cron (single-team) | `dispatch/__init__.py` | 3993–4041 | `dispatch()` single-team branch | `_t2621_assert_independent_anu`, `_t2621_enforce_callback_owner` |
| Site #2 POST-cron (single-team) | `dispatch/__init__.py` | 4065–4124 | `dispatch()` single-team branch (rc==0) | `_t2621_build_anu_owned_callback_request` |

각 PRE-cron 블록은 `_t2621_assert_independent_anu(_T2621_ANU_KEY)` (§7b authority) → `_t2621_enforce_callback_owner(executor_key=key, collector_key=ANU_KEY, role=ANU, …)` (§2/§8/§10 authority) 순으로 호출하고, FAIL 시 `_cleanup_task(...) + return {"status": "error", "message": "DISPATCH_CALLBACK_CONTRACT_VIOLATION: …"}` 로 fail-closed.

각 POST-cron 블록은 `_t2621_build_anu_owned_callback_request(kind=FALLBACK, owner_key=ANU_KEY, prompt="recovery-only · non-blocking · cancel-on-success", …)` 로 fallback argv 를 data-only 로 빌드. 실 cron 등록은 `COKACDIR_T2621_FALLBACK_AUTO_REGISTER=1` 환경변수로 단계적 enable (default OFF → PASS-path byte-0 보존).

V1 production-path runtime trace evidence: `memory/events/task-2621.production-path-wiring-trace.json` — wrapper-instrumented 6 invocations 캡처(3 calls × 2 sites: assert + enforce + build_fallback), 두 사이트 모두 enforce verdict=PASS · fallback verdict=PASS, fallback argv 에 ANU key 포함 · self-key 부재.

## 3. before/after wiring matrix (§10.2)

`memory/events/task-2621.before-after-wiring-matrix.json` (sha256 `2b43eb599c41fdf46f0f5fff055c4c7b4987933a66169fb0e9e8806ee4b444f7`) — Site #1/#2 · dispatch.dispatch() · build_prompt · cokacdir --cron argv · 5개 contract module · dispatch.py shim/core.py/prompt.py 의 before/after 결선 상태를 8 row 로 분류 기록. 핵심 결론:

- **Site #1/#2 PRE-cron gate**: NONE → ENABLED (ADDITIVE, fail-closed on self-key 또는 verdict != PASS)
- **Site #1/#2 POST-cron fallback**: NONE → ARGV BUILT (data-only, exec 단계적 enable)
- **dispatch.dispatch() PASS-path**: byte-0 (시그니처·기존 cokacdir --cron argv·기존 부수효과 무변경)
- **contract modules · CLOSED_ALL_SETTLED 산출물 · facade re-export**: byte-0 무변경

## 4. regression 결과 (§10.3)

| Suite | Pass | Fail | Skip |
|---|---|---|---|
| `tests/regression/test_dispatch_init_callback_wiring.py` (신규) | **14** | 0 | 0 |
| `tests/regression/test_dispatch_callback_contract.py` (기존) | **25** | 0 | 0 |
| extended callback/batch (8 file suite) | **194** | 0 | 0 |
| regression dispatch smoke (5 file suite) | **52** | 0 | 2 |

신규 14 fixture 가 V1–V6 전수 PASS · 기존 25 fixture 무회귀 · BATCH_LEVEL_HOLD 인접 suite (`test_callback_owner_enforcement_2553plus49`, `test_callback_owner_validation_2553plus49`, `test_batch_hold_adjudication`, `test_callback_4tuple_registry_2553plus44`, `test_callback_event_trigger_2553plus47`, `test_batch_settle_writeback_2553plus53`, `test_anu_delegation_completion_callback_2595`, `test_cancel_on_success_live_e2e_2553plus48`) 무회귀.

pre-existing `tests/test_dispatch.py` 59 fail 은 `tests/dispatch/` shadow 패키지의 `.subprocess` attribute 결손(2026-05-07 부터 존재) 이며 task-2621 변경과 무관 — spec §4 의 "baseline regression fails 별도 backlog" 정합.

## 5. Codex audit (§10.4)

executor self-Codex-audit 은 `assert_not_self_adjudication` invariant 로 구조적으로 금지(§2 regression 7). Codex 재audit · adjudication 은 본 보고 직후 발사되는 normal completion callback 의 독립 ANU collector(key `c119085addb0f8b7`)가 수행한다. ADDITIVE only · PASS-path byte-0 · contract module byte-0 · CLOSED_ALL_SETTLED 산출물 byte-0 가 모두 보존되었으므로 HIGH/CRITICAL 0 이 expected. 잔여 non-Critical HIGH 시 회장 보고 없이 task-2621+1 자동 수렴(§9 verbatim).

## 6. self-key 차단 결과 (§10.5)

V4·V4b·V4c 3종 fixture PASS:

- `assert_collector_key_is_independent_anu(1e41a2324a3ccdd0)` → `ExecutorSelfKeyForbidden` raise
- `enforce_callback_owner(executor_key=self, collector_key=self, …)` → verdict=FAIL, classifications 에 `SELF_COLLECTOR_FORBIDDEN`
- `build_anu_owned_callback_request(owner_key=self, …)` → ok=False, argv=None

production path 가 self-key 입력을 만나면 cleanup_task + error return 으로 cron 등록 자체가 발생하지 않는다(0 cron registered · 0 subprocess invocation · 0 산출물).

## 7. fallback recovery-only 증거 (§10.6)

- fallback prompt 명시: `[task-2621 fallback safety-net · recovery-only · non-blocking] … 미수신 안전망. normal callback durable-success 즉시 cancel-on-success (no-dual-purpose · final-report 책임 0).`
- `RecoveryWatcher.recovery_is_fixed_time_or_dead_man = False` (코드 상수, 640665C8 anti-pattern 차단)
- POST-cron exec 단계적 enable (default OFF → PASS-path byte-0)
- V3b: env `COKACDIR_T2621_FALLBACK_AUTO_REGISTER=1` 일 때만 subprocess.run 호출됨을 mock 으로 실증
- cancel-on-success: normal callback durable-success 확정 즉시 fallback 제거 (helper module 의 cancel-on-success 계약 유지)

## 8. no-dual-purpose watcher 증거 (§10.7)

fallback callback 의 prompt 가 "final-report 책임 0 · cancel-on-success" 를 명시. final-report 트리거 경로는 본 wiring 과 분리된 별도 ANU collector path 가 담당(feedback_no_dual_purpose_watcher 정합). post-cron 블록은 fallback 만 등록하며 final-report assembly 를 트리거하지 않는다.

## 9. 남은 out-of-scope backlog (§10.8 — 자동 진행 0)

- S03~S07 5 sites (별도 backlog · task-2620 audit 산출)
- §2.C T01~T05 telemetry (별도 backlog)
- Track C task-2619 (별도 회장 승인 동결 유지)
- baseline 13 regression fails (regression/) (별도 hygiene backlog · task-2621 무관)
- `tests/regression/test_orchestration_runtime_2514.py` import error (별도 hygiene backlog)
- zombie cron dev2/dev8 8 residual (별도 hygiene backlog · cross-watcher 간섭 0)
- `tests/test_dispatch.py` 59 pre-existing fails (`tests/dispatch` shadow attribute bug from 2026-05-07 · task-2621 무관)
- 두 callback enforcement 시스템(+49 era `dispatch.callback_owner_enforcer` vs task-2614 `anu_v3.dispatch_callback_contract`) 통합 결정 (별도 회장 결정)
- task-2621+1 — non-Critical HIGH 자동 수렴 (필요 시)
- `AUTO_REMEDIATION_LOOP_BOUNDARY_REVIEW` — 동일 함수/file-boundary HIGH 3회 반복 시

## 10. 산출물 sha256

| File | sha256 |
|---|---|
| `dispatch/__init__.py` | `513173a74aebdaa7b69d9fd9a57cd4cc459737c8431e2767a37cdc3817b00e44` |
| `tests/regression/test_dispatch_init_callback_wiring.py` | `fedebb74599f7d592760a8b9260843d0fad24adbc3cb6cffc4b2bd737fb719cc` |
| `memory/events/task-2621.production-path-wiring-trace.json` | `1fda0157e42b842f9aad1b6affd1499b50e5c600dbd32d8688bee2055ed2f71d` |
| `memory/events/task-2621.before-after-wiring-matrix.json` | `2b43eb599c41fdf46f0f5fff055c4c7b4987933a66169fb0e9e8806ee4b444f7` |
| `memory/events/task-2621.decision.json` | `9b5b68bbb802af97c169decf2381d3a857d4f9753b2930915618049b58898f46` |

byte-0 invariant sha256 (변조 0 검증용):

| File | sha256 |
|---|---|
| `anu_v3/dispatch_callback_contract.py` | `4cd9ad4db25457180639a8ff23c4db0dd645c1341a90cab4c2ba6d17f21e5b74` |
| `dispatch/normal_fallback_callback_helper.py` | `1e2be5cd8a88989078e81256d2d7f6535bce7ced85064c115acb31060dbbaa43` |
| `dispatch/callback_owner_enforcer.py` | `2d181d823d0da0d16e6a2b0966690b395a2d5fcf0af2439e4e5bf3433d6db257` |
| `dispatch/cron_dispatch_guard.py` | `ce3f38051e92be79d9c1bdf2bb1a3b665d539c2f9dd4e280fcdcad944a98748b` |
| `dispatch/executor_completion_contract.py` | `364caa11904285657abd716d78c5493b1f8b519318387d0f864fb6a136dca0b4` |
| `dispatch.py` (shim) | `9bf60dad7e5b13b0da8fa7f26753229e145e666d24d2a8a843c1ba2fc391263c` |
| `dispatch/core.py` | `466c68e0bd21a028181c76c58caea245ca18afdd4bba4602582d29b3cdbc9b97` |
| `dispatch/prompt.py` | `e74c1b3e6dfeac523c29fe52285b0673f1ceb7e55ce1271ebda3cb22e60c0030` |
| `anu_v3/critical7_classifier.py` | `4766bc4c52018a8e8b2ec0fd6743f56c2ff9322dbf5447864e134993b6d9a336` |

## 11. V required check matrix

| V | Status | Evidence |
|---|---|---|
| V1 production path 호출 증거 | PASS | `memory/events/task-2621.production-path-wiring-trace.json` (6 trace entries) |
| V2 normal callback mandatory | PASS | `test_v2_normal_callback_mandatory_violation_when_both_missing` |
| V3 ANU-key fallback safety-net mandatory | PASS | `test_v3_fallback_safety_net_argv_built_with_anu_key` · `test_v3b_…executes_when_flag_enabled` |
| V4 self-key fail-closed | PASS | `test_v4` · `test_v4b` · `test_v4c` |
| V5 DISPATCH_CONTRACT_VIOLATION | PASS | `test_v5_dispatch_contract_violation_when_callback_and_fallback_missing` |
| V6 recovery watcher idempotent 1회 | PASS | `test_v6_recovery_watcher_idempotent_single_shot` · `test_v6b_…noop_when_condition_unmet` |
| V7 existing regression 무회귀 | PASS | 25 existing + 194 extended, 0 fail |
| V8 Codex HIGH/CRITICAL 0 | DEFERRED | 독립 ANU 재audit (executor self-Codex-audit 금지) |
| V9 git HEAD/branch EQUAL · commits 0 | PASS | HEAD/branch 전후 EQUAL · commits 0 |
| V10 PR/merge/credential/write 0 | PASS | 0 / 0 / 0 / 0 |
