Editor undo/redo is still non-functional — handleUndo/handleRedo never call setPaths (re-opens #70 false-positive close) #89
Labels
No labels
blocked:commit-ready-failed
blocked:gate-fetch
blocked:gate-lint
blocked:gate-plan
blocked:gate-research
blocked:needs-attention
blocked:needs-decision
blocked:needs-human
blocked:no-changes
blocked:verify-failed
bug
deferred
feature-request
in-progress
needs-decompose
needs-triage
quickfix
security/medium
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/Kimi_Agent_Brother_10_Digitizing_App#89
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Where:
src/pages/Editor.tsx:408-418(handleUndo,handleRedo).Bug:
handleUndoandhandleRedoonly adjusthistoryIndex; they never callsetPaths(history[…]). The canvas consumespathsas a prop (EditorCanvas.tsx:16), so without a state update onpaths, the canvas never re-renders.The
canUndo/canRedoflags computed atEditor.tsx:507-508and:516-517correctly reflecthistoryIndex, so the buttons enable/disable on time. But the canvas, which only re-renders when thepathsprop changes, never updates. Visually: click Undo / press Ctrl+Z → button disables, nothing on canvas changes. Click Redo → button enables, nothing happens. Repeat 49 times → history is fully traversed, canvas still identical.This was filed as #70 ("Editor undo/redo is non-functional (history never advances, no state snapshots taken)") on 2026-09-14 03:17 UTC and closed 23 minutes later (commit
f68a671). That close was a false-positive: the commit only added twovi.mock(...)lines toEditor.test.tsxso the smoke test could mount<Editor />(withoutAnimatePresence/ExportDialogmocks). It added no assertions on undo/redo behavior, nosetPaths(history[…])calls. The smoke test (Editor.test.tsx:45-65) only verifies that the layout zones render and that the filename snapshot round-trips — neither of which exercises undo/redo. So #70 was closed without the bug being fixed.The
pushHistoryandsetHistoryIndexplumbing was added correctly (Editor.tsx:184-194, plus the seven call sites at L256, L280, L293, L319, L351, L396, pluscommitDigitizedResultanalog), so history DOES advance now (history.length grows beyond 1 when the user mutates a node, andcanUndoflips true on the next render). The new bug is purely in the read side — the undo/redo handlers don't restorepathsfrom the snapshot at the new index.Reproduction (any image uploaded + Confirm & Edit, or directly from
/editorwith the demo paths):/editoropens withpaths = DEMO_PATHS(or whatever the snapshot has).select_nodesmode, drag it ~10 px.historyshows 5–10 entries from the drag,historyIndexdecreased to 1 — butpathsis still the post-drag state.)Severity: high. The Editor's primary safety net (undo) is missing. Users will lose work after any mutation. The buttons render enabled but are inert — classic "clickable but does nothing" class, same family as #58 (nav links) and #71 (Export PES / Settings).
Fix consistent with existing patterns: Mirror
useWorkspace.ts:118-127(pushHistory) which already does this correctly. The Worker should:handleUndo(Editor.tsx:408), aftersetHistoryIndex(historyIndex - 1):historyIndexhere is the closure-captured value; the read order matters — capture the new index first, then readhistory[newIndex]. Cleanest: compute the new index, then call both setters with the computed value: (Same shape forhandleRedowithnewIndex = prev + 1and the upper-bound guard.)src/pages/Editor.test.tsxthat:EditorCanvaswith a prop-recorder that exposes the latestpathsprop.handleUndo(via the keyboard shortcut mock firingonUndo).pathsmatches the snapshot at the prior history index.The existing
f68a671mocks were insufficient — they let the smoke test mount but didn't actually exercise undo. The new test should fire the shortcut handler and assert the prop changed.Cross-reference: #70 was closed false-positive on 2026-09-14; this issue is its re-open. The original commit's only contribution (
AnimatePresence+ExportDialogmocks) is still useful — leave it. The fix is purely additive in the handler bodies.