Skip to content

Make CompositeCommand.Undo all-or-nothing - #86

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/undoredo-82-composite-undo-rollback
Sep 26, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/undoredo-82-composite-undo-rollback

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #82

What was wrong

CompositeCommand.Undo() kept going when a sub-command's Undo threw, then rethrew. Since #75, the stack keeps its position when Undo throws, so it still recorded the composite as fully applied. The retry then undid the already-undone parts a second time. In the issue's repro that leaves a=-1.

Change

  • Undo() now stops at the first failure and re-Executes the sub-commands it already undid in this call, in forward order, ignoring restore errors. It then rethrows the original exception. This mirrors the rollback in Execute(). Redo() goes through Execute(), so it was already all-or-nothing.
  • CompositeCommand_UndoFailure_DoesNotAffectOtherCommands asserted the old partial-undo behaviour. It is renamed to CompositeCommand_UndoFailure_LeavesEveryCommandApplied and now expects the composite to stay fully applied.
  • New test CompositeCommand_UndoFailureThenRetry_UndoesEachCommandOnce is the issue's repro run through UndoRedoService. It expects a=1 b=1 at position 0 after the failed Undo, and a=0 b=0 at -1 after the retry.

Verification

  • Full suite on this branch: 58/58 pass.
  • With the fix reverted, both composite tests above fail.

🤖 Generated with Claude Code

https://claude.ai/code/session_016ToeUpj3nH61YEnatKdb8d


Generated by Claude Code

When a sub-command's Undo threw, the composite kept undoing the rest and
rethrew, but the stack (since #75) keeps its position on a failed Undo.
The next Undo then undid the already-undone parts a second time. Stop at
the first failure and re-execute what this call undid, mirroring the
rollback in Execute(). Redo goes through Execute() and was already safe.

Fixes #82

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ToeUpj3nH61YEnatKdb8d
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 46ea529 into main Sep 26, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the claude/undoredo-82-composite-undo-rollback branch September 26, 2026 09:53
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.

CompositeCommand whose Undo half-fails gets its already-undone parts undone twice on the next Undo

2 participants