Lifecycle and recovery
Use Plot.onLifecycleChange() to pause during an interruption and rebuild from
current state when Plot is connected. A connected callback runs only after
Party, Game State, every player's Player Data, and synchronized time are ready
to read together. Register it before Plot.ready() to handle startup as well
as later recovery.
The callback receives only 'connected' or 'disconnected'. Registering before
readiness does not start Plot or emit an initial disconnected notification; its
first callback is connected after the complete initial state is installed,
before ready() resolves. Registering after startup immediately calls the
listener with the established current status. The method returns an unsubscribe
function that is safe to call more than once.
Rebuild the state your message handlers depend on synchronously in the connected callback. Plot does not await a returned promise before continuing with retained messages. A listener error is reported without stopping other listeners.
Lifecycle notifications do not describe ordinary data changes. Another player's
arrival or departure, a state write, or a latest-channel outage does not itself
notify this listener. Keep using focused onChanged() and party events for live
changes. Complete per-domain subscribe() methods also remain available when a
view needs that domain's initial, change, and recovery snapshots.
Recover before replaying events
During an interruption, Plot reports disconnected and keeps the last readable state, which may be stale. Recovery installs all current synchronized state, calls pre-registered per-domain recovery subscribers, then reports connected through pre-registered lifecycle listeners. A listener registered inside another callback still receives the current status immediately. Retained reliable messages follow these callbacks in accepted order, before live traffic resumes. Missed state changes become one current snapshot; Plot does not replay every intermediate state revision.
Replayed events are historical relative to that snapshot. If Game State already includes a solved puzzle, a replayed puzzle-solved event must not award its points again. Render facts from synchronized state and use channels for moments. Store player choices in Player Data and shared results in Game State.
Recovery in a surviving page is automatic and does not need another
Plot.ready() call. A replacement iframe is a new page and calls ready() as
part of its normal startup. Browser-hosted game logic still pauses while that
host's browser is suspended; Plot restores data, not code that never ran.
Optional recovery diagnostics
Plot.connection.status and isConnected provide current status without a
listener. Plot.connection.recovery is null before the first complete state
installation. After installation it is an immutable { kind, replayGap } value,
updated before the connected lifecycle callback and retained during a later
disconnect.
For example, a game with an event-only activity log can discard an incomplete log after reconnecting:
Ordinary data writes do not change the recovery kind. A newly reported replay gap updates the diagnostics without creating a lifecycle notification. Games that maintain event-only history can also check this value while processing channel messages. These diagnostics describe the installed recovery state; they are not a stream of gameplay changes.
Five-minute reliable replay
An activated player can temporarily disconnect, switch apps, or reload and recover current state plus unreceived reliable events retained for five minutes. Retention is measured from each event's admission. The buffer has finite message and byte limits. Plot applies backpressure before accepting traffic that would require dropping an unexpired event; unlimited message rates are not supported. Latest channels are lossy and never replayed.
After expiry, or when a crash snapshot identifies lost transient history,
Plot.connection.recovery.replayGap describes the known missing delivery range:
This means deliveries 13 through 19 are unavailable. These numbers are diagnostic positions, not game action IDs. A gap does not undo the installed synchronized state. Rebuild event-only presentation from current state, and avoid showing a complete event history when Plot reported a gap.
Messages admitted after the last crash snapshot may leave no saved delivery
position. A checkpoint-restored recovery therefore signals possible history
loss even when replayGap is null.
Service updates and unexpected crashes
Normal accepted writes become authoritative immediately. Plot periodically saves a complete state snapshot for crash recovery; each write does not wait for a disk save. Before a planned service update, Plot saves all accepted state and unexpired reliable history, then restores the same game after restart.
An unexpected crash may restore an older state snapshot and lose transient channel events. A newly started game can be lost if it has not been snapshotted yet. Render the restored state rather than insisting that an old local score, revision, or phase must remain current. Plot permits checkpoint rollback only at an explicitly validated recovery boundary; a late ordinary response cannot overwrite newer state.
Checkpoint recovery also discards queued outgoing channel messages from before the crash. Plot does not submit those stale effects against rolled-back state. Ordinary reconnects and completed planned updates preserve queued reliable work.
An uncertain old write may reject with operation-superseded when its exact
outcome is no longer available. The installed state remains authoritative.
Inspect state and any game-owned action receipts before submitting another
non-idempotent action; Plot does not rerun the old updater to guess what happened.