# Callback Lifecycle Wiring — Integration Handoff Plan (read-only)

- **doc_id**: callback_lifecycle_wiring_handoff_plan_260522
- **authored_by**: ANU (read-only · 코드 0 · push/PR/merge 0 · foreign dirty 미접촉 · callback 재발사 0)
- **trigger**: 회장 결정 2026-05-22 — task-2629 CALLBACK_LIFECYCLE_CLASSIFIER_CORE_READY · wiring handoff plan 작성 지시
- **single_source_spec**: memory/specs/system_callback_lifecycle_state_schema_260522.md

---

## 1. 현재 미반영 스택 표 (전부 origin/main 4187332c 미반영)

**Chain A — branch `task/task-2625-reconcile-evidence` (선형 체인 · ★dependency-INVERTED)**
순서: 7f2fb42f → 4a01553a → edf05f49 → d8ea371f → 89f1eda4

| 스택 | commit | task | 변경 | regression | 비고 |
|---|---|---|---|---|---|
| reconcile evidence | 7f2fb42f | task-2625 | 3 files / +613 | (체인 base) | origin/main 미반영 — 체인 최하단 |
| callback enforcement | 4a01553a | task-2626/2627 | 9 files / +3171 | 10/10 (task-2626 reverify) | ★anu_v3 import하나 **dep 이전에 위치** |
| result.json | edf05f49 | task-2626 | 1 file / +138 | — | callback 산출물 |
| anu_v3 12 closure | d8ea371f | task-2628 | 13 files / +3319 | 8/8 | callback 의 **의존**인데 **소비자 이후** 위치 |
| import isolation fix | 89f1eda4 | task-2628+1 | 1 file / +41-28 | 8/8 (3 context) | d8ea371f 위 chained |

**Independent — branch `task/task-2629-dev6` (★clean · origin/main 직결)**
| 스택 | commit | task | 변경 | regression | 비고 |
|---|---|---|---|---|---|
| classifier core | 03c151cd | task-2629 | 16 files / +791 | 8/8 (3 fixture + UNKNOWN + DELIVERY_GAP residual) | base=origin/main · **anu_v3 import 0(docstring 1줄만)** · decoupled |

> 표는 스펙 문서용(보고 시 산문화).

---

## 2. ★ 핵심 문제: Chain A 의 dependency 역순

- callback enforcement(4a01553a)가 anu_v3 12(d8ea371f)를 **import 하는데**, 체인상 **dep 보다 먼저** 커밋됨.
- 결과: 4a01553a 단독 checkout 시 callback 모듈 ImportError(anu_v3 부재). 테스트는 conftest false-pass(이번에 task-2628+1 로 차단)로 가려졌던 것.
- → Chain A 를 그대로 fast-forward push 하면 **중간 commit 이 dependency-broken**. 클린 layered merge 불가.
- 추가: 체인 base 7f2fb42f(task-2625 reconcile)도 origin/main 미반영 → 체인 통째 push 시 task-2625 reconcile 까지 동반.

---

## 3. 추천 merge/integration 순서 (dependency-correct re-layering)

Chain A 를 그대로 밀지 말고, **fresh origin/main 위에 의존 순서로 재적층** 권고:

- **Layer 0 (선결정)**: task-2625 reconcile(7f2fb42f) — 본 integration 포함 여부 회장 결정(논리적 별개 트랙).
- **Layer 1 — anu_v3 dependency closure (foundation)**: anu_v3 12 파일(d8ea371f) + **FIX 버전 test**(89f1eda4). dep 먼저.
- **Layer 2 — callback enforcement reflection**: callback 9 파일(4a01553a) on Layer 1. 이제 anu_v3 import 해소.
- **Layer 3 — classifier core**: 03c151cd 16 파일. **decoupled 라 독립/병렬 머지 가능**(Layer 1·2 와 순서 무관). 단 wiring 전 origin/main 에 존재해야 함.
- **Layer 4 — wiring (Phase 3 · 미구현)**: result.json fields 10~14 emit + collector 경로 classifier 호출. Layer 1~3 가 origin/main 반영된 **후** 신규 task 로 구현.

대안(더 안전): 회장/OWNER 가 clean origin/main 위에 위 layer 들을 **수동 cherry-pick(의존 순서)**로 1개 integration PR 조립 → 봇 finish-task GIT-GATE 우회. (BOT App token 부재라 어차피 push 주체=회장/OWNER)

---

## 4. classifier core ↔ wiring 분리 유지 방안

- **core**(utils/callback_lifecycle_classifier.py + states · 03c151cd): anu_v3 import 0 · 순수함수 · Layer 3 로 **독립 머지**. 재검증도 origin/main 단독에서 가능.
- **wiring**(Phase 3): dispatch/executor_completion_contract.py 가 classifier 를 **호출**해 fields 10~14 emit. callback enforcement(Layer 2)에 결합 → Layer 2 와 같은 bundle/후속.
- 분리 불변식: core 는 dispatch/ 를 import 하지 않음 / wiring 이 core 를 import(단방향). core 는 wiring 없이도 standalone 검증 가능(이미 8/8).

---

## 5. fields 10~14 를 executor completion contract 에 append 하는 위치

- 대상 파일: **`dispatch/executor_completion_contract.py`** (executor 완료 시 result.json emit 모듈 · 현재 origin/main MISSING · 4a01553a callback layer 소속).
- append 방식: 기존 callback contract 9 fields 뒤에 (10)delivery_outcome (11)normal_callback_miss_cause (12)root_cause_tags (13)lifecycle_state_evidence (14)classified_by/applied_count 추가. **9 fields 대체 0 · append-only**.
- 호출: executor_completion_contract → `utils.callback_lifecycle_classifier.classify(evidence)` → 결과를 10~14 에 기록. (Layer 4 wiring)
- ★ 이 변경은 dispatch/ 라 callback enforcement layer(Layer 2)와 함께 가야 함 → core(Layer 3, utils/)와 물리 분리 유지.

---

## 6. callback gate PASS / notification sent / collector received 구분 artifact 위치

3개를 절대 혼동 말 것 — 각각 별도 신호:
- **gate PASS**: `scripts/finish-task.sh` §5.5 게이트 로그 + result.json `callback_registration_status` (envelope 준비/게이트 통과 여부).
- **notification sent**: cron 등록+발사 → `schedule_history/<cron_id>.log` + **cron owner key**(c119085a=ANU/1e41a232=self) + result.json `callback_cron_id`.
- **collector received**: collector artifact 존재 → `memory/events/<task>.independent-anu-collector.result.json`(fallback/manual) 또는 normal 수집 레코드 + result.json `delivery_outcome`.
- → 3 신호 = result.json 의 3개 독립 필드(registration_status / cron_id+fired / delivery_outcome). gate PASS ≠ fired ≠ received.

---

## 7. fallback collector artifact ↔ lifecycle classifier artifact 관계

- **fallback collector artifact** = `memory/events/<task>.independent-anu-collector.result.json` — fallback/manual collector 가 쓰는 **RAW 수집 기록(INPUT 증거)**.
- **lifecycle classifier artifact** = `memory/events/<task>.callback_lifecycle.json`(Layer 4 신규) — classifier 가 증거 읽어 산출한 **DERIVED 2축 분류(OUTPUT)**.
- 관계: classifier 가 collector artifact 를 **증거의 하나로 소비** → delivery_outcome=FALLBACK_COLLECTOR_APPLIED 판정. collector=입력 / classifier=출력. **혼용 금지**(collector 는 복구 기록, classifier 는 파생 상태).
- 실증: task-2628+1 = collector artifact(independent-anu-collector.result.json) 존재 → classifier 가 FALLBACK_COLLECTOR_APPLIED 판정(frozen fixture 로 검증됨).

---

## 8. foreign dirty / shared workspace GIT-GATE 오발화 재발 방지 clean integration path

- **근본**: finish-task scope-guard/GIT-GATE 가 **공유 메인 workspace** main..HEAD(384 files / foreign dirty 5)를 검사 → GIT_GATE_SHARED_WORKSPACE_MISFIRE + SCOPE_GUARD_MAIN_HEAD_DIVERGENCE. (task-2628/2628+1/2629 3연속 동일 패턴 · per-task diff 는 전부 in-scope · deliverable defect 0)
- **clean path**:
  1. 각 layer 를 **fresh isolated worktree on origin/main** 에서 빌드(task-2629 03c151cd 가 이미 clean 입증).
  2. push/PR/merge 는 **clean worktree commit 기준**으로 회장/OWNER 수행(BOT App token 부재).
  3. **폴루션된 메인 workspace 경유 integration 절대 금지**.
  4. (권고) 회장/OWNER 가 clean origin/main 에 layer commit 들을 의존 순서로 cherry-pick 해 integration PR 수동 조립 → 봇 finish-task GIT-GATE 완전 우회.
  5. foreign dirty 5건(memory/specs ×3 + replacement_pr_runner.py + 그 test)은 **integration 과 별개** 정리(회장 결정) — replacement_pr_runner.py 는 production sole source 라 단독 정리 불가.

---

## 9. risk / blocker

- **R1 (HIGH)**: Chain A dependency 역순(callback 4a01553a < anu_v3 d8ea371f) → 클린 layered merge 위해 재적층 필수. fast-forward push 불가.
- **R2 (MED)**: 체인 base 7f2fb42f(task-2625 reconcile) 미머지 → 통째 push 시 동반. 포함/분리 회장 결정.
- **R3 (HARD blocker)**: BOT App token(ghs_) 부재 → push/PR/merge 주체 = 회장/OWNER 만.
- **R4 (HIGH)**: 메인 workspace foreign dirty 5 → clean worktree 경유 필수, 메인 경유 금지.
- **R5 (Phase 3)**: wiring(fields 10~14 emit + classifier 호출) 미구현 → Layer 1~3 origin/main 반영 후 신규 task.
- **R6 (LOW)**: 03c151cd 가 tests/regression/conftest.py 신규 추가(현재 origin/main 무충돌) — 후속 layer 와 충돌 없는지 integration 시 재확인.

---

## 10. 회장 결정 필요 항목

1. **재적층 vs 역순 체인 push**: dependency-correct 재적층(권고) 채택 여부.
2. **task-2625 reconcile(7f2fb42f)**: 본 integration 포함 vs 별도 트랙.
3. **merge 순서 승인**: Layer1 anu_v3 → Layer2 callback → Layer3 classifier(독립) → Layer4 wiring.
4. **classifier core 머지 타이밍**: 독립 조기 머지(decoupled) vs callback bundle 동반.
5. **push/PR/merge 실행 주체/방식**: 회장/OWNER 수동(App token 부재) — cherry-pick 수동 조립 vs clean worktree finish.
6. **foreign dirty 5 정리**: 시점/주체(integration 과 분리).
7. **Phase 3 wiring task 발행 시점**: 지금 spec 만 vs Layer1~3 origin/main 반영 후.

---

## scope_invariants_preserved
read-only · 코드 수정 0 · push/PR/merge 0 · foreign dirty 미접촉 · callback 재발사 0 · marker 삭제 0 · production enforcement 완료 판정 0 · core/wiring 무리한 1-task 병합 0

끝
