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

- 작업 유형: **dispatch layer hardening (verifier 정밀도 향상)**
- 작업 레벨: **Lv.2~3** (코드 수정 + 회귀 테스트 + audit 보강)
- 담당: **dev3-team (다그다)** — task-2503 본체 작성자, false-positive fix 자기 회귀
- 우선순위: **★★ blocking** — 회장 통합 결정 (2026-05-08T12:35)
- Track: **dispatch_hardening / merge_topology_gate_precision**
- 일시: 2026-05-08
- 선행: task-2503 머지 완료 (mergeCommit fc49a9fd, 2026-05-08T12:08:52)
- 회장 결정: 2026-05-08T12:35 (B안 채택, emergency bootstrap 1회 우회 승인)

## ⚠️ 본 task의 본질 — 회장 명시

> Gate가 dependency 있는 task와 이미 merged 된 task overlap을 잘못 BLOCK하는 문제를 수정한다.

## 발사 경로 — Emergency Bootstrap (회장 §2 명시)

> task-2503+1은 dispatch.py Gate catch-22로 인해 정식 dispatch가 BLOCK된다. 회장 결정에 따라 dev3 다그다 봇별 cron으로 **1회 emergency bootstrap** 발사. 이 우회는 정상 경로가 아니며 evidence 3건 박제로 audit 보강.

**우회 evidence**:
- `memory/events/task-2503+1.gate-bypass-via-cron`
- `memory/events/task-2503+1.catch22-bootstrap`
- `memory/events/task-2503+1.chair-override`

## ★ amendment 보호 의무 (회장 §7 — 본 task에 강제 적용)

> task-2503에서 amendment(Phase 1/Phase 2 분리)가 무력화된 사고 재발 방지. 본 task는 amendment가 발생하면 **즉시 적용**한다. 이미 commit한 코드라도 amendment 본문이 충돌하면 commit revert 또는 별도 PR 분리 의무.
>
> - amendment 수신 시 진행 중단 + 보고 + 적용
> - amendment 본문이 이미 commit된 코드와 충돌 시 즉시 회장에게 보고 + 결정 대기
> - mid_dispatch_correction_disregard는 forbidden_action으로 차단

## 회장 §3 필수 수정 6건 (회장 통합 결정 2026-05-08T12:35)

### a. dependency 문자열 정규화
- `"task-2502.merged"`, `"task-2503.merged"` 형태를 `task_id + required_state`로 분리
- 예: `"task-2503.merged"` → `{task_id: "task-2503", required_state: "merged"}`
- 후방 호환: 기존 단순 task ID 명시(`["task-2487+1"]`)도 자동 `required_state="merged"` 추론
- 헬퍼: `_parse_dependency_spec(spec: str) -> dict` 신설

### b. merged evidence 검증 (4 충족 경로)
- `required_state=merged` dependency는 다음 중 **하나로 충족 판단**:
  1. **merged PR evidence**: `gh pr list --state merged --search "[task-XXXX]"` 또는 PR mergedAt != null
  2. **mergeCommit evidence**: `git log --grep=task-XXXX --merges` 또는 task-timers.json `merge_commit` 필드
  3. **memory/events/{task_id}.done** 존재
  4. **memory/reports/{task_id}.md** 내 `merged` 또는 `mergeCommit` evidence 라인 존재
- 검증 결과 캐시: 동일 dependency 재검증 비용 최소화
- task-2503은 fc49a9fd main 머지 완료 → dependency satisfied
- task-2502는 46c16bee main 머지 완료 → dependency satisfied
- 헬퍼: `_verify_merged_state(task_id: str) -> tuple[bool, str]` 신설 (충족 여부 + evidence 종류)

### c. merged task active/conflict 제외
- 이미 main에 merged 된 task는 active_tasks/conflicting_tasks에서 제외
- task-2503이 task-2503+1의 DUPLICATE_FILE conflict 대상으로 잡히면 안 됨
- **task-timer 미정리로 active처럼 보이더라도 merged evidence가 우선**
- 헬퍼: `_filter_active_tasks(tasks: list, exclude_merged: bool = True) -> list` 신설
- merged 검증은 §b 헬퍼 재사용

### d. parallel_safe false declaration 보정
- `parallel_safe` 선언이 false인지 판단할 때 active task 전체가 아니라 **실제 expected_files/risk_area overlap이 있는 task만 비교**
- expected_files 교집합 0이고 mutation risk 0이면 PARALLEL_SAFE_FALSE_DECLARATION 발행 금지
- 헬퍼: `_compute_overlap(spec_a, spec_b) -> dict` 신설 (files / risk_area / verifier 별도 overlap 점수)

### e. read-only report task 예외
- read-only report 생성 task는 다음 조건 모두 충족 시 **ALLOW 또는 LIMITED 이하로 처리**:
  - `expected_files`이 `memory/reports/**` 또는 `memory/orchestration/**` 아래 단 1건만
  - `forbidden_actions`에 `any_code_modification` + `any_test_modification` + `any_pr_modification` + `any_branch_modification` 모두 포함
  - `parallel_policy: "parallel_safe"` 또는 `risk_area: "read_only_*"`
- task-2494-rejudge는 task-2503+1 머지 후 정식 dispatch에서 ALLOW 되어야 함
- 헬퍼: `_is_pure_read_only(spec) -> bool` 신설

### f. BLOCK override 허용 룰 (회장 신규 명시)
- 회장 명시 승인 + `--override-merge-topology-gate` 플래그가 있는 경우 **BLOCK 판정도 우회 가능**
- 단 audit에 다음 9 필드 반드시 박제:
  ```jsonl
  {
    "original_decision": "BLOCK",
    "override_used": true,
    "override_decision": "ALLOW_WITH_CHAIR_OVERRIDE",
    "override_reason": "<회장 명시 사유>",
    "approved_by": "chair",
    "original_reason_codes": ["DUPLICATE_FILE", "MISSING_DEPENDENCY", ...],
    "conflicting_tasks": [...],
    "task_id": "...",
    "timestamp": "..."
  }
  ```
- override는 다음에 사용 **불가**:
  - force push
  - rebase
  - admin override
  - manual .done
  - required CI bypass
- override 시 `run_gate()` 반환값에 새 decision `ALLOW_WITH_CHAIR_OVERRIDE` 추가

## 회장 §4 필수 회귀 테스트 8건

1. **dependency `"task-2502.merged"` satisfied** → ALLOW (mergeCommit 46c16bee)
2. **dependency `"task-2503.merged"` satisfied** → ALLOW (mergeCommit fc49a9fd)
3. **merged task는 active/conflicting task에서 제외** → task-2503은 active_tasks에서 빠짐
4. **task-2503+1이 task-2503과 expected_files overlap 있어도 task-2503 merged 상태면 DUPLICATE_FILE BLOCK 금지** → ALLOW (real-world case)
5. **read-only report task expected_files overlap 0이면 ALLOW** → task-2494-rejudge 입력 → ALLOW
6. **expected_files 교집합 0이면 PARALLEL_SAFE_FALSE_DECLARATION 금지** → false-positive fix
7. **동일 파일 overlap이 active unmerged task와 발생하면 BLOCK 유지** → 기존 룰 #2 회귀
8. **BLOCK + override flag + chair approval → ALLOW_WITH_CHAIR_OVERRIDE + audit 9 필드** → 신규 §f 룰 회귀

## Merge Topology Gate 7 metadata (자기참조 검증 의무)

```yaml
expected_files:
  - "utils/merge_topology_gate.py"
  - "tests/regression/test_merge_topology_gate_real_world_2503_plus_1.py"
  - "tests/regression/test_merge_topology_gate_classifier_2503.py"
  - "memory/specs/merge-topology-gate-schema.yml"

risk_area: "dispatch_layer / governance / parallel_policy_enforcement"

dependency: ["task-2503.merged"]

parallel_policy: "serial_only"

merge_queue_position: 2

stale_recheck_required: true

cherry_pick_allowed: false
```

## allowed_resources

```yaml
allowed_resources:
  read_only_paths:
    - "memory/tasks/task-2503*"
    - "memory/feedback/feedback_merge_topology_gate_260508.md"
    - "memory/feedback/feedback_amendment_not_enforced_260508.md"
    - "memory/orchestration/phase_b_integration_items_260507.md"
    - "memory/events/task-2503.classifications"
    - "memory/events/task-2503+1.gate-bypass-via-cron"
    - "memory/events/task-2503+1.catch22-bootstrap"
    - "memory/events/task-2503+1.chair-override"
    - "memory/events/task-2494-rejudge.override-evidence.json"
    - "memory/events/task-2502.essence-pass-escalated-verifier-limitation"
    - "memory/specs/merge-topology-gate-schema.yml"
    - "utils/merge_topology_gate.py"
    - "memory/task-timers.json"
    - ".env.keys"
  paths:
    - "memory/tasks/task-2503+1*"
    - "memory/reports/task-2503+1*"
    - "memory/events/task-2503+1*"
    - "memory/plans/tasks/task-2503+1/**"
    # workflow files (also listed under workflow_paths for documentation)
    # — guard.sh B-3 task scope check reads `paths` only, so workflow files must
    #   appear here too for clean replacement PR (PR #57).
    - "utils/merge_topology_gate.py"
    - "tests/regression/test_merge_topology_gate_real_world_2503_plus_1.py"
    - "tests/regression/test_merge_topology_gate_classifier_2503.py"
    - "memory/specs/merge-topology-gate-schema.yml"
  workflow_paths:
    - "utils/merge_topology_gate.py"
    - "tests/regression/test_merge_topology_gate_real_world_2503_plus_1.py"
    - "tests/regression/test_merge_topology_gate_classifier_2503.py"
    - "memory/specs/merge-topology-gate-schema.yml"
  forbidden_paths:
    - ".secrets/**"
    - ".github/workflows/**"
    - "scripts/auto_merge.py"
    - "scripts/finish-task.sh"
    - "dispatch.py"
    - "dispatch/**"
    - "teams/shared/verifiers/git_evidence.py"
    - "teams/shared/verifiers/critical_gap.py"
    - "memory/events/task-2487+1*"
    - "memory/events/task-2497*"
    - "memory/events/task-2498*"
    - "memory/events/task-2494*"
    - "memory/events/task-2506*"
    - "memory/events/task-2507*"
    - "dashboard/**"
    - "report_parser.py"
    - "tests/poc/**"
    - "tools/poc/**"
    - "memory/poc/**"
  forbidden_actions:
    - admin_override
    - required_ci_bypass
    - manual_done_creation
    - existing_pr_force_push
    - existing_pr_close_or_delete
    - pr_52_modification
    - pr_49_50_51_modification
    - task_2497_2498_2494_rerun_interference
    - auto_cherry_pick_implementation
    - auto_merge_mixing
    - dashboard_intrusion
    - report_parser_modification
    - rebase
    - workspace_full_sync
    - dispatch_py_modification
    - git_evidence_py_modification
    - critical_gap_py_modification
    - amendment_ignore
    - mid_dispatch_correction_disregard
    - audit_jsonl_real_write_outside_target
    - token_value_logging
    - override_used_for_force_push
    - override_used_for_rebase
    - override_used_for_admin_override
    - override_used_for_manual_done
    - override_used_for_ci_bypass
```

## 완료 조건

1. ✅ dependency 문자열 정규화 헬퍼 + 후방 호환 동작
2. ✅ merged evidence 4 경로 검증 동작
3. ✅ merged task active/conflict 제외 동작 (task-2503 case)
4. ✅ parallel_safe false declaration 판정 보정 (실제 overlap 0이면 ALLOW)
5. ✅ read-only report task 예외 룰 동작
6. ✅ BLOCK override 허용 룰 + audit 9 필드 박제 동작
7. ✅ 회장 §4 회귀 테스트 8건 ALL PASS
8. ✅ 기존 회귀 테스트 23/23 PASS 유지
9. ✅ 자기참조 PASS (본 task spec이 ALLOW 판정)
10. ✅ task-2494-rejudge 입력 → 머지 후 정식 ALLOW
11. ✅ CI 11/11 SUCCESS
12. ✅ Gemini fresh evidence 확보
13. ✅ PR #52/#49/#50/#51 보존
14. ✅ 회장 공통 금지 위반 0건
15. ✅ amendment 보호 의무 명시 + 적용 evidence

## 시스템 3문서 참조

- 정책 본체: `memory/feedback/feedback_merge_topology_gate_260508.md`
- amendment 무력화 회고: `memory/feedback/feedback_amendment_not_enforced_260508.md`
- task-2503 4분류: `memory/events/task-2503.classifications`
- task-2494-rejudge override: `memory/events/task-2494-rejudge.override-evidence.json`
- emergency bootstrap evidence 3건: `memory/events/task-2503+1.{gate-bypass-via-cron,catch22-bootstrap,chair-override}`
- 시스템 청사진: `/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/system_bot_orchestration_blueprint_260506.md`

## 보고

- SCQA 4섹션
- 6 false-positive fix 결과 (a~f 각 회귀 테스트 PASS evidence)
- real-world case task-2494-rejudge → ALLOW 판정 회귀 evidence (머지 후)
- 기존 23/23 회귀 PASS 유지 evidence
- 자기참조 PASS evidence
- audit 9 필드 박제 evidence (BLOCK override 사례)
- 회장 공통 금지 위반 0건 명시
- amendment 적용 evidence
- emergency bootstrap evidence 3건 인용
- 헤르메스/아누 통합 요약 경유, 회장 직접 장문 보고 X

## 후행 (회장 결정 사안)

- task-2503+1 머지 후 task-2494-rejudge 정식 dispatch (회장 §5)
- task-2503+1 머지 후 Track A/B (task-2497/2498) 재dispatch 회장 결정
- task-2503+1 자기 fix 검증 시 본 spec이 ALLOW 판정되는지 회귀
