Skip to content

The data model

This page explains the OpenBody data model in plain terms. It is a simplified companion to the normative text — where the two differ, SPEC.md wins.

Everything is a record with a shared envelope

OpenBody models data as records. There are eight addressable record kinds:

PillarRecord kinds
A — ObservationMeasurement
B — Structured TrainingProgram, Session, Block, Exercise, WorkUnit
Shared / contextThresholdProfile, StatusPeriod

Nested elements like Rep and value objects like Target and Load are sub-objects, not standalone records.

Every record — in either pillar — carries the same record envelope (§7). That envelope is what lets records from different sources reference, deduplicate, correct, and relate to one another:

  • Identityid (globally-unique, producer-assigned, stable), recordType (the discriminator), subject (who the record is about), and optional clientRecordId (the source app’s own key).
  • Typed links — a links array of { type, ref }, where type is a closed core relation: partOf, sameActivityAs, derivedFrom, peerSensor, measuredBy, performedFrom, groupActivity. Novel relations are namespaced extension links — never an overloaded core type.
  • Provenancemethod (manual|sensor|estimated|algorithm), device, sourceApp, optional algorithm and confidence.
  • Lifecycle — records are immutable: status (active|superseded|deleted, absent ⇒ active), supersedes, revision.

Conformance tiers

Each model element has a tier — the per-element columns in SPEC §§4–7 are normative:

  • Required (core) — an implementation MUST read and write these; without them interoperation is meaningless.
  • Recommended — an implementation SHOULD support these; if it doesn’t, it MUST preserve them losslessly.
  • OptionalMAY support; unsupported optional elements that appear on input MUST still be preserved.

There are also conditional (required only when a stated condition holds) and required-in-X (structural to a record kind) tokens.

Immutability & corrections

Records are never edited in place. To correct one, emit a new record with a new id, a supersedes pointer at the prior record, and an incremented revision; the prior record’s status becomes superseded. A deletion is a tombstone — a record with status: deleted — not a physical removal, so references and sync lineage stay intact. To satisfy GDPR Article 17, a tombstone strips subject and all payload fields on the wire, leaving only id, recordType, and status: deleted (zero PII).

Extend, don’t modify

OpenBody is extended by adding under a namespace, never by changing the core (§8.1). Namespaces are reverse-DNS (com.acme.metric) or a registry-allocated prefix (acme:). An extension value is an object keyed by namespace, so independent extenders never collide:

"extension": { "com.acme.metric": { "moodScore": 7 }, "acme": { "uiColor": "#ff0" } }

An extension MUST NOT change the meaning of a core field, and a consumer that doesn’t understand it MUST preserve it and MAY ignore it. This is the mechanism that lets any surveyed niche be addable without a core release — no structural dead-ends.

Where to go next