---
task_id: task-2550
type: context
scope: task
created: 2026-05-11
updated: 2026-05-11
status: completed
---

# 맥락 노트: task-2550 — .worktrees auto-cleanup policy

**task**: task-2550

---

## 결정 근거

### 결정 1: Option A (anu_v2/post_merge_smoke_runner 통합) 채택

- **결정 이유**: post-merge smoke + reconcile + worktree cleanup이 자연스러운 lifecycle step의 연속이며, task-2539 박제(post_merge_smoke_runner v0)와 동일 도메인.
- **대안 (Option B: lifecycle_reconciliation_manager)**: 1,932 라인의 거대 모듈에 추가 책임 부여는 SRP 위반. reconcile은 evidence 생성 책임이지 cleanup 책임이 아님.
- **기각 이유**: ANU v2 5 모듈 doctrine에서 lifecycle_reconciliation_manager를 6번째 책임으로 확장하면 doctrine 자체가 흐려짐. anu_v2 내부 helper(worktree_cleanup.py)는 6번째 "모듈"이 아니라 post_merge_smoke_runner의 단일책임 helper로 분류.

### 결정 2: 단일책임 helper 분리 (anu_v2/worktree_cleanup.py)

- **결정 이유**: 6대 안전조건 검증 로직과 git worktree 명령 실행 로직은 별도 helper로 분리해 테스트 가능성 + 책임 분리 확보.
- **post_merge_smoke_runner에서 직접 구현하지 않은 이유**: post_merge_smoke_runner는 smoke 실행 + evidence 박제 단일책임. cleanup은 별개 책임.
- **6번째 모듈 doctrine 위반 아닌 이유**: worktree_cleanup.py는 anu_v2 내부 helper로 post_merge_smoke_runner에서만 import. 외부 노출 X. → "5 module + N helpers" 구조.

### 결정 3: dry-run default + --apply 회장 별도 승인

- **결정 이유**: 본 task 본질은 81개 누적 .worktrees의 의도된 정리. 자동 삭제로 실수 시 다른 작업의 in-progress worktree 손실 위험. dry-run으로 후보 list만 산출, 실제 삭제는 회장 승인 후 별도 실행.
- **task 명시**: "기존 .worktrees/ 실제 삭제 X (dry-run only, --apply는 PR 머지 후 회장 별도 승인)"

### 결정 4: 6대 안전조건 모두 AND 게이트

- **결정 이유**: 어느 하나라도 FAIL이면 skip. 안전 조건의 OR 게이트는 사고 가능성. AND 게이트로 보수적 정책 적용.
- **task 명시**: "6대 안전장치 강제"

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

### 1st Why: 왜 Option A (post_merge_smoke_runner 통합)이 필요한가?
A: ANU v2 5 모듈 doctrine 박제 — 6번째 모듈 발행 금지. post-merge lifecycle의 자연스러운 step이라 단일 모듈 내 통합이 doctrine 일관성.

### 2nd Why: 왜 A가 최선의 접근인가?
B: lifecycle_reconciliation_manager(1932 LOC, reconcile 책임)에 cleanup을 추가하면 SRP 위반 + 거대 모듈 확장으로 변경 영향 범위 폭증. post_merge_smoke_runner는 489 LOC로 새 책임 추가에 적합. 게다가 cleanup은 smoke PASS 후 자연스러운 다음 step (smoke가 main에서 PASS했다면 worktree는 더 이상 활성 작업 영역이 아님).

### 3rd Why: 왜 B가 다른 대안보다 나은가?
C: 신규 모듈 발행(예: utils/worktree_cleanup_manager.py)은 5 모듈 doctrine 명시적 위반. anu_v2 내부 helper(worktree_cleanup.py)는 외부 노출 0으로 모듈 카운트 X. helper로 분리하면 단위 테스트 가능 + 책임 분리 + doctrine 준수 동시 달성. 거대 모듈 확장이나 신규 모듈 발행보다 모든 axis에서 우위.

**로키(DA) 적대적 질문**: 이 설계가 실패할 수 있는 시나리오는?
- F1: post_merge_smoke가 FAIL인데 cleanup이 실행되면 머지되지 않은 worktree 삭제. → mitigation: 안전조건 #2 (PR MERGED) + #4 (branch ancestor of main) AND 게이트로 차단.
- F2: cleanup 도중 다른 봇이 worktree에서 작업 중. → mitigation: 안전조건 #5 (pgrep + git worktree list lock 검사).
- F3: --apply 실수 (스크립트 자동화로 --apply 항상 전달). → mitigation: dry-run default + --apply 시 추가 로그 박제 + 본 task에서는 --apply 실행 0건 (회장 별도 승인 후 별도 실행).
- F4: main worktree path를 cleanup 후보에 포함. → mitigation: 명시적 차단 어설션 (workspace_root path 비교).
- F5: .done.acked / .merge-done 마커 파일 손상으로 false PASS. → mitigation: AND 게이트 6조건 모두 검증, OR 조건 단독으로 PASS 불가.

## 참조 자료

- 본질 문서: `/home/jay/workspace/memory/tasks/task-2550.md`
- 기존 모듈: `/home/jay/workspace/anu_v2/post_merge_smoke_runner.py` (489 LOC, task-2539 박제)
- 기존 회귀: `/home/jay/workspace/anu_v2/tests/test_post_merge_smoke_runner_2539.py`
- 선행 task: task-2549 (ci.sh worktree exclude, 대증요법)
- 본 task는 근본 해결 (정리 정책)

## 주의사항

- ★ 기존 `post_merge_smoke_runner.PostMergeSmokeRunner.run_post_merge_smoke()` 시그니처 절대 변경 금지 (task-2539 박제). cleanup은 새 메서드 `run_post_merge_worktree_cleanup_dry_run()`로 추가.
- ★ Critical 7종 #7 (POST_MERGE_SMOKE_FAILURE) 분류 책임 변경 X. worktree cleanup 실패는 Critical 7 미포함, operational nudge만.
- ★ dry-run default. --apply는 본 task에서 절대 실행 X (회장 별도 승인 후 다른 task에서).
- ★ main worktree (workspace_root 절대경로 비교) 절대 삭제 X — 명시적 어설션 + 명시적 path 차단.
- ★ chat_id 6937032012 격리 어설션 (다른 chat ID로 박제 메시지 누출 차단).
- ★ token / API key raw 노출 0 — _sanitize_text 사용.
- ★ 다른 task 마커 절대 수정 X (.done.acked / .merge-done 파일은 read-only 검사만).
- ★ forbidden paths: scripts/ci.sh, dispatch/, prompts/team_prompts.py, dashboard/, .github/workflows/, .worktrees/실제삭제 X.
