Tracked at source via @remarks JSDoc tags. This file consolidates them for
planning. Last updated: 2026-06-22 (D4). Paths are relative to repo root.
[[link]] targets stale after renameFiles: apps/tauri/src/components/PageView.vue:26, apps/tauri/src/composables/usePageNavigation.ts:33, apps/tauri/src/composables/useSidebarIndex.ts:10
Renaming a page does not update existing [[links]] in other files that
reference the old title. Backlink counts also reflect the stale title.
links.target = oldTitle, update
file contents and re-indexFile: apps/tauri/src/pages/[...slug].vue:43
#block-{id} is appended to the URL when navigating to a block ref
(((block-id))), but the receiving PageView has no onMounted scroll-to
logic. The hash fragment is in the URL for future use only.
onMounted → check route.hash, query DOM for [data-block-id],
scrollIntoView()Files: apps/tauri/src/pages/[...slug].vue:36, components/JournalDay.vue
Auto-save always overwrites the file on disk regardless of whether an external editor changed it between debounce triggers.
modified_at is index-time, not file mtimeFiles: apps/tauri/src/components/TagView.vue:19, apps/tauri/src/lib/indexer.ts:70
blocks.modified_at is set to Date.now() / 1000 during indexing, not the
file's mtime from fs::metadata. Blocks from the same file indexed in the same
pass share the same timestamp, making ORDER BY modified_at unreliable.
fs::metadata during indexingmtime through the indexer's
incremental update pathFile: apps/tauri/src/lib/indexer.ts:67
Workspaces indexed before the computePageTitle fallback was added (D4) may
have pages.title = '' for pages without an # H1. These won't be fixed until
a fullReindex (app restart) or incremental re-index on file change.
[[links]] don't resolveUPDATE pages SET title = ... WHERE title = ''String.slice() can split multi-byte charactersFiles: components/PageView.vue:22, apps/tauri/src/pages/[...slug].vue:40
Excerpt extraction uses String.slice() (UTF-16 code units). If a [[link]]
offset falls inside a 4-byte character (e.g. emoji), the excerpt may be
truncated mid-character, producing a replacement character (�).
Array.from() or Intl.SegmenterFile: components/TagView.vue:24
The tag aggregation query uses LIMIT 50 with no cursor/offset pagination.
If a tag has hundreds of references, only the last 50 are returned.
safeName() doesn't handle all Unicode edge casesFile: apps/tauri/src/composables/usePageNavigation.ts:35
safeName strips <>:?*"\ characters but doesn't handle zero-width spaces,
RTL markers, or other Unicode control characters. These are rare in page names
but could produce surprising URL paths.
.normalize('NFC') and filter Unicode control
character rangesFile: components/TagView.vue:23
Links are extracted with lowercased tag names (see extractLinks in
parse.ts). Mixed-case tags from a prior index version may not match.
UPDATE tags SET name = LOWER(name) migrationFiles: packages/editor/src/composables/useBlockKeyboardHandlers.ts:132, packages/editor/src/components/EditorBlock.vue:668, packages/editor/src/components/Editor.vue:1085
Tab/Shift+Tab indent/outdent handling is wired end-to-end (handler in
useBlockKeyboardHandlers, pure operations in editor-operations.ts,
event handling in Editor.vue) but the browser may capture the Tab key
for focus navigation before it reaches the ProseMirror handleKeyDown
prop, which is set at EditorBlock.vue:668.
handleKeyDown: Ensure event.preventDefault()
is called and the PM EditorView DOM element captures Tab — check
tabindex and contenteditable interaction.depth > 0 and its content is empty when Enter is pressed, outdent
one level instead of creating a new empty block at the same depth.
This is how many outliners (Logseq, Roam, Workflowy) handle it.handleKeyDown fires at all for Tab,
or if the browser / PM default captures it first.File: apps/tauri/src/lib/indexer.ts:74
The indexer tracks has_id_stamp per block but the stamp creation
(id:: <nanoid> written to the file when a ((ref)) is created) is
deferred to D2. The indexer is read-only and never modifies files.
((ref)) syntax works in the editor
but there's no way to assign a stable ID to a block yetFile: Sidebar (apps/tauri/src/components/AppSidebar.vue, not yet implemented)
Full-text search via SQLite FTS5 is built into the schema (pages_fts,
blocks_fts) and the indexer populates it. No search input or results UI
exists in the sidebar yet.
File: packages/editor/src/components/EditorBlock.vue (core editor)
Click targets between blocks (FIXME: Replace with Editor shell insertion
zone) are not yet materialised as visual insertion zones. Boundary
navigation (ArrowUp from first block, ArrowDown from last) creates
paragraphs inline as a temporary workaround.
These are tracked for completeness but not yet scoped into any milestone.
| Item | Area | Notes |
|---|---|---|
Automatic [[link]] update on rename |
Cross-file | Requires write-lock pattern |
| Conflict dialog on external file change | Auto-save | Low priority for single-user |
| Paginated backlinks / tag view | UI | Simple cursor pattern |
| Block ref scroll-to | Navigation | Depends on block ID stamp |
| Full-text search UI | Sidebar | FTS5 already built |
| File-mtime-based block ordering | Indexer | Requires fs::metadata |