Skip to content

Keep a trimmed stack dirty at -1 through save, load, and restore [major] - #122

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/83-persist-initial-state-clean
Sep 29, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/83-persist-initial-state-clean

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #83

What was wrong

SaveBoundaryManager tracks whether position -1 still holds the clean initial state. That flag was never saved, and RestoreFromState calls Clear(), which sets it back to true. Take a stack whose oldest commands were trimmed and that has no save boundary. After any LoadStateAsync or RestoreFromState, including a restore from its own GetCurrentState(), it reported no unsaved changes at -1. This brought back #76.

Change (option 1 from the maintainer's decision, a major bump)

  • ISaveBoundaryManager gains InitialStateIsClean { get; } and SetInitialStateClean(bool).
  • IUndoRedoSerializer.SerializeAsync gains an initialStateIsClean parameter, placed before the cancellation token.
  • UndoRedoStackState gains InitialStateIsClean { get; init; } = true. GetCurrentState() fills it in.
  • RestoreFromState restores the flag after Clear() and before recreating save boundaries. Restoring a boundary still clears the flag.
  • JsonUndoRedoSerializer writes initialStateIsClean. When the field is missing it reads it as true, so data saved before this change still loads with the meaning it had.
  • docs/serialization.md shows the new signature and property.

Tests

New tests in SerializationTests:

With the SetInitialStateClean call in RestoreFromState taken out, the three repro tests fail. With it in place, all 121 tests pass on net10.0.

Existing SerializeAsync call sites in the tests now pass the new argument.

Notes

🤖 Generated with Claude Code

https://claude.ai/code/session_01XEFMRMk4z5RaHqHVp4rTtj


Generated by Claude Code

The "initial state is clean" flag on SaveBoundaryManager was not part of the
saved state, and RestoreFromState's Clear() reset it to true. A stack whose
oldest commands were trimmed, with no save boundary, reported no unsaved
changes at -1 after every LoadStateAsync or RestoreFromState, which is #76
again.

Breaking changes, per the maintainer's decision on #83:
- ISaveBoundaryManager gains InitialStateIsClean and SetInitialStateClean(bool)
- IUndoRedoSerializer.SerializeAsync takes an initialStateIsClean parameter
- UndoRedoStackState gains an InitialStateIsClean init property, default true

JsonUndoRedoSerializer writes the flag and reads a missing one as true, so
data saved before this change still loads with its old meaning.

Fixes #83

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XEFMRMk4z5RaHqHVp4rTtj
@sonarqubecloud

Copy link
Copy Markdown

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.

After RestoreFromState/LoadStateAsync, a never-saved state at position -1 reports no unsaved changes again (#76 regresses on load)

2 participants