Skip to content

Two kinds of identity

Think of a book. The title, say The Origin of Species, names the work itself. It stays the same no matter how many printings exist. Each printing, by contrast, is fixed forever: the third printing of 1861 has exactly the pages it has, and no one can change a word of it now. When you cite a fact from the book, you name the printing, not only the title, because only a printing has exact pages. MTRL gives every result the same two kinds of identity, and for the same reason.

Every saved result in MTRL has two identifiers.

  • The CheckpointId is the title. It names the logical result: “the spectrum”. It is stable, and it is the name you, your colleagues, and your transforms use when you talk about the result.
  • The RecordId is the printing. It names one immutable version of that result. Once a record is committed, its RecordId never changes and its content never changes.

A correction makes the distinction concrete. When you corrected the saturated FTIR spectrum of polymer-film-01, the CheckpointId stayed: it is still “the spectrum”. MTRL minted a new RecordId for the corrected version, and the old version kept its own RecordId forever. The title endured; a new printing was bound.

Because one CheckpointId can stand behind several records over time, a CheckpointId alone cannot say exactly which data you mean. For that, MTRL uses a RecordRef: a small frozen object that pairs a CheckpointId with a RecordId. It names one exact version of one logical result, with no room for drift.

This is the only acceptable way to point at scientific input. New lineage must never refer to a CheckpointId alone, because that would leave the version ambiguous. When a transform records its source, or an aggregate records its members, each reference is a full RecordRef. A RecordRef also refuses to be built half-hearted: it rejects an empty CheckpointId or RecordId at construction, so a vague reference cannot exist.

MTRL uses a handful of identities. Some are logical names for things that persist; the rest are version or history identities for things that are fixed forever.

Identity Names Kind
CheckpointId One logical scientific result, such as “the spectrum” Logical name
RunId One logical instrument or aggregate run, such as ftir-replicate-01 Logical name
RecordId One immutable version of a checkpoint Version identity
RevisionId One committed view of the whole archive History identity
ArchiveId One archive history, from first commit onwards History identity
SampleUid One physical specimen or material unit Physical identity

Generated identities, such as fresh RecordId, RevisionId, ArchiveId, and SampleUid values, are time-ordered UUIDv7 values. Each one is unique, and newer ones sort after older ones. When you supply your own RunId or CheckpointId, MTRL keeps it; it only asks that logical identifiers are non-empty and safe to use inside archive paths.

Two practical guarantees fall out of this split.

Corrections are honest. A correction keeps the CheckpointId and mints a new RecordId, so the logical name your colleagues use survives while the old version remains retrievable by its own RecordId. You saw this in Fix a mistake: the saturated spectrum is still in the history, linked to its corrected successor.

Recipes are exact. Lineage and aggregates point at RecordRefs, not bare checkpoint names, so a recorded recipe always names the exact versions it used. The mean spectrum from your three replicates names each input record precisely. If one replicate is later corrected, the recipe still points at the version it genuinely consumed, and nothing silently retargets.

Corrections keep the CheckpointId, but a replacement mints a new one — the difference is in Corrections versus replacements. To see both identities at work in code, revisit Fix a mistake.