# task-2644 — ANU_CALLBACK_COLLECTOR_CONTROL_PLANE (v2.4 Harness Recovery)

- Level: Lv.4 (Harness + cokacdir + file-state control plane 결합 · 4 트랙 병렬)
- 담당: dev6 페룬 (회장 결정 후 dispatch · 별도 worktree)
- base: origin/main 최신 (PR #146 task-2643 merge 후 진입 권장 · 미merge 시 0e172435 기준)
- 단일소스 spec: `memory/specs/system_anu_callback_collector_control_plane_spec_260524.md`
  - sha256: `b27da557d4245bce476cd63f4ab174aefc8a25d2da07ec2c8d2c83b01ee96153` (회장 보강 5 + fixture 8 + source enum 8 반영 후)
  - 정독 전 sha256sum 검증 필수
- 정책 spec: `memory/specs/system_ci_watch_handoff_policy_spec_260523.md`
- runner spec: `memory/specs/system_ci_watch_handoff_runner_spec_260523.md`
- runtime enforcement spec: `memory/specs/system_ci_watch_handoff_runtime_enforcement_gate_spec_260523.md`
- 사고 박제: PR #146 task-2643 처리 중 dev6 callback 미인지 사건 + ANU "callback received" 거짓 표현 사고 (2026-05-23 ~00:40 KST)
- 개발방향: `ANU_v3_master_development_direction_final_260517_v2_4_harness_recovery.md`
- 회장 결정 (2026-05-24 00:50 KST · verbatim): ANU collector 세션이 callback 을 단순 log 저장 후 종료하지 않고, 자율 판단과 다음 action 까지 수행하게 만든다

## 목표 (회장 verbatim)
- Harness 단독으로 전체 자동화 불가능 (ANU 외부 daemon 의존)
- Harness + cokacdir + file-state control plane 결합 으로 자동화 결선 가능
- live `~/.claude/settings.json` 수정 0 · live cokacdir 수정 0 · live `claude --resume` 적용 0
- 본 ANU 대화 세션 hook 감지 = 이중 안전망 · 주 경로 아님 (주 경로 = ANU collector 자율 진행)
- PR #146 와 혼합 0 (별도 worktree / 별도 PR)

## 핵심 구조 (회장 verbatim flow)
```
dev bot normal callback → cokacdir 가 ANU collector 세션 spawn → SessionStart hook 이
ANU_CALLBACK_COLLECTOR 모드 강제 → collector 가 task/spec/.anu_state/frozen anchor 로
context recovery → callback adjudication (terminal_state/policy/Critical7 판정) →
next_action decision (11 enum) → 자동 가능하면 dispatch · 회장 결정 필요하면 Telegram
report → .callback ledger 기록 → Stop hook 이 의무 완료 검증 후 종료 허용
```

## 4 트랙 (병렬)

### Track A — SessionStart hook + Stop hook + source attribution guard
- `hooks/session_start_anu_callback_collector.py` (staged · live 미적용)
- `hooks/stop_anu_callback_collector_verifier.py` (staged)
- `utils/source_attribution_guard.py` (Stop hook 사용)
- `hooks/user_prompt_submit_hook_callback_inbox.py` (이중 안전망 · staged)

### Track B — callback adjudicator + next_action runner
- `utils/callback_adjudicator.py` (terminal_state/policy/Critical7 판정)
- `utils/callback_next_action_runner.py` (11 enum decision)

### Track C — schemas + fixtures
- `schemas/callback_ledger_v1.json`
- `schemas/callback_next_action_decision_v1.json`
- `schemas/anu_state_v1.json` (minimal)
- `schemas/callback_batch_aggregation_v1.json`
- fixtures (8+): MERGE_READY / Critical7 / auto-remediation / sibling incomplete / final sibling / log only fail / "callback received" misuse fail / **fallback_safety_net_log_recovery_without_control_plane_adjudication** (★ task-2643 1C0F6F52 박제)

### Track D — regression + rollback + staged template + telegram template
- regression tests (각 fixture × adjudicator + next_action + Stop hook + source guard)
- `memory/specs/task_2644_rollback_plan_260524.md`
- `memory/specs/staged_settings_template_anu_callback_collector_260524.json`
- `memory/specs/telegram_chair_report_packet_template_260524.json`

## 15 완료 산출물 (회장 verbatim 1:1)
1. SessionStart hook draft → `hooks/session_start_anu_callback_collector.py`
2. Stop hook draft → `hooks/stop_anu_callback_collector_verifier.py`
3. callback adjudicator module → `utils/callback_adjudicator.py`
4. next_action runner module → `utils/callback_next_action_runner.py`
5. callback ledger schema → `schemas/callback_ledger_v1.json`
6. next_action decision schema → `schemas/callback_next_action_decision_v1.json`
7. .anu_state minimal schema → `schemas/anu_state_v1.json`
8. batch callback aggregation schema → `schemas/callback_batch_aggregation_v1.json`
9. telegram chair report packet template → `memory/specs/telegram_chair_report_packet_template_260524.json`
10. source attribution guard → `utils/source_attribution_guard.py`
11. user_prompt_submit_hook .callback 안전망 → `hooks/user_prompt_submit_hook_callback_inbox.py` (staged)
12. fixtures 7+ (위 Track C 7종)
13. regression tests (각 fixture × adjudicator + next_action + Stop hook + source guard)
14. rollback plan → `memory/specs/task_2644_rollback_plan_260524.md`
15. staged settings template → `memory/specs/staged_settings_template_anu_callback_collector_260524.json`

## 우선순위 8 (회장 verbatim 1:1)
1. SessionStart hook — collector mode 감지 + 의무 prompt/context 주입
2. callback adjudicator — terminal_state / policy / Critical7 판정
3. next_action runner — 자동 진행 or chair report 결정
4. .callback ledger — 처리 결과 durable 기록
5. Stop hook — 처리 의무 미완료/거짓 표현/next_action 누락 시 종료 차단
6. batch callback aggregation — 병렬 작업 all-settled 판단
7. user_prompt_submit_hook .callback 감지 — 이중 안전망
8. active session resume 은 shadow 검증만, live 적용 금지

## next_action enum (회장 verbatim 11)
1. REQUEST_CHAIR_MERGE_APPROVAL
2. REPORT_CRITICAL7
3. REPORT_PERMISSION_OR_CREDENTIAL_EXPANSION
4. DISPATCH_AUTO_REMEDIATION
5. RERUN_ALLOWED_GATE
6. RUN_OWNER_GEMINI_TRIGGER_ROUTER
7. CREATE_FOLLOWUP_TASK_SPEC
8. WAIT_FOR_BATCH_SIBLINGS
9. BATCH_ADJUDICATE
10. NOOP_TERMINAL
11. HOLD_FOR_CHAIR

## 자동 진행 허용 (회장 verbatim 8)
- expected_files 내부 non-critical remediation
- phase3 timing race rerun
- allowed OWNER_GEMINI_TRIGGER_ROUTER nudge
- batch sibling callback wait
- all-settled batch adjudication
- follow-up task spec/preflight
- regression rerun
- callback ack/ledger update

## 자동 진행 금지 (회장 verbatim 11)
- merge 실행
- live settings.json 적용
- live cokacdir 수정
- BOT App token 사용
- chair_authorization 발급
- PR #141 pilot
- production PR lifecycle activation
- expected_files 밖 수정
- credential/permission expansion
- admin override
- destructive git / foreign dirty cleanup

## SessionStart hook 의무 (회장 verbatim 7 단계)
1. envelope parse
2. context recovery (task md / spec md / .anu_state.json / frozen anchor)
3. terminal_state classify
4. next_action decide
5. auto action OR chair telegram
6. .callback ledger write
7. source attribution + exit

## Stop hook 종료 차단 8 조건 (회장 verbatim)
- collector mode 에서 callback_envelope_parsed 없으면 fail
- context_recovered 없으면 fail
- terminal_state_classified 없으면 fail
- next_action_decided 없으면 fail
- auto_action_dispatched / chair_report_emitted / noop_terminal_recorded / batch_wait_recorded 중 하나 없으면 fail
- callback_ledger_written 없으면 fail
- "callback received / 도착 / 수신" 표현 + source attribution 없으면 fail
- schedule_history 사후 조회를 inbound 수신처럼 표현하면 fail

## 완료 등급 (회장 verbatim)
- RUNTIME_GUARDED: staged hook + dry-run + regression + ledger/adjudicator 구현 (★ 본 task 목표)
- HARNESS_ENFORCED: live settings 적용 + deny/allow/collector-mode live smoke + rollback 확인 후 (★ 별도 회장 verbatim signature task)

## ANU-Codex loop (회장 verbatim)
- non-critical finding (lint/test/schema/style/quality/medium/non-critical HIGH) → 자동수렴
- Codex final verdict 명시
- PASS_WITH_RECOMMENDATIONS → recommendations acceptance backlog 기록 후 계속 진행

## 공통 acceptance (회장 verbatim)
- forbidden 28종 (기존 25 + 신규 3: hooks/* live · cokacdir live · claude --resume) 무수정 verified
- net-new credential 0 (PR scope)
- 신규 regression 전체 PASS
- 기존 baseline 유지 + 3 pre-existing 무관
- 본 ANU 직접 polling 0 (정책 dogfood)
- live settings.json 수정 0
- live cokacdir 수정 0
- live `claude --resume` 적용 0
- PR #146 와 task-2644 혼합 0

## 회장 보고 트리거 (verbatim 6)
- Critical7 hit
- credential expansion
- permission expansion
- live settings 적용 시도
- GitHub destructive write
- forbidden target 수정

## 허용 (회장 verbatim)
- spec/schema/fixture/test/hook draft/staged settings template/dry-run runner/rollback plan/telegram template 작성
- ANU-Codex loop 반복
- 병렬 subagent fan-out (4 트랙 동시)
- non-critical lint/test/schema finding 자동수렴
- PASS_WITH_RECOMMENDATIONS continue

## 필수 regression
- 신규 7 fixture × (adjudicator + next_action + Stop hook + source guard) 전체 PASS
- 기존 baseline 유지
- full new fail 0 (3 pre-existing 무관)

## expected_files (task-2644 범위 · ~30 file 추정)
- spec/template 4 (본 task md + rollback plan + staged settings template + telegram packet template)
- hooks 3 (SessionStart + Stop + UserPromptSubmit)
- utils 3 (callback_adjudicator + callback_next_action_runner + source_attribution_guard)
- schemas 4 (callback_ledger + next_action_decision + anu_state + batch_aggregation)
- fixtures ~14 (7 시나리오 × evidence/expected/PROVENANCE)
- regression ~7 (각 fixture × 4 모듈 통합)
- INDEX 1

## finalize 프로토콜 (★ BOT App token 부재 — 로컬 한정)
1. base = origin/main 최신 clean (PR #146 merge 후 권장)
2. 신규 helper + schema + fixture + regression PASS · 기존 baseline 유지 · full new fail 0
3. **로컬 commit 만** (push/PR/merge 금지)
4. ANU normal callback (★ 본 task = harness enforcement 자체 자기검증 강제):
   - validate_spawn_callback_contract self-check (task-2640 결선 active)
   - envelope 5축 + canonical_root=/home/jay/workspace 명시
   - REGISTERED + schedule_id non-null + DELIVERED + UNCONFIRMED
   - envelope UTF-8 ≤3900 bytes
   - result.json 에 callback prompt UTF-8 byte 수 기록
5. ANU collector key: c119085addb0f8b7
6. executor 시작/종료 ts + 로컬 commit SHA 명기

## frozen anchor (spec md 1:1)
- ANCHOR-1: "본 task = ANU collector 자율 처리 + 다음 action 자동 진행 control plane · 박제/spec 수준 넘어 Harness+cokacdir+file-state 결합"
- ANCHOR-2: "Harness 단독 불가능 명시 (claude-code 본질 한계) · 협업 구조 필수"
- ANCHOR-3: "8 우선순위 산출물 + 15 필수 산출물 1:1 박제"
- ANCHOR-4: "SessionStart hook = collector mode 강제 자율 진행 / Stop hook = 의무 미완 거짓표현 종료 차단"
- ANCHOR-5: "next_action 11 enum + 자동 허용 8 + 자동 금지 11 명시"
- ANCHOR-6: "RUNTIME_GUARDED 까지만 본 task · HARNESS_ENFORCED = 별도 회장 verbatim signature task"
- ANCHOR-7: "본 ANU 대화 세션 hook = 이중 안전망 · 주 경로 아님"
- ANCHOR-8: "PR #146 task-2643 와 격리 · 별도 worktree / 별도 PR / 병렬 진행"
- ANCHOR-9: "거짓말 패턴 (수신 vs 사후 조회 흐림) Stop hook 으로 사전 차단"
- ANCHOR-10: "본 ANU 직접 polling 0 · 회장 verbatim dogfood 유지"

## 회장 보강 5 (2026-05-24 01:10 KST · verbatim · dispatch 전 반영 필수)

### 보강-1 source attribution enum 8 (5 → 8 · 회장 verbatim 2회 누적)
기존 5 enum 에 추가:
- CALLBACK_COLLECTOR_PROCESSED (★ task-2644 의 주 경로 · collector 세션 직접 처리)
- CALLBACK_LEDGER_RECONCILED (post-hoc reconciliation)
- LOG_LOOKUP_OR_SCHEDULE_HISTORY_VERIFICATION (★ 회장 verbatim 2026-05-24 · 1C0F6F52 사건 후 추가 · ANU 회장-facing 세션 사후 chain 확인 시)

### 보강-2 next_action 3 분기 mutually exclusive
- auto-executable branch: DISPATCH_AUTO_REMEDIATION / RERUN_ALLOWED_GATE / RUN_OWNER_GEMINI_TRIGGER_ROUTER / CREATE_FOLLOWUP_TASK_SPEC / WAIT_FOR_BATCH_SIBLINGS / BATCH_ADJUDICATE
- chair-required branch (Telegram 의무): REQUEST_CHAIR_MERGE_APPROVAL / REPORT_CRITICAL7 / REPORT_PERMISSION_OR_CREDENTIAL_EXPANSION / HOLD_FOR_CHAIR
- terminal noop branch: NOOP_TERMINAL
- ★ Telegram 은 chair-required 에서만 발사 (auto/terminal_noop 에서 발사 금지)

### 보강-3 merge policy lock (hardcoded)
- MERGE_READY callback 의 기본 next_action = REQUEST_CHAIR_MERGE_APPROVAL (override 불가)
- collector merge 실행 절대 금지
- 본 task-2644 범위 merge execution = 0 (hardcoded)
- merge 실행은 pre-existing merge_policy.auto_merge_allowed=true AND live auto-merge flag active 일 때만 (별도 회장 verbatim signature task 필요)

### 보강-4 .anu_state freshness
- 회장-facing ANU 세션은 회장 verbatim 결정 수신 시 .anu_state append/update
- task dispatch 시 .anu_state snapshot_id 또는 state_version 기록 (envelope 에 명시)
- callback collector 는 state_version 검증
- state mismatch / missing 시 SAFE_DEGRADED_MODE (NOOP_TERMINAL / HOLD_FOR_CHAIR 한정) OR HOLD_FOR_CHAIR

### 보강-5 next_action_result evidence (Stop hook 강화)
**필수 필드 4종**: next_action_decided / next_action_attempted / next_action_result / next_action_evidence_path

**허용 result enum 6종**:
- DISPATCH_REGISTERED (schedule_id non-null)
- TELEGRAM_SENT
- LEDGER_ONLY (noop_terminal)
- HOLD_PACKET_CREATED
- BATCH_WAIT_RECORDED
- FAILED

**Stop hook 추가 종료 차단 (8 → 10 조건)**:
- next_action_result 없으면 fail
- state_version mismatch / .anu_state stale 인데 SAFE_DEGRADED_MODE / HOLD_FOR_CHAIR 둘 다 아니면 fail

## callback envelope byte-limit 정책 (★ task-2612+3 박제 강제)
- callback prompt UTF-8 ≤3900 bytes hard limit · 3500+ warning
- envelope 만 포함 · 상세는 result.json/report.md 위임
- 측정: `printf '%s' "$P" | wc -c` (wc -c · NOT wc -m)
- result.json 에 callback prompt UTF-8 byte 수 기록 강제

## allowed_resources (본 task의 capability)

```yaml
allowed_resources:
  paths:
    - "hooks/session_start_anu_callback_collector.py"
    - "hooks/stop_anu_callback_collector_verifier.py"
    - "hooks/user_prompt_submit_hook_callback_inbox.py"
    - "utils/callback_adjudicator.py"
    - "utils/callback_next_action_runner.py"
    - "utils/source_attribution_guard.py"
    - "schemas/callback_ledger_v1.json"
    - "schemas/callback_next_action_decision_v1.json"
    - "schemas/anu_state_v1.json"
    - "schemas/callback_batch_aggregation_v1.json"
    - "memory/specs/telegram_chair_report_packet_template_260524.json"
    - "memory/specs/task_2644_rollback_plan_260524.md"
    - "memory/specs/staged_settings_template_anu_callback_collector_260524.json"
    - "tests/fixtures/callback_control_plane/**"
    - "tests/regression/callback_control_plane/**"
    - "tests/test_callback_adjudicator*.py"
    - "tests/test_callback_next_action_runner*.py"
    - "tests/test_source_attribution_guard*.py"
    - "tests/test_session_start_anu_callback_collector*.py"
    - "tests/test_stop_anu_callback_collector_verifier*.py"
    - "tests/test_user_prompt_submit_hook_callback_inbox*.py"
    - "memory/tasks/task-2644.md"
    - "memory/reports/task-2644.md"
    - "memory/events/task-2644.done"
    - "INDEX.md"
  forbidden_paths:
    - "/home/jay/.claude/settings.json"
    - "/home/jay/.claude/settings.local.json"
    - "/usr/local/bin/cokacdir"
    - ".github/**"
    - "memory/events/*.cron-*"
    - "memory/tasks/task-2643*"
    - "memory/tasks/task-2641*"
    - "memory/tasks/task-2642*"
    - "memory/specs/system_real_merge_executor_wiring_spec_260523.md"
    - "memory/specs/system_anu_callback_collector_control_plane_spec_260524.md"
    - "scripts/finish-task.sh"
    - "dispatch.py"
    - "utils/replacement_pr_runner.py"
    - "**/.env*"
    - "**/credentials*"
  commands:
    - "pytest"
    - "python3 -m py_compile"
    - "python3 -m json.tool"
    - "git status"
    - "git diff"
    - "git add"
    - "git commit"
    - "git log"
    - "git checkout"
    - "git branch"
    - "git worktree"
    - "sha256sum"
    - "wc"
    - "ls"
    - "grep"
    - "find"
  merge_policy: "local_only"
  ttl_hours: 72
```