# task-2700 — LOCAL_MAIN_DIVERGENCE_AND_EXTERNAL_DIRTY_BLOCKER_PREVENTION (회장 verbatim 2026-05-27)

- Level: Lv.3 (인프라/거버넌스 · dispatch·worktree·finish-task base 안정성)
- 담당: **dev6-team Perun 페룬** (★ 회장 verbatim 2026-05-27 지정 · bot key 1e41a2324a3ccdd0 · dev1 제외(task-2699+1 작업 중))
- chair_authorization_id: **`CHAIR-AUTH-TASK-2700-LOCAL-MAIN-DIVERGENCE-PREVENTION-20260527-JJONGS-IMPLEMENT-001`** (★ 회장 verbatim 2026-05-27 발급 확정)
- 완료 목표: **`LOCAL_MAIN_DIVERGENCE_PREVENTION_COMPLETE`**

## ★ 배경

task-2699 사고: 로컬 main(f14b3850) ↔ origin/main(a2a20f94) divergence(ahead 68/behind 6) → 봇 worktree stale base 분기 → PR #158 CONFLICTING + 로컬 808 dirty 로 finish-task GIT-GATE 차단 → callback 미발사. 봇 산출은 정상이나 환경 블로커.
박제: `memory/events/task-2699-callback-missing-main-dirty-deepcheck-plan-260527.json`

## ★ 필수 내용 (★ 회장 verbatim 15)

1. dispatch 전 local main ↔ origin/main **ahead/behind 측정**
2. local main ≠ origin/main 이면 coding/security/callback/finish-task 관련 task dispatch **기본 HOLD**
3. 봇 worktree 는 local main 이 아니라 **origin/main fetch 후 origin/main SHA 기준으로만 생성**
4. worktree 생성 시 **base SHA 를 task marker 에 기록**
5. task finish 시 **merge-base 가 origin/main 과 일치하는지 검증**
6. main dirty snapshot 을 **dispatch 전/finish 전 모두 기록**
7. dirty 파일별 mtime/git status/diff summary/추정 소유 task 를 **registry JSONL** 에 기록
8. task expected_files ∩ dirty = 0 이면 task 실패 아니라 **`EXTERNAL_DIRTY_BLOCKER`** 분류
9. callback 미발사 원인을 **`NORMAL_CALLBACK_MISSING`** vs **`FINISH_TASK_GIT_GATE_BLOCKED`** 구분
10. finish-task GIT-GATE 는 **own expected_files dirty 와 unrelated dirty 분리 진단**
11. code task 의 **own dirty 는 계속 FAIL 유지**
12. read_only_watcher / diagnosis / callback_only / closeout_marker_only 를 **task_mode finish profile 과 연결**
13. **task-2699 사례를 regression fixture 로 추가**
14. local main ahead 68/behind 6 같은 divergence 상태에서 **dispatch 가 HOLD 되는 테스트 추가**
15. PR #158 처럼 stale base PR 생성 방지 — **spawn verification 에 base SHA 검증 추가**

## ★ 설계 원칙

- 기존 finish-task.sh GIT-GATE / task-scope-guard 로직 **재사용·확장** (재작성 금지)
- divergence 측정 = `git rev-list --left-right --count origin/main...HEAD`
- worktree 생성 base 강제 = `git worktree add <path> <origin/main SHA>` (로컬 HEAD 금지)
- HOLD 는 fail-closed (divergence 시 dispatch 거부 + 사유 marker)
- own dirty FAIL 유지(11) ↔ unrelated dirty 는 EXTERNAL_DIRTY_BLOCKER(8) — 분리 진단 핵심

## ★ 검증 시나리오 (★ "이게 되면 성공")

1. divergence test: 로컬 main ahead/behind ≠ 0 → coding task dispatch HOLD (fail-closed)
2. clean test: 로컬 main == origin/main → dispatch 통과
3. base SHA test: worktree 생성 base != origin/main SHA → spawn verification FAIL
4. EXTERNAL_DIRTY_BLOCKER test: expected_files ∩ dirty = 0 + unrelated dirty 존재 → task 실패 아닌 EXTERNAL_DIRTY_BLOCKER 분류
5. own dirty FAIL test: expected_files ∩ dirty ≠ 0 → GIT-GATE FAIL 유지
6. callback 구분 test: .done 차단 시 NORMAL_CALLBACK_MISSING vs FINISH_TASK_GIT_GATE_BLOCKED 정확 분류
7. task-2699 fixture: 실제 ahead68/behind6 + 808 dirty 재현 → EXTERNAL_DIRTY_BLOCKER + dispatch HOLD 둘 다 검증
8. registry JSONL: dirty 파일별 mtime/owner 기록 검증

## ★ 금지

- 기존 finish-task.sh GIT-GATE / dispatch.py 핵심 로직 무단 재작성 (확장만)
- live settings.json / hooks live / Axis runtime 변경
- own dirty FAIL 완화 (11 위반)
- divergence HOLD 를 우회 가능하게 만드는 bypass flag (fail-closed 유지)
- artifact PR head commit

## allowed_resources

```yaml
allowed_resources:
  paths:
    - "scripts/finish-task.sh (★ GIT-GATE 분리 진단 확장 · 코어 보존)"
    - "scripts/task-scope-guard.sh (있으면 확장)"
    - "dispatch.py 또는 dispatch/ (★ divergence 측정 + HOLD 게이트 — 회장 별도 승인 시에만 핵심 수정)"
    - "anu_v2/ 또는 utils/ (신규 divergence_guard / dirty_registry 모듈)"
    - "tests/regression/** (divergence/base-SHA/EXTERNAL_DIRTY_BLOCKER/task-2699 fixture)"
  forbidden_paths:
    - "settings.json · hooks/** · Axis/** · .github/** · **/.env* · **/credentials*"
    - "memory/** PR head commit (artifact 0)"
  commands:
    - "git fetch/rev-list/merge-base/worktree/diff/log (read + 신규 모듈 test)"
    - "python3 -m pytest"
  merge_policy: "no_merge_chair_approval_required"
  ttl_hours: 8
```

## ★ 주의 (★ dispatch.py 핵심 변경 경계)

회장 doctrine: **dispatch.py 전역 변경 금지**. divergence HOLD 게이트가 dispatch.py 핵심 수정 필요 시 → **별도 회장 승인 요청** (HOLD_FOR_CHAIR). 가능하면 dispatch.py 외부 pre-flight 모듈 + hook 연결로 설계.

## ★ 보고 필드

1. divergence 측정 구현 (ahead/behind)
2. dispatch HOLD 게이트 (fail-closed)
3. worktree origin/main SHA 강제 + base SHA marker
4. finish merge-base 검증
5. dirty registry JSONL
6. EXTERNAL_DIRTY_BLOCKER vs own dirty FAIL 분리
7. callback 원인 구분 (NORMAL_CALLBACK_MISSING / FINISH_TASK_GIT_GATE_BLOCKED)
8. 검증 8 시나리오 + task-2699 fixture
9. dispatch.py 핵심 변경 여부 (변경 시 회장 승인 근거)
10. forbidden_action_count

## 종결

성공: **`LOCAL_MAIN_DIVERGENCE_PREVENTION_COMPLETE`** (★ merge 회장 결재)

★ 회장 verbatim 2026-05-27 예방 설계. task-2699 stale base + EXTERNAL_DIRTY_BLOCKER 재발 방지. fail-closed divergence HOLD + origin/main SHA worktree 강제 + base SHA spawn 검증.

끝