From 738eb9c9cf1e32db87f8ff9b8b994b1ee906bd33 Mon Sep 17 00:00:00 2001 From: pjay Date: Mon, 22 Jun 2026 13:44:30 -0400 Subject: [PATCH] Quality bugfix plan (#2) * fix(persist): atomic+durable .margin writes Route save_book, write_file, write_bytes through a shared atomic_write helper: write to a temp file, fsync, then rename into place so a crash mid-write can never leave a truncated or empty manuscript. Rotate the prior copy to .bak for manuscripts (not exports) so one good copy always survives. Claude-Session: https://claude.ai/code/session_01RzTWrLiy4zGuw2hZSQGamk * fix(editor): isolate undo history per chapter Key the editor by chapter id so each chapter gets a fresh TipTap instance with its own history. Previously a single instance was reused across chapters, so the content swap entered the undo stack and Ctrl+Z after switching restored the prior chapter's doc into the current one, which autosave then persisted. With remount, save the cursor/scroll position on unmount (from a ref, not the editor, which is destroyed by then) and load it on mount, replacing the in-place chapter-switch bookkeeping. Claude-Session: https://claude.ai/code/session_01RzTWrLiy4zGuw2hZSQGamk * feat(editor): persist active chapter per book Remember which chapter was open per book and restore it on reopen, falling back to the first chapter when the saved id is no longer valid. Claude-Session: https://claude.ai/code/session_01RzTWrLiy4zGuw2hZSQGamk * fix(persist): flush pending save on navigate-away and quit Edits are saved on an 800ms debounce, so leaving a book within that window lost the latest changes. Flush a dirty book before openBook / closeBook swap state (covers All books, open-another, Cmd+N), and add a window close-request handler that saves before destroying on quit. Claude-Session: https://claude.ai/code/session_01RzTWrLiy4zGuw2hZSQGamk * fix(persist): guard markSaved against in-flight edits markSaved cleared dirty unconditionally, so an edit made while a save was in flight had its dirty flag wiped and its follow-up save dropped. Only clear dirty when the book reference is unchanged since the save started (immutable updates give a fresh reference per edit). Claude-Session: https://claude.ai/code/session_01RzTWrLiy4zGuw2hZSQGamk * fix(persist): persist new books on create A freshly created book lived only in memory until the first edit, so quitting beforehand lost it and it never appeared in the library. Save it to disk on creation via a shared createAndOpenBook used by both the Library card and the New Book menu action. Claude-Session: https://claude.ai/code/session_01RzTWrLiy4zGuw2hZSQGamk * fix(export): correct list nesting, marks, line-start escaping, svg type Four export-correctness fixes intermingled across the Typst and EPUB renderers: - H7: neutralize newlines in escaped text and apply leading-marker escaping (= - + / and N.) to the first text node of every block (paragraph, heading, list item, blockquote) and figure captions, even when that run carries a mark, so author text can never inject Typst markup or phantom headings/TOC entries. - H9: render lists recursively so nested lists survive and multi- paragraph list items keep their paragraph breaks (Typst functional list()/enum(); EPUB nested