# task-2782 착수 packet — 4종 종단 terminal callback 결선 (dispatch 전 검토용)

상태명: `TASK2782_KICKOFF_PACKET_ACTIVE_FALSE`
작성: ANU 직접 (2026-07-03 KST). **착수 packet only — dispatch/PR 생성/코드 수정 0.** 근거: GPT 판정(PR#263 merge+root-cause 수용 → task-2782 착수 packet 준비, 단 dispatch 전 expected_files/scope/위험경계/STOP조건/terminal-callback-vs-artifact-surfacing/owner-pickup≠callback 확인). 단일소스: [[bside_bounded_task_draft_260702]] · [[infra_defect_two_axis_260702]] · task md `memory/tasks/task-2782.md`.

## 0. 한 줄 목표 (GPT 프레이밍 고정)
finish-task **4종 종단(SUCCESS/FAILED/BLOCKED/ESCALATED) 모두**가 ANU terminal status(terminal marker + 최소 result.json + terminal callback 등록 **또는** fail-closed marker)를 **남기도록 결선**한다.
★ 지금 하는 일 = **terminal callback artifact를 더 정확히 남기고 드러내는 것**. **owner-pickup runner 활성화가 아니다.**

## 1. expected_files (이 3개만)
- `scripts/finish-task.sh` — state_file_missing/ESCALATED/BLOCKED/FAILED 분기(≈878~929)에 (a)최소 result.json 원자적 write (b)terminal_state_callback emit 호출 추가.
- `scripts/harness/v36/terminal_state_callback.py` — dispatched marker 부재 시 fallback context(schedule_id) 또는 fail-closed marker. **silent exit 0 제거**.
- `tests/regression/test_finish_task_terminal_termination_2782.py` (신규).

## 2. scope (무엇을 결선하나)
- `.done.escalated`(escalation 종단)를 정상완료가 아니라 **terminal callback 대상**으로 편입.
- 4종 종단 각각 **필수 3산출**: ①terminal marker ②최소 result.json(고정 envelope) ③terminal callback 등록 **또는** fail-closed marker.
- dispatched marker 부재 시 **silent exit 0 금지**(fallback context 또는 fail-closed marker + 명시 신호).
- result.json 최소 envelope: `{task_id, terminal_state, result_path, report_path, callback_schedule_created:bool, callback_context, reason, ts(UTC ISO8601)}` — marker 발행 직후 원자적 write, write 실패 시 fail-closed(침묵 통과 금지).

## 3. 위험 경계 / forbidden_paths (건드리면 STOP)
- `utils/replacement_pr_runner.py` **및 merge-executor 체인**(`merge_queue_executor.py`·`real_merge_hooks.py`·`repository_policy_adapter.py`·`automation_contracts.py`) — **무접촉**(방금 PR#263으로 손댄 A축, 이번 B축과 분리).
- `.github/**` · ruleset/branch protection · `.git/hooks/**` · `dispatch.py` · `scripts/gemini_evidence_verify.py` · `.claude/**` · `.env*` · `memory/state/**`.
- expected_files 밖 전부.

## 4. ★ terminal callback vs artifact surfacing 구분 (GPT 필수 확인)
서로 **다른 층**이며 혼동 금지:
- **artifact surfacing (PR#258 task-2778A, 이미 merged)** = worktree↔canonical **visibility gap을 표면화**하는 READ/surface 레이어. 이미 남은 terminal artifact가 canonical에서 안 보이는 것을 수거·index. **드러내기.**
- **terminal callback (task-2782, 본 건)** = finish-task **종단마다 terminal status를 실제로 생산**하는 WRITE/emit 레이어(finalize 시점). **애초에 남게 결선.**
- 관계: 2782가 생산하는 terminal artifact를 2778A가 표면화한다. 2782는 2778A가 표면화할 **"재료"를 정확히 만드는** 것 — surfacing을 다시 구현하는 게 아니다.

## 5. ★ owner-pickup ≠ callback (핵심 경계, GPT 강조)
- 본 task는 **"종단마다 terminal status가 남는다"만 보장**. **executor self-key 콜백 신규 발사 0**(OS-level pickup contract 준수).
- `callback_schedule_created=true`여도 `owner_pickup_required`면 **CALLBACK_DELIVERED로 승격 금지**. 분류는 `CALLBACK_REGISTERED_BUT_NOT_PICKED_UP`까지만.
- callback 분류 enum(검증용): `CALLBACK_DELIVERED / CALLBACK_NOT_DELIVERED / CALLBACK_REGISTERED_BUT_NOT_PICKED_UP / CALLBACK_FALSE_CLAIM`.
- **owner-pickup runner 활성화 / real fire / systemd / cron 전부 범위 밖. ACTIVE=false.** merge≠activation과 동일하게, terminal callback 결선≠pickup 활성화.

## 6. 실패 시 STOP_REPORT 조건
1. merge_queue_executor/replacement_pr_runner 등 **merge-executor 체인 수정이 필요**해지면 STOP(A축 침범·재승인).
2. **expected_files 밖 확장** 필요 시 STOP.
3. dispatched marker fallback이 **executor self-key 발사를 요구**하게 되면 STOP(OS-level pickup contract 위반).
4. finish-task.sh **종단 게이트 구조가 예상(878~929)과 다르면** STOP.
5. 테스트가 canonical 무접촉(mock/tmp 격리)로 안 짜이면 STOP(A축 truncate 교훈 — self-cannibal write 금지).
6. 봇 finish-task 종단 결과를 **수정본 end-to-end proof로 주장**하려는 유혹 시 STOP(canonical finish-task는 수정 전 버전일 수 있음 → isolated pytest로만 검증).

## 7. truncate watcher 전제 (완화됨)
- 초안(2026-07-02)은 "C안 inotify watcher arm 없이 dispatch 금지"가 **hard 전제**였음(truncate 구조원인 미수정 시).
- **PR#263 merge(2c79ffc5)로 truncate 구조원인(WORKSPACE fallback)이 canonical에 fail-closed로 반영됨** → task-2782 finish-task는 재truncate 안 할 것으로 예상.
- → watcher arm은 이제 **hard blocker 아님**. 단 **fix 발효 후 첫 finish-task 확인용으로 bounded watch(90분) 1회 arm 권장**(재발 0 확인 시 truncate 축 완전 종결). 선택.

## 8. 산출물 & 보고 (PR 생성 없음 — ANU 선보고)
1. worktree 브랜치 커밋. **PR 생성 금지**(ANU 독립검증 후 별도 승인 시).
2. ANU 선보고: 수정/생성 파일 범위 / 로컬 pytest 결과 / forbidden 무접촉(.github·merge-executor 체인 diff 0) / 수정본은 isolated 실행 근거만.
3. 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B).

## 9. 착수 조건 (dispatch 전 회장/GPT 승인 대기)
- 본 packet 승인 시: dispatch.py로 dev팀 위임(코드는 dev팀, ANU 코딩 0) → ANU 독립검증 → 선보고 → 별도 승인 시 PR.
- **현 단계 = packet 제출까지. dispatch/PR/코드수정 0.**
