# task-2503+1 — Merge Topology Gate false-positive BLOCK fix (SCQA)

- 일시: 2026-05-08
- 담당: dev3-team (다그다)
- 발사 경로: **Emergency Bootstrap (회장 §2 1회 cron 우회)** — dispatch.py 미경유
- 회장 결정: 2026-05-08T12:35 B안 채택
- 자기참조 검증: PASS — `dry-run` 결과 ALLOW (reason_codes=[], overlap_score=0.0, conflicting_tasks=[])

## S — Situation
회장 §1 Merge Topology Gate(task-2503 fc49a9fd) 본체 enforcement 도입 후, dependency 명시 task가 이미 merged 된 task와 expected_files overlap한다는 이유로 false-positive BLOCK 6건 발생. 본 task 자기 자신(task-2503+1)이 catch-22로 정식 dispatch 차단됨.

## C — Complication
1. `task-2503.merged` dependency 문자열을 task ID로 파싱 실패 → MISSING_DEPENDENCY false-positive.
2. task-timer 미정리로 merged task가 active로 잡혀 → DUPLICATE_FILE false-positive.
3. `parallel_safe`에서 실제 file overlap 0인데도 active task 존재만으로 PARALLEL_SAFE_FALSE_DECLARATION 오발.
4. read-only 보고서 task가 동일 reports 디렉터리 동시 active일 때 BLOCK.
5. 회장 명시 override 승인이 BLOCK 판정에는 적용되지 않음(REQUIRE_CHAIR_OVERRIDE 한정) → catch-22 정식 우회 경로 부재.

## Q — Question
회장 §3 6 fix + §4 8 회귀 + 23/23(실제 33/33) 기존 회귀 유지 + 자기참조 PASS를 한 번에 충족하면서 PR #52/#49/#50/#51, dispatch.py, git_evidence.py(task-2507), critical_gap.py(task-2506) 영역을 건드리지 않을 수 있는가?

## A — Answer (구현 결과)

### §3 6 fix (모두 PASS)
- **a. dependency 문자열 정규화** — `_parse_dependency_spec()` 신설. `task-2503.merged` → `{task_id, required_state}` 분리, 후방 호환(단순 task ID → `merged` 추론) 포함.
- **b. merged evidence 4 충족 경로** — `_verify_merged_state()` 신설. 우선순위: ① `memory/events/{tid}.done` ② `memory/reports/{tid}.md` 내 `mergeCommit/merged-PR` 라인 ③ `task-timers.json::merge_commit` ④ `git log --grep` ⑤ (opt-in) `gh pr list`. 모듈 캐시(`_MERGED_VERIFY_CACHE`)로 중복 호출 비용 제거. `check_dependency_merged()`가 이 헬퍼를 재사용하여 overrideable.
- **c. merged task active/conflict 제외** — `_filter_active_tasks()` 신설, `classify()` 진입 직후 호출. task-timer status가 running으로 잘못 남아도 merged evidence 우선.
- **d. parallel_safe false declaration 보정** — `_compute_overlap()` 신설(files/risk_area/verifier/mutation_risk). 룰 9 판단을 `mutation_risk`(실제 file overlap 또는 verifier overlap)로 좁힘. `expected_files` 교집합 0이면 발행 금지.
- **e. read-only report task 예외** — `_is_pure_read_only()` 신설. expected_files 1건이 `memory/reports/**` 또는 `memory/orchestration/**`이고 forbidden_actions 4종 모두 + (parallel_safe 또는 risk_area=read_only_*) 조건 충족 시, BLOCK→ALLOW 다운그레이드. 단 `MISSING_DEPENDENCY`는 예외 미적용(dependency 강제 유지).
- **f. BLOCK override 허용 룰** — `run_gate(override_merge_topology_gate=True, chair_override_reason=…, chair_approved_by=…)` 신설. BLOCK 판정도 회장 명시 + 플래그 + 사유 모두 있을 때 `ALLOW_WITH_CHAIR_OVERRIDE`로 다운그레이드. `_audit_log_chair_override()`가 회장 9 필드(`original_decision/override_used/override_decision/override_reason/approved_by/original_reason_codes/conflicting_tasks/task_id/timestamp`) 박제. force push/rebase/admin override/manual .done/CI bypass에는 사용 불가(allowed_resources `forbidden_actions`로 차단; 코드는 plain ALLOW로 회귀하지 않으므로 호출자 책임).

### §4 회귀 8건 + 보너스 (11/11 PASS)
`tests/regression/test_merge_topology_gate_real_world_2503_plus_1.py` 신규 11 케이스:
1. dependency `task-2502.merged` satisfied → ALLOW (.done evidence)
2. dependency `task-2503.merged` satisfied → ALLOW (report `mergeCommit` evidence)
3. merged task → active filter 제외
4. task-2503 merged 상태에서 expected_files overlap 있어도 ALLOW
5. read-only report task expected_files overlap 0 → ALLOW
6. expected_files 교집합 0 → PARALLEL_SAFE_FALSE_DECLARATION 발행 금지
7. 동일 파일 overlap이 unmerged active task와 발생 → BLOCK 유지(기존 룰 #2 회귀)
8. BLOCK + override + chair approval → ALLOW_WITH_CHAIR_OVERRIDE + 9 필드 audit 박제
+ helper unit (`_parse_dependency_spec`)
+ 부작용 회귀 (override flag 없을 때 BLOCK 유지)
+ 자기참조 (task-2503+1.md → !=BLOCK)

### 기존 회귀 유지
- 회장 §6 33/33 PASS 유지 (audit_format 10 + classifier 11 + dispatch_integration 5 + schema 7).
- `tests/regression/` 전체 188/188 PASS.

### 자기참조 PASS evidence
```
$ python3 utils/merge_topology_gate.py --dry-run --task-file memory/tasks/task-2503+1.md --no-audit --json
{"status":"ok","task_id":"task-2503+1","decision":"ALLOW","reason_codes":[],"overlap_score":0.0,"conflicting_tasks":[],"metadata_keys_present":["cherry_pick_allowed","dependency","expected_files","merge_queue_position","parallel_policy","risk_area","stale_recheck_required"],"active_tasks_count":3,"dry_run":true}
```

## 회장 공통 금지 위반 0건
- PR #52/#49/#50/#51 미수정 (수정 사항 없음, 본 task는 `utils/merge_topology_gate.py` + 신규 회귀 테스트 1건 한정).
- cherry-pick / force push / rebase / admin override / manual .done / required CI bypass — 0건.
- dispatch.py / git_evidence.py / critical_gap.py — 0건 수정.
- amendment 미수신(현재 회기 진행 중 추가 amendment 없음) — 보호 의무 룰만 유지.

## amendment 보호 의무 적용
- 본 작업 진행 중 새로운 amendment 수신 0건. amendment 수신 시 즉시 적용 + ack + commit 충돌 시 회장 보고 + 결정 대기 절차 코드 변경 없이 운영 룰로 유지(중간에 forbidden_action `mid_dispatch_correction_disregard`로 차단).
- 본 task는 task-2503 amendment(Phase 1/Phase 2 분리)에서 Phase 1 dry-run CLI를 보존한 채 enforcement 룰 정밀도만 보강하여 amendment를 무력화하지 않음.

## emergency bootstrap evidence 인용
- `memory/events/task-2503+1.gate-bypass-via-cron` — Gate catch-22 우회 사유, dispatch.py audit/timer 누락 보강 약속.
- `memory/events/task-2503+1.catch22-bootstrap` — bootstrap_resolution 절차 박제.
- `memory/events/task-2503+1.chair-override` — B안 채택, override_audit 9 필드 사전 박제.

## dispatch.py 미경유로 인한 누락분 (수동 보강)
- task-timer는 `python3 memory/task-timer.py start task-2503+1 dev3-team` 수동 등록(2026-05-08T12:49:03 KST).
- dispatch.py audit log entry, dispatch metadata cache 등록은 이번 1회 우회로 누락. evidence 3건으로 박제됨.
- 향후 동일 catch-22 발생 시 본 task가 도입한 §3.f override 경로를 사용하면 정식 audit 박제 가능.

## 후행 (회장 결정 사안)
- task-2503+1 머지 후 `task-2494-rejudge` 정식 dispatch 재시도 시 §3.e read-only report 룰로 ALLOW 예상(스펙 충족 시).
- Track A/B(task-2497/2498) 재dispatch는 회장 결정 대기.
