All posts
EngineeringEngineering Team

Field notes

Why an election-results system needs an event queue

Polling-unit → Ward → LGA → State → National is not a data-processing pipeline in the textbook sense — it is a rumour with receipts. Here is how we model it.

Every textbook that describes a map-reduce pipeline has it a little wrong for elections. In a textbook pipeline, data flows in, is transformed through well-defined stages, and arrives at the other end as a single answer. An election result flows like that too — right up until the moment it does not.

A polling-unit result arrives with a signature, sometimes with a disputed correction, sometimes with three versions of the same sheet. A ward rolls up its polling units, but only after an agent at one of them sends a late amendment. A state cannot certify until the last LGA has reconciled, which cannot happen until a disputed ward has been adjudicated. The system is not a pipeline. It is a rumour with receipts.

That is why ERMS is built on an event queue. Every result submission, every correction, every incident, every signature, every adjudication is an event. Aggregations — ward, LGA, state, zone — are projections of the event log at a particular timestamp. You can replay them, you can audit them, you can answer the question "what did the LGA result look like at 18:32 local time" and get the same answer you got five minutes ago.

Operationally this lets us do three things that the old systems could not. First, a correction to a polling-unit sheet flows automatically upward to every aggregate, without a human being tasked with reconciling spreadsheets. Second, the audit trail is the data: there is no separate "audit log" that could be doctored independently of the results. Third, independent observers can be given a read-only stream of the same event log, with no risk that their dashboard is showing a different reality from the commission’s.

The trade-off is that every event has to be immutable once committed, and every aggregate has to be idempotent under replay. That is not hard to enforce in code, but it does require discipline about what "saving a result" means. We are happy to accept the discipline. Elections are not a domain where we are going to skip to the fast path.