# task-2694+1 — NORMAL_CALLBACK_REGISTRATION_ENFORCEMENT (★ 회장 verbatim 2026-05-27 옵션 A · dev7 이참나 재발의)

- chair_authorization_id: **`CHAIR-AUTH-NORMAL-CALLBACK-REGISTRATION-ENFORCEMENT-20260527-JJONGS-REDISPATCH-001`**
- PR: https://github.com/Jeon-Jonghyuk/dev_workspace/pull/155 (auto-merge 0, no-merge enforcement-only)
- PR head SHA: `af24dbf5` (round-2 보안 hardening 반영)
- worktree: `/home/jay/workspace/.worktrees/task-2694+1-dev7` (base = origin/main `319170b9`, fresh fetched 2026-05-27 03:52)
- branch: `task/task-2694+1-dev7`

## SCQA

### S — Situation
**S**: 회장 verbatim 2026-05-26 task-2693 사고 분류는 **NORMAL_CALLBACK_NOT_REGISTERED** 였다. envelope 텍스트는 작성됐으나 actual cokacdir cron registration 0건. finish-task.sh가 `state_file_missing` 으로 ESCALATED → cron 등록 시도 0. 정확한 우회 어구: envelope에 `schedule_type=to_be_registered_by_finish_task_sh` 명기로 deferred 통과. task-2694 1차 dispatch(dev8 라)는 BOT_DID_NOT_START + DISPATCH_FALSE_OK로 회피 → 2026-05-27 옵션 A로 dev7 이참나에게 재발의.

### C — Complication
**C**: 다층 복잡도가 동시에 존재한다.
- envelope 작성만으로 완료 처리되는 우회 패턴이 코드 레벨에서 차단되지 않음.
- 단일 source (envelope / schedule_id / owner_key 각각) 의존 시 모두 우회 가능.
- `dispatch.py` 전역 변경 / settings.json / hooks 변경 모두 금지 (회장 verbatim 금지 10).
- 본 enforcement 자체가 자기 작업 완료에 fail-closed로 적용되어야 함 (dogfood ANCHOR-4).
- helper의 Layer A NO-CRON 9-R.1 원칙 (subprocess/cokacdir exec 0) 유지 의무.

### Q — Question
**Q**: envelope-only completion을 코드로 차단하되, dispatch.py / live infra 변경 0, PR #152 / #154 / #151 혼합 0, helper/wrapper 레벨 enforce만으로 어떻게 fail-closed를 강제할 수 있는가?

### A — Answer
**A**: 4-source AND validator + JSON Schema enum + finish-task.sh Step 2.9.5 게이트 + 자동 marker 발행 + 회귀 30 케이스로 다층 차단. dogfood 4-source 04:23:14 verdict=PASS 확인.

## 필수 보고 10 필드

### 1. PR head SHA
`af24dbf593...` (8 commits on top of `319170b9`). 라운드별 commit:
- `e2cb58a3`: MT-1+2+3 (validator + marker + schema)
- `f58e00d2`: pyright type fix (validator Sequence, marker import)
- `94b17b06`: MT-4+5 (helper enforce + finish-task.sh Step 2.9.5)
- `1d9a032f`: helper top-level import + pyright ignore
- `a2aba47a`: MT-6+7 (회귀 30 케이스)
- `eeb535fa`: 회귀 테스트 pyright ignore
- `a8639851`: Gemini round-1 fix (security-high Python injection, glob.escape, hex case-insensitive, streaming read)
- `af24dbf5`: Gemini round-2 fix (security-high Path Traversal, Arbitrary File Bypass, events_dir 빈값 방어)

### 2. fresh worktree 생성 evidence
- worktree path: `/home/jay/workspace/.worktrees/task-2694+1-dev7`
- base SHA after `git reset --hard origin/main`: `319170b95b1330c3e9554eca88973e68f60e93e9`
- preflight 4-step:
  - `git fetch origin main` → OK
  - `git ls-remote origin main` → `319170b9...`
  - `git rev-parse origin/main` → `319170b9...`
  - `gh api repos/Jeon-Jonghyuk/dev_workspace/branches/main` → `commit.sha=319170b9...`
- 초기 worktree HEAD가 PR #154 관련 commit (`f14b3850`)이어서 즉시 `git reset --hard origin/main` 으로 정렬 (ANCHOR-6 PR #154 head 끌어오기 금지 준수).

### 3. 4 source validator 코드 추가 evidence
파일: `utils/normal_callback_registration_validator.py` (455 lines, commit `e2cb58a3`)

- `validate_callback_registration()`: 4-source AND 판정
  1. `_check_schedule_id()`: envelope schedule_id placeholder/blocked schedule_type 다층 검증
  2. `_check_schedule_history()`: `/home/jay/.cokacdir/schedule_history/<sid>.log` 파일 + status=ok 라인 grep (JSON-line 우선, plain text fallback)
  3. `_check_owner_key()`: envelope owner_key == ANU_KEY (`c119085addb0f8b7`). executor_key 일치 시 NON_AUTHORITATIVE
  4. `_check_inbound_receipt()`: envelope `inbound_evidence`/`collector_receipt` 필드 우선, 부재 시 `memory/events/anu_callback/` glob
- envelope의 `task_id`와 호출 시 `task_id` 결속 검증 (stale sid 재사용 차단)
- BLOCKED_SCHEDULE_TYPES = {`to_be_registered_by_finish_task_sh`, `deferred`, `pending`, `to_be_registered`, `none`, `null`, `""`}

helper에 thin wrapper `assert_normal_callback_actually_registered()` (commit `94b17b06`, +149 lines) — Layer A NO-CRON 9-R.1 원칙 유지 (subprocess/cokacdir exec 0).

### 4. envelope-only completion 차단 evidence (test fixture 실증)
- `tests/regression/normal_callback_registration_enforcement/test_validator_4_source.py::test_envelope_missing_fails` — envelope 파일 없으면 verdict=FAIL
- `tests/regression/finish_task_callback_fail_closed/test_enforce_helper_integration.py::test_envelope_only_fails_and_emits_marker` — envelope 존재하나 schedule_history/inbound 부재 시 FAIL + marker 자동 발행
- L1 dogfood 직접 확인 (현 보고서 작성 시점):
  ```
  $ python3 -m utils.normal_callback_registration_validator --task-id task-2694+1 \
      --envelope-path memory/events/anu_callback/task-2694-normal-completion.json
  verdict=FAIL  sources={schedule_id:PASS, schedule_history:FAIL, owner_key:PASS, inbound_receipt:PASS}
  exit=2
  ```
  envelope이 존재하고 owner_key/inbound 통과해도 schedule_history 미생성 단계에서 정확히 FAIL → **task-2693 사고 동일 시점 차단 확인**.

### 5. schedule_type=to_be_registered 차단 evidence
- `schemas/anu_normal_callback_envelope_v1.json` enum 명시 reject:
  ```json
  "schedule_type": { "enum": ["cron_once", "cron_recurring", "absolute_one_time"] }
  ```
  `deferred` / `pending` / `to_be_registered_by_finish_task_sh` 모두 enum 외 → JSON Schema 단계 reject.
- `test_schema_blocks_deferred.py::test_blocked_schedule_type_rejected` — 3종 차단 어구 모두 `jsonschema.ValidationError` raise 검증
- validator 단에서도 다층 방어: `BLOCKED_SCHEDULE_TYPES` 체크 + envelope 필드 자체에 차단 어구 있으면 즉시 FAIL
- `test_validator_4_source.py::test_blocked_schedule_type[3 parametrize]` — 3종 차단 어구 모두 verdict=FAIL

### 6. regression 결과
```
$ python3 -m pytest tests/regression/normal_callback_registration_enforcement/ \
                    tests/regression/finish_task_callback_fail_closed/ -v
============================== 30 passed in 0.27s ==============================
```
- validator 7케이스: envelope missing / blocked schedule_type 3종 / schedule_history missing / self-key NON_AUTHORITATIVE / inbound missing / stale task_id mismatch / dogfood PASS
- marker 6케이스: emit / has-true / has-false / idempotent overwrite / corrupted fail-safe / hold_for_chair=False non-blocking
- schema 8케이스: file exists / valid / blocked 3종 reject / allowed 3종 accept / required field missing / owner_key pattern
- helper 5케이스: envelope-only fail+marker / blocked schedule_type fail+marker / emit_marker=False / envelope missing+marker / task_id mismatch+marker
- jsonschema 4.26.0 가용 (importorskip 폴백 미사용)

### 7. forbidden_action_count
- dispatch.py 전역 변경: **0**
- /usr/local/bin/cokacdir 수정: **0** (read-only invoke만)
- .github/** / settings.json / hooks/** / Axis/** 변경: **0**
- HARNESS_ENFORCED 전체 선언: **0**
- auto-merge 시도: **0** (PR open-only, no merge)
- DISABLE_NORMAL_CALLBACK_ENFORCE 우회 env 추가: **0**
- 총 forbidden_action: **0**

### 8. PR #152 / PR #154 / PR #151 / PR #149 / task-2691+b 혼합 evidence
- worktree base = `319170b9` (origin/main HEAD), PR #154 head(`f14b3850`)는 reset으로 제거됨.
- `git diff origin/main..HEAD --stat` → 13 파일, 1718 insertions만. PR #152/#154/#151/#149 영역 파일 0건 포함.
- 혼합 여부: **0**

### 9. 8 우회 패턴 감지 여부
- envelope-only completion: 차단 OK
- schedule_type=deferred/pending/to_be_registered 어구: 차단 OK
- self-key channel hit: NON_AUTHORITATIVE 분리
- stale sid 재사용: task_id 결속 검증
- envelope sha256 위조: schema strict required field 검증
- bypass env (DISABLE_*): 미추가
- finish-task.sh latency 영역 손대기: 미수정 (Step 2.9.5만 추가)
- helper Layer A NO-CRON 위반: subprocess 0 유지
- 감지: **0건**

### 10. ★ 본인 dogfood
- cokacdir cron 등록: `schedule_id=7FA863F5`, schedule_type=absolute, owner_key=ANU `c119085addb0f8b7`, status=ok (`cokacdir --cron-history 7FA863F5 --chat 6937032012 --key c119085addb0f8b7` 응답 hit 확인).
- envelope: `memory/events/anu_callback/task-2694-normal-completion.json` (908 bytes ≤ 3900, schema PASS, chair_facing_sid=`53e89540-5bed-4692-a726-ed857820758a`).
- **★ 4-source 최종 검증 (2026-05-27 04:23:14 cron 실행 후)**:
  ```
  $ python3 -m utils.normal_callback_registration_validator --task-id task-2694+1 \
      --envelope-path memory/events/anu_callback/task-2694-normal-completion.json
  verdict=PASS
  sources_checked={schedule_id:PASS, schedule_history:PASS, owner_key:PASS, inbound_receipt:PASS}
  schedule_history_match=jsonl
  exit=0
  ```
- schedule_history snippet:
  ```json
  {"bot_key_verifier":"81b8faa2186673384475e495cfd9e62f535956b7ced3dc4c950aa650377ac45b",
   "chat_id":6937032012, "duration_ms":40792, "schedule_id":"7FA863F5",
   "status":"ok", "ts":"2026-05-27T04:23:11.903+09:00", ...}
  ```
- owner_key_verifier sha256: `81b8faa2186673384475e495cfd9e62f535956b7ced3dc4c950aa650377ac45b`
- chair_facing_sid: `53e89540-5bed-4692-a726-ed857820758a`
- **시간 순서 차단점 증명**:
  - 04:17:30 envelope 작성 + cron 등록 → **첫 dogfood validator FAIL (schedule_history 부재)** = task-2693 사고 동일 시점 정확한 차단
  - 04:22:29 cron 실행, 04:23:11 schedule_history 작성
  - 04:23:14 **두번째 dogfood validator PASS** (4 source AND 충족)
- 이로써 envelope-only 단계에서 fail-closed, actual cron + schedule_history + ANU key + inbound 4-source 모두 PASS 단계에서만 callback PASS — 회장 verbatim ANCHOR-3 완전 충족.

## 작업 모델 사용 기록
| 멤버 | 역할 | 모델 | 작업 |
|---|---|---|---|
| 쿠쿨칸 | 백엔드 | sonnet | MT-1 validator (e2cb58a3) |
| 쿠쿨칸 | 백엔드 | sonnet | MT-2 marker (e2cb58a3) |
| 쿠쿨칸 | 백엔드 | sonnet | MT-3 schema (e2cb58a3) |
| 쿠쿨칸 | 백엔드 | sonnet | MT-4+5 helper enforce + finish-task.sh (94b17b06) |
| 카마소츠 | 테스터 | sonnet | MT-6+7 regression 30 케이스 (a2aba47a) |
| 이참나(팀장) | Opus | - | pyright 진단 fix 3건 (f58e00d2, 1d9a032f, eeb535fa), 통합 검증, 보고서 |

- 이쉬첼(프론트)·아쿠인(UX/UI): 본 작업과 무관 (백엔드 전용 코드 — 활성화 안 함)
- haiku 미사용 (critical task — sonnet 이상 의무)
- 팀장 직접 코딩은 pyright type fix 3건과 통합 단계만 (Opus 토큰 절감 원칙 준수)

## 발견 이슈 및 해결

### 이슈 1: Pyright import 미해결 (worktree-local 파일)
- 증상: 새 utils 파일과 그를 import 하는 helper/test에서 `reportMissingImports` 진단
- 근거: `pyrightconfig.json::extraPaths` 가 `/home/jay/workspace` (메인 워크스페이스) 만 가리킴. worktree-local 신규 파일은 PR merge 전까지 메인에 부재 → pyright 미해결.
- 해결: 우리 추가 import 3개 site에 `# pyright: ignore[reportMissingImports]` 주석 추가 (commits f58e00d2, 1d9a032f, eeb535fa). PR merge 후 자동 해소.
- 런타임 영향: 0 (pytest 30 케이스 PASS, CLI smoke PASS, import 정상 동작).

### 이슈 2: helper 기존 코드 pre-existing 진단
- 증상: helper line 34/53 imports / line 618 `kind` 미사용 등 pre-existing pyright 진단
- 처리: 본 작업의 allowed_resources 가이드에서 helper의 기존 함수 수정 금지 → 미수정. origin/main과 동일 표면 유지.

## 머지 판단
- **머지 필요**: No (회장 verbatim 금지 10번 auto-merge 0)
- **브랜치**: `task/task-2694+1-dev7`
- **워크트리 경로**: `/home/jay/workspace/.worktrees/task-2694+1-dev7`
- **머지 의견**: PR open-only enforcement. Gemini 리뷰 + 회장 결재 후 수동 처리. 본 PR 머지 시 main의 pyright extraPaths가 새 utils 파일을 자동 인식하여 ignore 주석 제거 가능 (별도 follow-up task).

## Codex 게이트 결과
- 사전 검증 결과 파일: `memory/events/task-2694+1.codex-gate`
- pass: false (현재 상태 기준), critical=1 / high=2 / medium=2
- 5 risks 모두 본 작업으로 해결:
  - (critical) finish-task.sh 4-source 미검증 → Step 2.9.5 게이트 삽입
  - (high) 신규 파일 부재 → 본 작업으로 신규 생성
  - (high) sid 재사용/stale → envelope task_id 결속 검증
  - (medium) marker 일관성 → emit_not_registered_marker 단일 emit 경로
  - (medium) 회귀 oracle 부족 → 30 케이스 (6 fail + 1 pass + 보강 23)
- 본 PR이 Codex 지적 갭을 정확히 메움.

## 3 Step Why 자문 (context-notes.md 박제)
- **1st Why**: task-2693 정확한 사고 (envelope-only completion → 코드 enforce 필요)
- **2nd Why**: 4-source AND가 단일 source 우회 모두 차단
- **3rd Why**: envelope 텍스트만 / schedule_id만 단일 검증은 task-2693 사고에서 이미 우회됨 → 4-source 결합 + envelope 결속 검증이 유일하게 견고

A-B-C 일관성: OK.

## L1 스모크테스트 결과 (필수 기록)
- 서버 재시작: 해당없음 (subprocess 0 코드 변경 — validator는 read-only file 접근)
- API 응답 확인:
  ```
  $ cokacdir --cron-history 7FA863F5 --chat 6937032012 --key c119085addb0f8b7
  {"count":0,"history":[],"id":"7FA863F5","status":"ok"}
  ```
  schedule_id 등록 확인 (ANU key 응답 hit), schedule_history 5분 후 생성 예정.
- 스크린샷: 해당없음 (백엔드 CLI 작업, UI 없음)
- 추가 L1 (validator CLI dogfood):
  ```
  $ python3 -m utils.normal_callback_registration_validator --task-id task-2694+1 \
      --envelope-path memory/events/anu_callback/task-2694-normal-completion.json
  verdict=FAIL (schedule_history file missing) exit=2  ← fail-closed 정상 동작
  ```
- 추가 L1 (helper enforce CLI):
  ```
  $ python3 -m dispatch.normal_fallback_callback_helper enforce \
      --task-id test-fake --envelope-path /nonexistent.json --no-marker-on-fail
  verdict=FAIL exit=2  ← envelope 부재 fail-closed
  ```

## frozen anchors 준수
- ANCHOR-1 (envelope-only 차단): ✅ Step 2.9.5 게이트 + validator + marker
- ANCHOR-2 (deferred/pending 어구 차단): ✅ schema enum + BLOCKED_SCHEDULE_TYPES
- ANCHOR-3 (4-source AND): ✅ validate_callback_registration() 본문
- ANCHOR-4 (본인 dogfood): ✅ envelope 작성, cokacdir cron 등록, 4-source 현재 fail-closed 동작 확인
- ANCHOR-5 (state_file_missing PASS 금지): ✅ enforce 게이트가 .done 차단
- ANCHOR-6 (PR #152/#154/#151/#149/task-2691+b 혼합 0): ✅ git diff stat 확인
- ANCHOR-7 (dispatch.py 전역 변경 0): ✅ helper만 patch
- ANCHOR-8 (8 우회 패턴 감지 시 HOLD_FOR_CHAIR): ✅ 0건 감지

## finish-task.sh dogfood 실행 기록
- 명령: `cd /home/jay/workspace && CALLBACK_ENVELOPE_PATH=memory/events/anu_callback/task-2694-normal-completion.json bash scripts/finish-task.sh task-2694+1 dev7`
- 실행 시각: 2026-05-27 04:43
- 결과:
  - QC: **PASS** (8 PASS / 13 SKIP / 2 WARN — three_docs_check PASS, l1_smoketest_check PASS, git_evidence PASS, critical_gap PASS, spec_compliance PASS, file_check PASS, data_integrity PASS, duplicate_check PASS)
  - SCOPE-GUARD: SKIP (diff 비어있음 — 시스템 작업)
  - 머지 단계: SKIP (PROJECT_PATH 미지정 — 시스템 작업)
  - GIT-GATE: 커밋 **8건** 확인 (task-2694+1 한정)
  - GIT-GATE: **BLOCKED** — main workspace 외부 dirty 상태 (다른 봇/팀의 미커밋 변경 6개 unstaged: `config/constants.json`, `dashboard/data/naver-sa-stats.json`, `memory/specs/anu-system-spec.md`, `utils/replacement_pr_runner.py`, `memory/reports/task-2692.md`, `INDEX.md` 등)
- ★ 본 작업의 enforcement(Step 2.9.5) 자체는 dogfood validator CLI에서 이미 4-source PASS 확인됨 (verdict=PASS, exit=0). 다만 finish-task.sh 호출 흐름상 GIT-GATE(Step 2.5)가 Step 2.9.5보다 먼저 실행되어 외부 dirty 상태로 차단.
- 이는 **fail-closed 정상 동작** — 본 enforcement의 책임 영역 외. GIT-GATE는 회장 verbatim forbidden 영역 (`scripts/finish-task.sh callback registration 단계 외 latency / scope-guard 영역 수정 금지`)이므로 우회/수정 시도 0.
- ★ 회장 verbatim "★ 단, dogfood 차단 시 회장 보고 후 회피 우회 0 — fail-closed가 정상 동작" 명시 그대로 수용. 본 작업은 enforcement가 정상 작동했고, finish-task.sh의 별도 게이트(GIT-GATE)에서 외부 환경 dirty로 BLOCKED — 회장 결재 영역.

## 완료 상태
`TASK_2694_PLUS_1_NORMAL_CALLBACK_REGISTRATION_ENFORCEMENT_PR_OPEN_DOGFOOD_VERIFIED` — PR #155 open + dogfood 4-source PASS + finish-task.sh GIT-GATE 외부 환경 dirty (회장 결재 대기, 회피 우회 0).
