---
task_id: task-2515
type: context
scope: task
created: 2026-05-09
updated: 2026-05-09
status: completed
---

# 맥락 노트: task-2515

**task**: task-2515

---

## 결정 근거

### 결정 1 — worktree base를 task/task-2514-dev3에서 시작
- task-2515는 task-2514의 wiring 코드를 import해 검증한다. origin/main HEAD(818c23b8)에는 task-2514 wiring이 아직 미반영이고, worktree default는 main 기준이라 5 모듈 import가 실패한다.
- 따라서 task/task-2514-dev3 브랜치(8bd09c6b)를 reset --hard로 적용해 worktree base를 정렬했다. 추가 코드 변경은 정확히 2 신규 파일.
- 대안: origin/main을 직접 진행 → 5 모듈 import 실패. 기각.

### 결정 2 — fixture JSON + 9 pytest 함수 (1:1 매핑)
- 9 시나리오를 단일 fixture JSON에 메타데이터로 표현하고, 각 시나리오를 단일 pytest 함수로 박제한다. 1 fn = 1 시나리오 = 12 assertions.
- `assert_12_verifications(scenario_id, fixture)` 헬퍼로 12 항목 검증 일관 적용.
- 대안 (parameterize): 함수 분리 시 시나리오별 디버깅 컨텍스트 부족 → 9 함수 분리 채택.

### 결정 3 — 5 모듈 호출은 ExecutorContext 주입 + fake runner
- task-2514가 정의한 ExecutorContext의 9 신규 hook 필드(replacement_runner / triage_fn / smoke_envelope_fn / task_file / following_queue / triage_threads / triage_fix_commits / triage_pr_head_sha / apply_triage)를 통해 fixture 데이터를 주입한다.
- 실제 gh CLI 호출 없음. fake_runner가 모든 subprocess 응답을 시뮬레이션.
- 5 모듈 본체 READ-ONLY 보호 + reproducible test environment 양립.

### 결정 4 — Critical 7종 외 보고 0건은 assertion으로 강제
- "Critical 7종 외 회장 보고 금지" (회장 명시 §12)를 fixture별 expected_classification ("critical"/"auto-handled") 으로 박제.
- non-critical 시나리오에서 process_event(...) → classification == "auto-handled" + packet is None 검증.
- 그 외 임의의 escalation 호출은 발생 자체를 차단.

### 결정 5 — 9 시나리오 PR 번호 매핑 (회장 §replay)
- PR #55 (task-2507) — clean auto merge (정상 1)
- PR #57 (task-2503+1) — false-positive 합성 (정상 2)
- PR #58 (task-2509) — Gemini quota fallback (정상 3)
- PR #64 (task-2512) — smoke PASS (정상 4)
- PR #57 contamination 합성 — replacement runner (capability gap 1)
- PR #61 (task-2510) — 5 unresolved → triage 모두 OUTDATED/CODE_ALREADY_FIXED resolve (capability gap 2)
- Critical #7 smoke FAIL 합성 (critical 1)
- forbidden path 합성 (critical 2)
- diff contamination replacement 실패 합성 (critical 3)

### 결정 6 — live pilot 후보 = task-XXXX (보고서에서 선정)
- 후보 기준: expected_files 1~2 파일, forbidden path 0, smoke command 정의, dependency cycle 없음, LOW risk_level.
- 선정 작업은 보고서 단계에서 수행 (다음 큐 후보 검토 후 결정).

### 결정 7 — Codex G1 권고 반영 (2026-05-09)
- **CLI JSON 출력**: 회장 명시 옵션 CLI는 `QueueDecision` JSON을 출력한다. 이는 실제 wired 5 모듈 pipeline의 정식 결과 타입이다 (`utils/merge_queue_executor.py:1525`). 설계 초안의 "AutomationDecision JSON"은 표현 오류. fixture에서도 `QueueDecision` 필드(decision/critical_code/smoke_status/review_gate_passed/replacement_used 등) 기대값을 박제한다.
- **test_orchestration_runtime_2514.py와 차별화**: 본 e2e harness는 **실전 9 PR fixture 메타데이터**(PR 번호 / 실제 발생한 시나리오 패턴 / 실제 발생한 contamination/triage/quota/smoke fail 사례) 를 **JSON fixture에 외부화**해 데이터 주도(data-driven) 시나리오 박제로 동작한다. 회귀 테스트 14 케이스는 단위 wiring 회로 검증, 본 harness는 실전 PR 사례 replay → 역할 분리.
- **evaluate_pr ↔ verify_head_lock_then_merge 분리 설계**: 12 검증 중 §1~5,7 (queue head, diff, forbidden, replacement 분기, triage 분기, review_gate_passed) 는 `evaluate_pr` 단계에서, §8~10 (decision, smoke envelope, following stale) 는 `verify_head_lock_then_merge` 단계에서, §11~12 (critical reportable, non-critical audit-only) 는 양쪽 결과 + `process_event()` 호출 결과로 검증한다. helper에 step 명시.

## 3 Step Why 자문 (Lv.3+)

**1st Why** — "왜 이 설계(fixture JSON + 9 pytest fn + 12 verification helper)가 필요한가?"
**A**: 회장 §1~12의 12 항목을 모든 fixture에 일관 적용해야 사람 개입 0 자동화의 신뢰도를 박제할 수 있다. fixture 메타데이터를 코드와 분리하면 추가 시나리오를 코드 변경 없이 확장 가능하다.

**2nd Why** — "왜 A(fixture 분리 + 12 helper)가 최선의 접근인가?"
**B**: 12 검증을 코드에 인라인하면 9 시나리오마다 12 assertion을 복붙해야 해 108 assertions의 일관성이 깨진다. helper로 추출하면 단일 진실 원천(SSOT)으로 12 검증 의미가 보존되고, 새 시나리오 추가 시 fixture row만 추가하면 된다.

**3rd Why** — "왜 B(helper SSOT)가 다른 대안보다 나은가?"
**C**: 대안 1) parametrize fixture만 사용 → 디버깅 시 어느 시나리오 어느 검증이 실패했는지 추적 어려움. 대안 2) 12개 별도 helper → 시나리오별 12 호출이 모두 같은 fixture context 공유해야 해서 결합도 증가.
B는 1 함수 = 1 시나리오로 디버깅 컨텍스트를 보존하면서, 12 검증을 동일 helper로 일관 적용한다. 회장 §1~12 매핑이 코드에서 명시적이라 감사 가능성도 높다.

## 참조 자료

- 5 모듈: `utils/automation_contracts.py` / `utils/merge_queue_executor.py` (W1~W7) / `utils/replacement_pr_runner.py` / `utils/auto_gemini_triage.py` / `utils/post_merge_smoke_runner.py` / `utils/critical_escalation_reporter.py`
- 회귀 정합 reference: `tests/regression/test_orchestration_runtime_2514.py` (TC-N1~A3, 14 케이스)
- 회장 정책 본체: `memory/feedback/feedback_critical_escalation_only_260508.md`

## 주의사항

- **5 모듈 본체 / dispatch.py / automation_contracts 절대 수정 금지** — 위반 시 forbidden_path Critical packet
- **expected_files = 정확히 2 파일** — Merge Topology Gate 자기참조 PASS 필수
- **fixture JSON은 PII 없음** — 외부 PR 번호 + 합성 SHA만 사용. sanitize gate 자동 PASS
- **dry_run=False + smoke_command 정의된 시나리오만** AUTO_MERGE_SUCCESS 진입 가능 (정상 흐름 4건)
- **fake_runner는 forbidden git flag(--admin/--force/-f/rebase) 절대 호출 금지** — 자동 차단 assertion 포함
- **fixture 시나리오 추가 시** schema 검증: 모든 필수 필드 존재 + expected_decision enum + classification enum 강제
