DEV Community

qnbs
qnbs

Posted on AI-assisted

Safe Snapshot Restore Under Project Replacement

A restore button makes a simple promise: “Put this project back the way it was.” The implementation has a harder job. The selected snapshot may be older, the editor may have changed since the user opened the restore dialog, and another writer may have replaced the project in the meantime.

Treating restore as an ordinary save misses those races. It is safer to treat it as a replacement transaction with its own admission and commit rules.

First decide whether the snapshot is admissible

A snapshot is historical data. Its format may differ from the current model, and the product may intentionally support snapshots that are older but still exportable. The snapshot policy therefore cannot simply be “serialize the current project model.”

WorldScript Studio separates snapshot admission from canonical project egress. The snapshot path preserves supported stored snapshots under its own rule, while refusing shapes the application cannot safely accept. That lets a recovery artifact remain useful without pretending that every old structure is safe to load as the active project.

An accepted snapshot also needs a carrier. Where the storage path preserves exact text, the admitted snapshot’s text can travel with its parsed representation. Where the store holds structured values, its boundary is different. The carrier must be accepted for the specific project replacement, not copied into an unrelated future project.

Then prove the replacement still has authority

An editor can be looking at the same project identifier while the project’s durable authority has changed. A stale tab or delayed save may still carry an older view of the project.

The replacement path binds its baseline to the storage target, authority, and editor epoch. When a snapshot is restored, the editor checks that its identity and epoch still match before accepting the new carrier. The IndexedDB authority uses generation compare-and-swap: the candidate replacement is committed against the current generation, rather than blindly overwriting whatever is there.

This gives the commit a clear meaning. If the comparison fails, the writer does not get to declare itself current. It must stop and let the application recover or retry with fresh authority.

Advance the baseline after the write

There are two moments that can look like success: the UI has rendered the restored snapshot, and the durable store has committed it. Only the second should advance the editor’s baseline.

If the editor advances early and the write later fails, subsequent edits may proceed from a replacement that never became authoritative. If it advances only after commit, the old baseline remains visible to the concurrency check until the new data is durable.

This rule also clarifies why a restored snapshot is saved as a whole replacement, rather than merged as if it were a set of ordinary field edits. A restore changes the document’s content and may change which carrier should seed future saves.

Fail closed when the state is ambiguous

The autosave writer rejects malformed data, unsupported future shapes, unsupported older shapes, and generation contradictions instead of routing them to a fallback save path. Fallbacks can look helpful, but a write to the wrong authority turns uncertainty into silent replacement.

A user-facing recovery path can still explain what happened and offer a safe retry. The important property is that a refusal does not mutate the project into a blank or misleading state.

The release record for the #553 work also calls out remaining restore ingress. That is useful discipline: one correct restore path is not proof that every library or recovery flow uses it. Article diagrams and claims should show the path that is implemented and leave the residual path marked as open.

The transaction checklist

Before calling a restore complete, ask:

  • Did the snapshot pass the format and support policy?
  • Is its preserved carrier bound to the intended project?
  • Does the writer still own the current authority and epoch?
  • Was the replacement committed against the current durable generation?
  • Did the baseline advance only after the commit?
  • If any answer is unknown, did the system stop without mutating a different authority?

These are concrete, reviewable conditions. They turn “restore is safe” into an explanation a reader can verify against code and tests.

Continue reading

Next in Engineering for No-Loss Data Integrity: Why Backups Should Exclude Machine-Local Metadata applies the portability boundary to backups.

Related: Preserve First: Recovery Design for Local Creative Data covers the recovery-first design that complements snapshot restore.

Practical extension: make restore a visible transaction

Treat restore as a sequence whose commit point the user can understand:

  1. Read the chosen snapshot without changing the active project.
  2. Validate format, version, project identity, and required fields.
  3. Preserve the current project as a recovery point.
  4. Stop or invalidate writes that were created against the prior project generation.
  5. Persist the replacement and wait for the durable operation's success signal.
  6. Advance the active baseline only after that signal.
  7. Reopen the result and report what was restored.

If any step fails, keep the previous active state and recovery point available. Do not update the in-memory baseline optimistically and then hope storage catches up. In IndexedDB, group logically coupled changes in one transaction; separate clear and write operations can leave an empty store if execution stops between them. The MDN IndexedDB guide explains transaction completion and abort behavior.

Test the race that ordinary happy-path restore misses: begin restore, edit the project or select another project, then resolve the pending storage operation. The older operation must not overwrite the newer authority. Record the project ID, generation, snapshot ID, transaction result, and post-restore read-back so a support report can distinguish “selected,” “written,” and “verified.”

Top comments (0)