Skip to the content.

Events

Everything is an immutable event

A vehicle’s history is a timeline of append-only events. Nothing is ever edited or deleted in place. A mistake, a correction, or a status change is recorded as a new event that supersedes or references the old one — the same discipline as signed Git commits or a ledger, and for the same reason: an editable history is not a trustworthy one.

“Current state” — mileage, whether the timing belt has been done, whether there’s an open recall — is never stored directly. It’s always a projection, computed by replaying the timeline. This keeps the source of truth singular even as ten different applications each want a different summary view of the same vehicle.

Example event types

This list is intentionally not exhaustive or final — the event type namespace needs to stay extensible without a central body having to bless every new type a workshop or integrator wants to add. (Likely shape: a reverse-domain or namespaced type field, so third parties can mint their own event types without collision, the way custom MIME types or Matrix event types work.)

Facts before opinions

Events fall into two categories, and the format must never blur them:

Opinions can be regenerated, superseded, or discarded as models improve. Facts cannot. An event schema should make it structurally obvious which one you’re looking at — e.g., a top-level kind: fact | opinion — so no downstream consumer can accidentally treat a prediction as history.

The event envelope (illustrative)

Every event, regardless of type, carries a common envelope so any client can at least verify and order events it doesn’t understand the payload of:

{
  "id": "evt_01K0Y6...",
  "vehicle_id": "ovp:01K0Y5...",
  "type": "com.opendiag.oil_changed",
  "kind": "fact",
  "timestamp": "2026-07-06T09:14:00Z",
  "actor": "ovp-identity:workshop:racetune-tallinn",
  "signature": "ed25519:...",
  "payload": { "product": "5W-30", "quantity_l": 5.5 },
  "attachments": ["ovp-blob:sha256:..."]
}

Corrections append, they don’t rewrite

If a workshop logs the wrong date or the wrong part, the fix is a new event referencing the one it corrects (supersedes: "evt_..."), not an edit to the original. The original stays visible, because part of the value of an immutable timeline is being able to see that a correction happened, not just the corrected value.