Skip to content

fix(editor): let Undo revert every write of a multi-request gesture - #35

Open
helloforvets wants to merge 1 commit into
flowtricks:mainfrom
helloforvets:fix/undo-multi-request-gesture
Open

helloforvets wants to merge 1 commit into
flowtricks:mainfrom
helloforvets:fix/undo-multi-request-gesture

Conversation

@helloforvets

Copy link
Copy Markdown

What

Undo after deleting a node restores the markup but not the imports the delete pruned. Astro then fails the page with <Component> is not defined.

Why

A delete is one gesture of two requests (removeNode in App.tsx): the remove-node, then a set-frontmatter that drops the imports nothing reads any more. The undo step is owed one write when the gesture is queued (addGesture), so the first reply settles it to applied and recordApplied discards the second write's inverse. revertedSteps then reverts only the removal.

Reproduced on 0.1.37: select a wrapper element holding several components in the Navigator, press Backspace, press ⌘Z. The wrapper comes back; its imports do not. The log shows two writes for the delete and one for the undo.

Fix

sendGesture owes the step one more write right before each later request goes out (oweAnother). Owing lazily keeps a retried gesture honest: a request that never went out is never waited for. A record no step reads (a preview's, dropped) stays dropped.

Tests

  • pageEdits.test.js, the fake-send outcome table: the step holds every write of a two-request gesture; nothing extra is owed when the first request is refused with a retry.
  • A new end-to-end case through main's real handlers: delete a wrapper, let the prune follow, revert the step newest first, expect the original file byte for byte.

Both fail without the fix (the undo step holds every write of the gesture, the step waited for both writes) and pass with it. npm run check:changed and the full gate pass.

Aside, unrelated to this change: on a UTC+10 machine the full gate fails one pre-existing case, renderer/history/historyPanel "today is Today". Its fixed now of 15:00Z minus two hours crosses local midnight there, so the group reads "Yesterday". It passes under TZ=UTC, as CI runs.

🤖 Generated with Claude Code

A gesture that writes more than once — removing a node whose unused
imports are then pruned, say — owed its undo step one answer, so the
second write's inverse was dropped and Undo put the markup back without
the imports, leaving the page with a component it no longer declared.

Every send now goes through one loop (sendRequests), and before each
request after the first that loop owes the step one more answer
(oweAnother): a pending step waits for one more, a step that had just
settled is pending again with what it already holds. The replacement
fallback sends several node rewrites through the same loop, so it is
covered the same way. Tests pin a two-write gesture's undo and redo,
and a refusal mid-way.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@helloforvets
helloforvets force-pushed the fix/undo-multi-request-gesture branch from 598e2b6 to 685bf98 Compare October 10, 2026 23:47
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.

1 participant