Follow-up from #34 review. Perf concern, not a correctness bug.
Both ChatView.svelte and StepTree.svelte derive from buildTree(preview.doc):
const built = $derived(preview ? buildTree(preview.doc) : null);
$derived dedups when its deps haven't changed, but the dep here is effectively preview — any mutation to the slice (treeQuery typing, treeFilter tab, selectedStep, viewMode toggle, expandedBranches) invalidates and re-runs buildTree, which walks every step to build stepMap / childrenMap / headSet. For a 1700-step doc that's a lot of redundant O(N) work.
Fix
Narrow the dep to preview.doc specifically — which is stable across most preview mutations:
const doc = $derived(preview?.doc ?? null);
const built = $derived(doc ? buildTree(doc) : null);
Svelte 5's $derived identity-compares, so when preview is spread-replaced but doc is the same reference, the second derived won't re-run.
Verification
Add a console.count("buildTree") temporarily, type in the tree search box, confirm it fires once per keystroke today (bad) vs zero times after the fix (good).
Follow-up from #34 review. Perf concern, not a correctness bug.
Both
ChatView.svelteandStepTree.sveltederive frombuildTree(preview.doc):$deriveddedups when its deps haven't changed, but the dep here is effectivelypreview— any mutation to the slice (treeQuerytyping,treeFiltertab,selectedStep,viewModetoggle,expandedBranches) invalidates and re-runsbuildTree, which walks every step to buildstepMap/childrenMap/headSet. For a 1700-step doc that's a lot of redundant O(N) work.Fix
Narrow the dep to
preview.docspecifically — which is stable across most preview mutations:Svelte 5's
$derivedidentity-compares, so whenpreviewis spread-replaced butdocis the same reference, the second derived won't re-run.Verification
Add a
console.count("buildTree")temporarily, type in the tree search box, confirm it fires once per keystroke today (bad) vs zero times after the fix (good).