# task-2632 — merge-ready classifier 구현 보고 (dev6 페룬)

- **승인 범위**: classifier 까지만 (auto-merge executor 실행 미승인 · ANCHOR-4)
- **executor 시작/종료**: 2026-05-22 21:54:00 KST → 2026-05-22 22:06:57 KST
- **base**: origin/main `24fadbf8e5a4c7438dd7a90e2013166e05769630` (clean isolated worktree)
- **branch**: `task/task-2632-dev6`
- **로컬 commit SHA**: `e5449c24a11c68b401242af31a355cef378d63ed`
- **push/PR/merge**: 0 (BOT App token 부재 → 로컬 commit only)

## 1. spec 검증 (sha256 일치)

- task-2632.md: `15813c5e294d814ebf2417b70a4656d9d3a8f958a781e87fe1b0e0b10957f42d` ✅
- system_merge_ready_executor_spec_260522.md: `dc082f767c8c4bb1d409f08cc2e8bae7c7418b1996617f7b1257ae8541d23364` ✅

둘 다 일치 → 추측 없이 spec 그대로 구현.

## 2. 구현 (expected_files 범위 — 그 밖 수정 0)

54 files · +2851. tracked file 수정 0 (순수 additive).

- `utils/merge_ready_states.py` — enum/상수 단일소스
  - verdict enum 4값: PASS / HOLD / CHAIR_REQUIRED / UNKNOWN (ANCHOR-1)
  - precedence: UNKNOWN > CHAIR_REQUIRED > HOLD > PASS
  - credential 3계층(+NONE) · Critical7 1:1 (C7#1~#7)
  - 8 회장 보고 트리거 (+ lifecycle incident + auto-remediation loop boundary)
  - auto_remediable enum · 자동 머지 10조건 키 · ANU key `c119085addb0f8b7`
  - sha256 `d113f461fee72c9b9e921a63fd60056c971fb051ec275a60a20d2f44a85bb62f`
- `utils/merge_ready_classifier.py` — 순수함수 classifier
  - `classify_merge_ready(evidence, *, anu_keys, expected_files) -> dict`
  - 반환: verdict · blocking_reasons · chair_triggers · auto_remediable ·
    auto_merge_10_conditions · critical7_hits · credential_tier ·
    evidence_completeness · next_action · classified_by (+ 진단 필드)
  - sha256 `6b3cb48831fa26872c3213a656c98766bd42c666348a8f2c5c4db7e1af5f1d8f`
- `tests/regression/test_merge_ready_classifier.py` — 50 tests
  - sha256 `1dff7d9c34d6dcf9ae943ad9d00d42532be5ec8583528d2d632b10f4daa45226`
- `tests/fixtures/merge_ready/<17>/{evidence,expected,PROVENANCE}` — 51 files
  - aggregate sha256 `68ef893320c74be96c1e8f2121cffbe8488486daf510cd2da8eadd27ce515f40`

## 3. doctrine 반영

- **credential 3계층**: BLOCKING_SECRET(ghp_/ghs_/PAT/PEM/AWS)→CHAIR · NET_NEW(origin/main 부재 봇 key)→CHAIR · EXISTING_SYSTEM_IDENTIFIER(기존 식별자)→fail 아님·PASS 영향 0 · NONE. "문자열 발견=fail" 금지 — 식별자 교차확인 결과를 `net_new_identifier_exposure` bool 로 입력받음(classifier 가 git grep 직접 호출 X).
- **Critical7 1:1**: forbidden_path / out-of-scope+replacement_fail / scope확장 / override / dep_cycle·serial / replacement_fail / smoke_fail → 전부 CHAIR_REQUIRED.
- **Gemini auto-remediation**: medium/style/non-critical HIGH + expected_files 내부 + Critical7 0 + credential 0 → HOLD(auto_remediable) · 회장 A/B/C X. stale → HOLD(operational nudge). 같은 함수 HIGH 반복/scope 확장 조짐 → CHAIR.
- **callback lifecycle fields 10~14**: delivery_outcome/normal_callback_miss_cause/root_cause_tags/classification/applied_count 입력 반영. classification==INCIDENT(self-key fired non-authoritative 등 production 신뢰성 훼손) → CHAIR_REQUIRED. owner key 교차확인(anu_keys)으로 self-key 발사 감지.
- **순수성**: merge/write/live-git/subprocess 호출 0 — `tokenize` 기반 코드토큰 정적검증으로 강제(ANCHOR-3).

## 4. 17 fixture 검증 결과 (frozen evidence snapshot · live 의존 0)

전부 expected verdict/triggers 일치 (**ALL 17 MATCH**). 4 verdict 모두 도달.

- PASS(2): `pass_all_green`, `existing_identifier_passthrough`(tier=EXISTING)
- HOLD(4): `hold_ci_pending`, `hold_gemini_medium`, `hold_gemini_stale`, `hold_unresolved_medium`
- CHAIR_REQUIRED(10): `chair_forbidden_path`, `chair_blocking_secret`, `chair_net_new_identifier`, `chair_out_of_scope`, `chair_replacement_fail`, `chair_smoke_fail`, `chair_dependency_cycle`, `chair_serial_collision`, `chair_admin_override`, `chair_lifecycle_incident`
- UNKNOWN(1): `unknown_insufficient_evidence`(completeness=MISSING)

★ `chair_dependency_cycle` 와 `chair_serial_collision` 은 분리된 별도 fixture (ANCHOR-2) — 서로 다른 신호(dependency_cycle vs serial_only_collision)로 구성.
★ precedence 단언: UNKNOWN>CHAIR_REQUIRED>HOLD>PASS (MISSING+chair→UNKNOWN, chair+hold→CHAIR, hold+pass→HOLD) 통과.

## 5. regression

- merge_ready: **50 passed**
- full tests/regression: **943 passed · 11 skipped · 3 failed** → **신규 fail 0**
- 기존 fail 3건: `tests/regression/test_stash_origin_audit_compat.py` 의 finish-task.sh stash-audit guard 단언. task-2632 와 무관하며 base 24fadbf8 에 선재(finish-task.sh / 해당 test 파일 모두 무수정 — diff empty 로 검증). 내 변경은 순수 additive(신규 4 path)라 기존 테스트에 영향 0.

## 6. finalize 결정 — finish-task.sh 미실행 (skipped-with-reason)

`finish-task.sh` 는 `WORKSPACE=/home/jay/workspace` 를 하드코딩한다. 현재 공유 main workspace 는
foreign `task/task-2625-reconcile-evidence` (`d8ea371f`) 가 checkout 되어 `main..HEAD` 에 **384개 foreign 파일**이 있다.
PROJECT_PATH 를 비워 머지 단계는 스킵되지만, scope-guard 단계가 이 foreign diff 를 대상으로 실행되어
task-2632 scope 와 불일치 → **spurious `memory/events/task-2632.escalate` 생성 + `exit 1`** 가 발생한다.

이는 회장 verbatim 금지("foreign dirty 정리 금지 · production service task 혼입 금지 · marker 오염")에 직접 저촉되므로
**finish-task.sh 를 실행하지 않고 로컬 commit 으로 로컬 종결**했다. (lock 은 start_task_guard schema 로 생성, pre-commit guard PASS.)

→ ANU 가 fresh main 재적층 후 **clean tree** 에서 정상 finalize 하는 것이 안전하다.

## 7. ANU 정상완료 콜백

- owner_key **`c119085addb0f8b7`** (독립 ANU key) · collector_role=ANU
- executor self-key(`1e41a2324a3ccdd0`) 자가발사 금지 준수 · SELF_COLLECTOR 금지 준수
- envelope UTF-8 **2384 bytes** (≤3900) · envelope 만 전송, 상세는 result.json/report.md 위임
- schedule: absolute one-time (+1m, 발사 후 auto-delete)

## 8. 다음 단계 (ANU)

봇 로컬 commit fresh main 재적층 → OWNER push → PR open → Gemini auto-remediation →
회장 9항목 보고 → 회장 merge 승인. (auto-merge executor 는 별도·회장 활성화 게이트 — 본 task 범위 밖.)
