Coherence · dive 01
A message
about a name
Two identities and a colon. Twenty-nine bytes. The version is the clock.
A coherence message is the smallest thing that can carry the truth and nothing more.
payload/2 is id <> ":" <> version — the cached
name, a colon, the writer’s mint-time version. Two 14-byte branded ids and one separator:
no value, no timestamp, no node identity, no clock vector. The decision the module turns on — “is
this newer than what I have?” — is a string comparison, not a clock read:
newer?/2 compares the eleven-byte snowflake payloads and ignores the namespace, so it
holds across kinds. Coherence needs no coordinator, no lock, and no clock but the one inside
every id, and it is idempotent by construction.
The message: two names, twenty-nine bytes
The message carries the cached name and the writer’s version — and refuses anything that is not
two valid branded ids. The shape is the validation: the binary pattern only matches a 29-byte string
with a colon in exactly the right place, and the two BrandedId.valid? checks reject a
string of the right length but a malformed name. A message that does not parse is dropped, never half-applied.
# EchoStore.Coherence — payload/2 and parse/1 # A coherence message is two identities and a colon. Nothing else crosses. def payload(<<_::binary-14>> = id, <<_::binary-14>> = version), do: id <> ":" <> version # parse/1 only succeeds for two well-formed branded ids — a malformed # message is :error, never a half-applied invalidation. The colon must # sit exactly between two 14-byte names for the pattern to match at all. def parse(<<id::binary-14, ":", version::binary-14>>) do if BrandedId.valid?(id) and BrandedId.valid?(version), do: {:ok, id, version}, else: :error end def parse(_), do: :error
There is no value in the message because the reader does not need one: a stale row is dropped, not replaced — the next read will miss and re-fill from the store with the current value. The invalidation says only “the value you have for this name is no longer the newest”.
The message · twenty-nine bytes, mapped
Newer wins — across kinds, with no clock
The whole module turns on one comparison, and it is a byte comparison of the eleven-byte snowflake payloads — the three-byte namespace is dropped, so the comparison holds across kinds.
# EchoStore.Coherence — newer?/2 # True when `a` was minted after `b`. The branded id's eleven payload bytes # sort lexicographically in mint order (the order theorem), so a plain byte # comparison answers "newer" with no clock and no coordinator. The leading # three namespace bytes are dropped, so the test holds ACROSS kinds. def newer?(<<_::binary-3, pa::binary-11>>, <<_::binary-3, pb::binary-11>>), do: pa > pb
Two facts make this work:
- Lexicographic equals chronological. The eleven Base62 payload
characters encode a 63-bit snowflake
ts(41) | node(10) | seq(12), and Base62 is monotonic — comparing the strings byte-for-byte gives the same order as comparing mint instants. NoTIMEcall, no counter: the order is in the id. - It holds across namespaces. Because
newer?/2drops the leading three namespace bytes, aGAMversion and aPLRversion are still comparable. Coherence does not need the two sides to agree on a type — only to be branded ids.
And so coherence is idempotent by construction: applying the same version twice is a
pa > pb that answers not newer the second time. A re-delivered broadcast, a
replayed job, a duplicate from two lanes at once — all converge, because “is this newer than what I
have” is a question with a stable answer however many times it is asked.
Compare two versions
Pick an incoming version against a stored one and read the verdict newer?/2 returns.
The model runs the exact byte comparison of the eleven-byte payloads over a fixed pair of branded ids —
including a cross-kind pair, where the incoming and stored versions carry different namespaces
and the comparison still holds.
newer?/2 · compare the eleven-byte payloads
The comparison reads the clock straight out of the name. There is no second clock to keep in sync,
no coordinator to ask — only two strings and the > that the order theorem makes
mean later.
Pattern & implementation
When two writers race, pick the later one — but “later” needs a clock the readers agree on without coordinating. A monotonic, embedded, globally-comparable id is exactly such a clock, and the version carries it for free.
newer?/2 reads the clock out of the name with a string comparison of the eleven
payload bytes; parse/1 guarantees both sides are well-formed branded ids. No
coordinator, no lock, no TIME — the order is in the id.
A message about a name needs no shared clock, because the name already carries one.
Where the message goes next
The vocabulary is settled; the next dive is how the message travels — the two lanes, broadcast and job, chosen by the cost of staleness — and the dive after is the one inline Lua that applies it on the far side. The id contract this comparison rests on is the subject of the Protocol’s branded-id gate.
References
Sources
- King — Announcing Snowflake — the time-ordered id whose byte order is the coherence comparison.
- Lamport — Time, Clocks, and the Ordering of Events — the logical clock the embedded snowflake plays the role of.
- Helland — Life Beyond Distributed Transactions — coherence as a message about a name, not a shared object.
- Erlang/OTP — the ets module — the L1 row a newer version will later evict.
Related in this course
- Coherence — the module hub.
- The two lanes — how this message travels.
- Newer wins: the conditional drop — what the receiver does with it.
- Immutability & branded ids — the gate the version is minted at.
- The Branded Component System · the Store — the manuscript chapter this pillar realizes.