---
task_id: task-2503
type: context
scope: task
created: 2026-05-08
updated: 2026-05-08
status: completed
---

# 맥락 노트: task-2503

**task**: task-2503

---

## 결정 근거

### 결정 1: classifier를 별도 모듈(`utils/merge_topology_gate.py`)로 분리
- 이유: dispatch/__init__.py가 이미 4502줄. hook 1곳만 추가하고 본체 룰 로직은 별도 모듈에서 단위 테스트 가능
- 대안: dispatch/__init__.py에 직접 추가
- 기각 이유: 본체가 더 비대해지고, 룰 변경 시 dispatch 전체 회귀 부담 + auto_merge.py와 격리하여 회장 §7-2 위반 회피

### 결정 2: dispatch hook 위치 = `dispatch()` 함수 내부, session-health 체크 직후
- 이유: task_id가 결정되어 있고, allowed_resources/affected_files도 파싱 후 활용 가능
- 정확한 위치: `dispatch/__init__.py` 본체 함수 — 같은 팀 running 태스크 검증 직전
- 대안: argparse 단계에서 hook
- 기각 이유: argparse는 task_desc가 단순 텍스트 — affected_files 파싱이 dispatch() 내부에서 이루어짐. hook은 활성 task_id 등록 직전이 자연

### 결정 3: 7 metadata 추출은 task_desc 안의 fenced yaml 코드블록 우선, frontmatter fallback
- 이유: `_parse_allowed_resources()`와 동일 패턴. task-2503 spec도 ```yaml 블록에 metadata 명시
- frontmatter는 P3-10 표준이지만 expected_files 등이 들어가지 않음

### 결정 4: BLOCK 시 dispatch 즉시 거부 + audit 기록 + Telegram 경고 X
- 이유: Telegram은 `_send_overlap_telegram_warning`이 이미 담당. Gate는 jsonl audit으로만 기록 → 이중 기록 방지
- override 시에는 audit에 `override_used: true` 명시

### 결정 5: cherry_pick_allowed=true → REQUIRE_CHAIR_OVERRIDE (BLOCK 아님)
- 이유: 회장 §6에서 "복구 경로(recovery_only)로만 허용" — 즉시 차단이 아니라 회장 명시 승인 후 진행 가능
- 우회 방법: `--override-merge-topology-gate` flag 사용 시 audit에 evidence 기록

### 3 Step Why 자문 결과
- **1st Why**: 왜 이 설계가 필요한가?
  → A: 회장 §1 명시. dispatch 단계에서 병렬 작업의 충돌 가능성을 자동 판정하여 task-2487+1/task-2502 사고 재발 방지. 단순 affected_files 겹침 경고로는 lifecycle/verifier/dependency 충돌을 잡지 못함.

- **2nd Why**: 왜 A가 최선의 접근인가? — Codex 사전 리뷰 질문: "이 설계의 대안은 무엇이며, 왜 이 접근이 최선인가?"
  → B: 별도 모듈로 분리하면 (1) dispatch.py 본체 변경 최소화 (1 hook + 1 flag), (2) 9 classifier 룰을 독립 단위 테스트로 검증 가능, (3) auto_merge.py와 물리 격리 (회장 §7-2 위반 회피)
  - 대안 1: dispatch.py 본체에 직접 9 룰 인라인 → 4502줄이 더 비대 → 룰 추가 시 회귀 폭 큼
  - 대안 2: 별도 게이트 서비스(daemon) → 운영 복잡성, 영속 상태 관리 부담 → 정책 룰 단순함에 비해 과도
  - 대안 3: PR-merge 단계에 게이트 → "발행 전 차단" 의지(회장 §1) 위반 — dispatch 시점이어야 함

- **3rd Why**: 왜 B가 다른 대안보다 나은가?
  → C: 회장 §7-2 "auto_merge 실행부와 섞기 금지" 명시. 모듈 분리는 auto_merge.py 미수정 보장 + classifier 룰을 독립 검증 가능 + 향후 룰 추가/수정 시 dispatch 본체 변경 0건. 단위 테스트의 신뢰성 + 정책 룰 진화의 격리. → A-B-C 일관 PASS.

## 참조 자료

- 정책 본체: `memory/feedback/feedback_merge_topology_gate_260508.md`
- task spec: `memory/tasks/task-2503.md`
- Phase B 통합 항목 §9.7: `memory/orchestration/phase_b_integration_items_260507.md`
- 사고 evidence:
  - task-2487+1 SCOPE-GUARD: `memory/events/task-2487+1.scope-violation.json`
  - 6팀 batch ESCALATED: `memory/events/six-team-batch.essence-pass-escalated-verifier-limitation`
  - task-2502: `memory/events/task-2502.essence-pass-escalated-verifier-limitation`
- dispatch 구조 진입점: `dispatch/__init__.py` `def dispatch()` (3108줄)
- 패턴 참조: `_parse_allowed_resources` (823줄), `_check_affected_files_overlap` (1093줄)

## Codex 사전 검증 결과 (2026-05-08T11:31)

- pass=false (critical 1, high 3, medium 1) — 모두 **"현재 코드베이스에 미구현"** 지적
- Codex suggestions가 본 설계와 정확히 일치:
  1. Gate hook을 `dispatch/__init__.py` `main()`의 `dispatch()` 호출 직전 — **수용** (계획 미세 조정)
  2. 7 metadata 파서 + schema validator 먼저, 누락 시 즉시 BLOCK — **수용**
  3. classifier를 별도 계층, task-timers.json + dependency 함께 입력 — **수용**
  4. `--override-merge-topology-gate` flag + 9 필드 audit jsonl — **수용**
  5. 회귀 테스트를 schema/classifier/dispatch integration 3종으로 분리 — **수용**
- **결론**: critical "구현 부재"는 본 task의 구현 대상 자체이므로 즉시 PASS 전환됨. 설계는 변경 불필요.
- 결과 파일: `memory/events/task-2503.codex-gate`

### Hook 위치 미세 조정
- 기존: `dispatch()` 함수 내부, session-health 직후
- 수정: `main()` 함수에서 args 파싱 후, `dispatch()` 호출 직전 (`dispatch/__init__.py` 4250줄 인근)
- 이유: `dispatch()` 시그니처 비변경 + override flag 처리 + import 경로 우회 방지 (Codex high 지적)

## 주의사항

- **회장 §7 절대 금지 5건**: 자동 cherry-pick / auto_merge 통합 / PR #52,49,50,51 수정 / task-2497,2498,2494 흐름 방해 / dashboard·report_parser·auto_merge.py 침범
- **자기참조 검증 필수**: 본 task-2503 자신이 schema 7 metadata에 대해 통과해야 함 → spec이 schema에 합치하는지 테스트 1건 추가
- **Sanitize 게이트**: 외부 AI 호출 전 PII 마스킹 (실제 코드는 PII 없음 — 로직만 코드)
- **append-only audit jsonl**: `merge-topology-gate.jsonl`만 허용. `forbidden_actions.audit_jsonl_real_write_outside_target` 준수
- **dispatch hook 위치**: dispatch() 함수의 등록 직전 1곳만. 다른 위치(예: argparse) 추가 금지
