Skip to content
PROTOWORKS

02 · Events · causal ledger · append-only

Nothing happens once.

Every action is an event. Every event provokes a reaction. We keep both, in order, forever, and read the graph between them for the loops nobody designed.

The third law

For every action, an equal and opposite reaction. Most software only remembers where it ended up.

A row in a table remembers where it ended up. An event log remembers how it got there. In an event-sourced system nothing is overwritten: state is not stored, it is derived, a left fold over everything that has ever happened.

Replay the fold and you get the present. Stop it early and you get the past, exactly. Every reaction carries the id of the action that caused it, so the history is not a list. It is a graph.

state(t)   = fold(apply, ∅, events[0 ‥ t])

present    = state(now)     // rebuilt, never stored
past       = state(t₀)      // exact, not approximate
cause(e)   = e.causation_id
thread(e)  = e.correlation_id
Stream · ord_7Q2X5 events
000001order.placedACTION
000002stock.reserved← 000001
000003payment.requested← 000001
000004payment.failed← 000003
000005stock.released⇠ OPPOSES 000002
An action, its reactions, and the equal and opposite event that answers the failure. Nothing was deleted. The mistake and its correction are both facts.

Invariants

Six laws of the ledger.

  1. 01

    Append only

    Events are facts. Facts are never edited, only followed by newer facts.

  2. 02

    Every reaction cites its cause

    A causation id and a correlation id on every event. The graph is declared at write time, not guessed at read time.

  3. 03

    State is derived

    Projections are disposable. Drop one and replay rebuilds it, bit for bit.

  4. 04

    Time is an axis

    Any aggregate can be read exactly as it stood at any instant, under any version of the code that folds it.

  5. 05

    Compensate, never delete

    A mistake is answered by an equal and opposite event. Both stay on the record.

  6. 06

    Loops are findings

    A reaction that eventually causes its own cause is a bug, a market or an attack. Either way, it is reported.

Read continuously

Six questions a table cannot answer.

A table that is updated in place remembers where things ended up. It does not remember why. Here every event names the event that caused it, so the chain exists the moment the write commits. Pick a question; watch the machine answer it over thirty event types and forty-six recorded causes, and read its reasoning as it goes.

The question

Can this system set itself off, with nobody pressing a button?

Method · Tarjan · strongly connected components · O(V+E). Visit every event once and keep the ones that can each, eventually, cause every other.

step 0 / 34
The reasoningIn progress
  1. The questionCan this system set itself off, with nobody pressing a button?
  2. The recordThirty event types and forty-six causes. Every one was written down at the moment it happened, with the event that caused it. Nothing below is inferred.
4 feedback regions · 30 events · 46 causal edges○ event◇ compensation── loop

Live · this page, since you arrived

You have been here long enough to cause something.

Events appended
0
Reactions derived
0
Loops caught
0
Snapshots folded
0
SeqTime (UTC)TypeCorrelationCauseKind

Simulated in your browser by the graph at the top of this page. Nothing is sent to us, and nothing is stored.

Downstream

Built for systems that have to explain themselves.

Payments and ledgers

Every balance is a sum you can audit. Every reversal is a fact, not a correction.

Command and control

Who tasked what, what it set in motion, and in what order. Replayable after the fact.

Fraud and abuse

Rings are cycles. Mule chains are paths. Both are visible the moment the edges exist.

Games and economies

Exploit loops surface as cycles before the economy inflates around them.

In production

Not a new idea. A proven one.

The append-only log is older than the computer. The systems below run on it today, at scales most teams will never need. We borrow their invariants, not their headcount.

1494Ledger

Double-entry bookkeeping

Pacioli's Summa codified the journal and the ledger. Entries are appended, errors are answered by reversing entries, and every balance is derived from the record.

Source · history of double-entry ↗
2011Exchange

LMAX

Around six million orders a second through business logic on one thread, in memory, with no database. State is rebuilt by replaying the input journal; with nightly snapshots a full restart takes under a minute.

Source · Fowler, The LMAX Architecture ↗
2005Version control

Git

Every repository is an append-only, content-addressed graph of immutable commits. A branch is a pointer into it. Every developer already works in an event-sourced system.

Source · Git internals, objects ↗
2019Streaming

Kafka at LinkedIn

Over seven trillion messages a day across more than 100 clusters, 4,000 brokers and roughly seven million partitions. The partitioned log, as infrastructure.

Source · LinkedIn Engineering ↗
Durable executionWorkflows

Temporal

Workflow state is never stored directly. A crashed worker replays the event history, reuses recorded activity results instead of re-running them, and non-deterministic code is caught on replay.

Source · Temporal docs, event history ↗
PaymentsDatabase

TigerBeetle

A database built around one shape of event: the transfer. Each one debits an account and credits another, so total debits equal total credits by construction.

Source · TigerBeetle docs ↗
2020Banking

Datomic at Nubank

An accumulate-only database in which every fact carries the transaction that asserted it. Nubank built a bank on it, then acquired its makers, Cognitect, in 2020.

Source · Building Nubank ↗