Counters are the gentlest introduction to convergence, because addition does not care about order. Send each change as a signed delta instead of a new total, and simultaneous edits simply add up; there is nothing to overwrite.
They climb in guarantee: a server-sequenced scalar, then a grow-only lattice that stays correct even when a delta is delivered twice, then a signed counter built from two of those lattices so it can move in both directions offline.
The structures from this family that fit the shared gauge rig run
below on watershed’s Gleam kernels. Structures with dedicated
interactions link to their own demos. Pending edits print in
magenta; once the sequencer stamps
an SN, every replica lands the same ink
state. The picker switches among the loaded views, which share one
ordered stream.
Nudge a value, race a concurrent write, or stretch the link latency
to watch each merge rule hold.
1 · local edit prints in magenta
2 · the sequencer stamps it with an SN
3 · every client lands the same ink state
Merge rule: last write wins. Race two writes to the
same key and the op the sequencer stamps later overwrites the earlier
one, identically on every replica.
Merge rule: increments commute. Race two increments
and both apply. The counter converges on the sum; nothing is
overwritten.
Merge rule: grow-only max per replica. Each client owns
one monotonically increasing tally. Race two inspections or deliver a
delta twice: replicas converge by keeping the maximum count seen for
each author.
Merge rule: deltas join a lattice. Every update
travels as a CRDT delta; merging is commutative and idempotent. Race
it, resend it, deliver it twice: it counts exactly once, and the
balance converges on fill − cut.
Merge rule: first writer wins. A claim commits only
if the slot is still unclaimed when the sequencer stamps it (or its
reference SN matches the holder’s exactly). Nothing prints
optimistically: a filed claim is invisible, even to you, until it
round-trips as won or lost.
Merge rule: add-wins, observed-remove. A strike only
removes stockpile entries the striker had seen. Race a strike against a
concurrent delivery and the row survives, with every logged yard.
Re-opening a struck pile brings its ledger back.
Merge rule: add-wins, observed-remove. Clearing a marker
removes only the add tags this replica had observed. Race a clear against
a concurrent re-mark and the marker remains present because the fresh tag
was unseen by the clear.
Merge rule: grow-only union. Marking a benchmark is a
permanent fact. Race two marks or deliver one twice: the registry only
grows, and duplicate deltas are absorbed.
Merge rule: tombstone wins. A retired marker can never
become active again. Race a re-place against a retire: both replicas keep
the tombstone, and duplicate retire deltas are absorbed.
Merge rule: atomic plus retained versions. A write that
knew the current atomic sequence wins the linearizable slot. Concurrent
losers still append a version, so LWW reads can intentionally diverge from
atomic reads.
Merge rule: FIFO by sequence. Adds enter the queue in
server order. Acquires remove the front item when their op sequences; a
racing acquire may come back empty because the earlier SN already took it.
Merge rule: one assignee, FIFO waiters. Volunteers join
a per-task queue in sequenced order. The first connected volunteer owns the
task; abandon promotes the next waiter, and complete clears the queue.
Merge rule: quorum acceptance. A set first prints as
pending with a frozen signoff list. It becomes accepted only after every
connected client signs off, or leaves drain the list.
Client A
0 pending
Shared map replica on Client A
mill-race
24
kettle-run
61
low-ford
42
sandbags-placed
earthwork-balance · yd³
fill Σ
74
cut Σ
30
cutfill
inspection-count
A Σ
0
B Σ
0
C Σ
0
Claims replica on Client A
north-levee
spillway-gate
pump-house
OR-map stockpile ledger replica on Client A
spoil-north
borrow-pit-7
wash-fill
OR-set field marker roster replica on Client A
north-stake
sluice-tag
borrow-flag
G-set permanent benchmark registry replica on Client A
BM-17
BM-22
BM-31
2P-set retired marker ledger replica on Client A
stake-3
gate-pin
silt-flag
RegisterCollection replica on Client A
register
atomic
LWW
revise
north-bench
gate-setpoint
pump-mode
OrderedCollection replica on Client A
sheet
state
op
queue
held jobs
PactMap replica on Client A
pact
accepted
pending
op
datum-grid
gate-policy
inspection-window
TaskManager replica on Client A
task
assigned
waiters
op
sluice-inspection
pump-watch
crest-walk
Client B
0 pending
link cut — ops park locally until the link is restored
Shared map replica on Client B
mill-race
24
kettle-run
61
low-ford
42
sandbags-placed
earthwork-balance · yd³
fill Σ
74
cut Σ
30
cutfill
inspection-count
A Σ
0
B Σ
0
C Σ
0
Claims replica on Client B
north-levee
spillway-gate
pump-house
OR-map stockpile ledger replica on Client B
spoil-north
borrow-pit-7
wash-fill
OR-set field marker roster replica on Client B
north-stake
sluice-tag
borrow-flag
G-set permanent benchmark registry replica on Client B
BM-17
BM-22
BM-31
2P-set retired marker ledger replica on Client B
stake-3
gate-pin
silt-flag
RegisterCollection replica on Client B
register
atomic
LWW
revise
north-bench
gate-setpoint
pump-mode
OrderedCollection replica on Client B
sheet
state
op
queue
held jobs
PactMap replica on Client B
pact
accepted
pending
op
datum-grid
gate-policy
inspection-window
TaskManager replica on Client B
task
assigned
waiters
op
sluice-inspection
pump-watch
crest-walk
Client C
0 pending
Shared map replica on Client C
mill-race
24
kettle-run
61
low-ford
42
sandbags-placed
earthwork-balance · yd³
fill Σ
74
cut Σ
30
cutfill
inspection-count
A Σ
0
B Σ
0
C Σ
0
Claims replica on Client C
north-levee
spillway-gate
pump-house
OR-map stockpile ledger replica on Client C
spoil-north
borrow-pit-7
wash-fill
OR-set field marker roster replica on Client C
north-stake
sluice-tag
borrow-flag
G-set permanent benchmark registry replica on Client C
BM-17
BM-22
BM-31
2P-set retired marker ledger replica on Client C
stake-3
gate-pin
silt-flag
RegisterCollection replica on Client C
register
atomic
LWW
revise
north-bench
gate-setpoint
pump-mode
OrderedCollection replica on Client C
sheet
state
op
queue
held jobs
PactMap replica on Client C
pact
accepted
pending
op
datum-grid
gate-policy
inspection-window
TaskManager replica on Client C
task
assigned
waiters
op
sluice-inspection
pump-watch
crest-walk
Sequencer
Loading
booting watershed kernels…
Latency and jitter affect simulated arrival order; animation speed
changes playback only. “Ops in flight” counts every hop still
travelling: one client → sequencer leg, then one
sequencer → replica leg per client.
The live demo couldn’t start: it runs watershed’s runtime counter channel
and kernels as compiled JavaScript modules, and this browser didn’t load
them. The rest of the page works fine without it. Reload the page to retry.
No. 01
SharedCounter
DDS
counter_kernel
One number that many people can add to at once, without conflicts.
A shared counter holds a single integer. Each client submits a signed delta (+5, −1) rather than a new absolute value. Addition commutes, so the server can sequence deltas in any order and every replica lands on the same total.
Shipping the change instead of the result is the whole trick: two clients incrementing at the same instant never clobber one another. A local delta renders immediately as an unsequenced Δ beside the committed value. When the sequencer stamps it, the pending delta folds into the total.
Best for
Live tallies: votes, reactions, attendees, items in a shared cart
Running totals where concurrent +/− must never be lost and order does not matter
Inventory or quota counters that many clients adjust at once
Merge rule
everyone sends +/− changes instead of overwriting, so simultaneous edits just add up
Optimistic behavior
your change shows next to the confirmed total right away
Summary shape
only one number needs saving, since every change is an add
Model
Distributed data structure: converges by server order
No. 02
GCounter
CRDT
lattice_counters/g_counter
A count-up-only counter that stays correct even if an update arrives twice.
A grow-only counter keeps one monotone count per replica. Client A only ever raises A’s slot; client B only B’s. The visible value is the sum of every slot.
Merging two states takes the larger count for each replica. That pairwise maximum is idempotent, so a delta delivered twice (after a reconnect, say) changes nothing the second time. The price: a G-counter can only increase. It has no decrement.
Best for
Idempotent counters over at-least-once or unreliable delivery
Distributed metrics where the same increment may arrive more than once
The building block beneath the PN counter and other lattice counters
Merge rule
each client keeps its own tally; the totals combine safely even if a change arrives twice
Optimistic behavior
your increment overlays the total in magenta until it’s confirmed
Summary shape
each client’s running tally reloads intact
Model
Conflict-free replicated data type: converges by merge
No. 03
PnCounter
CRDT
pn_counter_kernel
A counter that goes up and down and survives duplicate or out-of-order updates.
A single G-counter can only grow, which rules out decrements. A PN counter restores them by pairing two G-counters: a positive ledger and a negative ledger, each keyed by replica. The value you read is the positive sum minus the negative sum.
Each half is a max-merge CRDT, so the whole thing is order- and duplicate-independent. A decrement re-delivered after reconnect is absorbed idempotently. The demo frames this as a cut-and-fill earthwork balance and lets you re-send a sequenced delta to watch the merge shrug it off. An op-based counter needs the runtime's sequence-number dedup to survive that; here the merge alone is enough.
Best for
Counters that go up and down under unreliable delivery (reserve/release, like/unlike)
Collaborative budgets or capacity that both grows and shrinks concurrently
Offline-first counters that reconcile on reconnect without dropping edits
Merge rule
keeps separate up and down tallies, so it can move both ways and still shrug off duplicates
Optimistic behavior
adds and subtractions can be re-sent without being counted twice
Summary shape
per-client tallies survive reconnect and repeated delivery
Model
Conflict-free replicated data type: converges by merge
Magenta indicates revisions not yet field-checkedConvergence by server sequencing — assumptions on the models sheettylerbutler.com