---
task_id: task-2509+2
type: context
scope: task
created: 2026-05-08
updated: 2026-05-08
status: completed
---

# 맥락 노트: task-2509+2

**task**: task-2509+2

---

## 결정 근거

### [결정 1] 회장 명시 enum 이름을 정확히 사용 (기존 task-2509+1 이름과 차이 발생)

기존 `utils/merge_queue_executor.py`에는 다음 string 상수들이 정의되어 있다 (회장 §14):
- `CRITICAL_FORBIDDEN_PATH = "FORBIDDEN_PATH_INVASION"`
- `CRITICAL_DIFF_REPLACEMENT_FAILED = "EFFECTIVE_DIFF_CONTAMINATION_REPLACEMENT_FAILED"`
- `CRITICAL_GEMINI_SCOPE_EXPANSION = "GEMINI_REAL_BUG_SCOPE_EXPANSION"`
- `CRITICAL_BLOCK_OVERRIDE = "BLOCK_OVERRIDE_REQUIRED_OR_INSUFFICIENT_REASON"`
- `CRITICAL_DEPENDENCY_CYCLE = "DEPENDENCY_CYCLE_OR_SERIAL_ONLY_CONFLICT"`
- `CRITICAL_REPLACEMENT_FAILED = "REPLACEMENT_PR_ALSO_FAILED"`
- `CRITICAL_POST_MERGE_SMOKE = "POST_MERGE_SMOKE_FAILURE"`

회장 task-2509+2 명시 이름:
- `FORBIDDEN_PATH_INTRUSION`
- `REPLACEMENT_PR_AUTO_CREATION_FAILED_FOR_CONTAMINATED_DIFF`
- `GEMINI_REAL_BUG_REQUIRES_SCOPE_EXPANSION`
- `BLOCK_OVERRIDE_REQUIRED_OR_REASON_INSUFFICIENT`
- `DEPENDENCY_CYCLE_OR_SERIAL_ONLY_COLLISION`
- `REPLACEMENT_PR_FAILED`
- `POST_MERGE_SMOKE_FAILED`

→ 회장이 task 파일에 직접 명시: "기존 task-2509+1의 enum 이름은 후속 wiring task에서 정렬. 본 task는 freeze만." 즉 task-2509+2는 회장 정확 매칭 이름으로 freeze하고, 기존 string 상수는 그대로 유지 (후속 wiring task에서 정렬). breaking change 0 보장.

- 결정 이유: 회장 직접 명령. 후속 4 모듈이 import할 단일 source-of-truth는 새 `utils/automation_contracts.py`. 기존 string 상수는 wiring 시점 정렬.
- 대안 (기각): 기존 string 상수에 맞춰 enum 이름을 정렬 → 회장 명시 위반. 기각.

### [결정 2] dataclass 직렬화: dataclasses.asdict + Enum.value 변환

JSON 직렬화 가능성(요구사항 #3)을 위해 모든 dataclass는 `dataclasses.asdict()` + Enum 멤버는 `.value` 사용. 별도 `to_dict()` 메서드는 helper로 제공해 양쪽 모두 호환.

- 결정 이유: 표준 라이브러리만 사용, 외부 의존성 0. JSON 직렬화 시 Enum이 자동으로 string으로 변환되도록 helper 작성.
- 대안 (기각): pydantic — 외부 의존성 추가, 회장 정책 위반 가능.

### [결정 3] 조건부 필수 필드 검증은 dataclass `__post_init__`에서 수행

`AutoMergeResult.merged=True 시 merge_commit 필수`, `ReplacementResult.success=False 시 failure_reason 필수`, `AutomationDecision.critical_escalation_type 있으면 requires_chair=True` — 이 세 조건은 dataclass 생성 시점에 ValueError raise하여 enforce.

- 결정 이유: 후속 4 모듈에서 잘못된 조합으로 dataclass를 만들면 즉시 실패하도록 강제. test 4/6/11이 이를 검증.
- 대안 (기각): 외부 validator 함수 — 개발자가 호출을 잊을 수 있음. 기각.

## 3 Step Why 자문

**1st Why: 왜 이 설계가 필요한가?**
A: 후속 4 자동화 모듈이 각자 다른 enum/dataclass 형식을 만들면 merge_queue_executor가 결과를 일관되게 처리할 수 없고, Critical 회장 보고가 7종 외로 새는 사고가 발생할 수 있다. 공통 계약을 Python 코드로 freeze해 단일 source-of-truth를 보장한다.

**2nd Why: 왜 A가 최선의 접근인가?**
B: Python dataclass + Enum 조합은 (1) 표준 라이브러리만으로 IDE 자동완성/타입체크/JSON 직렬화 모두 가능, (2) `__post_init__`로 조건부 필수 필드를 런타임 강제 가능, (3) snapshot 회귀 테스트로 enum 멤버 7종을 lock 가능. 다른 대안(JSON schema, pydantic, protobuf)은 외부 의존성 또는 별도 컴파일 step이 필요해 회장의 "정책 문서 X, 코드 + 회귀 테스트" 원칙에 부합하지 않는다.

**3rd Why: 왜 B가 다른 대안보다 나은가?**
C: pydantic은 v1/v2 호환성 이슈와 외부 의존성 추가, protobuf은 .proto 파일 + 별도 컴파일 + Python wrapper 생성 step 필요. 반면 dataclass+Enum은 Python 3.7+ 표준이며, dataclasses.asdict로 dict 변환 → json.dumps 직렬화가 한 줄로 가능. 회장이 "JSON 직렬화 가능 (dataclass + to_dict 또는 dataclasses.asdict 호환)"으로 직접 명시한 점도 이 결정을 뒷받침한다.

→ A-B-C 일관성 PASS.

## 참조 자료

- 본 task spec: `memory/tasks/task-2509+2.md`
- 정책 본체: `memory/feedback/feedback_critical_escalation_only_260508.md`
- 기존 merge_queue_executor: `utils/merge_queue_executor.py` (origin/main `e0396365`)
- task-2509 evidence: `memory/events/task-2509.lifecycle-backfill`

## 주의사항

- ⚠️ expected_files 정확히 2 파일. 다른 파일 수정 시 Merge Topology Gate 차단.
- ⚠️ merge_queue_executor.py에 정의된 기존 string 상수(`FORBIDDEN_PATH_INVASION` 등)는 절대 수정 금지. import smoke만 검증.
- ⚠️ Critical 7종 외 string을 생성하면 EscalationPacket 검증에서 ValueError raise.
- ⚠️ enum 멤버 추가/삭제 시 snapshot test #1, #2 자동 실패 — 회장 승인 없이 변경 금지.
- ⚠️ task 명칭은 task-2509+2 (task-2510-pre 폐기). 보고서/이벤트/PR 제목 모두 task-2509+2.
