# task-2640 — SELF_COLLECTOR enforcement wiring hardening batch (Track A/B/C/D · 회장 forbidden unfork 6항목)

- Level: Lv.4 (callback runtime enforcement wiring · dispatch entrypoint + prompt + settings + read-only D spec)
- 담당: dev6 페룬
- base: origin/main **93598660** (PR #142 snapshot crossref 정책 머지 반영)
- 단일소스 spec: `memory/specs/system_self_collector_enforcement_wiring_spec_260523.md`
  - sha256: `db635c7dc5a03fa85d133b87fe4409c1d866532f15f4ff109c5937c76d8fcc1c`
  - 정독 전 sha256sum 검증 필수
- 회장 결정 (2026-05-23): SELF_COLLECTOR 3회 재발 원인 = 코드 정의 ≠ runtime path 결선. 본 task = 결선 추가 정책.

## 회장 verbatim unfork 결정 6항목 (★ 반드시 반영)
1. **dispatch/__init__.py 수정 허용** — public import surface 확장 한정 (enforcer/helper/validator import만)
2. **dispatch/core.py 수정 허용** — 봇 spawn 직전 callback contract validator 호출. ANU-owned callback contract 부재 시 fail-closed 또는 dispatch block
3. **dispatch/prompt.py 수정 허용** — prompt 생성 전 enforce guard 통과 확인. prompt 텍스트만으로 callback 정책 전달 금지
4. **prompts/team_prompts.py 수정 허용** — ANU_KEY 텍스트 + 코드 contract 연결 강제. SELF_COLLECTOR / SENDFILE_ONLY / NOT_REGISTERED 변종 prompt-level 명시 차단
5. **bot_settings 정책 위치** — dev bot 후보 제안 후 ANU 정합 검증. runtime 읽기 가능한 명시적 설정 파일. `require_anu_callback_on_finish=true` 기본값 설계
6. **finish-task.sh 수정 금지** — Track D read-only spec만. unfork 별도 회장 결정

## Track A — dispatch entrypoint hardening
허용 수정:
- `dispatch/__init__.py` (import 결선만 — enforce_callback_owner / build_anu_owned_callback_request / validate_spawn_callback_contract)
- `dispatch/core.py` (봇 spawn 직전 contract validator 호출)
- `dispatch/prompt.py` (prompt 생성 전 enforce guard)
- `dispatch/spawn_callback_contract_validator.py` (신규 helper)

목표:
- 봇 spawn 전 ANU-owned callback contract validator 호출
- callback owner enforcement 가 실제 runtime path 에 결선
- self-key / self-collector / sendfile-only / not-registered 를 dispatch 단계에서 fail-closed

## Track B — prompt/lifecycle hardening
허용 수정:
- `prompts/team_prompts.py`

목표:
- 텍스트 doctrine 만 삽입하는 구조 제거
- 코드 contract 에서 생성된 callback policy 를 prompt 에 반영
- prompt 본문 자동 주입 (verbatim doctrine block):
  ```
  ## SELF_COLLECTOR / SENDFILE_ONLY / NOT_REGISTERED 차단 (코드 contract 강제)
  - normal callback cron 등록 강제 (ANU key c119085addb0f8b7)
  - executor self-key cron → SELF_COLLECTOR_FORBIDDEN
  - cron 0 + sendfile 만 → NOT_REGISTERED fail-closed
  - 봇 본인 callback 자가검증 → SELF_COLLECTOR_VERIFICATION_FORBIDDEN
  ```
- 봇이 자의적 해석 불가능하도록 코드 단언 강화

## Track C — bot settings policy
허용:
- 신규 `utils/bot_settings_policy_loader.py`
- 신규 settings 파일 (dev bot 후보 제안 + ANU 정합 검증)

목표:
- `require_anu_callback_on_finish=true` 기본값
- callback 미등록 종료 fail-closed
- settings 누락 시 안전 기본값 적용
- settings 위치 후보 (dev bot 제안): `/home/jay/workspace/config/callback_policy.json` 또는 `bot_settings.json` 확장 등

## Track D — finish-task / cokacdir wrapper (read-only spec만)
허용:
- `memory/specs/system_finish_task_cokacdir_unfork_analysis_260523.md` (신규 read-only)

금지:
- `scripts/finish-task.sh` 수정 금지
- `cokacdir` 본체 수정 금지
- 실제 wrapper 수정 금지

목표 (read-only):
- finish-task.sh callback 자동 발사 도입 시 영향/위험/정책 분석
- cokacdir CLI wrapper SELF_COLLECTOR 차단 가드 도입 시 영향
- 후속 unfork 회장 결정 입력 자료

## 신규 fixture (SELF_COLLECTOR 재발 방지 · 최소 6 시나리오)
`tests/fixtures/self_collector_enforcement/<scenario>/{evidence.json,expected.json,PROVENANCE.md}` (6×3 = 18 files):
- `spawn_contract_pass_anu_key` → spawn 통과
- `spawn_contract_fail_self_key` → SELF_COLLECTOR_FORBIDDEN (dispatch block)
- `spawn_contract_fail_no_prompt_doctrine` → CONTRACT_FAILED (prompt 본문 doctrine 부재)
- `bot_finalize_require_callback_missing_fail_closed` → BOT_FINALIZE_POLICY_VIOLATION
- `bot_settings_default_safe_fallback` → 기본값 적용 (settings 누락 시)
- `prompt_level_self_collector_block` → prompt-level 차단 동작 단언

## 신규 regression
- `tests/regression/test_spawn_callback_contract_validator.py` — 6 fixture parametrized
- `tests/regression/test_dispatch_entrypoint_wiring.py` — dispatch/__init__.py import 결선 + core.py spawn 호출 + prompt.py guard 단언
- `tests/regression/test_team_prompts_doctrine_injection.py` — prompts/team_prompts.py 자동 주입 verbatim 검증
- `tests/regression/test_bot_settings_policy_loader.py` — require_anu_callback_on_finish 기본값 + fail-closed

## 안전 불변식
- replacement_pr_runner.py / finish-task.sh / merge_ready_classifier / merge_ready_dryrun_executor **무수정** (forbidden 유지)
- cokacdir CLI 본체 **무수정**
- ANU key `c119085addb0f8b7` 단일 출처 유지 (변경 0)
- envelope UTF-8 ≤3900 bytes 유지
- live cokacdir CLI 실호출 0 (regression mock)
- merge/push/PR/cron/admin override 호출 0
- real auto-merge activation 0
- PR #141 pilot 재시도와 혼합 0
- foreign dirty 정리 0
- production service task 와 혼합 0
- ANU 직접 코드 구현 0 (dev bot 위임)
- expected_files 외부 수정 0
- BLOCKING_SECRET 0

## 필수 regression
- 신규 4 regression PASS
- 기존 snapshot crossref 23 + canonical-root 63 + callback consistency 40 + task-2635 helper 68 + baseline 264 + real_merge wiring 8 = 466+ 유지
- full new fail 0 (3 pre-existing test_stash_origin_audit_compat 무관)

## 자동수렴
- Gemini medium/style/quality + expected_files 내부 → 자동수렴
- 동일 함수 HIGH 반복 시 LOOP_BOUNDARY → 회장 보고
- 회장 보고 트리거: Critical7 / credential expansion / expected_files 밖 / admin override / replacement_pr fail / post-merge smoke fail

## 금지 (회장 verbatim)
- real auto-merge activation 금지
- PR #141 pilot 재시도와 혼합 금지
- foreign dirty 정리 금지
- replacement_pr_runner 수정 금지
- finish-task.sh 수정 금지 (Track D read-only spec만)
- cokacdir 본체 수정 금지
- production service task 와 혼합 금지
- ANU 직접 코드 구현 금지

## expected_files (task-2640 범위)
신규:
- `dispatch/spawn_callback_contract_validator.py`
- `utils/bot_settings_policy_loader.py`
- (dev bot 후보 제안) settings 파일 1개
- `tests/fixtures/self_collector_enforcement/<6 시나리오>/{evidence,expected,PROVENANCE}` (18 files)
- (선택) `tests/fixtures/self_collector_enforcement/INDEX.md`
- `tests/regression/test_spawn_callback_contract_validator.py`
- `tests/regression/test_dispatch_entrypoint_wiring.py`
- `tests/regression/test_team_prompts_doctrine_injection.py`
- `tests/regression/test_bot_settings_policy_loader.py`
- `memory/specs/system_finish_task_cokacdir_unfork_analysis_260523.md` (Track D read-only)

수정 (forbidden unfork 회장 verbatim 승인):
- `dispatch/__init__.py` (import 결선만)
- `dispatch/core.py` (spawn 직전 validator 호출)
- `dispatch/prompt.py` (prompt 생성 전 guard)
- `prompts/team_prompts.py` (텍스트 + 코드 contract 연결)

총 ~30 files. **프로덕션 영향**: dispatch entrypoint 4 file 결선 + team_prompts 1 file + 신규 helper 2 + settings 1 + fixture 18 + regression 4 + Track D read-only spec 1.

## finalize 프로토콜 (★ BOT App token 부재 — 로컬 한정)
1. base = origin/main 93598660 clean
2. Track A+B+C+D 전부 PASS + 기존 466+ 유지 + full new fail 0
3. **로컬 commit만** (push/PR/merge 금지)
4. ANU normal callback (★ 본 task 가 enforcement 정책이므로 자기검증 패턴 매우 중요):
   - 신규 validate_spawn_callback_contract 호출로 self-check 강제
   - envelope 5축 + canonical_root 명시
   - REGISTERED + schedule_id non-null + DELIVERED + UNCONFIRMED
5. envelope UTF-8 ≤3900 bytes
6. executor 시작/종료 ts + 로컬 commit SHA 명기

## frozen anchor
- ANCHOR-1: "본 task = SELF_COLLECTOR 재발 원인 (코드 정의 ≠ runtime 결선) 해소 batch · Track A/B/C 구현 + Track D read-only"
- ANCHOR-2: "회장 verbatim unfork 6 항목 정확 반영 (dispatch/__init__.py · core.py · prompt.py · team_prompts.py · bot_settings 위치 · finish-task.sh 금지)"
- ANCHOR-3: "dispatch entrypoint 결선 (enforce_callback_owner + build_anu_owned_callback_request + spawn_callback_contract_validator import)"
- ANCHOR-4: "prompt 생성 전 enforce guard 통과 + verbatim doctrine block 자동 주입 (텍스트+코드 이중 안전)"
- ANCHOR-5: "bot_settings_policy_loader · require_anu_callback_on_finish=true 기본값 · fail-closed"
- ANCHOR-6: "finish-task.sh / cokacdir 본체 무수정 · Track D read-only spec 만 · unfork 별도 회장 결정"
- ANCHOR-7: "신규 6 fixture (spawn_contract_pass/fail_self_key/fail_no_prompt_doctrine/bot_finalize_require/bot_settings_default/prompt_level_block) · regression 4"
- ANCHOR-8: "real auto-merge OFF 유지 · ACTIVATION_FLAG_DEFAULT=False · chair_authorization 발급 0 · PR #141 pilot 재시도와 분리"
