Define the promise before the schema
Caveman Taxi promises campaign progress and stars on the same browser and device. Super Air Hockey promises tickets, unlocks and event progress. GridInc and BuyoutInc promise a persistent economy with offline earnings. Those player promises determine which state is durable and which state can be reconstructed.
A current puck position does not belong in a Super Air Hockey save. An unlocked mallet does. A transient animation can disappear. A purchased company cannot. The save model becomes smaller and safer when it stores player consequences instead of every variable in memory.
Version the meaning as carefully as the shape
Schema migration is often described as renaming fields. Balance changes are harder. If an upgrade used to cost one amount and now costs another, the loaded save still needs a coherent economic meaning. The migration must preserve the player's achievement without granting an accidental windfall or erasing progress.
Every durable payload should carry a version. Migrations should move forward in explicit steps, remain testable with real old fixtures and stop safely when the input is unknown. Silently coercing a damaged save into plausible data is how corruption becomes permanent.
Offline progress is a balance system with a clock
An idle game stores enough state to calculate what happened while the tab was closed. The elapsed time needs bounds, the earning model needs a version, and the result should return the player to an interesting decision. A giant number with nothing useful to buy is a failed return session.
Clock changes and long absences need explicit policy. So does an update that changes production rates. I prefer a calculation that can explain itself in a return summary. If the game cannot account for the result, neither the player nor the developer can trust it.

Storage providers should be replaceable
An owned website may use browser-local storage while a portal requires its data service. The game should ask a storage interface to load and save. It should not teach every progression system which SDK happens to be hosting the page.
Caveman Taxi's target profile selects the provider at build time. That keeps the save contract stable while the persistence mechanism changes. It also makes local development honest because a test provider can reproduce failure without pretending to be a live portal.
Design the failure state before it happens
Storage can be unavailable, full, blocked or corrupt. The game needs a defined response for each case. A fresh session may be safer than loading half a company. An import or recovery path may be justified for a long-running save. Repeated write failure should become visible instead of allowing false confidence.
Save fixtures and migration checks stay beside the release rules. Every meaningful schema change is tested against old state before deployment. A feature is incomplete until it can coexist with the players who arrived before it.
The save system holds the consequences a player earned. It needs explicit versions, tested migrations and a visible failure policy before those consequences can be trusted to last.
