# merge-ready executor spec (read-only classifier 단계) — 260522

회장 결정(2026-05-22, CALLBACK_RUNTIME_ENFORCEMENT_PRODUCTION_VERIFIED 직후): PR 자동 merge 가능 여부를 ANU가 결정적으로 판정하는 **merge-ready classifier**를 설계한다. 본 문서는 **read-only classifier/spec 단계**다 — merge 실행은 별도 executor 단계로 분리하며, **auto-merge 실행/branch protection 우회/admin override 자동화/Natural Language Intake는 본 단계 범위 아님.**

기존 doctrine 코드화: Critical7([[feedback-critical-escalation-only-260508]]) + 자동 머지 10조건 + Gemini auto-remediation([[feedback-gemini-medium-auto-remediation-260522]]) + credential 3계층([[feedback-credential-scan-3tier-doctrine-260522]]) + callback lifecycle fields 10~14(CALLBACK_RUNTIME_ENFORCEMENT_PRODUCTION_VERIFIED).

설계 원칙: callback lifecycle classifier와 동형 — **evidence-only · 순수함수 · I/O 0 · 추정 금지(증거 결핍 시 HOLD/UNKNOWN) · merge 실행 0**.

---

## 1. merge-ready 판단 schema

```
classify_merge_ready(evidence: dict, *, anu_keys, expected_files) -> dict
  반환 = {
    "verdict": PASS | HOLD | CHAIR_REQUIRED | UNKNOWN,
    "blocking_reasons": [str, ...],          # CHAIR_REQUIRED/HOLD 사유
    "chair_triggers": [enum, ...],           # 8 보고 트리거 중 적중
    "auto_remediable": [enum, ...],          # HOLD 중 ANU 자동수렴 가능 항목
    "auto_merge_10_conditions": {cond: bool},# 10조건 개별 결과
    "critical7_hits": [enum, ...],
    "credential_tier": NONE | EXISTING_SYSTEM_IDENTIFIER | NET_NEW | BLOCKING_SECRET,
    "evidence_completeness": COMPLETE | PARTIAL | MISSING,
    "next_action": str,                      # executor 단계 진입 가능 여부 포함
    "classified_by": "merge-ready-classifier",
  }
```
순수함수. evidence 수집(gh/git 조회)은 별도 read-only collector가 담당, classifier는 dict만 입력받는다.

**verdict precedence (상태기계):** UNKNOWN > CHAIR_REQUIRED > HOLD > PASS.
1. evidence_completeness == MISSING(핵심 gate evidence 결핍) → **UNKNOWN** (추정 0 · 재수집 필요 · merge/보고 판정 보류)
2. chair_triggers 비어있지 않음 → **CHAIR_REQUIRED** (절대 auto-merge 아님)
3. auto_remediable 비어있지 않음(또는 gate pending/stale) → **HOLD** (ANU 자동수렴/재평가, merge 아님)
4. 위 전부 해소 + 자동 머지 10조건 전부 PASS → **PASS** (executor 후보)

> UNKNOWN 을 CHAIR_REQUIRED 보다 앞에 두는 이유: 증거 자체가 불완전하면 chair_trigger 판정도 신뢰 불가 → 성급한 escalate/merge 대신 재수집. 단 evidence 가 충분히 모인 뒤 chair_trigger 가 있으면 CHAIR_REQUIRED 가 우선.

---

## 2. 입력 evidence 목록

**A. scope/diff**: expected_files(declared) · effective_diff_files · exact_match(bool) · forbidden_path_hits · out_of_expected_files_modification(bool)
**B. credential(3계층)**: blocking_secret_hits(ghp_/ghs_/PAT/PEM/AWS) · net_new_identifier_exposure(git grep origin/main 교차확인 후) · existing_system_identifier_reuse(정보용·fail 아님)
**C. gates**: ci_checks{name:state}·all_pass · gemini_review_gate(pass/fail/pending/stale) · phase3_merge_gate · mergeStateStatus(CLEAN/BLOCKED/UNKNOWN) · mergeable(MERGEABLE/CONFLICTING) · unresolved_threads(+high/medium 분해)
**D. Gemini remediation**: gemini_findings[{severity,path,within_expected_files,resolved}] · medium_auto_remediation_status(converged/pending/N-A) · high_or_critical_unresolved(count) · evidence_freshness(fresh-for-head/stale)
**E. Critical7 신호**: critical7_hits · replacement_pr_failure · admin_override_required · branch_protection_bypass_required · dependency_cycle / serial_only_collision · merge_policy_change_required · post_merge_smoke_failure
**F. merge mechanics**: queue_head(bool) · serial_conflict(bool) · head_sha_lock_match(bool) · post_merge_smoke_defined · post_merge_smoke_runnable
**G. callback lifecycle(fields 10~14, ★신규 입력)**: delivery_outcome · normal_callback_miss_cause · root_cause_tags · classification(NORMAL/INCIDENT) · applied_count → PR 자기 closeout lifecycle 건전성 증거. classification==INCIDENT(예: SELF_KEY_FIRED_NON_AUTHORITATIVE) PR은 auto-merge 부적격.

---

## 3. verdict enum: PASS / HOLD / CHAIR_REQUIRED / UNKNOWN

- **UNKNOWN**: 핵심 gate evidence 결핍(추정 금지) → 재수집 필요, merge/escalate 판정 보류. evidence_completeness=MISSING.

- **PASS** (MERGE_READY): 15 조건 + 자동 머지 10조건 전부 충족, chair_trigger 0, 자동수렴 대기 0, lifecycle classification NORMAL → **auto-merge executor 후보**(실행은 별도 단계·회장 활성화 전까지 advisory).
- **HOLD** (AUTO_REMEDIATION_OR_TRANSIENT): ANU가 스스로 해소 가능한 것만 막고 있음 — CI pending · gemini evidence stale(재트리거) · medium/style(+non-Critical HIGH) expected_files 내부 미수렴 · unresolved medium thread(해소 가능) · mergeStateStatus 일시 BLOCKED. → ANU 자동수렴 루프 → 재분류. **회장 보고 X · merge X.**
- **CHAIR_REQUIRED**: 아래 8 트리거 중 1개 이상 → escalate, **절대 auto-merge X.**

**8 회장 보고 트리거 (CHAIR_REQUIRED)**: Critical7 적중 / credential·permission expansion(BLOCKING_SECRET·NET_NEW) / expected_files 밖 수정 필요 / admin override 필요 / replacement PR failure / post-merge smoke failure / dependency cycle·serial_only collision / merge policy 변경 필요. (+ lifecycle classification==INCIDENT 는 CHAIR_REQUIRED 로 승격)

---

## 4. Critical7 mapping (회장 7종 → classifier 입력)

1. forbidden path 침범 → `forbidden_path_hits > 0` → CHAIR_REQUIRED
2. effective diff 오염 + replacement PR 자동생성 실패 → `out_of_expected_files_modification && replacement_pr_failure` → CHAIR_REQUIRED
3. Gemini real bug가 expected_files 밖/scope 확장 요구 → `gemini finding requires out_of_expected_files || scope_expansion` → CHAIR_REQUIRED
4. BLOCK override 필요/override reason 불충분 → `admin_override_required || branch_protection_bypass_required` → CHAIR_REQUIRED
5. dependency cycle / serial_only 충돌 → `dependency_cycle || serial_only_collision` → CHAIR_REQUIRED
6. replacement PR도 실패 → `replacement_pr_failure` → CHAIR_REQUIRED
7. post-merge smoke 실패 → `post_merge_smoke_failure` → CHAIR_REQUIRED

자동 처리(회장 보고 X, HOLD/PASS): false-positive Gemini dismiss · style-only dismiss · 허용 파일 내 minor fix · clean replacement PR 생성 · dependency satisfied · queue 선두 CI/Gemini/CLEAN 확인 · post-merge smoke + stale 재검증.

---

## 5. Gemini auto-remediation 연동

- medium/style/quality + expected_files 내부 + Critical7 0 + credential expansion 0 → `auto_remediable` 에 적재 → **HOLD** → ANU-Codex 자동수렴(fix/reasoned-resolve→regression→push→thread resolve→재검증) → 재분류. **회장 A/B/C X.**
- non-Critical HIGH + expected_files 내부 → 자동수렴(Critical7만 chair-hold) → HOLD.
- 단, 같은 함수/file-boundary HIGH 반복 → AUTO_REMEDIATION_LOOP_BOUNDARY_REVIEW(회장 요약보고)로 분기([[feedback-auto-remediation-loop-boundary-review-260519]]).
- medium/HIGH가 expected_files 밖/scope 확장 요구 → CHAIR_REQUIRED(Critical7 #3).
- gemini evidence stale(SHA mismatch) → HOLD(OWNER /gemini review 재트리거 = operational nudge, 회장 보고 X).

---

## 6. credential scan 3계층 연동 ([[feedback-credential-scan-3tier-doctrine-260522]])

- **BLOCKING_SECRET**(ghp_/ghs_/PAT/PEM/AWS/신규 실 secret) → `credential_tier=BLOCKING_SECRET` → CHAIR_REQUIRED(merge 차단·즉시 보고).
- **EXISTING_SYSTEM_IDENTIFIER**(origin/main+머지된 코드/fixture에 이미 존재하는 ANU/dev key·denylist self-key 예시) → `credential_tier=EXISTING_SYSTEM_IDENTIFIER` → fail 아님(정보용·PASS 영향 0).
- **NET_NEW_IDENTIFIER_EXPOSURE**(기존 origin/main에 없던 봇 key 신규추가) → `credential_tier=NET_NEW` → CHAIR_REQUIRED(merge 전 보고).
- 판별 알고리즘: diff 추가라인에서 식별자 후보 추출 → ghp_/ghs_/PEM/AWS 정규식은 즉시 BLOCKING → 봇 key 후보는 `git grep <id> origin/main` 교차확인(존재=EXISTING, 부재=NET_NEW). 단순 "문자열 발견=fail" 금지.

---

## 7. regression fixture — **17종 확정** (회장 2026-05-22, frozen evidence snapshot)

> 정정: 초안에서 `chair_dependency_cycle`/`chair_serial_collision`을 1줄로 합쳐 16처럼 보였으나, 회장 확정대로 **둘을 분리해 17종**으로 확정한다.

1. `pass_all_green` — 15+10 충족·lifecycle NORMAL → PASS
2. `hold_ci_pending` — CI pending → HOLD
3. `hold_gemini_medium` — medium expected_files 내부 미수렴 → HOLD
4. `hold_gemini_stale` — gemini evidence SHA mismatch → HOLD
5. `hold_unresolved_medium` — medium thread unresolved → HOLD
6. `chair_forbidden_path` — forbidden_path_hits>0 → CHAIR_REQUIRED(C7#1)
7. `chair_blocking_secret` — ghp_/PEM 등 추가 → CHAIR_REQUIRED(BLOCKING_SECRET)
8. `chair_net_new_identifier` — main에 없던 봇 key 추가 → CHAIR_REQUIRED(NET_NEW)
9. `chair_out_of_scope` — expected_files 밖 수정 → CHAIR_REQUIRED(C7#2/#3)
10. `chair_replacement_fail` — replacement PR 실패 → CHAIR_REQUIRED(C7#6)
11. `chair_smoke_fail` — post-merge smoke 실패 → CHAIR_REQUIRED(C7#7)
12. `chair_dependency_cycle` — dependency cycle → CHAIR_REQUIRED(C7#5)
13. `chair_serial_collision` — serial_only collision → CHAIR_REQUIRED(C7#5)
14. `chair_admin_override` — admin override/branch protection 우회 필요 → CHAIR_REQUIRED(C7#4)
15. `chair_lifecycle_incident` — closeout classification=INCIDENT(SELF_KEY_FIRED_NON_AUTHORITATIVE 등 production 신뢰성 훼손) → CHAIR_REQUIRED
16. `existing_identifier_passthrough` — ANU/dev key 재사용만 → credential_tier=EXISTING, PASS 영향 0
17. `unknown_insufficient_evidence` — gate evidence 결핍 → UNKNOWN(추정 0)

각 fixture = {evidence.json, expected.json(verdict+triggers), PROVENANCE.md}. live workspace 의존 0.

---

## 8. auto-merge executor 로 넘어가기 위한 조건 (다음 단계 gate)

merge 실행 **executor**(별도·후속·회장 활성화 게이트)는 다음 전부 충족 시에만 동작:
- classifier verdict == **PASS**
- 자동 머지 10조건 전부 충족
- queue 선두 + serial conflict 0
- admin override 불필요 + branch protection 우회 불필요
- post-merge smoke path 존재 + 실행 가능
- callback lifecycle artifact 정상 생성 가능
- **AND 회장이 executor 활성화를 명시 승인** (classifier 자체는 활성화 전까지 advisory/read-only)

executor 미충족·CHAIR_REQUIRED·HOLD 는 merge 실행 0.

---

## 구현 단계 (본 spec 이후·별도 dispatch 승인 대기)

1. (현재) read-only classifier spec ← 본 문서
2. py 구현 `utils/merge_ready_classifier.py`(순수함수·decoupled) + states 상수 모듈 + read-only evidence collector(gh/git)
3. frozen fixture(§7) + regression `tests/regression/test_merge_ready_classifier.py`
4. (그 다음·별도) auto-merge executor — 회장 활성화 게이트 하에서만

**금지(본 단계)**: auto-merge 실행 · branch protection 우회 · admin override 자동화 · production service task 혼입 · foreign dirty 혼입 · Natural Language Intake 동시 구현.
