Records
A capability owns collections of records. Only the owner writes them (ATLAS013: one owner per collection; ATLAS017: writes and removes only to owned collections). Others read them through a foreign read with a declared shape, or react to the owner’s facts.
owns: { orders: t.object({ orderId: t.string, customerId: t.string, status: t.enum('placed', 'cancelled'), lines: t.array(Line), totalCents: t.int, placedAt: t.string, cancelReason: t.nullable(t.string), }),},Versions and conflicts
Section titled “Versions and conflicts”Every record carries a version. A decision that read a record commits only if the version is unchanged; otherwise the decision runs again (optimistic concurrency). A read with checked: false opts out for advisory checks (see Commands).
Removal and tombstones
Section titled “Removal and tombstones”d.remove('drafts', id) deletes an owned record atomically with the other effects. Use it only for true deletion; keep records with audit value.
A removed record stays as a tombstone (value null, version kept), so a decision that read it, or read the record before the removal, conflicts instead of overwriting a newer life of the key. atlas compact --db <url> --older-than 30d deletes tombstones removed longer ago than that. It is safe once no decision can still hold a version it read before the removal; decisions hold one only between their read and their commit, so the CLI refuses less than one hour.
Record evolution
Section titled “Record evolution”Owned records version the same way as facts, with t.versioned (the same function as t.fact):
owns: { stores: t.versioned(2, StoreV2, { from: 1, shape: StoreV1, up: (v1) => ({ ...v1, currency: v1.currency ?? 'CRC' }), examples: [...] }),}Each record stores the shape version it was written at. Every read lifts an older row to the latest shape before anyone sees it: the owner’s and foreign reads in commands, reactions and record queries, and runtime.store.get/list. A write always stores the latest version, so rows migrate as they are touched; nothing is rewritten in bulk. A row no chain can lift rejects with upcast-failed. Never advise a database reset for a shape change.
Sensitive fields
Section titled “Sensitive fields”Owned records may hold t.sensitive(...) fields. They leave the capability only through a record query with non-public access (ATLAS022).
Free reads
Section titled “Free reads”runtime.store.get(collection, key) and runtime.store.list(collection) read without versions, lifted to the owner’s latest shape. Prefer declared queries: they check access and never leak sensitive fields.