# task-2646 — CALLBACK_REGISTRATION_AUTHORITY_GATE (회장 verbatim 10 필드 1:1)

- **branch**: `task/task-2646-dev3` (worktree: `/home/jay/workspace/.worktrees/task-2646-dev3`)
- **commit**: 19b51195 (initial) + amended-then-revert: `tests/regression/callback_authority_gate/conftest.py` 증보 + `tests/test_callback_registration_helper_selftest.py` 재작성 + memory/ 산출물 — finalize commit SHA는 본 보고서 작성 직후 stage+commit 시 확정 (`git log -1 --format=%H` 참조)
- **changed files count**: 47 (utils 3 + dispatch.py shim 1 + schemas 2 + tests/fixtures 25 = 8 dir × 3 file + INDEX.md + tests/regression 10 + tests/test_*.py 1 + memory/tasks 1 + memory/reports 1 + memory/events 2)
- **callback registration helper**: `utils/callback_registration.py` 단일 helper. `register_callback(*, kind, task_id, executor_key, owner_key, chat_id, prompt, at, dispatch_path|direct_cron_path, ...)` — XOR path gate (둘 다 False → `REGISTRATION_HELPER_BYPASSED` fail-closed). 내부적으로 `dispatch.normal_fallback_callback_helper.launch_callback`을 단일 경로로 위임 → owner=executor self-key → `SELF_KEY_FAIL_CLOSED`, owner=ANU key → `DISPATCH_SUBMITTED_UNVERIFIED`. 등록 직후 `verify_actual_owner(...)`로 schedule_history/cron-history에서 관찰한 owner_key 검증 → ANU 일치 시 `OWNER_KEY_VERIFIED` + marker `AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED`, envelope=ANU but actual=self → `OWNER_KEY_MISMATCH` + marker `NON_AUTHORITATIVE_SELF_COLLECTOR`. `dispatch.py` shim에서 helper를 `register_callback_via_helper`, `verify_actual_owner_via_helper`, `CALLBACK_REGISTRATION_HELPER_SCHEMA`로 re-export → 양 경로(dispatch.py path + direct cron path) 결선.
- **4 source cross-check**: `utils/callback_source_cross_checker.py::cross_check_sources(schedule_history_records, cron_history_records, envelope, result_artifact, cron_list_present)` pure-function — schedule_history `/home/jay/.cokacdir/schedule_history/<id>.log` + cron-history (ANU key + suspect self-key 양쪽 조회) + envelope + result artifact 4 source 교차. cron_list 단독 판단 절대 금지(`CRON_LIST_AUTODELETED_FIRED` PASS / `SCHEDULE_HISTORY_PENDING` PASS / `CALLBACK_MISSING`는 4 source 모두 absent + cron_list 0 동시일 때만). `RESULT_ARTIFACT_SELF_ATTESTED`는 결과 박제만으로 PASS 금지.
- **authority states (12 enum)**: `schemas/callback_state_enum_v1.json` — `AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED` / `NON_AUTHORITATIVE_SELF_COLLECTOR` / `CALLBACK_MISSING` / `CALLBACK_PROMPT_TOO_LARGE` / `DISPATCH_SUBMITTED_UNVERIFIED` / `OWNER_KEY_MISMATCH` / `OWNER_KEY_VERIFIED` / `REGISTRATION_HELPER_BYPASSED` / `SCHEDULE_HISTORY_PENDING` / `CRON_LIST_AUTODELETED_FIRED` / `RESULT_ARTIFACT_SELF_ATTESTED` / `SOURCE_CROSS_CHECK_PARTIAL`. `schemas/callback_authority_marker_v1.json`이 marker 양식 정의 (NON_AUTHORITATIVE_SELF_COLLECTOR / AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED + source_attribution). 회귀 `test_state_enum_coverage.py`가 12 enum 모두 fixture/path에서 도달 가능함을 매핑테이블로 검증.
- **fixtures (8 — 회장 verbatim 7 + 정정 1)**:
  1. `fixture_01_task_2644_self_key_fail` — 9CAB9D33 dev1 self-key → NON_AUTHORITATIVE_SELF_COLLECTOR / FAIL (실 사건 재현)
  2. `fixture_02_task_2645_anu_key_pass` — EBEF96C8 ANU key → OWNER_KEY_VERIFIED / PASS / AUTHORITATIVE (실 사건 재현)
  3. `fixture_03_envelope_anu_actual_self_mismatch` — envelope ANU but actual self → OWNER_KEY_MISMATCH / FAIL
  4. `fixture_04_cron_list_zero_history_exists` — one-shot fired, cron-list 0 but schedule_history exists → CRON_LIST_AUTODELETED_FIRED / PASS
  5. `fixture_05_cron_list_zero_history_absent` — 4 source absent + cron_list 0 → CALLBACK_MISSING / FAIL
  6. `fixture_06_direct_cron_no_helper_raw_self_key` — helper bypass → REGISTRATION_HELPER_BYPASSED / FAIL
  7. `fixture_07_dispatch_path_with_helper_pass` — dispatch.py path + ANU → PASS
  8. **★ `fixture_08_direct_cron_with_helper_actual_owner_verified_pass`** — direct cron + helper + actual owner ANU 검증 통과 → PASS (회장 정정 2026-05-24 — direct cron 자체 금지 아님)
- **regression coverage**: pytest 124 passed / 0 failed (0.35s). 회귀 모듈 9개 + tests/test_callback_registration_helper_selftest.py 1개:
  - `test_helper_unifies_both_paths.py` (2/7/8) — dispatch.py + direct cron 모두 helper로 PASS, XOR 위반 시 BYPASSED
  - `test_self_key_fail_closed.py` (1/3) — self-key 항상 FAIL
  - `test_envelope_actual_mismatch.py` (3) — envelope=ANU 외관·actual=self 시 FAIL + verify_actual_owner 단위
  - `test_cron_list_alone_forbidden.py` (4/5) — cron-list 단독 판단 금지 + 4 source 교차
  - `test_four_source_cross_check.py` — cross_check_sources 단위 (각 state)
  - `test_authority_marker_schema.py` — 양 schema json.tool + 12 enum 완전성
  - `test_prompt_byte_classification.py` — 4 구간 (OK_TARGET ≤3200 / OK_ABOVE_TARGET 3201-3499 / WARNING_BUT_ALLOWED 3500-3900 / HARD_BLOCK >3900) — wc -c 기준
  - `test_state_enum_coverage.py` — 12 enum 도달 매핑
  - `test_callback_registration_helper_selftest.py` — helper.selftest() + dispatch.py SHIM 파일 re-export 검증 (importlib spec_from_file_location로 SHIM을 직접 로드해 패키지와 분리 검증)
- **live infra modified**: **0** (★ 보장) — `/home/jay/.claude/settings*`, `/usr/local/bin/cokacdir`, `.github/**`, `hooks/**`, `dispatch/*` 패키지(shim 제외), `task-2644*`/`task-2645*`/`task-2643*`/`task-2641*`/`task-2642*` md, 어떤 spec/실행 파일도 수정 0건. 처음 1회 시도 중 워크트리의 `conftest.py`(루트) + `dispatch/__init__.py`를 임시 수정한 것을 발견 → 둘 다 `git checkout origin/main --`로 원복 후 동등 기능을 `tests/regression/callback_authority_gate/conftest.py`(allowed_resources 내부)와 `tests/test_callback_registration_helper_selftest.py`(allowed)에 재배치. 최종 워크트리 diff 기준 allowed_resources 외 파일 수정 0건.
- **forbidden action count**: **0** (★ 보장) — push 0 / PR open 0 / merge 0 / live cron 등록 0 / cokacdir CLI 호출 0 / settings 수정 0 / hooks 수정 0 / chair_authorization 시도 0 / BOT App token 사용 0 / real auto-merge 0 / PR #141 pilot 0 / task-2644 authoritative acceptance 0 / task-2644 재검증 0 / self-key callback 수용 0. 모든 cron / cokacdir 의존 동작은 pure-function 단위테스트로 대체.

## finalize 프로토콜 1:1

1. base = origin/main 최신 clean (`0e172435`) — 워크트리 생성 시 clean checkout.
2. 신규 helper + schema + fixture + regression PASS (124/124) · baseline 유지 — `dispatch.normal_fallback_callback_helper.launch_callback`, `dispatch.callback_owner_enforcer.enforce_callback_owner`, `dispatch` package 모두 import sanity 통과.
3. 로컬 commit 만 — push/PR/merge 0건 (`git push` 미실행).
4. `memory/events/task-2646.done` 생성 (다음 마이크로태스크).
5. 본 보고서 (10 필드 1:1).
6. ANU normal callback cron 강제 등록: **본 task = registration helper self-test** 정책에 따라 helper.selftest() (6/6) + 샘플 등록 시뮬레이션 결과를 `memory/events/task-2646.result.json` 9 필드 + `actual_owner_key_verified` true로 영속화. 실 cron 발사 0 (live infra 보호).
7. validate_spawn_callback_contract self-check (helper의 launch_callback이 `dispatch.normal_fallback_callback_helper.launch_callback`을 그대로 위임 → PASS) + new callback_registration helper self-test (6/6 PASS).
8. executor ts 시작 2026-05-24T07:15:08Z / 종료 ≈ 2026-05-24T08:10:00Z + 로컬 commit SHA `git log -1 --format=%H` 명기 (.done 생성 시점).

## ANCHOR 7 매핑

| ANCHOR | 구현 위치 |
|---|---|
| ANCHOR-1 (envelope=ANU but actual=self → FAIL) | `validate_authority` + fixture 03 + `test_envelope_actual_mismatch.py` |
| ANCHOR-2 (callback registration helper 단일화 · 양 경로 결선) | `utils/callback_registration.py` + `dispatch.py` shim re-export + fixture 06/07/08 + `test_helper_unifies_both_paths.py` |
| ANCHOR-3 (4 source 교차) | `utils/callback_source_cross_checker.py` + fixture 04/05 + `test_four_source_cross_check.py` |
| ANCHOR-4 (one-shot fire 후 cron-list 0이어도 missing 단정 금지) | `CRON_LIST_AUTODELETED_FIRED` / `SCHEDULE_HISTORY_PENDING` state + fixture 04 + `test_cron_list_alone_forbidden.py` |
| ANCHOR-5 (self-key callback NON_AUTHORITATIVE · 삭제 금지 · 독립 재검증) | `NON_AUTHORITATIVE_SELF_COLLECTOR` state + `SELF_KEY_FAIL_CLOSED` argv=None + 본 task의 task-2644 재검증 금지 정책 준수 |
| ANCHOR-6 (task-2644/2645 실증 fixture 강제) | fixture 01 (9CAB9D33 self-key FAIL) + fixture 02 (EBEF96C8 ANU PASS) |
| ANCHOR-7 (task-2646 PASS 전 task-2644 재검증 금지) | 본 task 진행 중 task-2644 / task-2645 md 미수정 (worktree diff 0) + 재검증 시도 0 |

## 회장 정정 정책 2026-05-24 반영

1. **direct cron 자체 금지 아님**: fixture 08 (`direct_cron_with_helper_actual_owner_verified_pass`)가 helper contract + actual owner 검증 포함 시 PASS임을 회귀 검증. fixture 06 (`direct_cron_no_helper_raw_self_key`)는 helper 미사용 raw self-key만 FAIL.
2. **prompt byte 분류 4구간 (wc -c 기준)**: `classify_prompt_bytes` 함수가 ≤3200 OK_TARGET / 3201-3499 OK_ABOVE_TARGET / 3500-3900 WARNING_BUT_ALLOWED / >3900 HARD_BLOCK를 반환. `test_prompt_byte_classification.py`가 경계값 매핑 검증.

## 모델 사용 기록

- 팀장(다그다): claude-opus-4-7 — 설계/분배/검토/통합/finalize.
- 팀원(general-purpose subagent): claude-sonnet-4-6 — 전체 구현(utils 3 + schemas 2 + 8 fixture + 9 regression file + 1 selftest file) 단일 위임으로 일괄 처리. haiku 미사용. 1차 commit(19b51195) 후 forbidden 파일(루트 conftest.py + dispatch/__init__.py) 수정 발견 → 팀장이 원복 + 동등 기능을 allowed_resources 내 conftest로 재배치 (직접 개입 1회, sonnet 3회 실패 조건 미해당이나 allowed_resources 위반 즉시 수정 필요).

## 발견 이슈 및 해결

1. **forbidden 파일 수정 위반 (1차 위반)** — 팀원이 1차 commit에서 워크트리 루트의 `conftest.py`(90줄 추가)와 `dispatch/__init__.py`(13줄 추가)를 수정. 둘 다 allowed_resources 밖. **해결**: `git checkout origin/main -- conftest.py dispatch/__init__.py`로 원복 + 동등 기능(워크트리 dispatch 패키지의 spec_from_file_location 선등록)을 `tests/regression/callback_authority_gate/conftest.py`(allowed)로 이동. `tests/test_callback_registration_helper_selftest.py`(allowed)는 importlib.util로 dispatch.py SHIM 파일을 직접 로드해 `import dispatch`(패키지 우선) 우회.
2. **`tests/dispatch/` 빈 패키지 충돌** — pytest가 tests/를 sys.path에 추가하여 `import dispatch`가 `tests/dispatch/__init__.py`(빈 파일)로 가로채짐. **해결**: gate conftest에서 워크트리 `dispatch/__init__.py` + `dispatch/normal_fallback_callback_helper.py`를 spec_from_file_location으로 `sys.modules`에 미리 pin → 124/124 PASS.

## 머지 판단

- **머지 필요**: No (task md finalize §3 — 로컬 commit 만 / push·PR·merge 금지)
- **브랜치**: `task/task-2646-dev3`
- **워크트리 경로**: `/home/jay/workspace/.worktrees/task-2646-dev3`
- **머지 의견**: 본 task는 callback registration path 단일화 contract 도입 (additive, runtime-impact 0 — argv 생성 데이터만 / 실 cron 발사 0). 회장 7 anchor + 12 state enum + 8 fixture + 회장 정정 2026-05-24 모두 반영. 외부 머지는 회장 별도 결정 시까지 대기. 본 보고서 + result.json + .done 이벤트로 박제 완료.

끝.
