# 콜드메일 워크플로우 interrupt() 상태 보존 문제 해결

**날짜**: 2026-01-21
**작성자**: happybell80
**관련 파일**: `rb8001/app/services/workflows/coldmail_workflow.py`, `rb8001/app/services/slack/coldmail_service.py`

---

## 문제 상황

- Slack 버튼 클릭 시 `Email not found in waiting_confirmation` 에러 발생
- `interrupt()` 호출 후에도 워크플로우가 계속 진행되어 `waiting_confirmation`이 비워진 상태로 저장됨

## 원인 분석

- LangGraph 1.0의 `interrupt()`는 노드 실행을 즉시 중단시킴
- 노드가 반환(return)되기 전에 `interrupt()`가 호출되면 해당 노드 내 상태 변경이 checkpoint에 저장되지 않음
- 재개 시 노드가 처음부터 다시 실행됨

## 해결 방안

노드 분리 설계 적용:
- `coldmail_workflow.py:115-160`: `process_node` - 상태 업데이트 후 반환 (waiting_confirmation 저장)
- `coldmail_workflow.py:163-197`: `wait_confirmation_node` - interrupt() 호출하여 사용자 확인 대기
- `coldmail_workflow.py:200-236`: `confirm_node` - 재개 후 confirmed_email_id 처리

워크플로우 플로우: `fetch → filter → process → wait_confirmation (interrupt) → confirm → send → END`

## 테스트 결과

- `tests/test_coldmail_interrupt_return_pattern.py`: 4개 테스트 모두 통과
- 기존 `tests/test_coldmail_workflow_interrupt.py`: 4개 테스트 모두 통과

## 교훈

1. **LangGraph interrupt 동작 이해**: `interrupt()` 호출 시 노드 반환 전이면 상태가 저장되지 않음
2. **노드 분리 필수**: 상태 저장이 필요한 로직과 `interrupt()` 호출을 별도 노드로 분리
3. **TDD 중요성**: 단위 테스트로 interrupt/resume 동작 검증 후 배포
