Repository navigation
Date navigation triggers state_unsafe_mutation and leaves the app unresponsive - #1565
Conversation
…loses #1564) navigateDate() called onNodeIdChange and onTitleChange as two separate tabState writes, leaving a window where a subscriber could observe a tab whose title and content pointed at different dates. Added onNavigate / updateTabContentAndTitle to update both atomically in one store write. hydrateNode() also had no guard against a stale in-flight ensureNode() resolving after a newer navigation superseded it, and no error handling around the await, which produced the reported state_unsafe_mutation and unhandled promise rejection under rapid navigation or a slow/failed fetch. It now tracks the latest requested nodeId and discards stale responses, and catches ensureNode() failures instead of throwing. Co-Authored-By: Claude <noreply@anthropic.com>
Pragmatic Code Review — PR #1565Review Type: Initial Review Requirements Check (issue #1564)
Code Review Findings🟡 Important: "Typing
|
malibio
left a comment
There was a problem hiding this comment.
Comment-only review posted above: solid, well-tested fix for the atomicity/race-guard mechanism, but 2 of 6 acceptance criteria (slash-command node disappearance, post-navigation click-responsiveness) are unverified rather than demonstrated by this diff. Recommend a manual repro check before merge; not blocking.
…er 2)
Every viewer (BaseNodeViewer, DateNodeViewer, QueryNodeViewer,
CollectionNodeViewer, AiChatNodeViewer) computed a title and pushed it
into tabState via an onTitleChange callback — from onMount, from an
$effect, or from an input handler. Each push site was an independent
write racing against the same tabState store other reactive code reads,
which is the exact shape that produces state_unsafe_mutation.
Replaced all of it with computeTabTitle(), a pure function that derives
a tab's title from its content (nodeId/nodeType) and the current node in
sharedNodeStore, with a new pluginRegistry.getNodeTitle()/getTitle hook
for the one case that needs type-specific logic: date nodes, whose title
("Today"/"Tomorrow"/a date string) is computed from the id, not content.
Every other node type falls back to node.title || node.content — the
same value the removed pushes were already computing, just read instead
of written.
onTitleChange, onNavigate, and disableTitleUpdates are gone from every
viewer and from the shared NodeViewerProps interface; nothing pushes a
title anymore, so there is no longer a mechanism to reintroduce this bug
through a future viewer. tab-persistence-service's date-title-recompute
migration step is also gone since node-tab titles are never persisted or
read from storage anymore — they're computed fresh on every render.
Co-Authored-By: Claude <noreply@anthropic.com>
Pragmatic Code Review — PR #1565 (Re-review of commit a4b3ced)Review Type: Re-review of new commit since prior review (314b709 → a4b3ced). Scope limited to what changed in this commit; not re-litigating findings already resolved or unrelated to it. Prior Review Findings — Disposition
Architectural Assessment of the New CommitThis is a legitimate root-cause fix, not just closing the prior review's comment. The prior commit made the symptom (title/content desync) atomic via Verified claims from the task brief, all confirmed by reading the diff directly:
FindingsSuggested Improvements
Nitpicks
Testing AssessmentIndependently re-ran the five test files most relevant to this commit ( The deleted test blocks ( Recommendation: APPROVEThis commit is a clean, well-reasoned resolution of the prior review's Important finding (b), and it resolves it by removing the vulnerable pattern entirely rather than guarding against misuse of it — a stronger and more idiomatic fix given Svelte 5's rune model. The architectural conversion (push-based title mutation → pure derivation) is applied consistently across all 7 viewer components with no stragglers, the two production-code deletions in |
malibio
left a comment
There was a problem hiding this comment.
Re-review of a4b3ced (GitHub blocks self-approval on this account, so filing as COMMENT with an approve recommendation): prior Important finding (b) is resolved by fully removing the push-based title mechanism rather than guarding it — stronger fix than suggested. All viewer call sites migrated consistently, deleted tests correctly track deleted code, targeted test runs clean (215/215), no regression in svelte-check. One minor gap noted (computeTabTitle lacks direct unit tests) but not blocking. Recommendation: APPROVE — see full review comment above for details.
… assumption comment - computeTabTitle() only had indirect coverage via getNodeTitle's tests; added direct unit tests isolating its own branching (tab-type gating, getNode lookup, fallback-to-tab.title chain, formatTabTitle truncation). - The "node.title is backend-computed" assumption getNodeTitle relies on used to be explained in a comment on the old base-node-viewer.svelte code that this PR deleted; restored an equivalent note on getNodeTitle itself, pointing at NodeService::compute_title in the Rust core. Addresses the two minor suggestions from the pragmatic-code-review re-review of commit a4b3ced.
Addressed review feedback (commit c04f8f5)Both minor suggestions from the re-review of commit a4b3ced:
No other findings from either review round remain open. Re-Review DecisionDecision: NO RE-REVIEW NEEDED Rationale: Both changes are additive (new test file, one restored comment) with no logic changes to already-reviewed code. |
Closes #1564