An Introduction To Event Theory

Wed Sep 17 2025

Most of the vocabulary and conceptual repertoire of today’s event theory can be traced back to The Power Of Events by David Luckham published in 2002. It’s a super-influential book even though its core paradigm of Complex Event Processing (CEP) has all but gone out of fashion. In a way, this is a tragic outcome for such a prescient foretelling of the “global spaghetti pot” of distributed communications, with which we all still struggle. Luckham gave real thought to managing the very complexity which still plagues us today.

So what was so powerful about this book? I’d say that, at least in my own work, it can be distilled down to a few things to which I continuously return. First is a vocabulary, second is the time-cause axiom, and the third is the concept of event aggregation.

As for the vocabulary, it comes into play when asking what an event actually is. Specifically, Luckham takes care to differentiate an event marking the occurrence of an activity, from the transmitted message which carries its information. According to Luckham, an event has three aspects:

So these definitions give us a lot to work with, conceptually speaking.

In particular, we also learn that the three main ways events relate to one another are time, cause, and aggregation. But why are these interesting or useful to us? They are each worth exploring for a different reason.

Time is useful because we benefit from the ability to say that event AA had happened before event BB. This is such a common thing to want to say, that event theory has a mathematical short-hand notation for it with the right-arrow relation:

ABA \rightarrow B is usually read as ”AA happened before BB”.

Also, it’s the fundamental relation in most eventy systems because it can provide a total order for all events in the system. Here is when you start to get into my work with event algebras. In particular, I developed a foundational event algebra which can be used when designing event systems. It works because, though it’s base form is very generic, it can be generalized to specific problem domains. It helped me, anyway.

So let’s introduce some more rigorous definitions for things. We begin by defining EE, the set of all events:

E={eEvent(e)}E = \{e | \text{Event}(e)\}

Assuming sufficiently precise timestamps, we define happened before as being closed over the set of events:

x,yE.xyE\forall x,y \in E.x \rightarrow y \in E

Its type signature also expresses this closure, however implicitly:

:(E×E)E\rightarrow: (E \times E) \mapsto E

This is powerful on account of us having a carrier set, EE and a closed, binary operation over that set, \rightarrow. In fact, we can say that together, these form a basic algebraic structure called a magma The term magma comes from France since it was used both by Jean-Pierre Serre in 1965 and the orthodox math collective known as Nicolas Bourbaki. :

(E,)(E, \rightarrow)

Furthermore, since \rightarrow provides a total order over EE, we can say it’s a totally ordered magma. Although a magma is a fairly simple algebraic, structure, it can be imbued with additional properties to gain more complex, and more useful, algebraic structures. Sort of like evolving a Pokemon, but without the ominous overtones of children forcing animals to violently fight one another in elaborate battles. Indeed, maybe’s it’s not really like Pokemon. I’ll try to make better comparisons in the future.

Note, also, that an event may have different timestamps. It’s not uncommon for sensor data to have an “occurred at” timestamp in addition to “recorded at” and “transmitted at” timestamps. Two timestamps gets us into bitemporality a word you mostly hear in the database world. More than two timestamps quickly gets us into polytemporality a word you mostly don’t hear at all unless right next to me.

At this juncture, it seems worthwhile to clarify exactly what we mean by “timestamp”. In ordinary usage, it usually refers to a serialized pointer which indicates a particular moment of wall-clock time. Thankfully, we have standards like ISO 8601 and RFC 3339, which make our (programmer) lives significantly more manageable. But a timestamp doesn’t need to represent a moment in wall-clock time. It could just as easily concern itself with system time, such as that counted by logical clocks. In practice, logical clocks can be as basic as sequence numbers or as sophisticated as things like Lamport timestamps Dr. Leslie Lamport invented Lamport timestamps in 1978 for which he won the Turing award in 2013. or vector clocks.

Just because you can reason that ABA \rightarrow B doesn’t mean you can automatically say that AA caused BB. However, it does get you part of the way there. Trying to reason effectively about causality brings you to one of Luckham’s more subtle contributions. What he terms “the time-cause axiom” can be summed up like this:

For AA to have caused BB, all clocks in the system must agree that ABA \rightarrow B.

This sounds like it’s self-explanatory. Believe me when I tell you that it’s not. I have personally witnessed clock divergence induce errors in all sorts of distributed systems. This includes causing desktop/browser errors due to clock drift. If a machine’s clock is too far out-of-sync, it risks breaking most TLS certificate verification. That one really sucked to debug. Especially because it was guaranteed to happen whenever folks came back from a particularly long vacation or even just a leave of absence. If their time away from the office exceeded the life of their laptop battery, it was practically a sure thing. What a pain!

One power of the time-cause axiom is that it can eliminate certain complexities from our thought processes. If any part of a system disputes ABA \rightarrow B, then it automatically rules out any possibility of AA having caused BB.

You can use differing data structures to model event collections. This affords you the opportunity to choose the one which makes thinking about your system easier. Here are the three which I’ve encountered most often.

While you might have caught a whiff of it, I want to state explicitly that append-only semantics are key. Which is nice because suddenly everyone rediscovered the power and convenience of immutable logs. And not just thanks to overuse of Kafka, either.

Combined with earlier algebraic bits, it provides potential groundwork for undo via -, an unary inversion operator. Later down the road, we can get to composition and other cool aspects. For now, this should suffice as a brief introduction.

Back to All Posts