2.5.0: Notes workspace, vision board, and Quill/notes reliability fixes - #39
Conversation
Cites V7, V48, V49, V50, V51, V52, V54.
Cites V1, V2, V3, V7, V48, V50, V53, V54.
Cites V3 and V47.
Cites V5, V47, V48, V50, V52, V54, V55, V56.
Cites V18, V20, V47, V48, V49, V50, V51, V52, V53, V54, V55.
- Serialize note schema migration writes under _NOTES_LOCK and fall back to an unmigrated read instead of silently dropping a note when the migration write fails (V61). - Restore ffp_quill's documented fail-soft contract: get_minutes/ get_transcript/search_meetings/list_recent_meetings catch QuillToolError instead of letting it propagate, which was silently no-oping scheduled meeting batches and breaking the permanent-skip path for dead meetings (V62). - Add the missing optimistic-concurrency revision check to trash_note, and guard the two remaining bare int() revision parses in the daemon. Found via code-review skill pass across 8 angles before shipping 2.5.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 53dbdecd6c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| parsed = _FRONTMATTER_LINE_RE.match(line) | ||
| if not parsed: | ||
| rendered.append(line) | ||
| continue | ||
| key = parsed.group(1) | ||
| if key in wanted: | ||
| rendered.append(f"{key}: {_encode_frontmatter_value(wanted[key])}") |
There was a problem hiding this comment.
Preserve multiline YAML values during migration
When an existing Markdown note uses standard block-style YAML such as tags: followed by indented - alpha entries, _note_parts reads the field as empty and this loop replaces only the tags: line while retaining its indented children. Merely listing the vault therefore rewrites the note as invalid YAML (tags: [] followed by the old list) and loses the tags from Flowkey's index; migration should parse and replace the complete YAML value rather than a single line.
Useful? React with 👍 / 👎.
| metadata, body, text = _ensure_note_schema(source_path) | ||
| current_revision = int(metadata.get("revision") or 1) | ||
| if revision is not None and int(revision) != current_revision: |
There was a problem hiding this comment.
Detect filesystem edits before overwriting a note
When a note open in the dashboard is edited by Obsidian or another filesystem client, that edit does not increment the stored revision, so this comparison still succeeds. Because the dashboard subsequently submits all editor fields, even saving an unrelated tag can overwrite the newer external body without a conflict; the edit token needs to incorporate the file version or fingerprint observed when the note was opened.
Useful? React with 👍 / 👎.
| setEditorStatus(saved.error || "Save failed.", false); | ||
| return; | ||
| } | ||
| await syncEditorBoardPlacement(saved.note_id); |
There was a problem hiding this comment.
Stop reporting success when board placement conflicts
When another dashboard tab saves the board after this editor loaded it, syncEditorBoardPlacement receives a board revision conflict and returns after dropping the requested placement, but this call's result is ignored. The flow then reloads state and displays Saved., so a user who checked “on board” is told the whole operation succeeded even though the placement was lost; propagate the failed board save and surface the conflict instead.
Useful? React with 👍 / 👎.
Summary
Notes now works like a notepad, sticky-note wall, and vision board instead of a file browser. Capture first, shape the note in an editor, and organize it without leaving the Notes tab.
Added
.flowkey/board.json, keyed by stable note IDs. Removing a board placement never mutates or deletes the note.note_idand richer metadata without losing their body, source path, or unknown frontmatter. A backup is written to.flowkey/backups/v1/before the first rewrite.Changed
Ctrl+Alt+Nopens the Notes composer. A fresh selection prefills the draft; no selection opens a blank composer. Prior clipboard contents are never used as an implicit fallback, and capture no longer saves before review.Fixed
Review
Ran an 8-angle code-review pass (correctness, removed-behavior, cross-file tracing, reuse, simplification, efficiency, altitude, conventions) before opening this PR. Found and fixed 3 real pre-release bugs (B44-B46 in SPEC.md): the Quill error-handling regression above, the note-migration race/silent-drop above, and a missing revision check on trash_note. Deferred as follow-ups (not release blockers): an O(n) vault rescan on note-by-id lookup, a few duplicated-logic spots, and two accessibility gaps on custom widgets.
Test plan
ruff check .cleanpytestsuite green (536 tests, including 6 new regression tests for the fixes above)🤖 Generated with Claude Code