A publisher asked to add a field for one consumer will add it, and after five of those the event is a shared schema that nobody can change. The inversion is that consumers subscribe to what exists and take only what they need.
// consumer-driven: read the fields you use, ignore the rest
final class UpdateSearchIndex
{
public function handle(array $event): void
{
$this->index->update($event['order_id'], [
'total' => $event['total_cents'],
]);
// other fields exist and are none of this consumer's business
}
}
Practically this means never validating an event against an exact shape, only against the fields being read — a strict schema check turns an additive change into a breaking one. Where a consumer genuinely needs something the publisher does not emit, that is a conversation about the boundary rather than a field request.