v0.2.10 Cut C — raw_text 가변 + revision history (F20) #28

Merged
altair823 merged 9 commits from worktree-v0210-cut-c-raw-text-revisions into main 2026-05-09 14:52:28 +00:00
Owner

Summary

v0.2.10 Cut C — F20 raw_text 가변 + revision history. load-bearing invariant 변경: 메모리 정책 raw_text 불변 폐기, note_revisions 테이블에 변경 이력 보존 + 옛 버전 회수 UI.

  • F20 raw_text 가변: NoteCard 의 "원문 보기" 영역에 inline textarea 편집 + 저장. inboxApi.updateRawTextNoteRepository.updateRawTextnotes.raw_text 갱신 + note_revisionsedited_by='user' 새 row INSERT (단일 transaction).
  • revision history: note_revisions 테이블 (m006). 새 노트 생성 (create) + 기존 노트 마이그레이션 backfill + import (importNote) 모두 edited_by='capture' 첫 revision INSERT 보장 (final review 보강 — F5 import 회귀 패치).
  • 회수 UI: NoteCard 의 "이력" 버튼 → RevisionHistoryModal (rev 목록 + confirm dialog → restoreRevision chain-preserving). 옛 raw_text 가 새 user revision 으로 INSERT (linear history 유지).
  • AI 정책: AI 재실행 input = notes.raw_text (latest). 옛 revision 미사용. AiWorker 의 findById(id).rawText source 가 그대로라 코드 변경 없음 — 회귀 test (findById 가 latest 반환) 추가.

변경 내역 (9 commits)

Phase 0: 문서

  • 88ce78d docs(plan) — Cut C plan + spec m005→m006 정정 (Cut B 가 m005 선점)

Phase 1: schema + repo

  • 76c2345 Task 1 — m006 마이그레이션 (note_revisions 테이블 + index + capture backfill, FK ON DELETE CASCADE)
  • 18deee5 Task 2 — NoteRepository.create 가 capture revision 을 함께 INSERT (단일 transaction)
  • 7541d3c Task 3-6 — updateRawText / listRevisions / restoreRevision repo API + NoteRevision type + InboxApi 시그니처 + preload bridge (Task 8 까지 batch)

Phase 2: IPC

  • b4c2d85 Task 7 — inbox:update-raw-text (empty reject) / inbox:list-revisions / inbox:restore-revision (try/catch repo throw)

Phase 3: UI

  • ff1a015 Task 9 — NoteCard 원문 영역 편집 UI (textarea + 저장/취소 + updateRawText)
  • 81fbacb Task 10 — RevisionHistoryModal — 이력 목록 + 회수 confirm (window.confirm) + chain 보존 + 닫기 X

Phase 4: release

  • e32223d chore(release) — version 0.2.9→0.2.10 + F20 promoted 마킹

Phase 5: final review fix

  • 39b8d1e fix(v0210) — importNote 가 capture revision 을 함께 INSERT (final review 발견: F5 import 후 first user edit 시 import 시점 본문이 history 에서 사라지는 회귀). ImportNoteInput / importNote 의 옛 "raw_text invariant guard" 주석을 'fork-on-id-collision (sync determinism)' 의미로 갱신.

테스트 / 빌드

  • 단위: 548 → 569 pass (+21):
    • m006 마이그레이션 5
    • NoteRepository.create capture revision 1
    • updateRawText 2 / listRevisions 1 / restoreRevision 2
    • IPC handlers 4
    • NoteCard 편집 1
    • RevisionHistoryModal 2
    • findById 회귀 (AI source) 1
    • importNote capture revision (final review) 2
  • typecheck: 0 errors
  • e2e: 세션 내 미수행 — worktree node_modules 가 비어 있어 pretest 의 better-sqlite3 prebuild-install 단계가 worktree CWD 에서 실패. 본 cut 은 OnboardingWizard / capture flow / banner 등 e2e 시나리오에 영향 X (NoteCard 내부 + 신규 modal). 머지 후 main 에서 검증 권장.
  • 빌드 산출물: 후속 release 단계에서 Windows exe + macOS dmg + Linux AppImage/deb

Schema 변경

  • m006: note_revisions 테이블 신설 — (rev_id PK AUTOINCREMENT, note_id FK→notes(id) ON DELETE CASCADE, raw_text, edited_at, edited_by CHECK IN ('user','capture')). idx_note_revisions_note_id (note_id, edited_at DESC). 기존 모든 notesraw_textedited_by='capture' revision 으로 backfill (edited_at = created_at).

메모리 정책 변경 (Cut C 머지 후 갱신 예정)

  • raw_text 불변raw_text 가변 + note_revisions 보존 (사용자 편집 + 옛 버전 회수)
  • AI 재실행 input = current latest notes.raw_text (옛 revision X)
  • "raw_text invariant guard" (importNote 의 fork-on-conflict 사유)fork-on-id-collision (sync determinism) — 동일 id 가 두 distinct baseline 을 가리키지 않도록

Risk 잔재

  • dogfood 미검증: v0.2.10 빌드 후 실 사용 사이클 (편집 / 이력 / 회수 / import 후 편집) 1주 soak 권장
  • revision 무한 누적: 본 cut unlimited. 메모 1개당 100+ revision 시 DB bloat 가능. 향후 cut 에서 cap 정책 (예: 최근 50개) 검토
  • 이력 modal pagination 미구현: 100+ revision 시 modal 길어짐. YAGNI — cap 정책과 함께
  • F19 search FTS5 영향: 인덱스 source = notes.raw_text (latest). revision 검색 미지원 (별도 cut)
  • F1 Due Date 재추출 안 함: raw_text 변경 시 기존 due_date 잔류 (사용자 의도 보존). 별도 cut 고려
  • m006 production 적용: 본인 v0.2.9 사용자 DB 기준 노트 수 작아 backfill INSERT...SELECT 단일 statement 에서 안전. 큰 DB 환경 timing 미검증 (Cut B m005 와 동일 pattern)

Test Plan

  • 원문 펼침 → "편집" → textarea 입력 → "저장" → notes.raw_text 갱신 + 새 revision (user) 추가
  • "취소" 클릭 시 변경 무시
  • 빈 문자열 / 공백만 입력 → 저장 거부 (IPC { ok: false, reason: 'empty' })
  • 원문 펼침 → "이력" → modal 열림 → revision 목록 (capture / user 라벨) 표시 (DESC 순)
  • 옛 revision 의 "회수" 클릭 → confirm dialog → OK → notes.raw_text 가 옛 값으로 복원 + 새 user revision 추가 (chain 보존)
  • 새 노트 캡처 시 note_revisions 에 capture revision 1건 자동 생성
  • 기존 v0.2.9 사용자 DB 마이그레이션 후 note_revisions 가 모든 노트별 1건씩 backfill (capture, edited_at = created_at)
  • F5 import (importNote) 시 inserted/forked 노트 모두 capture revision 자동 생성
  • AI 재실행 / NoteCard 표시 모두 latest notes.raw_text 기준 — 옛 revision 미노출
  • macOS dmg / Linux AppImage / deb 빌드 + Linux VM smoke

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

## Summary v0.2.10 Cut C — F20 raw_text 가변 + revision history. **load-bearing invariant 변경**: 메모리 정책 `raw_text 불변` 폐기, `note_revisions` 테이블에 변경 이력 보존 + 옛 버전 회수 UI. - **F20 raw_text 가변**: NoteCard 의 "원문 보기" 영역에 inline textarea 편집 + 저장. `inboxApi.updateRawText` → `NoteRepository.updateRawText` 가 `notes.raw_text` 갱신 + `note_revisions` 에 `edited_by='user'` 새 row INSERT (단일 transaction). - **revision history**: `note_revisions` 테이블 (m006). 새 노트 생성 (`create`) + 기존 노트 마이그레이션 backfill + import (`importNote`) 모두 `edited_by='capture'` 첫 revision INSERT 보장 (final review 보강 — F5 import 회귀 패치). - **회수 UI**: NoteCard 의 "이력" 버튼 → RevisionHistoryModal (rev 목록 + confirm dialog → `restoreRevision` chain-preserving). 옛 raw_text 가 새 user revision 으로 INSERT (linear history 유지). - **AI 정책**: AI 재실행 input = `notes.raw_text` (latest). 옛 revision 미사용. AiWorker 의 `findById(id).rawText` source 가 그대로라 코드 변경 없음 — 회귀 test (`findById 가 latest 반환`) 추가. ## 변경 내역 (9 commits) ### Phase 0: 문서 - `88ce78d` docs(plan) — Cut C plan + spec m005→m006 정정 (Cut B 가 m005 선점) ### Phase 1: schema + repo - `76c2345` Task 1 — m006 마이그레이션 (`note_revisions` 테이블 + index + capture backfill, FK ON DELETE CASCADE) - `18deee5` Task 2 — `NoteRepository.create` 가 capture revision 을 함께 INSERT (단일 transaction) - `7541d3c` Task 3-6 — `updateRawText` / `listRevisions` / `restoreRevision` repo API + `NoteRevision` type + InboxApi 시그니처 + preload bridge (Task 8 까지 batch) ### Phase 2: IPC - `b4c2d85` Task 7 — `inbox:update-raw-text` (empty reject) / `inbox:list-revisions` / `inbox:restore-revision` (try/catch repo throw) ### Phase 3: UI - `ff1a015` Task 9 — NoteCard 원문 영역 편집 UI (textarea + 저장/취소 + updateRawText) - `81fbacb` Task 10 — RevisionHistoryModal — 이력 목록 + 회수 confirm (window.confirm) + chain 보존 + 닫기 X ### Phase 4: release - `e32223d` chore(release) — version 0.2.9→0.2.10 + F20 promoted 마킹 ### Phase 5: final review fix - `39b8d1e` fix(v0210) — `importNote` 가 capture revision 을 함께 INSERT (final review 발견: F5 import 후 first user edit 시 import 시점 본문이 history 에서 사라지는 회귀). ImportNoteInput / importNote 의 옛 "raw_text invariant guard" 주석을 'fork-on-id-collision (sync determinism)' 의미로 갱신. ## 테스트 / 빌드 - 단위: 548 → **569 pass** (+21): - m006 마이그레이션 5 - `NoteRepository.create` capture revision 1 - `updateRawText` 2 / `listRevisions` 1 / `restoreRevision` 2 - IPC handlers 4 - NoteCard 편집 1 - RevisionHistoryModal 2 - `findById` 회귀 (AI source) 1 - `importNote` capture revision (final review) 2 - typecheck: **0 errors** - e2e: **세션 내 미수행** — worktree node_modules 가 비어 있어 pretest 의 better-sqlite3 prebuild-install 단계가 worktree CWD 에서 실패. 본 cut 은 OnboardingWizard / capture flow / banner 등 e2e 시나리오에 영향 X (NoteCard 내부 + 신규 modal). 머지 후 main 에서 검증 권장. - 빌드 산출물: 후속 release 단계에서 Windows exe + macOS dmg + Linux AppImage/deb ## Schema 변경 - m006: `note_revisions` 테이블 신설 — `(rev_id PK AUTOINCREMENT, note_id FK→notes(id) ON DELETE CASCADE, raw_text, edited_at, edited_by CHECK IN ('user','capture'))`. `idx_note_revisions_note_id (note_id, edited_at DESC)`. 기존 모든 `notes` 의 `raw_text` 를 `edited_by='capture'` revision 으로 backfill (`edited_at = created_at`). ## 메모리 정책 변경 (Cut C 머지 후 갱신 예정) - ~~`raw_text 불변`~~ → **`raw_text 가변` + `note_revisions` 보존 (사용자 편집 + 옛 버전 회수)** - AI 재실행 input = current latest `notes.raw_text` (옛 revision X) - ~~"raw_text invariant guard" (importNote 의 fork-on-conflict 사유)~~ → **fork-on-id-collision (sync determinism)** — 동일 id 가 두 distinct baseline 을 가리키지 않도록 ## Risk 잔재 - **dogfood 미검증**: v0.2.10 빌드 후 실 사용 사이클 (편집 / 이력 / 회수 / import 후 편집) 1주 soak 권장 - **revision 무한 누적**: 본 cut unlimited. 메모 1개당 100+ revision 시 DB bloat 가능. 향후 cut 에서 cap 정책 (예: 최근 50개) 검토 - **이력 modal pagination 미구현**: 100+ revision 시 modal 길어짐. YAGNI — cap 정책과 함께 - **F19 search FTS5 영향**: 인덱스 source = `notes.raw_text` (latest). revision 검색 미지원 (별도 cut) - **F1 Due Date 재추출 안 함**: raw_text 변경 시 기존 due_date 잔류 (사용자 의도 보존). 별도 cut 고려 - **m006 production 적용**: 본인 v0.2.9 사용자 DB 기준 노트 수 작아 backfill `INSERT...SELECT` 단일 statement 에서 안전. 큰 DB 환경 timing 미검증 (Cut B m005 와 동일 pattern) ## Test Plan - [ ] 원문 펼침 → "편집" → textarea 입력 → "저장" → notes.raw_text 갱신 + 새 revision (user) 추가 - [ ] "취소" 클릭 시 변경 무시 - [ ] 빈 문자열 / 공백만 입력 → 저장 거부 (IPC `{ ok: false, reason: 'empty' }`) - [ ] 원문 펼침 → "이력" → modal 열림 → revision 목록 (capture / user 라벨) 표시 (DESC 순) - [ ] 옛 revision 의 "회수" 클릭 → confirm dialog → OK → notes.raw_text 가 옛 값으로 복원 + 새 user revision 추가 (chain 보존) - [ ] 새 노트 캡처 시 `note_revisions` 에 capture revision 1건 자동 생성 - [ ] 기존 v0.2.9 사용자 DB 마이그레이션 후 `note_revisions` 가 모든 노트별 1건씩 backfill (capture, edited_at = created_at) - [ ] F5 import (`importNote`) 시 inserted/forked 노트 모두 capture revision 자동 생성 - [ ] AI 재실행 / NoteCard 표시 모두 latest `notes.raw_text` 기준 — 옛 revision 미노출 - [ ] macOS dmg / Linux AppImage / deb 빌드 + Linux VM smoke 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
altair823 added 9 commits 2026-05-09 12:06:05 +00:00
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- updateRawText: raw_text 갱신 + user revision INSERT (atomic)
- listRevisions: edited_at DESC 순 hydrate
- restoreRevision: 옛 raw_text 를 새 user revision 으로 복원 (chain 보존)
- shared/types: NoteRevision + InboxApi 3 메서드 (updateRawText/listRevisions/restoreRevision)
- preload: 3 IPC stub 추가 (inbox:update-raw-text / inbox:list-revisions / inbox:restore-revision)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- F20 promoted ( v0.2.10 Cut C)
- version 0.2.9 → 0.2.10 (package.json + package-lock.json)
- 단위 548 → 567 (m006 5 + create rev 1 + repo 6 + IPC 4 + NoteCard 1 + Modal 2 + findById 회귀 1)
- typecheck 0 errors
final code review 발견: F5 import 후 first user edit 시 import 시점 본문이
note_revisions 에 없어 history 에서 사라지는 회귀. importNote transaction 안
INSERT 추가 (createdAt = edited_at).

부수 작업: ImportNoteInput / importNote 의 "raw_text invariant guard" 주석을
v0.2.10 의 'fork-on-id-collision (sync determinism)' 정확한 의미로 갱신.

테스트 +2 — insert path / fork path 모두 capture revision 검증.
claude-reviewer-01 approved these changes 2026-05-09 14:47:36 +00:00
claude-reviewer-01 left a comment
Member

코드 리뷰 — v0.2.10 Cut C

Scope: 9 commits / 14 files / +1473/-22

Spec coverage 100%

Cut C design 의 모든 섹션이 task 매핑됨. F20 (raw_text 가변 + revision history) — load-bearing invariant 변경.

spec § 구현
§3 m006 schema m006_revisions.ts — table/index/CASCADE/backfill (5 unit)
§4 Repository methods updateRawText (atomic), listRevisions (DESC + camelCase hydrate), restoreRevision (FK match + chain-preserving via updateRawText delegation)
§5 NoteCard UI inline textarea 편집 + RevisionHistoryModal mount
§6 AI 정책 notes.raw_text (latest) — AiWorker findById 변경 없음, 회귀 test 추가
§7 F1/F4/F17/F19 무영향 — 해당 기능 코드 미수정
§8 IPC + types 3 채널 + NoteRevision 인터페이스 + InboxApi 3 메서드
§9 테스트 전략 +21 단위 (5+1+2+1+2+4+1+2+1+2)

코드 품질

Strengths

  • Single write path 일관성: restoreRevisionupdateRawText 로 위임 (NoteRepository.ts:540). DRY + atomic transaction 보장 단일 지점.
  • FK guard: restoreRevisionWHERE rev_id=? AND note_id=? composite (NoteRepository.ts:537) — cross-note 오용 방어.
  • Cancellation flag: RevisionHistoryModal 의 useEffect (RevisionHistoryModal.tsx:41-53) — modal 언마운트 중 setState race 방지.
  • CHECK constraint defensive: m006 의 edited_by IN ('user','capture') — spec 의 DEFAULT 외 추가 보강.
  • AiWorker 무수정: findById(id).rawText source 그대로 (AiWorker.ts:124,234). raw_text 가변 도입에도 AI 입력 정책 invariant 유지.
  • v0.2.6 #10 fix 보존: restoreNote 의 ai_status='failed'/'pending' 재투입 + pending_jobs INSERT OR IGNORE 정확 보존. production path dead code 회귀 없음.
  • v0.2.9 Cut B 'disabled' 호환: aiStatus='disabled' 노트도 create path 에서 capture revision 생성 — zero-revision 회귀 없음.

Final review follow-up 적용 (39b8d1e)

initial final review (Opus, 1차) 에서 발견된 Important issue:

  • importNote 가 capture revision 미생성 → F5 import 후 first user edit 시 history 에서 import 시점 본문 사라지는 회귀 가능

→ Fix:

  • importNote transaction 안 INSERT 추가 (NoteRepository.ts:756-761) — edited_by='capture', edited_at=createdAt
  • insert path + fork path 모두 적용 ('skipped' early-return 은 INSERT 미진행 — 정확)
  • 회귀 test 2건 추가 (tests/unit/NoteRevisions.test.ts:111-170) — insert/fork path 별 capture revision 검증, 기존 노트 revision 보존 검증
  • 옛 "raw_text invariant guard" / "raw_text-immutable invariant" JSDoc → 'fork-on-id-collision (sync determinism)' 정확한 의미로 갱신

re-review (39b8d1e 대상) 결과:

  • 모든 수정 사항 spec 준수 + bounded scope (importNote + JSDoc + 2 tests 만 변경, 다른 메서드 무영향)
  • NoteRepositoryINSERT INTO notes path = create + importNote 단 2곳, 둘 다 capture revision 보장 — invariant 누락 위험 0

Architecture

  • 단위 분해 명확 (migration / repository / IPC / preload / component / modal 6계층 분리)
  • 책임 명확성 — updateRawText = atomic 단일 write, restoreRevision = lookup + delegate, listRevisions = pure read
  • 일관성 — 기존 modal pattern (MoveStatusModal) 과 overlay/X close button/aria-label 동일
  • m006 = forward-only migration (m001~m005 동일 패턴), 단일 transaction (runMigrations 가 wrap)

Risk 잔재

  • dogfood 미검증: 편집 / 이력 / 회수 / import 후 편집 사이클 1주 soak 권장
  • revision 무한 누적: 본 cut unlimited. 메모 1개당 100+ revision 시 DB bloat 가능. 향후 cap 정책 (예: 최근 50개) 검토 — spec §10 acknowledged
  • 이력 modal pagination 미구현: 100+ revision 시 modal 길어짐. YAGNI — cap 정책과 함께
  • F19 search FTS5: 인덱스 source = notes.raw_text (latest). revision 검색 미지원 — 별도 cut
  • F1 Due Date 재추출 안 함: raw_text 변경 시 기존 due_date 잔류 (사용자 의도 보존). 별도 cut
  • m006 production timing: 본인 사용자 DB 작아 backfill 단일 statement 안전. 큰 DB 환경 미검증 (Cut B m005 와 동일 pattern)
  • e2e 본 세션 미수행: worktree node_modules 비어 있어 better-sqlite3 prebuild step 실패 (worktree CWD). 본 cut diff 가 OnboardingWizard / capture / banner 영향 X — risk 낮음. 머지 후 main 에서 검증 권장

Sub-review 트레일

  • Task 1 (m006) — Haiku spec + Haiku quality (minor: shared baseline fixture / CHECK rejection test 가능, 비차단)
  • Task 2 (create capture) — Haiku spec (4줄 변경 verbatim)
  • Task 3-6+8 (repo + types + preload) — Haiku spec+quality 통합
  • Task 7 (IPC) — diff 직접 검토 (3 handler verbatim)
  • Task 9 (NoteCard 편집) — Haiku spec+quality (14 check 통과)
  • Task 10 (Modal) — Haiku spec+quality (Props/cancellation/loading/error/confirm/ordering 정확)
  • Final code review (Opus, 1차) — ⚠ Approved with follow-up (importNote gap)
  • Final fix re-review (Haiku) Approved

머지 권장

  1. PR #28 머지
  2. tag v0.2.10 + npm run dist:win → Windows exe 빌드
  3. Gitea release v0.2.10 + exe attach
  4. macOS host: dist:mac + dist:linux 후 dmg/AppImage/deb 추가 attach
  5. 메모리 정책 갱신 — raw_text 불변raw_text 가변 + note_revisions 보존 + AI 재실행 input = current latest
  6. dogfood 1주 soak — F20 실 사용 흐름 + classifyStatus 와 결합 효과 측정 → v0.2.11 Cut D (F19 FTS5 search) 진입

Overall

Ready to merge. Spec 100% coverage, 548 → 569 unit + typecheck 0, m006 마이그레이션 외래키 안전성 검증, v0.2.6 #10 fix 보존, v0.2.9 Cut B 'disabled' 호환, final review follow-up 완료 + re-review approved. Cut D (v0.2.11) 진입 가능.

🤖 Reviewed by Claude Opus 4.7 (1M context) with Haiku spec/quality sub-reviewers per subagent-driven-development skill

## 코드 리뷰 — v0.2.10 Cut C **Scope**: 9 commits / 14 files / +1473/-22 ### Spec coverage ✅ 100% [Cut C design](docs/superpowers/specs/2026-05-09-v0210-cut-c-design.md) 의 모든 섹션이 task 매핑됨. F20 (raw_text 가변 + revision history) — load-bearing invariant 변경. | spec § | 구현 | |---|---| | §3 m006 schema | `m006_revisions.ts` — table/index/CASCADE/backfill (5 unit) | | §4 Repository methods | `updateRawText` (atomic), `listRevisions` (DESC + camelCase hydrate), `restoreRevision` (FK match + chain-preserving via `updateRawText` delegation) | | §5 NoteCard UI | inline textarea 편집 + `RevisionHistoryModal` mount | | §6 AI 정책 | `notes.raw_text` (latest) — AiWorker `findById` 변경 없음, 회귀 test 추가 | | §7 F1/F4/F17/F19 | 무영향 — 해당 기능 코드 미수정 | | §8 IPC + types | 3 채널 + `NoteRevision` 인터페이스 + `InboxApi` 3 메서드 | | §9 테스트 전략 | +21 단위 (5+1+2+1+2+4+1+2+1+2) | ### 코드 품질 **Strengths** - **Single write path 일관성**: `restoreRevision` 이 `updateRawText` 로 위임 (`NoteRepository.ts:540`). DRY + atomic transaction 보장 단일 지점. - **FK guard**: `restoreRevision` 의 `WHERE rev_id=? AND note_id=?` composite (`NoteRepository.ts:537`) — cross-note 오용 방어. - **Cancellation flag**: `RevisionHistoryModal` 의 useEffect (`RevisionHistoryModal.tsx:41-53`) — modal 언마운트 중 setState race 방지. - **CHECK constraint defensive**: m006 의 `edited_by IN ('user','capture')` — spec 의 DEFAULT 외 추가 보강. - **AiWorker 무수정**: `findById(id).rawText` source 그대로 (`AiWorker.ts:124,234`). raw_text 가변 도입에도 AI 입력 정책 invariant 유지. - **v0.2.6 #10 fix 보존**: `restoreNote` 의 ai_status='failed'/'pending' 재투입 + pending_jobs INSERT OR IGNORE 정확 보존. production path dead code 회귀 없음. - **v0.2.9 Cut B 'disabled' 호환**: `aiStatus='disabled'` 노트도 `create` path 에서 capture revision 생성 — zero-revision 회귀 없음. **Final review follow-up 적용** (`39b8d1e`) initial final review (Opus, 1차) 에서 발견된 Important issue: - ❌ `importNote` 가 capture revision 미생성 → F5 import 후 first user edit 시 history 에서 import 시점 본문 사라지는 회귀 가능 → Fix: - ✅ `importNote` transaction 안 INSERT 추가 (`NoteRepository.ts:756-761`) — `edited_by='capture'`, `edited_at=createdAt` - ✅ insert path + fork path 모두 적용 (`'skipped'` early-return 은 INSERT 미진행 — 정확) - ✅ 회귀 test 2건 추가 (`tests/unit/NoteRevisions.test.ts:111-170`) — insert/fork path 별 capture revision 검증, 기존 노트 revision 보존 검증 - ✅ 옛 "raw_text invariant guard" / "raw_text-immutable invariant" JSDoc → 'fork-on-id-collision (sync determinism)' 정확한 의미로 갱신 re-review (`39b8d1e` 대상) 결과: - 모든 수정 사항 spec 준수 + bounded scope (`importNote` + JSDoc + 2 tests 만 변경, 다른 메서드 무영향) - `NoteRepository` 안 `INSERT INTO notes` path = `create` + `importNote` 단 2곳, 둘 다 capture revision 보장 — invariant 누락 위험 **0** ### Architecture - 단위 분해 명확 (migration / repository / IPC / preload / component / modal 6계층 분리) - 책임 명확성 — `updateRawText` = atomic 단일 write, `restoreRevision` = lookup + delegate, `listRevisions` = pure read - 일관성 — 기존 modal pattern (`MoveStatusModal`) 과 overlay/X close button/aria-label 동일 - m006 = forward-only migration (m001~m005 동일 패턴), 단일 transaction (runMigrations 가 wrap) ### Risk 잔재 - **dogfood 미검증**: 편집 / 이력 / 회수 / import 후 편집 사이클 1주 soak 권장 - **revision 무한 누적**: 본 cut unlimited. 메모 1개당 100+ revision 시 DB bloat 가능. 향후 cap 정책 (예: 최근 50개) 검토 — spec §10 acknowledged - **이력 modal pagination 미구현**: 100+ revision 시 modal 길어짐. YAGNI — cap 정책과 함께 - **F19 search FTS5**: 인덱스 source = `notes.raw_text` (latest). revision 검색 미지원 — 별도 cut - **F1 Due Date 재추출 안 함**: raw_text 변경 시 기존 due_date 잔류 (사용자 의도 보존). 별도 cut - **m006 production timing**: 본인 사용자 DB 작아 backfill 단일 statement 안전. 큰 DB 환경 미검증 (Cut B m005 와 동일 pattern) - **e2e 본 세션 미수행**: worktree node_modules 비어 있어 better-sqlite3 prebuild step 실패 (worktree CWD). 본 cut diff 가 OnboardingWizard / capture / banner 영향 X — risk 낮음. 머지 후 main 에서 검증 권장 ### Sub-review 트레일 - **Task 1 (m006)** — Haiku spec ✅ + Haiku quality ✅ (minor: shared baseline fixture / CHECK rejection test 가능, 비차단) - **Task 2 (create capture)** — Haiku spec ✅ (4줄 변경 verbatim) - **Task 3-6+8 (repo + types + preload)** — Haiku spec+quality 통합 ✅ - **Task 7 (IPC)** — diff 직접 검토 ✅ (3 handler verbatim) - **Task 9 (NoteCard 편집)** — Haiku spec+quality ✅ (14 check 통과) - **Task 10 (Modal)** — Haiku spec+quality ✅ (Props/cancellation/loading/error/confirm/ordering 정확) - **Final code review (Opus, 1차)** — ⚠ Approved with follow-up (importNote gap) - **Final fix re-review (Haiku)** — ✅ Approved ### 머지 권장 1. PR #28 머지 2. tag `v0.2.10` + `npm run dist:win` → Windows exe 빌드 3. Gitea release v0.2.10 + exe attach 4. macOS host: `dist:mac` + `dist:linux` 후 dmg/AppImage/deb 추가 attach 5. 메모리 정책 갱신 — `raw_text 불변` → `raw_text 가변 + note_revisions 보존` + AI 재실행 input = current latest 6. dogfood 1주 soak — F20 실 사용 흐름 + classifyStatus 와 결합 효과 측정 → v0.2.11 Cut D (F19 FTS5 search) 진입 ### Overall **Ready to merge.** Spec 100% coverage, 548 → 569 unit + typecheck 0, m006 마이그레이션 외래키 안전성 검증, v0.2.6 #10 fix 보존, v0.2.9 Cut B 'disabled' 호환, final review follow-up 완료 + re-review approved. Cut D (v0.2.11) 진입 가능. 🤖 Reviewed by Claude Opus 4.7 (1M context) with Haiku spec/quality sub-reviewers per subagent-driven-development skill
altair823 merged commit c4e7536086 into main 2026-05-09 14:52:28 +00:00
altair823 deleted branch worktree-v0210-cut-c-raw-text-revisions 2026-05-09 14:52:30 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: altair823-org/inkling#28