Versioned Event-Schema Registry¶
A tool — instantiates Event-Log-Centered Modeling
Versions event type contracts so producers and projections can evolve their schemas without silently breaking each other or the old history.
An event log is only useful if the events in it can be read — and in an append-only model that includes events written years ago, under an older idea of what that event type looked like. Versioned Event-Schema Registry is the authority that makes this possible: a catalog of every event type's contract — its required fields, types, and boundaries — with each contract versioned, so schemas can change over time while every past and present event remains interpretable. Its distinguishing role, and what separates it from the instrument that captures events, is that it governs the compatibility contract between producers and the projections that consume them: a new schema version may only be registered if it does not break the readers of the old one. It is the reason an append-only history stays legible as the model evolves, rather than fossilizing at version one or fracturing into unreadable dialects.
Example¶
A payments platform appends every state change of an order to a shared log — order_placed, payment_authorized, order_shipped — consumed by a dozen projections (customer timeline, fraud scoring, revenue analytics, warehouse dispatch). A new anti-fraud initiative needs payment_authorized to carry a risk_score field. Done carelessly, this is a landmine: services deployed last quarter still emit the field-less v1 event, newer ones emit v2, and a projection that assumes risk_score exists will crash on every historical and old-service event. The Versioned Event-Schema Registry prevents it. The team registers payment_authorized v2 with risk_score as an optional field defaulting to null; the registry checks this against v1 and accepts it as backward-compatible, so every existing reader keeps working and old events remain valid.
Had they tried to make risk_score required — a breaking change — the registry would have rejected the registration, forcing them to either keep it optional or cut a genuinely new event type. Months later, when someone replays the full log to rebuild the fraud-scoring projection, the registry is what lets a single consumer read v1 and v2 payment_authorized events side by side, upcasting the old ones, so years of order history fold cleanly into one current view.
How it works¶
- Register a contract per event type. Hold the canonical definition of each type — fields, types, required-versus-optional, boundaries of what the type does and doesn't cover — as the authoritative shape producers must emit and consumers can rely on.
- Version every change. Assign a new version on each schema change and keep all prior versions, so an event written under any version stays self-describing and readable.
- Enforce compatibility at registration. Before accepting a new version, check it against a compatibility rule (a new reader must handle old events, or an old reader must tolerate new ones) and reject changes that would break existing consumers or invalidate stored history.
- Serve schemas to readers. Let a replaying projection fetch the right version for each event and reconcile versions (defaults, upcasts), so mixed-version history reads as one coherent stream.
Tuning parameters¶
- Compatibility mode — backward, forward, full, or none. Stricter modes protect existing readers and stored history but constrain how schemas may change; looser modes free evolution at the cost of breakage risk.
- Enforcement point — whether compatibility is checked at registration, at write time, at read time, or all three. Earlier enforcement blocks bad schemas before any data is written; later enforcement is more permissive but lets problems reach the log.
- Versioning granularity — whether a change is a new version of a type or a new type entirely. Versioning preserves continuity of history; forking a new type is cleaner for genuinely different events but splits the trajectory.
- Deprecation policy — how long superseded versions and their producers are supported. Long support keeps old devices and old history first-class; short windows reduce the version sprawl readers must handle.
When it helps, and when it misleads¶
It earns its keep the moment an event log outlives its first schema — which is always. It lets producers and consumers evolve independently, keeps a lifetime of history readable, and turns "will this schema change break something?" from a nervous guess into a mechanical check performed before the damage is done. In any multi-team or long-lived event system it is the difference between a durable model and an accreting pile of mutually-unintelligible records.
Its failure modes sit at both extremes. Set compatibility too strict and the registry becomes a bottleneck that freezes the model — every real change has to masquerade as an optional add-on, and schemas rot into a swamp of never-removed fields.[1] Set it too loose, or enforce it only by convention, and a breaking change slips through and silently corrupts every reader of the affected type. The most corrosive misuse is treating the registry as documentation rather than an enforced gate: a registry that describes what schemas should be, while producers write whatever they like, provides false confidence and drifts from reality. The disciplines are to enforce compatibility mechanically at registration rather than trusting discipline, to version rather than mutate contracts in place, and to keep old versions genuinely readable so the append-only history it protects can always be replayed.
How it implements the components¶
The Versioned Event-Schema Registry realizes the archetype's type-governance slice — versioning and compatibility-gating what a valid event may become — and none of the capture, storage, derivation, or timing slices:
event_boundary_and_type_contract— it governs the evolution of this contract: it holds every version of each event type's fields and boundaries and enforces the compatibility rule that decides whether a proposed change may be registered. Its concern is how the contract may change over time, not authoring the first version or shaping any individual stored record.
It versions and gates the contract but does not fix the canonical record shape written at capture time (canonical_event_record) or produce record instances — both belong to Event Capture Template — and it does not assign the per-event identity used for deduplication, which is Event Replay Deduplication.
Related¶
- Instantiates: Event-Log-Centered Modeling — the authority that keeps an evolving log's event types coherent and readable.
- Sibling mechanisms: Event Capture Template · Event Replay Deduplication · Event-Sourced Projection · Snapshot Plus Replay
Notes¶
The registry governs type contracts; it is silent about the truth or ordering of any particular event's contents. It also underwrites replay quietly: because a schema change that breaks old events would make history unreplayable, the registry's compatibility gate is a precondition for every rebuild-from-history mechanism in the archetype, even though it performs none of the replaying itself.
References¶
[1] Backward and forward compatibility are the two directions a schema change can preserve: backward-compatible changes let new readers consume old data, forward-compatible ones let old readers tolerate new data. Enforcing one or both at registration is the mechanical discipline that keeps an append-only log readable across a lifetime of schema evolution. ↩