An offline-first client never blocks on the network: every edit is appended to a local, ordered mutation log while the device has no connection. Each entry is {recordId, value, t}. If the same record is edited five times before the next sync, the raw log holds five entries for it.
// Last-write-wins coalescing (a Map keeps only the newest entry per key)
const coalesced = new Map();
for (const m of rawLog) coalesced.set(m.recordId, m); // overwrite, don't append
// |coalesced| ≤ |rawLog|, equal only when every edit touched a distinct record
payloadBytes = sendCount × BYTES_PER_MUTATION
syncTimeSec = payloadBytes / (bandwidthKBps × 1024)
compressionX = rawCount / sendCount
- Active records / edit rate — how many distinct keys exist and how fast the offline client mutates them; a higher rate on a small record set means more repeat edits to the same key, so coalescing pays off more.
- Write coalescing ON — the queue keyed by record id keeps only the latest value per key (last-write-wins), so a record edited 10× still sends once.
- Write coalescing OFF — every mutation is replayed verbatim, exactly as a naive event log would, so payload size grows with edit count, not record count.
- Bandwidth slider — sets the sync link speed; sync time is payload size divided by bandwidth, shown live and animated as packets flying from the device to the server.
Real-world relevance: this is the same trade-off behind Realm/WatermelonDB/CouchDB-style mobile sync engines and CRDT op-logs — coalescing a bounded local mutation queue before a sync round trip cuts both payload size and conflict surface, at the cost of losing intermediate states nobody downstream ever needed.