A read model is a copy, and copies need a story about staleness

Replicating the data a second service reads removes the shared schema and introduces a lag, and the lag is a product decision rather than a technical detail.

// the consumer maintains its own table, shaped for its queries
final class CustomerProjection
{
    public function on(CustomerRenamed $event): void
    {
        DB::table('billing_customers')->updateOrInsert(
            ['customer_id' => $event->customerId],
            ['name' => $event->name, 'updated_at' => $event->occurredAt]
        );
    }
}

Storing the event timestamp rather than the local one is what makes staleness measurable — the age of the newest row is the lag, and it can be monitored and alerted on. The read model can be shaped for the queries that use it, which is frequently a bigger win than the decoupling: a denormalised table serving one screen beats a join across a boundary. Rebuilding it from the event history is the recovery path, and it only exists if the history is retained.