# Callback Lifecycle — Re-layering Execution Plan (read-only)

- **doc_id**: callback_lifecycle_relayer_execution_plan_260522
- **authored_by**: ANU (read-only · 코드 0 · push/PR/merge 0 · cherry-pick 0 · foreign dirty 미접촉 · callback 재발사 0)
- **trigger**: 회장 결정 2026-05-22 — 재적층 채택 / L1 anu_v3 → L2 callback → L3 classifier → L4 wiring 고정 / task-2625(7f2fb42f) 제외 / 역순 체인 push 금지
- **base**: origin/main 4187332c (clean)

---

## 1. Layer 1 — anu_v3 dependency closure (13 files · 1 commit)

source: d8ea371f(anu_v3 12) + 89f1eda4(test FIX 버전)
- anu_v3/active_dispatch_scanner.py · authoritative_verdict_selector.py · callback_4tuple_registry.py · callback_owner_validator.py · dispatch_callback_contract.py · executor_callback_contract.py · runtime_batch_state_updater.py · runtime_next_action_resolver.py · runtime_reconcile_checkpoint.py · runtime_reconcile_checkpoint_recovery_layer.py · self_collector_guard.py · task_artifact_detector.py (12 · from d8ea371f · 전부 NEW)
- tests/regression/test_anu_v3_dependency_isolation_2628.py (1 · ★from **89f1eda4**, FIX 버전 · NEW)
- 전부 origin/main 부재(신규) → blob checkout 안전.

## 2. Layer 2 — callback enforcement reflection (9 files · 1 commit · on Layer 1)

source: 4a01553a
- **NEW(A · blob checkout 안전)**: dispatch/callback_owner_enforcer.py · dispatch/cron_dispatch_guard.py · dispatch/executor_completion_contract.py · dispatch/normal_fallback_callback_helper.py · dispatch/spec_template_validator.py · utils/completion_callback_fallback_cancel.py · tests/regression/test_callback_runtime_enforcement_2626.py
- **MODIFIED(M · ★patch-apply 권장)**: prompts/DIRECT-WORKFLOW.md · scripts/finish-task.sh (origin/main 존재 — wholesale blob checkout 시 origin/main 의 최신 변경 clobber 위험 → diff patch 적용 권장, §9 참조)
- ★ dispatch/executor_completion_contract.py = **Layer 4 wiring 의 fields 10~14 emit 대상** (여기서 도착, 수정은 L4).

## 3. Layer 3 — callback lifecycle classifier core (16 files · 1 commit · 독립)

source: 03c151cd (base=origin/main · 전부 NEW)
- utils/callback_lifecycle_classifier.py · utils/callback_lifecycle_states.py
- tests/regression/conftest.py · tests/regression/test_callback_lifecycle_classifier.py
- tests/fixtures/callback_lifecycle/{task-2625,task-2628,task-2628_plus_1,unknown_insufficient}/{PROVENANCE.md,evidence.json,expected.json} (12)
- ★ decoupled(anu_v3 import 0) → Layer 1·2 와 순서 무관·독립 머지 가능.
- ⚠️ tests/regression/conftest.py 신규 → 다른 regression 수집에 영향 가능 → L3 후 **full tests/regression/ 수트 1회** 부수효과 확인 필수(§9 R6).

## 4. Layer 4 — wiring (Phase 3 · 미구현 · 별도 후속 PR)

나중에 **수정**할 대상:
- dispatch/executor_completion_contract.py — result.json fields 10~14(delivery_outcome/normal_callback_miss_cause/root_cause_tags/lifecycle_state_evidence/classified_by) emit + `utils.callback_lifecycle_classifier.classify()` 호출 (append-only · 9 fields 대체 0)
- 신규 artifact: memory/events/<task>.callback_lifecycle.json (classifier output writer)
- 전제: Layer 1~3 가 origin/main 반영된 후 신규 task 로 구현. 본 plan 범위 아님.

---

## 5. task-2625 reconcile(7f2fb42f) 제외 영향 = ZERO (실측)

- 7f2fb42f 변경: utils/lifecycle_reconciliation_manager.py(M) · utils/post_merge_smoke_runner.py(M) · tests/regression/test_reconcile_evidence_contract_2624.py(A)
- **Layer 1/2/3 가 위 2개 M 파일 import = 0건**(grep 실측). 두 파일은 origin/main 원본 그대로 유지되며 Layer 1~3 어디서도 task-2625 추가 API 미사용.
- Layer 3 의 `tests/fixtures/callback_lifecycle/task-2625/` 는 **frozen evidence 스냅샷 명칭**일 뿐 task-2625 reconcile 코드 의존 아님.
- 결론: task-2625 별도 트랙 분리해도 Layer 1~3 무영향. (task-2625 reconcile 자체 머지는 독립 트랙 회장 결정)

---

## 6. Layer별 regression 명령 / 기대

- **Layer 1**: `pytest tests/regression/test_anu_v3_dependency_isolation_2628.py` → **8 passed** (FIX 버전이므로 worktree 포함 어디서나 8/8)
- **Layer 2**: `pytest tests/regression/test_callback_runtime_enforcement_2626.py` → **10 passed** (anu_v3 = Layer 1 필요 → 의존 순서 검증됨. Layer 1 없이는 ImportError = 역순 방지 증명)
- **Layer 3**: `pytest tests/regression/test_callback_lifecycle_classifier.py` → **8 passed** (3 fixture 단일값 + UNKNOWN + DELIVERY_GAP residual)
- **L3 후 부수효과**: `pytest tests/regression/` 전체 → 신규 conftest.py 가 기존 테스트 깨지 않는지 확인(기대: 기존 통과분 유지)

---

## 7. Layer별 forbidden / credential / scope 확인

- **공통 forbidden 부재 확인**: anu_v2/** · utils/replacement_pr_runner.py · utils/merge_queue_executor.py · .github/** · .env* · *.pem · *.key 변경 0 (각 Layer diff name-only grep)
- **Layer 1**: forbidden 0 · credential = anu_v3 모듈 내 ANU/self-key denylist 상수(baseline 동일·신규 secret 0) · scope 13 files
- **Layer 2**: forbidden 0(replacement/merge_queue 무관) · credential = callback 모듈 denylist 상수(baseline) · scope 9 files
- **Layer 3**: forbidden 0 · credential 0 · anu_v3 import 0(docstring 1줄만) · scope 16 files
- 각 Layer commit 후 `git diff --name-only origin/main <layer-head>` 로 scope 파일 수 = 13/22/38 누적 확인.

---

## 8. PR 분리 vs 단일 PR 추천

- 회장 선호 = 가능하면 분리. 현실 = BOT App token 부재로 전부 회장/OWNER 수동.
- L1↔L2 는 **dependency-coupled**(L2 test 가 L1 anu_v3 필요) → 분리 PR 시 L1 머지 후 L2 rebase 필요(순차 머지 사이클 2회).
- L3 는 **decoupled** → 독립 PR 언제든 가능.
- **ANU 추천(균형안)**: ① **L3 독립 PR**(저위험·decoupled·지금 머지 가능) + ② **L1+L2 한 PR(2 commit, L1→L2 순서)**(coupled라 묶는 게 rebase 부담↓). ③ **L4 별도 후속 PR**.
- 대안: 회장이 granular review 원하면 3 PR(L1→L2 순차 머지 필수). 단일 통합 PR 도 가능하나 **commit 순서 반드시 L1→L2→L3**.

---

## 9. 회장/OWNER 수동 반영 명령 순서 (blob-checkout · 안전 · task-2625 미유입)

```bash
git fetch origin
git worktree add /tmp/relayer-cbl origin/main
cd /tmp/relayer-cbl && git switch -c integration/callback-lifecycle

# ── Layer 1 (NEW blobs) ──
git checkout d8ea371f -- anu_v3/active_dispatch_scanner.py anu_v3/authoritative_verdict_selector.py \
  anu_v3/callback_4tuple_registry.py anu_v3/callback_owner_validator.py anu_v3/dispatch_callback_contract.py \
  anu_v3/executor_callback_contract.py anu_v3/runtime_batch_state_updater.py anu_v3/runtime_next_action_resolver.py \
  anu_v3/runtime_reconcile_checkpoint.py anu_v3/runtime_reconcile_checkpoint_recovery_layer.py \
  anu_v3/self_collector_guard.py anu_v3/task_artifact_detector.py
git checkout 89f1eda4 -- tests/regression/test_anu_v3_dependency_isolation_2628.py
git add -A && git commit -m "Layer 1: anu_v3 dependency closure(12)+import isolation fix (task-2628/2628+1)"
pytest tests/regression/test_anu_v3_dependency_isolation_2628.py            # → 8 passed

# ── Layer 2 — NEW(A) blobs ──
git checkout 4a01553a -- dispatch/callback_owner_enforcer.py dispatch/cron_dispatch_guard.py \
  dispatch/executor_completion_contract.py dispatch/normal_fallback_callback_helper.py \
  dispatch/spec_template_validator.py utils/completion_callback_fallback_cancel.py \
  tests/regression/test_callback_runtime_enforcement_2626.py
# ── Layer 2 — MODIFIED(M) 2개는 patch-apply (origin/main 최신 보존) ──
git diff 4a01553a~1 4a01553a -- prompts/DIRECT-WORKFLOW.md scripts/finish-task.sh | git apply --3way
git add -A && git commit -m "Layer 2: callback enforcement reflection (task-2627)"
pytest tests/regression/test_callback_runtime_enforcement_2626.py          # → 10 passed

# ── Layer 3 (NEW · decoupled) ──
git checkout 03c151cd -- utils/callback_lifecycle_classifier.py utils/callback_lifecycle_states.py \
  tests/regression/conftest.py tests/regression/test_callback_lifecycle_classifier.py \
  tests/fixtures/callback_lifecycle/
git add -A && git commit -m "Layer 3: callback lifecycle classifier core (task-2629)"
pytest tests/regression/test_callback_lifecycle_classifier.py             # → 8 passed
pytest tests/regression/                                                   # full suite (conftest 부수효과 확인)

# 검증 후 회장/OWNER push + PR (BOT App token 부재 → 수동)
```
- ★ NEW 파일은 blob checkout, MODIFIED 2개(DIRECT-WORKFLOW.md·finish-task.sh)는 **patch-apply**(`git apply --3way`)로 origin/main 최신 변경 clobber 방지. 충돌 시 회장/OWNER 수동 resolve.
- ★ 이 시퀀스는 7f2fb42f(task-2625) blob 을 일절 가져오지 않음 → task-2625 미유입 보장.
- L3 를 독립 PR 로 할 경우: 별도 worktree(origin/main)에서 Layer 3 블록만 실행.

---

## 10. 남은 blocker

- **B1(HARD)**: BOT App token(ghs_) 부재 → push/PR/merge = 회장/OWNER 수동만.
- **B2(검증)**: MODIFIED 2파일 patch-apply 충돌 가능 → `--3way` 실패 시 수동 resolve(원본 = origin/main).
- **B3(검증)**: L3 신규 tests/regression/conftest.py 부수효과 → full suite 1회 확인 필수.
- **B4(분리)**: foreign dirty 5건은 clean worktree 경로라 무접촉(이번 integration 무관).
- **B5(후속)**: Layer 4 wiring 미구현 → L1~3 머지 후 별도 task.

---

## 11. 회장 최종 승인 필요 항목

1. PR 전략 확정: ANU 추천(L3 독립 + L1+L2 묶음 + L4 후속) vs 3 PR vs 단일 통합 PR(L1→L2→L3 순)
2. blob-checkout 수동 시퀀스(§9) 채택 vs cherry-pick 선호
3. 실행 주체/시점(회장 직접 vs OWNER)
4. branch/PR 명명 규칙
5. L3 후 full tests/regression/ 게이트 의무화 확인
6. Phase 3 wiring task 발행 시점(L1~3 머지 후)

---

## scope_invariants_preserved
read-only · 코드 0 · push/PR/merge 0 · cherry-pick 0 · 역순 체인 push 0 · task-2625 유입 0 · foreign dirty 미접촉 · replacement_pr_runner 미접촉 · callback 재발사 0 · marker 삭제 0 · production enforcement 완료 판정 0

끝
