Skip to content

Rolling state.json snapshots, and keep an unreadable state file instead of overwriting it #166

Open

Description

@AThraen

This was generated by AI during triage.

Summary

Keep rolling snapshots of state.json in addition to the single .bak, so a bad save (or a bad sequence of saves) can be rolled back further than one generation.

Motivation

StateService writes atomically and keeps a one-generation .bak (#88). It is rewritten on ~33 UI actions, though, so a mistake gets rotated out within seconds. Examples: a bulk close, a bad import, or a restore loop that sleeps everything.

Herdr (v0.9.2, session state):

  • keeps up to 48 snapshots in session-snapshots/, at most one every 15 minutes, skipping unchanged content;
  • keeps the timing across restarts, so a burst of changes can't push out older snapshots;
  • copies an unreadable save to session-backups/ before overwriting it, keeping the 3 most recent.

Proposal

  • Rolling snapshots. Inside StateService.WriteAsync (already under SaveGate, off the UI thread since fix(perf): take three blocking paths off the UI thread and the thread pool #160): if the last snapshot is older than 15 minutes and the content differs, copy the outgoing file to %AppData%\CodeShellManager\state-snapshots\state-<yyyyMMdd-HHmmss>.json, then prune to the newest 48.
  • Back up an unreadable state file. When LoadAsync falls back to .bak because the primary won't parse, copy the unreadable primary aside before the next save replaces it (keep 3). Today the next save overwrites it.
  • Discoverability. Add a Settings ▸ "Open state snapshots folder" link. A restore UI is not needed for v1.
  • --clean. Writes nothing in --clean mode (already true, since saves short-circuit).

Tests

Add to StateServiceTests:

  • the snapshot interval is respected;
  • unchanged content is skipped;
  • pruning keeps 48;
  • an unreadable primary is preserved.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions