# task-2632 — merge-ready classifier 구현 (read-only · decoupled · merge 실행 0)

- Level: Lv.3 (거버넌스 자동화 코어 · evidence-only classifier)
- 담당: dev6 페룬
- base: origin/main **24fadbf8** (CALLBACK_RUNTIME_ENFORCEMENT_PRODUCTION_VERIFIED 반영분)
- 단일소스 spec: `memory/specs/system_merge_ready_executor_spec_260522.md`
  - sha256: `dc082f767c8c4bb1d409f08cc2e8bae7c7418b1996617f7b1257ae8541d23364` (정독 전 sha256sum 검증, 불일치 시 중단·ANU 보고)
- 승인 범위: **classifier 구현까지만**. auto-merge executor 실행은 미승인.

## 목표
PR/Gemini/CI/phase3/scope/credential/lifecycle evidence 를 종합해 merge 가능 여부와 회장 보고 필요 여부를 결정적으로 판정하는 **순수함수 classifier** 를 구현한다. callback lifecycle classifier 동형 — evidence-only · I/O 0 · merge 실행 0.

## 필수 구현
1. `utils/merge_ready_classifier.py` — decoupled pure module
2. `utils/merge_ready_states.py` — enum/상수 단일소스
3. `classify_merge_ready(evidence, anu_keys, expected_files)` 순수함수
4. **verdict enum: PASS / HOLD / CHAIR_REQUIRED / UNKNOWN** (회장 확정 — UNKNOWN 포함 4값)
5. 반환 dict 필드: `verdict · blocking_reasons · chair_triggers · auto_remediable · auto_merge_10_conditions · critical7_hits · credential_tier · evidence_completeness · next_action · classified_by`
6. **verdict precedence (상태기계): UNKNOWN > CHAIR_REQUIRED > HOLD > PASS** (spec §1/§3)
7. callback lifecycle fields 10~14(delivery_outcome/normal_callback_miss_cause/root_cause_tags/classification/applied_count) 입력 evidence 반영. classification==INCIDENT(self-key fired non-authoritative 등 production 신뢰성 훼손) → CHAIR_REQUIRED
8. Gemini auto-remediation doctrine 반영: medium/style + expected_files 내부 + Critical7 0 + credential 0 → HOLD(auto_remediable). non-critical HIGH 도 expected_files 내부면 자동수렴 후보(HOLD)이되, 같은 함수 HIGH 반복 또는 scope 확장 조짐이면 CHAIR_REQUIRED. gemini stale → HOLD(operational nudge 후보)
9. credential scan 3계층 반영: BLOCKING_SECRET(ghp_/ghs_/PAT/PEM/AWS/신규 secret)→CHAIR_REQUIRED · EXISTING_SYSTEM_IDENTIFIER(origin/main 기존 식별자)→fail 아님 · NET_NEW→CHAIR_REQUIRED. "문자열 발견=fail" 금지 (식별자 후보는 교차확인 입력 evidence 로 받음 — classifier 는 순수함수라 git grep 직접 호출 X, evidence 에 `net_new_identifier_exposure` bool 로 주입)
10. Critical7 1:1 mapping 반영 (spec §4): forbidden_path / out-of-scope+replacement_fail / scope확장 / override / dep_cycle·serial / replacement_fail / smoke_fail → 전부 CHAIR_REQUIRED

## CHAIR_REQUIRED 조건 (회장 verbatim)
Critical7 / credential·permission expansion / expected_files 밖 수정 필요 / admin override 필요 / replacement PR failure / post-merge smoke failure / dependency cycle·serial_only collision / merge policy 변경 필요 / lifecycle incident가 self-key fired non-authoritative 등 production 신뢰성을 훼손하는 경우.

## 자동수렴 원칙 (회장 verbatim — classifier 가 HOLD/AUTO_REMEDIATION 으로 분류)
- Gemini medium/style/quality + expected_files 내부 + Critical7 0 + credential 0 → HOLD/AUTO_REMEDIATION. 회장 A/B/C X.
- Gemini stale → OWNER /gemini review operational nudge 자동수렴 후보(HOLD).
- non-critical HIGH 도 expected_files 내부면 자동수렴 가능하되, 같은 함수 HIGH 반복/scope 확장 조짐이면 CHAIR_REQUIRED.

## 필수 fixture — **17종 frozen evidence snapshot** (회장 확정, live 의존 0)
1. pass_all_green 2. hold_ci_pending 3. hold_gemini_medium 4. hold_gemini_stale 5. hold_unresolved_medium 6. chair_forbidden_path 7. chair_blocking_secret 8. chair_net_new_identifier 9. chair_out_of_scope 10. chair_replacement_fail 11. chair_smoke_fail 12. chair_dependency_cycle 13. chair_serial_collision 14. chair_admin_override 15. chair_lifecycle_incident 16. existing_identifier_passthrough 17. unknown_insufficient_evidence
- 경로: `tests/fixtures/merge_ready/<name>/{evidence.json, expected.json, PROVENANCE.md}`
- expected.json = {verdict, chair_triggers, credential_tier, ...}. evidence.json = frozen snapshot(live GitHub/git status/current main 의존 절대 0). PROVENANCE 에 근거 명기.
- 12·13 은 반드시 **분리된 별도 fixture** (합치지 말 것).

## 필수 regression
- `tests/regression/test_merge_ready_classifier.py` — 17 fixture 각각 verdict+triggers 일치 단언 + verdict precedence(UNKNOWN>CHAIR_REQUIRED>HOLD>PASS) 단언 + 각 enum 도달 경로 커버
- full tests/regression 신규 fail 0
- live workspace 의존 0 (WORKSPACE_ROOT env override / Path(__file__) / frozen fixture)

## expected_files (task-2632 범위)
- `utils/merge_ready_classifier.py` (신규)
- `utils/merge_ready_states.py` (신규)
- `tests/regression/test_merge_ready_classifier.py` (신규)
- `tests/fixtures/merge_ready/<17 names>/{evidence.json,expected.json,PROVENANCE.md}` (신규)

## 금지 (회장 verbatim — 절대 준수)
- auto-merge 실행 금지 · merge 명령 금지 · push/PR/merge 금지(코드 자체에 merge/write 호출 0)
- branch protection 우회 금지 · admin override 자동화 금지
- Natural Language Intake 동시 구현 금지
- foreign dirty 정리 금지 · replacement_pr_runner 수정 금지
- production service task 와 섞기 금지
- classifier 내부 GitHub write/live git status 조회 0 (순수함수 — evidence dict 만 입력)

## finalize 프로토콜 (★ BOT App token 부재 — 로컬 한정)
1. base = 최신 origin/main 24fadbf8 clean worktree
2. 구현 + 17 fixture + regression 전부 PASS + full new-fail 0
3. **로컬 commit만** (push/PR/merge 금지). finish-task.sh project_path 없이 로컬 종결
4. ANU normal completion callback — **반드시 독립 ANU key `c119085addb0f8b7`**(executor self-key 자가발사 금지·SELF_COLLECTOR 금지)·collector_role=ANU
5. callback envelope UTF-8 ≤3900 bytes (printf '%s'|wc -c), envelope 만: task_id=task-2632 · 로컬 commit SHA · result_path · report_path · 구현 파일 목록 · 17 fixture 검증 결과 · regression 요약 · sha256. 상세는 result.json/report.md 위임. result.json 에 callback prompt byte 수 기록
6. executor 시작/종료 ts · 로컬 commit SHA 명기

이후 ANU: 봇 로컬 commit fresh main 재적층 → OWNER push → PR open → Gemini auto-remediation → 회장 9항목 보고 → 회장 merge 승인.

## 검증 시나리오 (이게 되면 성공)
- 17 fixture 전부 expected verdict/triggers 일치 + precedence UNKNOWN>CHAIR_REQUIRED>HOLD>PASS 단언 통과
- classifier 내 merge/write/live-git 호출 0 (순수함수)
- credential 3계층·Critical7 1:1·lifecycle fields 10~14·Gemini auto-remediation doctrine 전부 분류에 반영
- full regression 신규 fail 0

## frozen anchor (D-SPEC-EXACTNESS)
- ANCHOR-1: "verdict enum 4값 PASS/HOLD/CHAIR_REQUIRED/UNKNOWN · precedence UNKNOWN>CHAIR_REQUIRED>HOLD>PASS"
- ANCHOR-2: "fixture 17종 · chair_dependency_cycle 와 chair_serial_collision 분리"
- ANCHOR-3: "classifier 순수함수 · merge 실행 0 · GitHub write 0 · live git status 조회 0"
- ANCHOR-4: "auto-merge executor 실행 미승인 — 본 task 는 classifier 까지만"
