v2.6.0
Stability & Persistence Hardening
이번 릴리스는 daemon 안정성과 세션 영속성을 강화하는 방어·복원 작업이다. 사용자 데이터 파일 포맷 자체는 동일하되, 저장 경로와 에러 처리에 내부 변화가 있다. 업그레이드 시 추가로 할 일은 없다. 자동 마이그레이션으로 처리된다.
Added
src/daemon/util/atomicWrite/— 공통 atomic-write 모듈. tmp→bak→rename 순서와__proto__/constructor/prototypesanitizer를 한 곳에서 관리한다. SessionManager와 StateWriter의 중복 구현이 이 모듈로 통합된다.src/daemon/util/AsyncQueue.ts— 30~50줄 수준의 자체 Promise 큐.saveDebounced경로에서 concurrent write 경합을 제거한다.flushSync()메서드로 종료 시점의 synchronous drain을 보장한다.src/main/ipc/wrapHandler.ts—ipcMain.handle전용 래퍼. 핸들러 예외를 구조화 JSON 로그({ts, level, event, channel, error_code, stack})로 메인 프로세스 stderr에 기록하고, 에러에code속성을 부여한다..bakrotation chain — save 성공 시.bak.2→.bak.3,.bak.1→.bak.2,.bak→.bak.1rename 체인이 실행되어 최근 3개 스냅샷이 유지된다. 읽기 경로는 primary → .bak → .bak.1 → .bak.2 → .bak.3 순서로 fallback한다.- Lazy 마이그레이션 프레임워크 —
src/daemon/migrations/. load 시점에 스키마 버전을 확인하고 메모리에서만 체이닝 변환한다. 새 포맷 기록은 다음 save에서 이루어진다. 프로덕션 레지스트리는CURRENT_VERSION=1로 identity 유지 상태다. - 손상 파일 격리 — validate 실패 시 파일을
{userData}/corrupted/서브디렉토리로 이동하고CORRUPT_FILE이벤트를 JSON 로그로 남긴다. 30일 경과 또는 10개 초과 시 오래된 격리 파일이 자동 정리된다. - Premigrate 스냅샷 — 스키마 업그레이드가 발생하는 load 경로에서 원본을
{basename}.v{N}.premigrate.bak로 일회성 보존한다. 롤백 자료로 사용된다.
Changed
- IPC 에러 포맷이 통일된다. 이전에는 핸들러 예외가 renderer로 그대로 promise
rejection 되어 stack이 불분명했다. 이번 릴리스부터 메인 프로세스 stderr에 JSON
line으로 기록되고, 에러 객체에
code속성이 붙는다. 사용 가능한 코드는DAEMON_DISCONNECTED,VALIDATION_ERROR,NOT_FOUND,PERMISSION_DENIED,UNKNOWN이다. renderer 호출부의 응답 값 자체는 그대로 raw value를 반환한다 (정규화는 후속 작업인 T4useIpc훅에서 수용 예정). StateWriter와SessionManager의 내부 구조 — atomic-write 중복 경로를 공통 모듈 호출로 치환했다. 외부 API 시그니처는 변경 없다.saveImmediate는 기존 동기 시그니처를 유지한다(shutdown/suspend emergency sync 경로 호환).- Rotation allowlist regex가
^sessions\.json\.bak(\.[123])?$패턴에 한정된다.corrupted/디렉토리와*.premigrate.bak파일은 rotation 대상에서 제외된다.
Fixed
- StateWriter/SessionManager의 concurrent save race — AsyncQueue coalescing (같은 key 재진입 시 마지막 값만 실행, key 간은 FIFO 보장)로 해결.
- IPC 핸들러에서 던진 예외가 메인 로그에 남지 않는 문제 —
wrapHandler가 전 핸들러 공통 try/catch 경로로 흡수하고 stderr JSON 로그로 기록한다. - validate 실패 시 무음으로 빈 세션이 출발하던 문제 — 손상 파일을 corrupted/로 격리하고, .bak 체인에서 fallback을 시도한다. 복구에 성공하면 즉시 승격 save.
Migration Notes
사용자 데이터 손실은 발생하지 않는다. 업그레이드 절차에서 수동 작업은 없다.
다만 {userData} 디렉토리 내부에 다음 두 종류의 새 경로가 등장한다.
{userData}/corrupted/— validate 실패로 격리된 파일의 보관소. 30일 경과 또는 10개 초과 시 자동 정리된다.{basename}.premigrate.bak— 스키마 업그레이드 load 시점에 생성되는 원본 스냅샷. 자동 정리 대상이 아니다. 수동 삭제 가능(향후 릴리스에서 자동 정리 검토).
플랫폼별 {userData} 경로와 롤백 절차는
docs/upgrade-2026-04-17.md를 참고한다.