# Callback Lifecycle — PR-ready Checklist (회장/OWNER 수동 실행용)

- **doc_id**: callback_lifecycle_pr_ready_checklist_260522
- **authored_by**: ANU (worktree PR-ready 검증 완료 · commit/push/PR 미실행 — 회장/OWNER 수동)
- **dry-run 근거**: callback_lifecycle_relayer_dryrun_result_260522.json (전 단계 PASS)
- **승인**: 회장 2026-05-22 — 10/10 정본 / pre-existing 3 분리 / 3 PR 전략 / blob-checkout+patch-apply / cherry-pick·역순 push·task-2625 금지

---

## ★ 사전 인지: git hook 게이트 (중요)

scripts/git-hooks/pre-commit·pre-push 가 모든 commit/push 에 적용:
- 검증3: branch 가 `task/task-N-bot` 패턴이어야 task-id 추출 / 검증4: `.tasks/locks/<task-id>.lock` 필요.
- integration 브랜치는 이 패턴이 아니므로 **그냥 commit 하면 BLOCKED**.
- **정식 우회(--no-verify 아님 · evidence 자동 로깅)**: `TASKCTL_BYPASS=1 TASKCTL_BYPASS_REASON="<사유>"`. 이게 hook 내장 sanctioned 경로(.tasks/evidence/ 에 4필드 기록). **`--no-verify` 는 금지(silent), TASKCTL_BYPASS 는 허용(audited)**.
- pre-push 도 동일 → push 시에도 동일 env 필요(또는 PR 브랜치 push 환경에서 동일 적용).

---

## 1. L3 classifier core 독립 PR (16 files)

PR-ready worktree: `/home/jay/.cokacdir/workspace/relayer-l3` (16 staged · 검증 완료) — 또는 아래 from-scratch.

diff 파일 (16):
- 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}/{evidence.json,expected.json,PROVENANCE.md} (12)

검증: classifier 8 passed · full suite 833 passed(=baseline 825 +8) · forbidden 0 · anu_v3 import 0 · raw credential 0.

from-scratch 실행:
```bash
git fetch origin
git worktree add /tmp/pr-l3 origin/main
cd /tmp/pr-l3 && git switch -c <L3-branch>
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 diff --cached --name-only | grep -E 'anu_v2/|replacement_pr_runner|merge_queue|\.github/|\.env|\.pem|\.key'   # → 비어야 함
python3 -m pytest tests/regression/test_callback_lifecycle_classifier.py -q                                       # → 8 passed
python3 -m pytest tests/regression/ -q                                                                            # → 833 passed / 3 failed(pre-existing) / 11 skipped
TASKCTL_BYPASS=1 TASKCTL_BYPASS_REASON="L3 callback lifecycle classifier core (task-2629) clean integration — chair approved" \
  git commit -m "callback lifecycle classifier core (evidence-only decoupled · task-2629)"
# push + PR: 회장/OWNER (App token) — pre-push 도 동일 TASKCTL_BYPASS 필요 가능
```

---

## 2. L1+L2 묶음 PR (22 files · commit 순서 L1 → L2)

PR-ready worktree: `/home/jay/.cokacdir/workspace/relayer-l1l2` (22 staged 검증 완료) — 단 2-commit 순서 분리 위해 아래 from-scratch 권장.

L1 diff (13): anu_v3 12개 + tests/regression/test_anu_v3_dependency_isolation_2628.py
L2 diff (9): dispatch/{callback_owner_enforcer,cron_dispatch_guard,executor_completion_contract,normal_fallback_callback_helper,spec_template_validator}.py · utils/completion_callback_fallback_cancel.py · tests/regression/test_callback_runtime_enforcement_2626.py · (M)prompts/DIRECT-WORKFLOW.md · (M)scripts/finish-task.sh

검증: L1 8 passed · L2 10 passed(정본) · full suite 843 passed(=baseline 825 +18) · patch-apply --3way clean · forbidden 0 · credential 0 · task-2625 유입 0.

from-scratch 실행 (base = L3 머지 후 최신 main 권장 · L3 decoupled 라 origin/main 도 가능):
```bash
git fetch origin
git worktree add /tmp/pr-l1l2 origin/main          # 또는 L3 머지 후 main
cd /tmp/pr-l1l2 && git switch -c <L1L2-branch>

# ── L1 commit ──
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
python3 -m pytest tests/regression/test_anu_v3_dependency_isolation_2628.py -q          # → 8 passed
TASKCTL_BYPASS=1 TASKCTL_BYPASS_REASON="L1 anu_v3 dependency closure (task-2628/2628+1) clean integration — chair approved" \
  git commit -m "Layer 1: anu_v3 dependency closure(12)+import isolation fix (task-2628/2628+1)"

# ── L2 commit ──
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
git diff 4a01553a~1 4a01553a -- prompts/DIRECT-WORKFLOW.md scripts/finish-task.sh | git apply --3way   # clean(검증됨)
git add -A
# 게이트: task-2625 유입 0 확인
git diff --cached --name-only | grep -E 'reconcile_evidence_contract_2624|lifecycle_reconciliation_manager|post_merge_smoke_runner'  # → 비어야 함
git diff --cached --name-only | grep -E 'anu_v2/|replacement_pr_runner|merge_queue|\.github/|\.env|\.pem|\.key'                       # → 비어야 함
python3 -m pytest tests/regression/test_callback_runtime_enforcement_2626.py -q          # → 10 passed
python3 -m pytest tests/regression/ -q                                                   # → 843 passed / 3 failed(pre-existing) / 11 skipped
TASKCTL_BYPASS=1 TASKCTL_BYPASS_REASON="L2 callback enforcement reflection (task-2627) clean integration — chair approved" \
  git commit -m "Layer 2: callback enforcement reflection (task-2627)"
# push + PR: 회장/OWNER
```

---

## 3. 각 PR diff 파일 목록
- L3 PR: 위 §1 (16) · 전부 신규(A) · origin/main 부재
- L1+L2 PR: 위 §2 (22 = L1 13 + L2 9) · L2 의 2개(DIRECT-WORKFLOW.md, finish-task.sh)만 수정(M), 나머지 20 신규(A)

## 4. regression 결과 (dry-run 실측)
- L3: classifier 8/8 · full 833 passed/3 failed/11 skipped (+8 vs baseline)
- L1: test_anu_v3_dependency_isolation_2628 8/8
- L2: test_callback_runtime_enforcement_2626 10/10 (정본)
- L1+L2 full: 843 passed/3 failed/11 skipped (+18 vs baseline 825)
- baseline(origin/main): 825 passed/3 failed/11 skipped

## 5. pre-existing 3 failures 분리 기록 (non-blocking backlog)
- tests/regression/test_stash_origin_audit_compat.py::{test_finish_task_sh_has_if_x_guard_for_stash_audit, test_finish_task_sh_stash_audit_guard_appears_twice, test_finish_task_sh_stash_before_greater_than_five_warn}
- origin/main baseline·L3·L1+L2 전부 동일 3건 FAIL → **integration 무관 pre-existing**. L2 finish-task.sh 변경(§5.5 callback gate)과 무관(다른 stash audit guard). 신규 유발 0·미해결 0.
- 별도 non-blocking cleanup backlog 등록: `memory/events/backlog_preexisting_stash_audit_fail_260522.json`

## 6. 회장/OWNER push/PR 전 최종 체크리스트
- [ ] L3 PR 먼저 (decoupled · 독립). PR merge 후 L1+L2 PR 의 base 를 최신 main 으로.
- [ ] 각 PR: forbidden path grep 0 · raw credential grep 0 확인
- [ ] L1+L2: task-2625(reconcile) 파일 유입 grep 0 확인 · commit 순서 L1→L2 엄수
- [ ] patch-apply(`--3way`) 결과 "clean" 확인 (충돌 시 원본=origin/main 기준 수동 resolve)
- [ ] 각 PR full `pytest tests/regression/` 신규 fail 0 (pre-existing 3 외 증가 없음) 확인
- [ ] commit 시 `TASKCTL_BYPASS=1 TASKCTL_BYPASS_REASON="..."` (--no-verify 금지)
- [ ] push/PR 는 회장/OWNER(App token) — 봇 시도 0
- [ ] L4 wiring 은 L1~L3 main 반영 **후** 별도 task 발행
- [ ] foreign dirty 5건 미접촉 유지 · 역순 체인 push 0 · cherry-pick 0

---

## scope_invariants_preserved
read-only 준비 · commit/push/PR/merge 미실행 · cherry-pick 0 · task-2625 유입 0 · 역순 체인 0 · foreign dirty 미접촉 · replacement_pr_runner 미접촉 · callback 재발사 0

끝
