Closes TODO(brush-persist). EditorStroke now serializes its brush as
the stable BrushKind name; sidecars written before this field, and any
unknown name, load as fountainPen (back-compat). PenStroke<->EditorStroke
carry brush both ways, so a ballpoint/highlighter/pencil stroke keeps
its opacity/blend after a document is closed and reopened.
Note: InkStroke (the note/scratchpad world-coord format) has no brush
field, so notes derive brush from the tool — highlighter is preserved,
ballpoint/pencil collapse to fountainPen on reload (TODO: extend
InkStroke). PDF documents persist brush fully. analyze clean,
379 tests green.
Phase 1 of the file-based storage plan. Pure library, no runtime
behavior change yet (editors still use SQLite).
- BadnoteSidecar: per-file annotation document (schema-versioned)
holding per-page ink (EditorStroke JSON), text highlights,
scratch-link anchors (ScratchLink JSON) each with its own
scratchpad (InkStroke world-coord JSON), and bookmarks. Reuses the
existing toJson formats — no parallel stroke format.
- SidecarStore.writeAtomic: temp-file + rename atomic write keeping a
.bak; read() falls back to .bak on a missing/corrupt primary.
Round-trip + atomic-write + .bak-recovery tests. analyze clean,
322 tests green.