Skip to content

Record node toggles in undo history#58

Open
kmatzen wants to merge 1 commit into
mainfrom
fix-toggle-node-history
Open

Record node toggles in undo history#58
kmatzen wants to merge 1 commit into
mainfrom
fix-toggle-node-history

Conversation

@kmatzen

@kmatzen kmatzen commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Fixes #54.

toggleNode mutated the tree without pushing a history entry, so tree and history[historyIndex] diverged as soon as a node was disabled. A subsequent undo then restored a snapshot predating both the toggle and the edit before it — discarding one more edit than the user asked to undo.

The new test demonstrates it directly. Toggle a node after a parameter change, undo, and pre-fix the parameter edit is gone too:

AssertionError: expected undefined to be 7

Disabling a node changes the rendered geometry and the exported mesh, so it is a document mutation, not view state. Compare toggleExpanded and selectNode, which are genuinely view-only and correctly stay out of history.

Also fixed

undo and redo restored only tree and historyIndex, never selectedNodeId. Both replace the tree wholesale and can land on one where the selected node no longer exists. Consumers mostly do findNode(...) and bail on null, so it degraded quietly rather than throwing — but removeNode was the only action that cleared a stale selection. A surviving() helper now drops the id when the restored tree doesn't contain it.

Verification

check result
tsc --noEmit exit 0
store suite, this branch 28/28 pass
new tests, pre-fix code 4 fail, 1 pass

The 23 pre-existing store tests still pass, which is the check that mattered most here — toggleNode now writes history, and nothing else in the suite depended on it not doing so. The new test that passes pre-fix asserts a selection surviving an undo, which the old code also did.

Scope note

The issue proposes extracting a commit(newTree) helper and routing all ~13 mutation sites through it, which would remove this bug class rather than this instance. I did not do that here: it is a much larger diff touching every mutating action, and I would rather it be reviewed deliberately than land as a side effect of a bug fix. The issue stays open-worthy on that point — happy to follow up with the refactor as its own PR if you want it.

🤖 Generated with Claude Code

Fixes #54.

toggleNode mutated the tree without pushing a history entry, so `tree` and
`history[historyIndex]` diverged as soon as a node was disabled. A
subsequent undo then restored a snapshot predating both the toggle and the
edit before it -- discarding one more edit than the user asked to undo. The
new test demonstrates this directly: toggle after a parameter change, undo,
and pre-fix the parameter edit is gone too.

Disabling a node changes the rendered geometry and the exported mesh, so it
is a document mutation, not view state. Compare toggleExpanded and
selectNode, which are genuinely view-only and correctly stay out of history.

Also clears a dangling selectedNodeId on undo/redo. Both restore the tree
wholesale and can land on one where the selected node no longer exists;
consumers mostly do findNode(...) and bail on null, so it degraded quietly
rather than throwing.

The tests fail 4/5 against the pre-fix code. The one that passes asserts a
selection surviving an undo, which the old code also did.

This is the focused fix, not the commit() refactor the issue proposes as the
better long-term shape -- see the PR for why.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

toggleNode desyncs the tree from undo history

1 participant