Skip to content

Type persisted snapshot round-trips - #5646

Merged
davidkpiano merged 2 commits into
nextfrom
feature/priceless-aryabhata-3c6ef7
Aug 17, 2026
Merged

Type persisted snapshot round-trips#5646
davidkpiano merged 2 commits into
nextfrom
feature/priceless-aryabhata-3c6ef7

Conversation

@davidkpiano

@davidkpiano davidkpiano commented Aug 14, 2026

Copy link
Copy Markdown
Member

What changed

  • actor.getPersistedSnapshot() now returns Snapshot<unknown> & PersistedSnapshotFor<TLogic>, branding the persisted snapshot with its source logic's machine id/version.
  • ActorOptions['snapshot'] now uses a new RestorablePersistedSnapshotFor<TLogic> type that checks the machine id only: restoring a snapshot into a machine with a different id is a compile-time error (mirroring the existing runtime guard), while snapshots from other versions of the same machine remain assignable, since cross-version restore via migrate is a supported runtime path. Unbranded (e.g. JSON-revived) snapshots remain accepted.
  • New type tests in packages/core/test/persistedSnapshot.types.test.ts: castless round-trip (plain + versioned), cross-version accepted, cross-id rejected, revived JSON accepted.
  • Removed the now-unneeded as AnyMachineSnapshot cast and @ts-ignores in examples/express-workflow.
  • The svelte UseActor test fixture's persistedState prop was retyped from AnyMachineSnapshot (incorrect — a persisted snapshot is not a machine snapshot) to Snapshot<unknown>, dropping its cast.

Why

Persist/restore round-trips previously required casts because getPersistedSnapshot() returned an unbranded Snapshot<unknown> with no link to its source logic. The brand makes same-machine round-trips castless and catches cross-machine restores at compile time.

Reviewer notes

  • A first attempt checked version strictly; that broke the versioning/migration tests, which intentionally restore old-version snapshots into newer machines — hence the id-only check on the restore side.
  • The cross-id runtime test in machineVersions.test.ts now carries an intentional @ts-expect-error; a stale version-mismatch @ts-expect-error in machineVersions.types.test.ts was removed.
  • Verified: repo tsc clean, 2159 core tests pass, svelte tests pass, lint/format pass. Changeset included.

Open in Devin Review

actor.getPersistedSnapshot() now returns a snapshot branded to its
source logic, and ActorOptions['snapshot'] accepts persisted snapshots
from any version of the same machine ID (cross-version restore stays
assignable for runtime migration via migrate). Restoring into a machine
with a different ID is now a compile-time error, mirroring the existing
runtime guard.
@changeset-bot

changeset-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b227c42

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
xstate Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@davidkpiano
davidkpiano changed the base branch from main to next August 15, 2026 00:57
devin-ai-integration[bot]

This comment was marked as resolved.

Addresses Devin review: the persisted-snapshot brand collapsed to never
for unversioned machines, so cross-ID restore was silently accepted.
The brand identity now requires only a machine id (version falls back
to string), and provide() returns 'this' so the MachineIdentity
intersection from createMachine survives providing implementations.
@davidkpiano
davidkpiano merged commit 2e77ff6 into next Aug 17, 2026
2 of 3 checks passed
@davidkpiano
davidkpiano deleted the feature/priceless-aryabhata-3c6ef7 branch August 17, 2026 21:41
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