v0.2.10 Cut C — raw_text 가변 + revision history (F20) #28
Reference in New Issue
Block a user
Delete Branch "worktree-v0210-cut-c-raw-text-revisions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
v0.2.10 Cut C — F20 raw_text 가변 + revision history. load-bearing invariant 변경: 메모리 정책
raw_text 불변폐기,note_revisions테이블에 변경 이력 보존 + 옛 버전 회수 UI.inboxApi.updateRawText→NoteRepository.updateRawText가notes.raw_text갱신 +note_revisions에edited_by='user'새 row INSERT (단일 transaction).note_revisions테이블 (m006). 새 노트 생성 (create) + 기존 노트 마이그레이션 backfill + import (importNote) 모두edited_by='capture'첫 revision INSERT 보장 (final review 보강 — F5 import 회귀 패치).restoreRevisionchain-preserving). 옛 raw_text 가 새 user revision 으로 INSERT (linear history 유지).notes.raw_text(latest). 옛 revision 미사용. AiWorker 의findById(id).rawTextsource 가 그대로라 코드 변경 없음 — 회귀 test (findById 가 latest 반환) 추가.변경 내역 (9 commits)
Phase 0: 문서
88ce78ddocs(plan) — Cut C plan + spec m005→m006 정정 (Cut B 가 m005 선점)Phase 1: schema + repo
76c2345Task 1 — m006 마이그레이션 (note_revisions테이블 + index + capture backfill, FK ON DELETE CASCADE)18deee5Task 2 —NoteRepository.create가 capture revision 을 함께 INSERT (단일 transaction)7541d3cTask 3-6 —updateRawText/listRevisions/restoreRevisionrepo API +NoteRevisiontype + InboxApi 시그니처 + preload bridge (Task 8 까지 batch)Phase 2: IPC
b4c2d85Task 7 —inbox:update-raw-text(empty reject) /inbox:list-revisions/inbox:restore-revision(try/catch repo throw)Phase 3: UI
ff1a015Task 9 — NoteCard 원문 영역 편집 UI (textarea + 저장/취소 + updateRawText)81fbacbTask 10 — RevisionHistoryModal — 이력 목록 + 회수 confirm (window.confirm) + chain 보존 + 닫기 XPhase 4: release
e32223dchore(release) — version 0.2.9→0.2.10 + F20 promoted 마킹Phase 5: final review fix
39b8d1efix(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)' 의미로 갱신.테스트 / 빌드
NoteRepository.createcapture revision 1updateRawText2 /listRevisions1 /restoreRevision2findById회귀 (AI source) 1importNotecapture revision (final review) 2Schema 변경
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보존 (사용자 편집 + 옛 버전 회수)notes.raw_text(옛 revision X)"raw_text invariant guard" (importNote 의 fork-on-conflict 사유)→ fork-on-id-collision (sync determinism) — 동일 id 가 두 distinct baseline 을 가리키지 않도록Risk 잔재
notes.raw_text(latest). revision 검색 미지원 (별도 cut)INSERT...SELECT단일 statement 에서 안전. 큰 DB 환경 timing 미검증 (Cut B m005 와 동일 pattern)Test Plan
{ ok: false, reason: 'empty' })note_revisions에 capture revision 1건 자동 생성note_revisions가 모든 노트별 1건씩 backfill (capture, edited_at = created_at)importNote) 시 inserted/forked 노트 모두 capture revision 자동 생성notes.raw_text기준 — 옛 revision 미노출🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.7 (1M context) <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코드 리뷰 — 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 변경.
m006_revisions.ts— table/index/CASCADE/backfill (5 unit)updateRawText(atomic),listRevisions(DESC + camelCase hydrate),restoreRevision(FK match + chain-preserving viaupdateRawTextdelegation)RevisionHistoryModalmountnotes.raw_text(latest) — AiWorkerfindById변경 없음, 회귀 test 추가NoteRevision인터페이스 +InboxApi3 메서드코드 품질
Strengths
restoreRevision이updateRawText로 위임 (NoteRepository.ts:540). DRY + atomic transaction 보장 단일 지점.restoreRevision의WHERE rev_id=? AND note_id=?composite (NoteRepository.ts:537) — cross-note 오용 방어.RevisionHistoryModal의 useEffect (RevisionHistoryModal.tsx:41-53) — modal 언마운트 중 setState race 방지.edited_by IN ('user','capture')— spec 의 DEFAULT 외 추가 보강.findById(id).rawTextsource 그대로 (AiWorker.ts:124,234). raw_text 가변 도입에도 AI 입력 정책 invariant 유지.restoreNote의 ai_status='failed'/'pending' 재투입 + pending_jobs INSERT OR IGNORE 정확 보존. production path dead code 회귀 없음.aiStatus='disabled'노트도createpath 에서 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:
importNotetransaction 안 INSERT 추가 (NoteRepository.ts:756-761) —edited_by='capture',edited_at=createdAt'skipped'early-return 은 INSERT 미진행 — 정확)tests/unit/NoteRevisions.test.ts:111-170) — insert/fork path 별 capture revision 검증, 기존 노트 revision 보존 검증re-review (
39b8d1e대상) 결과:importNote+ JSDoc + 2 tests 만 변경, 다른 메서드 무영향)NoteRepository안INSERT INTO notespath =create+importNote단 2곳, 둘 다 capture revision 보장 — invariant 누락 위험 0Architecture
updateRawText= atomic 단일 write,restoreRevision= lookup + delegate,listRevisions= pure readMoveStatusModal) 과 overlay/X close button/aria-label 동일Risk 잔재
notes.raw_text(latest). revision 검색 미지원 — 별도 cutSub-review 트레일
머지 권장
v0.2.10+npm run dist:win→ Windows exe 빌드dist:mac+dist:linux후 dmg/AppImage/deb 추가 attachraw_text 불변→raw_text 가변 + note_revisions 보존+ AI 재실행 input = current latestOverall
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