# task-2630 — L4 wiring: callback lifecycle classifier 실결선 (CALLBACK_RUNTIME_ENFORCEMENT L4)

- Level: Lv.3 (시스템 wiring / 기존 아키텍처 통합)
- 담당: dev6 페룬
- base: origin/main **94540f67** (L1+L2+L3 머지 완료분)
- 단일소스 스펙: `memory/specs/system_callback_lifecycle_state_schema_260522.md`
- 선행 머지: classifier core(`utils/callback_lifecycle_classifier.py`, L3) · executor_completion_contract/callback enforcement(L1+L2) 모두 origin/main 반영됨

## 목표 (회장 verbatim)
executor completion contract와 callback runtime 경로에 callback lifecycle classifier를 실제 결선한다.
result.json fields 10~14를 append emit하고, `memory/events/<task>.callback_lifecycle.json` artifact를 생성하게 하라.

## 필수 구현 (회장 verbatim — 10항)
1. executor_completion_contract에 fields 10~14 append
   - delivery_outcome
   - normal_callback_miss_cause
   - root_cause_tags
   - lifecycle_state_evidence
   - classified_by / applied_count
2. callback_lifecycle_classifier 호출 결선
3. callback_lifecycle.json artifact writer 추가
4. 기존 callback contract 9 fields를 대체하지 말고 append-only 확장
5. callback gate PASS / notification sent / collector received를 분리 기록
6. normal callback 미발사 시 fallback collector artifact와 lifecycle classifier artifact를 구분
7. evidence 부족 시 UNKNOWN / INSUFFICIENT_EVIDENCE로 기록하고 추정 금지
8. CALLBACK_DELIVERY_GAP은 residual로만 사용
9. SELF_KEY_FAIL_CLOSED_BEFORE_FIRE와 SELF_KEY_FIRED_NON_AUTHORITATIVE 분리 유지
10. production enforcement 완료 판정은 L4 merge 후 별도 검증까지 보류

## 구현 가이드 (grounding)
- classifier API: `from utils.callback_lifecycle_classifier import classify_callback_lifecycle` →
  `classify_callback_lifecycle(evidence: dict, anu_keys=DEFAULT_ANU_KEYS) -> dict`
  반환 키: `delivery_outcome, normal_callback_miss_cause, root_cause_tags, evidence_completeness, missing_evidence_sources, classification, lifecycle_state_evidence, classified_by`
- 결선 대상: `dispatch/executor_completion_contract.py` (CONTRACT_SCHEMA `dispatch.executor_completion_contract.v1`, `ExecutorCloseoutEvidence`, `classify_completion`). 기존 9 closeout/result 필드(result_json_present 등)는 보존하고 fields 10~14를 **append-only**로 확장.
- classifier는 순수함수(I/O 0). evidence snapshot(dict) 구성 → classifier 호출 → 결과를 result.json fields 10~14에 append + `memory/events/<task>.callback_lifecycle.json` artifact로 별도 기록.
- artifact writer는 **idempotent**(동일 입력 재실행 시 동일 결과·중복 0).
- `applied_count`는 collector 적용 횟수(fallback no-op 구분용).

## 필수 regression (회장 verbatim — 10항)
1. task-2625 fixture → SELF_KEY_FIRED_NON_AUTHORITATIVE
2. task-2628 fixture → FINISH_TASK_GIT_GATE_BLOCKED_BEFORE_CALLBACK + FOREIGN_DIRTY_BLOCKER
3. task-2628+1 fixture → FALLBACK_COLLECTOR_APPLIED + ENVELOPE_PREPARED_NOT_FIRED
4. UNKNOWN / INSUFFICIENT_EVIDENCE fixture
5. 기존 callback contract 9 fields 유지
6. fields 10~14 append 확인
7. callback_lifecycle.json idempotent artifact 생성
8. live workspace 의존 0
9. foreign dirty 미접촉
10. callback 재발사 0

- fixtures(이미 origin/main 존재): `tests/fixtures/callback_lifecycle/{task-2625,task-2628,task-2628_plus_1,unknown_insufficient}/{evidence.json,expected.json,PROVENANCE.md}` 재사용. frozen — fixture evidence 날조/수정 금지.
- 신규 wiring 통합 테스트는 `tests/regression/test_callback_lifecycle_wiring_2630.py`로 추가. live workspace 의존 0(WORKSPACE_ROOT env override / Path(__file__) 기반).

## 자동수렴 원칙 (회장 verbatim)
- Gemini medium/style/quality 제안은 expected_files 내부면 자동 반영하라.
- 회장에게 A/B/C 확인하지 말 것.
- Critical7, credential/permission expansion, expected_files 밖 수정, admin override 필요, post-merge smoke failure만 회장에게 보고하라.
- credential scan은 3계층 doctrine 적용(`memory/feedback_credential_scan_3tier_doctrine_260522.md`): BLOCKING_SECRET(ghp_/ghs_/PEM/AWS/신규 secret)만 차단. origin/main 기존 식별상수(ANU/dev key) 재사용은 fail 아님.

## 금지 (회장 verbatim — 절대 준수)
- L4 범위 밖 수정 금지
- foreign dirty 5건 정리 금지
- replacement_pr_runner 수정/commit/revert/stash 금지
- callback 재발사 금지
- marker 삭제 금지
- production enforcement 완료 판정 금지
- admin override 임의 사용 금지
- merge는 모든 gate 확인 후 별도 승인 전 금지

## expected_files (L4 범위)
- `dispatch/executor_completion_contract.py` (fields 10~14 append + classifier 결선)
- callback_lifecycle.json artifact writer (위 파일 내 함수 또는 `dispatch/`/`utils/` 신규 모듈 — 최소 범위)
- `tests/regression/test_callback_lifecycle_wiring_2630.py` (신규 통합 테스트)
- (필요 시) `memory/specs/system_callback_lifecycle_state_schema_260522.md` §wiring 보강 — 코드 정합 한정

## finalize 프로토콜 (★ BOT App token 부재 — 로컬 한정)
BOT App token 부재로 봇은 **push/PR/merge 불가**. 따라서:
1. base = 최신 origin/main 94540f67에서 clean worktree 작업
2. L4 구현 + 위 10 regression 전부 PASS + full tests/regression 신규 fail 0 확인
3. **로컬 commit만** (push 금지·PR 금지·merge 금지)
4. result.json + report + `.done` marker 생성, `finish-task.sh`는 project_path 없이 실행(로컬 종결)
5. ANU normal completion callback 발사 — **반드시 독립 ANU key `c119085addb0f8b7`**로(executor self-key 자가발사 절대 금지). collector_role=ANU.
6. callback envelope = **UTF-8 ≤3900 bytes**, envelope만 포함: task_id · 로컬 commit SHA · result_path · report_path · regression 요약 · expected_files · sha256. 상세는 result.json/report.md에 위임.
7. 산출물 귀속 명기: executor 윈도(시작/종료 ts) · 로컬 commit SHA · result.json에 callback prompt UTF-8 byte 수 기록.

이후 ANU가 봇 로컬 commit을 fresh clean worktree에 재적층 → OWNER 권한 push → PR open → Gemini auto-remediation → 회장 8항목 보고 → 회장 별도 merge 승인.

## 검증 시나리오 (이게 되면 성공)
- 4개 fixture가 classifier 결선 경로를 통해 expected.json의 (delivery_outcome, miss_cause, root_cause_tags)와 정확히 일치
- 실제 closeout 1건에 대해 result.json에 기존 9 fields + 신규 fields 10~14가 동시 존재
- `memory/events/<task>.callback_lifecycle.json`이 생성되고 동일 입력 2회 실행 시 byte-identical(idempotent)
- evidence 결핍 입력 → UNKNOWN/INSUFFICIENT_EVIDENCE 기록(추정 0)

## frozen anchor (D-SPEC-EXACTNESS — 본 spec 무손실 확인용)
- ANCHOR-1: "result.json fields 10~14를 append emit하고, memory/events/<task>.callback_lifecycle.json artifact를 생성"
- ANCHOR-2: "기존 callback contract 9 fields를 대체하지 말고 append-only 확장"
- ANCHOR-3: "CALLBACK_DELIVERY_GAP은 residual로만 사용 · SELF_KEY_FAIL_CLOSED_BEFORE_FIRE와 SELF_KEY_FIRED_NON_AUTHORITATIVE 분리 유지"
- ANCHOR-4: "production enforcement 완료 판정은 L4 merge 후 별도 검증까지 보류"
