# task-2639 — real_merge_hooks chair_authorization snapshot 교차검증 정책 수정 결과 (real merge 실행 0)

- 담당: dev6 페룬
- Level: Lv.3 (real merge wiring 정책 정정 · activation false default 유지)
- 단일소스 spec: `memory/specs/system_real_merge_hooks_snapshot_crossref_spec_260523.md`
  - sha256: `12b8af006913833596562c55ab9a0acca935830be90c5f17f2af4b7e1e632621` ✅ 일치
- base: origin/main `fa72e25a` (PR #140 real merge wiring OFF-mode 머지)
- 결과 commit: `40c9103e9ed5781ee7bcbbb15b1fa168aa428f19` (로컬 한정 · push/PR/merge 0)
- 작업 worktree: `/home/jay/.cokacdir/workspace/A97B5052/dev6-task-2639`
- 시작/종료: 2026-05-23T14:40:02+09:00 → 2026-05-23T15:02:10+09:00 (KST · 약 22분)

## 회장 D안 결정 verbatim 반영 (2026-05-23)

PR #141 B1 pilot NO_OP_FORBIDDEN_PATH 사고 — forbidden prefix 가드 vs
chair_authorization expected_files_snapshot 충돌. B안(우회) / C안(다른 target)
모두 기각 — pilot 가치 보존 + 정책 충돌 근본 해소. snapshot 교차검증 도입.

### 회장 verbatim 10항목 충족
1. forbidden prefix 검사 전 snapshot 로드 ✅ (`validate_snapshot_crossref` Step 0a/0b)
2. changed_files 전체 ⊆ expected_files_snapshot 단언 ✅ (classification 분리 기록)
3. PR number / head_sha 정확 일치 ✅ (`pr_match` / `sha_match`)
4. snapshot 외부 forbidden → `NO_OP_FORBIDDEN_PATH` 유지 ✅
5. snapshot 내 production / secret / admin override → CHAIR_REQUIRED 격상 ✅
6. `.tasks/locks/*` sanctioned 분리 기록 ✅ (`sanctioned_artifacts` 컬럼)
7. `tests/fixtures/...` doc-only snapshot 일치 시 통과 ✅
8. allow_reason `chair_authorization_snapshot_crossref` 명시 ✅
9. broad prefix allowlist 금지 ✅ (snapshot exact match 만)
10. forbidden 보안 의미 유지 ✅ (snapshot 정합 없으면 동일 동작)

## 구현 파일 (총 28 files)

### 신규 helper 1
- `utils/snapshot_crossref_validator.py` — Step 0b/0c/0d 통합 (schema `utils.snapshot_crossref_validator.v1`)

### 정책 결선 수정 (최소 변경) 2
- `utils/real_merge_hooks.py` — Step 0 흐름 정정 + v1→v2 schema bump
- `utils/real_merge_artifact_schema.py` — v2 필드 추가 (`allow_reason` + `snapshot_crossref`)

### 신규 enum 4종
- `NO_OP_AUTH_MISMATCH` — pr/head_sha 불일치 (재승인 강제)
- `CHAIR_REQUIRED_PRODUCTION_IN_SNAPSHOT` — snapshot 내 utils/scripts/dispatch 포함
- `CHAIR_REQUIRED_BLOCKING_SECRET_IN_SNAPSHOT` — snapshot 내 ghp_/PEM/private_key 토큰 포함
- `CHAIR_REQUIRED_ADMIN_OVERRIDE_REQUIRED` — admin override gate + snapshot 명시 동시 충족

### fixture 7 × 3 = 21 + INDEX.md
- `fixture_in_snapshot_pass_candidate` → REAL_MERGE_DONE + allow_reason
- `fixture_in_snapshot_mismatch_no_op` → NO_OP_FORBIDDEN_PATH
- `fixture_wrong_head_sha` → NO_OP_AUTH_MISMATCH
- `sanctioned_lock_separated` → REAL_MERGE_DONE + 분리 기록
- `production_in_snapshot_chair_required` → CHAIR_REQUIRED_PRODUCTION_IN_SNAPSHOT
- `blocking_secret_in_snapshot_chair_required` → CHAIR_REQUIRED_BLOCKING_SECRET_IN_SNAPSHOT
- `admin_override_required_chair_required` → CHAIR_REQUIRED_ADMIN_OVERRIDE_REQUIRED

### regression 신규 2 (23 PASS)
- `tests/regression/test_snapshot_crossref_validator.py` — 11 cases (7 fixture parametrized + 4 defensive)
- `tests/regression/test_real_merge_hooks_v2_step0_flow.py` — 12 cases (7 fixture parametrized + 5 unit)

### 신규 task lock
- `.tasks/locks/task-2639.lock`

## regression 결과
- **신규 23 PASS** (11 validator + 12 v2 step0 flow)
- **기존 baseline 유지** — 1350 PASS + 11 SKIPPED (excl. test_stash_origin_audit_compat 3 pre-existing failures unrelated)
- **full new fail 0** — 본 task 의 변경으로 인한 신규 실패 0

## 안전 불변식 (단언 결과)
- forbidden prefix 보안 의미 유지 ✅ (snapshot 정합 없으면 동일 fail-closed)
- broad prefix allowlist 금지 ✅ (snapshot exact match 만 허용)
- ANU key `c119085addb0f8b7` 단일출처 변경 0 ✅
- envelope UTF-8 ≤3900 bytes 유지 ✅
- live cokacdir / subprocess 실호출 0 ✅
- `gh pr merge` 실호출 0 ✅
- admin override 코드 경로 0 ✅
- merge / push / PR / cron / admin override 실행 0 ✅
- replacement_pr_runner / finish-task.sh / merge_ready_classifier / merge_ready_dryrun_executor 무수정 ✅
- callback_envelope_schema / anu_callback_registrar / canonical_root_resolver / anu_collector_action_trigger / activation_flag_validator / chair_authorization_validator / gate_snapshot_validator / dispatch/finalize_hooks / dispatch/__init__ 무수정 ✅
- expected_files 외부 수정 0 ✅
- BLOCKING_SECRET 0 ✅ (fixture filename 만 노출 · 실 token 미포함)

## frozen anchor 충족 확인
- ANCHOR-1: Step 0 흐름 (input → auth_match → snapshot_crossref → sanctioned_split → existing_gates) ✅
- ANCHOR-2: forbidden 보안 가드 유지 · snapshot exact match 만 통과 · broad allowlist 금지 ✅
- ANCHOR-3: schema v1→v2 bump · allow_reason + snapshot_crossref 필드 추가 ✅
- ANCHOR-4: production / secret / admin override 검출 시 CHAIR_REQUIRED 격상 (snapshot 포함 무관) ✅
- ANCHOR-5: sanctioned (.tasks/locks/) 분리 기록 ✅
- ANCHOR-6: real_merge_hooks / real_merge_artifact_schema 만 정정 · 나머지 wiring stack 무수정 ✅
- ANCHOR-7: PR #141 직접 merge 금지 · 기존 chair_authorization EXPIRED · 새 발급은 정책 머지 후 ✅

## 다음 단계 (ANU normal callback 이후)
1. 봇 로컬 commit `40c9103e` fresh main 재적층
2. OWNER push → PR open
3. Gemini 자동수렴 — expected_files 내부 medium/style → 자동수렴
4. 회장 보고 + merge 승인
5. 정책 수정 merge 후 → 새 chair_authorization 발급 (새 PR/head_sha 기준)
6. B1 pilot 재시도 또는 새 pilot target 결정
