A live view needs a starting snapshot and subsequent changes from a compatible point in the server log. Fetching a snapshot and then opening a change stream can leave a gap between those steps unless the snapshot carries a cursor or the stream can replay from a position tied to that snapshot. A delta cursor is a server-issued opaque position, not an array index invented by the client. Apply each change once, in order, and validate that it belongs to the same account, query, and authorization scope. If the replay window expires or a sequence gap appears, discard the cursor and fetch a new snapshot rather than pretending the view is current.
Snapshot, Delta Cursor, and Gap Recovery
Working case
The case queue loads 62 rows and then subscribes to updates. During the two seconds between the list response and subscription, case 47 changes owner. A stream that begins only with new events misses the change, leaving a stale row forever. The server instead returns a snapshot with cursor c-29 and replays all changes after c-29. If the client reconnects after the cursor expires, it fetches a new snapshot and clears the old delta state. A filter change from Open to All also requires a new scope; reusing the old cursor may omit records or expose the wrong set.
Implementation boundary
function applyOrderedChange(lastSequence, change) {
if (change.sequence === lastSequence + 1) return change.sequence;
if (change.sequence <= lastSequence) return lastSequence;
throw new Error("gap-requires-snapshot");
}
console.log(applyOrderedChange(29, { sequence: 30 }));
// Output: 30The numeric helper illustrates gap detection. Real cursors can be opaque and may encode tenant, query, version, and expiry. The server should issue a snapshot and cursor with a consistent relationship, document replay retention, and reject a cursor for another account or filter. The client applies deduplicated changes to a keyed record store and keeps tombstones long enough to process deletes. A gap, rejected cursor, or changed query triggers a full scoped snapshot; an ordinary reconnect can use the last confirmed cursor. Announce stale state while recovering and avoid presenting a partially rebuilt list as authoritative.
Cost and boundaries
Applying n ordered deltas is O(n) work and can avoid repeatedly transferring a full m-record snapshot. Retaining a replay log costs server storage proportional to change volume and retention length. A full snapshot costs O(m) transfer and client reconciliation; it is the safe fallback after a gap. Tombstone storage also grows and needs compaction rules. A tiny replay window makes reconnects expensive, while an unbounded window raises server cost. Measure reconnection age, gap frequency, bytes transferred, and time until a fully current view, including permission and filter changes.
Failure trace
The client loads a list at time T, opens a stream at T+2 seconds, and assumes no changes occurred in between. A case assignment from that interval is permanently missing. Use a cursor that links snapshot to replay. Another defect treats a sequence jump from 30 to 32 as a harmless dropped animation; the queue silently loses a case update. Stop applying deltas and fetch a new snapshot. A third defect reuses a cursor after a filter change, causing incorrect membership. Scope or invalidate cursors whenever the query or actor changes.
Verification
- A change between snapshot and subscription is not lost.
- Duplicate or missing deltas have explicit outcomes.
- Cursors cannot cross account or query boundaries.
Practice drill
Create a consistent 62-row snapshot with cursor c-29. Insert a case change between snapshot creation and stream subscription; verify replay includes it. Duplicate sequence 30, omit sequence 31, and inspect dedupe and gap recovery. Expire the cursor and ensure a fresh snapshot replaces stale data. Change the filter and actor while a reconnect is pending; old deltas must not enter the new view. Delete a case, replay the delete, and verify the tombstone prevents a late duplicate add from reviving it.
Decision note
Tie snapshots to replay positions, and recover from missing history with a fresh scoped snapshot.
Common Mistakes
- Opening a stream after a snapshot with no bridging cursor.
- Ignoring sequence gaps as cosmetic issues.
- Reusing a cursor for a different filter or account.
Connected lessons
Cross-Tab and Offline Data Coordination; Cross-Tab Invalidation and Version Checks; Offline Outbox, Idempotency, and Replay; Collaborative Conflicts and Presence Expiry; Live Update Reconnect and Event Ordering; Stream Cancellation and Partial-Result Contract; Search Filters and Result Cursors.
Apply and check
Build Project: multi-tab offline case review and review Web Development: operations and sync decisions quiz.
