# task-689: engine.py → engine_v2 봇 마이그레이션 실행

## 배경
engine_v2 패키지 구현 완료 (task-686.1). 기존 engine.py는 DEPRECATED 상태.
현재 8개 파일이 engine.py에 의존하며, engine_v2로 전환해야 한다.

## 참조 문서
- 마이그레이션 계획서: `memory/reports/task-685-migration-plan.md`
- engine_v2 구현 보고서: `memory/reports/task-686.1.md`
- engine_v2 코드: `services/multimodel-bot/engine_v2/`

## 호출처 전수조사 결과 (계획서에서 발췌)

### 프로덕션 파일 (6개)
1. `claude_bot.py:14` — `from engine import call_claude`
2. `codex_bot.py:14` — `from engine import call_codex`
3. `gemini_bot.py:14` — `from engine import call_gemini`
4. `main_bot.py:20` — `from engine import call_claude, call_codex, call_gemini`
5. `party_bot.py:17` — `from engine import call_gemini, call_codex, call_claude`
6. `conversation_memory.py:75` — `from engine import call_claude` (조건부 import)

### 테스트/도구 (2개)
7. `tests/test_engine.py` — 다수 라인에서 engine 모듈 직접 참조
8. `tools/test_insight_runner.py:245` — `from engine import call_claude`

## 마이그레이션 단계 (Phase M1→M2→M3 순차 진행)

### Phase M1: 호환 레이어 (기존 코드 변경 없이 동작 보장)
1. engine.py의 `call_gemini()`, `call_codex()`, `call_claude()`를 engine_v2 CLIRunner 래퍼로 교체
2. 기존 import 코드가 변경 없이 동작하도록 보장
3. 핵심: `from engine import call_claude` 가 engine_v2의 CLIRunner를 내부적으로 호출
4. 이 Phase에서는 호출측 코드 변경 없음

### Phase M2: 직접 마이그레이션 (각 봇 파일 전환)
1. 각 봇 파일에서 `from engine import call_xxx` → `from engine_v2.cli_runner import CLIRunner` 교체
2. 반환값: 기존 `str` → `EngineResult` 활용으로 에러 처리 개선
3. 각 봇 파일별 마이그레이션:
   - `call_claude(prompt)` → `CLIRunner.run_claude(prompt)` → `EngineResult`
   - `call_codex(prompt)` → `CLIRunner.run_codex(prompt)` → `EngineResult`
   - `call_gemini(prompt)` → `CLIRunner.run_gemini(prompt)` → `EngineResult`
4. 반환값 변환 주의: 기존 코드가 `str` 기대 시 `result.content` 사용
5. `conversation_memory.py`의 조건부 import도 전환

### Phase M3: engine.py 정리
1. 모든 호출처가 engine_v2로 전환되었는지 grep으로 최종 확인
2. engine.py를 **빈 redirect 파일**로 교체 (완전 삭제 아님):
```python
# DEPRECATED: engine_v2로 완전 마이그레이션됨
# 이 파일은 하위 호환성을 위해 유지됩니다.
# 직접 import하지 마세요. engine_v2를 사용하세요.
from engine_v2.cli_runner import CLIRunner as _runner

async def call_claude(prompt: str, **kwargs) -> str:
    result = await _runner.run_claude(prompt, **kwargs)
    return result.content

async def call_codex(prompt: str, **kwargs) -> str:
    result = await _runner.run_codex(prompt, **kwargs)
    return result.content

async def call_gemini(prompt: str, **kwargs) -> str:
    result = await _runner.run_gemini(prompt, **kwargs)
    return result.content
```
3. tests/test_engine.py 전환: engine_v2 기반으로 리팩터링
4. tools/test_insight_runner.py 전환

## 공통 규칙
- **기존 봇 동작 절대 깨뜨리지 말 것** — 마이그레이션 전후 동일 동작 보장
- 모듈화: 파일당 200줄 이하
- 타입 힌트 필수, pyright 통과
- 각 Phase 완료 후 전체 pytest 돌려서 회귀 확인
- 기존 test_engine.py 테스트가 모두 통과해야 함

## 위험 요소
1. OAuth 토큰 refresh race condition → engine.py와 engine_v2 동시 호출 방지
2. 봇 재시작 시 환경변수 미로드 → env_loader.py로 해결됨 (task-687.1)
3. `call_xxx()` 반환 타입 변경 (`str` → `EngineResult`) — 호출측에서 `.content` 접근 필요

## 롤백 계획
- engine.py는 삭제 안 하고 redirect 유지
- 문제 발생 시 git revert로 즉시 복구
- Phase M1 완료 후 봇 재시작 테스트 필수

## 산출물
- 수정된 봇 파일들 (6개 프로덕션 + 2개 테스트/도구)
- 정리된 engine.py (redirect 파일)
- 전체 pytest 통과 확인
- `memory/reports/task-689.md` 마이그레이션 완료 보고서
