Deferred. Not current work. None of these should interrupt v1.4 release work, and none is a merge blocker for anything already shipped. They are recorded here only so they do not evaporate with a merged PR review comment.
Each item has an explicit Trigger — the condition that makes it worth doing. Until that condition is met, the current code is correct and should be left alone.
All three came out of the #73 / #118 review (source-linked excerpts). The chain they belong to — Reader → SourceAnchor → excerpt → Note → openSourceAnchor() — is closed and in main; this is hardening of that chain, not repair of it.
1. appendExcerptCommand has a single global pending slot
let pending: AppendExcerptCommand | null = null
A command that arrives with no matching subscriber is held in one slot, so a second undelivered command for a different note overwrites the first.
Correct today: NotePanel mounts exactly one NoteEditor, so a command for the open note is delivered synchronously and never needs the slot; the slot only covers the "target editor has not mounted yet" window. noteId matching already prevents the cross-note misdelivery that mattered.
Trigger: multiple Note tabs, a background/secondary editor, or any flow that can leave more than one excerpt in flight at once. Then upgrade to a per-note queue.
Fix shape: Map<noteId, AppendExcerptCommand[]>; drain on subscribe; keep the existing noteId match and the entry-identity unsubscribe guard.
2. isExcerptSourceHref() matches with includes, not a prefix
href.includes('#know-note-source?')
An ordinary external link that happened to contain that fragment would be classified as an internal KnowNote anchor and would hijack the click (it would go through openSourceAnchor instead of openExternalUrl).
Correct today: every href this app generates starts with the fragment, and URLSearchParams percent-encodes #, so the marker cannot appear inside the anchor's own fields.
Trigger: opportunistic — fix it while touching link handling, or if a URL ever appears in a note that trips it. It is a small edge case, not a bug report.
Fix shape: match a strict prefix (and account for the base-resolved form, which is why it was written as includes in the first place), and keep the invariant that a non-excerpt link is never treated as one.
3. NoteEditor responsibilities are growing
The component now owns: the Markdown/Tiptap editor, the append-command subscription, source-availability marking, and the link click dispatch. That is 117 added lines in #118 and still readable, but the count of unrelated concerns in one component is worth watching.
Deliberately not split during #118: doing it then would have been a refactor with no second consumer to inform the boundary.
Trigger: a third source-link behaviour lands in the note body (e.g. highlighting all anchors of the current source, per-anchor actions, or a source-link inspector). Then the boundary is finally knowable.
Fix shape: extract useExcerptAnchors(editor, containerRef) covering the availability marking, the targeted-command subscription, and the click dispatch, leaving NoteEditor as the editor.
Deferred. Not current work. None of these should interrupt v1.4 release work, and none is a merge blocker for anything already shipped. They are recorded here only so they do not evaporate with a merged PR review comment.
Each item has an explicit Trigger — the condition that makes it worth doing. Until that condition is met, the current code is correct and should be left alone.
All three came out of the #73 / #118 review (source-linked excerpts). The chain they belong to —
Reader → SourceAnchor → excerpt → Note → openSourceAnchor()— is closed and inmain; this is hardening of that chain, not repair of it.1.
appendExcerptCommandhas a single global pending slotA command that arrives with no matching subscriber is held in one slot, so a second undelivered command for a different note overwrites the first.
Correct today:
NotePanelmounts exactly oneNoteEditor, so a command for the open note is delivered synchronously and never needs the slot; the slot only covers the "target editor has not mounted yet" window.noteIdmatching already prevents the cross-note misdelivery that mattered.Trigger: multiple Note tabs, a background/secondary editor, or any flow that can leave more than one excerpt in flight at once. Then upgrade to a per-note queue.
Fix shape:
Map<noteId, AppendExcerptCommand[]>; drain on subscribe; keep the existingnoteIdmatch and the entry-identity unsubscribe guard.2.
isExcerptSourceHref()matches withincludes, not a prefixAn ordinary external link that happened to contain that fragment would be classified as an internal KnowNote anchor and would hijack the click (it would go through
openSourceAnchorinstead ofopenExternalUrl).Correct today: every href this app generates starts with the fragment, and
URLSearchParamspercent-encodes#, so the marker cannot appear inside the anchor's own fields.Trigger: opportunistic — fix it while touching link handling, or if a URL ever appears in a note that trips it. It is a small edge case, not a bug report.
Fix shape: match a strict prefix (and account for the base-resolved form, which is why it was written as
includesin the first place), and keep the invariant that a non-excerpt link is never treated as one.3.
NoteEditorresponsibilities are growingThe component now owns: the Markdown/Tiptap editor, the append-command subscription, source-availability marking, and the link click dispatch. That is 117 added lines in #118 and still readable, but the count of unrelated concerns in one component is worth watching.
Deliberately not split during #118: doing it then would have been a refactor with no second consumer to inform the boundary.
Trigger: a third source-link behaviour lands in the note body (e.g. highlighting all anchors of the current source, per-anchor actions, or a source-link inspector). Then the boundary is finally knowable.
Fix shape: extract
useExcerptAnchors(editor, containerRef)covering the availability marking, the targeted-command subscription, and the click dispatch, leavingNoteEditoras the editor.