Event schema governance
Replay an older event into the new consumer
Historical messages exercise assumptions that fresh test fixtures miss. Test their final effects before relying on replay as a recovery tool.
In this article
Build a small historical collection
Select representative payloads from every contract version that remains within the supported replay period. Use synthetic or safely redacted examples. Preserve meaningful absences, null values and enum variants rather than normalising them into today's preferred shape.
A useful fixture includes why it exists. An old payment event might omit currency because its original producer served one currency only. The fixture should record the historical contract, not rely on a developer remembering that context.
Run through the actual boundary
Feed the messages through the same deserialiser and interpretation code used in production. A test that starts with an already converted internal object bypasses the area most likely to break.
Use an isolated destination and suppress real external effects. Rebuilding a projection should not resend receipts or reopen completed work unless that behaviour is explicitly part of the exercise.
Check the stored result, not just the absence of an exception. A missing numeric field converted to zero may pass validation and quietly damage a balance. The expected value needs a business explanation.
Mix versions and delivery conditions
Test old and new messages together. A rolling deployment can produce both formats, and a retained topic may contain years of history followed by current traffic.
Add duplicate delivery, an unsupported version and a message with a known field but changed meaning. For example, a timestamp formerly representing creation must not be interpreted as dispatch time merely because both are strings.
An unsupported message should reach a visible, recoverable state. Endless retries can block useful work. Silent acknowledgement can lose the only evidence that a record was never applied. Verify which behaviour your consumer uses and where the operator finds the affected identity.
Turn failures into a replay boundary
If a consumer cannot process an older contract, decide whether to add a translator, rebuild from an authoritative snapshot or narrow the supported replay period. Each option changes the recovery promise.
Record the oldest supported version and the fixture set used to establish it. A passing test against yesterday's producer does not establish compatibility with last year's retained events.
Finish by rebuilding a small known dataset and comparing business totals and selected records against independently calculated expectations. That final comparison catches interpretation errors that schema validation alone cannot see.
Primary sources
Confluent: schema evolution and compatibilityReferences checked 11 September 2026.