LWWMap
A map from K to last-writer-wins values V: per-key LWWRegisters composed under union-merge of keys. Each set (or remove — a tombstone write) tags one key with (timestamp, replicaId); merge picks the per-key max tag.
Suited to settings, ready-toggles, and similar small key→latest-value state where surfacing concurrent edits (a la MVRegister) is unwanted.
Immutable, and every mutator returns the change rather than a new map: set and remove hand back a Patch holding just the one cell they wrote, which is what belongs on the wire. piece is the per-key merge — it absorbs a patch, and it is also how a caller who wants the resulting whole map gets one: map.piece(map.set(replica, timestamp, key, value)).
Clock-skew warning. Wall-clock timestamps work only when clocks are well-synchronized across all replicas. NTP-class drift will cause surprising silent drops: a write with a lagging timestamp loses to an older write from a faster clock. For correctness under arbitrary clock skew, pair this map with a Hybrid Logical Clock above this layer.
Samples
val a = ReplicaId("A")
val b = ReplicaId("B")
// Two peers have converged on a settings map.
var alpha = LWWMap.empty<String, String>()
.piece { it.set(a, timestamp = 1L, key = "lang", value = "en") }
.piece { it.set(a, timestamp = 2L, key = "tz", value = "UTC") }
.piece { it.set(a, timestamp = 3L, key = "theme", value = "dark") }
var bravo = alpha
// B changes one setting and puts only that cell on the wire. The frame is the same size
// whether the map holds three keys or ten thousand, and the other keys are untouched.
val change = alpha.set(b, timestamp = 4L, key = "theme", value = "light")
alpha = alpha.piece(change)
bravo = bravo.piece(change)
check(alpha == bravo)
check(alpha["theme"] == "light")
check(alpha["lang"] == "en")
// Per key the higher (timestamp, replica) tag wins, and a remove is a write like any other,
// so its delta is a one-cell tombstone map…
val forget = bravo.remove(b, timestamp = 5L, key = "lang")
check(alpha.piece(forget)["lang"] == null)
// …and never an empty map, which is the lattice identity and carries no removal at all.
check(alpha.piece(LWWMap.empty<String, String>())["lang"] == "en")Properties
Functions
The causal Dots this state has delivered — (author, author-seq) per op.
The per-author high-water of dots this state delivered and has since compacted away without retaining their identities.
Remove key tagged with (timestamp, replica) — a last-writer-wins tombstone (LWWRegister.unset) that competes under merge exactly like a set: a remove at a later tag beats an earlier set, and a set at a later tag revives the key, with the same deterministic (timestamp, replicaId) tie-break. Removed keys disappear from get and entries. Returns the change: one key's tombstone cell, not the whole map.