savinglisted
Install: claude install-skill C-Aniruddh/lattice
# Saving
Three ideas, and every failure mode in this skill follows from one of them.
- **The chain *is* the version.** `createStore` reads the current version off the migration
chain's head, so declaring version 7 while shipping a chain that ends at 6 is not a bug you can
write down.
- **Every failure is a value.** `open()` never throws, for any content whatsoever. Seven ways a
save fails to become a state, and every one degrades to a fresh game *with a report*.
- **A save stores causes, not consequences.** Persist the player's brand hue, never the
`#rrggbb` it derives to.
The alternative to a chain — `parsed.version === SAVE_VERSION` with a fallback to `newGame()` —
is not a migration policy. It is a delete. The game this kit was extracted from said so in its
own source: *"a bump is not a migration — it is a deletion of every player's campus."*
---
## A save, its chain, and its autosave
```ts
import { asEpochMillis } from '@latticekit/core';
import { browserStorage, createStore, migrations, scheduleFrom } from '@latticekit/persist';
import type { Recognize } from '@latticekit/persist';
import type { Loop } from '@latticekit/loop';
interface V1 { readonly version: 1; readonly coins: number }
interface V2 { readonly version: 2; readonly wallet: { readonly coin: number }; readonly hue: number }
// A recognizer returns the value TYPED, or throws naming the field. Never a boolean —
// a boolean has already discarded the value that was wrong, so it cannot name it.