# 정제 cancel race condition 수정

## Lv.1 작업

## 문제
cancel API가 SIGTERM으로 프로세스를 종료하고 `refine-status.json`에 `status: "cancelled"`를 기록하지만, 죽어가는 프로세스가 `_write_progress()`를 한 번 더 실행하면 전체 파일을 덮어써서 `status: "running"`으로 복귀 + filePath 등 metadata 소실.

결과: resume API가 `status !== "cancelled"`를 보고 → "취소된 정제 작업이 없습니다" 에러 반환.

## 수정

### `_write_progress()` 함수 수정 (866줄)

현재:
```python
def _write_progress(progress_file: str, data: dict) -> None:
    try:
        Path(progress_file).write_text(
            json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
        )
    except Exception:
        logger.warning("progress file 쓰기 실패: %s", progress_file)
```

변경:
```python
def _write_progress(progress_file: str, data: dict) -> None:
    try:
        p = Path(progress_file)
        # cancelled 상태면 덮어쓰기 방지
        if p.exists():
            try:
                current = json.loads(p.read_text(encoding="utf-8"))
                if current.get("status") == "cancelled":
                    return
            except Exception:
                pass
        p.write_text(
            json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
        )
    except Exception:
        logger.warning("progress file 쓰기 실패: %s", progress_file)
```

## 참조
- 파일: `/home/jay/projects/insuwiki/scripts/kakao_knowledge/knowledge_extractor_v2.py`
- `_write_progress` 함수: 866줄
- cancel API: `/home/jay/workspace/dashboard/server.py` 5722줄
- resume API: `/home/jay/workspace/dashboard/server.py` 5947줄

## 테스트
- 정제 시작 → 취소 → 바로 "이어서 정제" → 성공해야 함
- 정상 정제 진행 시 progress 갱신이 기존과 동일하게 동작해야 함
- pytest 기존 테스트 전부 통과

## 보고서
`/home/jay/workspace/memory/reports/task-{TASK_ID}.md`
