# Changes and records

URL: /code/platform/changes-and-records · Id: `page:code/platform/changes-and-records`

> A Startup changes its definitions through Changes and writes its facts directly; both run as Actions, and nothing is ever purged.

A [Startup](/business/nouns/startup) writes in two ways: a [Change](/business/nouns/change) for its definitions, and a direct write for its facts. Both run as [Actions](/business/nouns/action), and no write ever purges a record.

## Two ways to write
| What | Written by | Examples |
| --- | --- | --- |
| Definitions | A Change, reviewed and merged | [Offers](/business/nouns/offer), [Pages](/business/nouns/page), [Templates](/business/nouns/template), [Permissions](/business/nouns/permission), [Nouns](/business/nouns/noun), [Verbs](/business/nouns/verb), [Policies](/business/nouns/policy), code |
| Facts | A direct write, one Action each | [Contacts](/business/nouns/contact), [Orders](/business/nouns/order), Leaseline's `Lease` records, [Events](/business/nouns/event), [Tasks](/business/nouns/task) |

Where the line falls is a [Setting](/business/nouns/setting) per Noun. Two writes always go through a Change, whatever the Setting says: widening a Permission and moving money.

## A Change
A Change is drafted against a base [Version](/business/nouns/version). Its branch holds only the rows it touches, and its preview reads them over live data. Leaseline sees a new notice on its real `Lease` records before any resident does.

```ts
import { $ } from 'startup-builder'

await $.Change.review({ change: 'change_3Ex8uVSOyQ' })
const { version } = await $.Change.merge({ change: 'change_3Ex8uVSOyQ' })
```

- [Change.review](/business/nouns/change/review) runs every [Evaluator](/business/nouns/evaluator) on the preview. A Change above the Startup's stakes threshold waits for an [Approval](/business/nouns/approval); a low-stakes Change merges without one.
- [Change.merge](/business/nouns/change/merge) is three-way and field-level. A field changed on both sides since the base sends the Change back to review. A definition changed on both sides waits for a rebase.
- [Change.revert](/business/nouns/change/revert) writes a new Change and a superseding [Decision](/business/nouns/decision). Nothing is deleted.

## Versions
A Version is an immutable build of a definition at a fingerprint. Which Version serves is a pointer that `merge` and [`Version.deploy`](/business/nouns/version/deploy) move. An Order keeps the Offer Version it bought, so a price change never rewrites a past sale.

## Records
A fact is written with the [Thing](/business/nouns/thing) Verbs that every Noun inherits: create, get, list, update and delete.

- A write may name `ifVersion`, the Version of the Thing it read, sent as `If-Match` on the API. When the Thing has moved past it, the write is refused and nothing changes.
- Every durable write takes an [idempotency key](/code/api/guides/idempotency), so a retry runs the Verb once.
- A delete is soft. The Thing leaves every list and keeps its history, and [`Thing.restore`](/business/nouns/thing/restore) brings it back.
- [Action.undo](/business/nouns/action/undo) removes the records a done Action created, each restorable. Money returns through a new Action, such as a refund.

## Further shapes
Each shape below has status `planned`, so an agent never offers it.

| Shape | What it adds |
| --- | --- |
| `Change.ops`, `Change.write` | Typed operations on paths: `set`, `add`, `remove`, `rename`, `move`. A rename rewrites every reference, and a batch that changes nothing writes no Version |
| Version history | `parent`, `author`, `source`, `ops`, `changes`, `issues` and `actionId` on every Version |
| `Version.compare` | A field-by-field diff of two Versions, in the words a founder reads |
| `Change.revert` by path | `paths` and `toVersion`: restore part of a definition to an earlier Version |
| Field preconditions | An expected value per field; a stale write answers `409` with the current value and who changed it |
| Insert once | A create with a fixed id that returns `inserted: true` or `false` |
| Delete preview | `Thing.delete` honors each [Relationship](/business/nouns/relationship)'s `onDelete` and previews what it removes; `list` takes a `deleted` filter |
| Field diffs | Each Event carries the fields it changed, from and to |
| Number floors | An auto-number is never given twice, even after a delete |
| Partial apply | A Change applies its fresh writes, skips the stale ones and expires at `expiresAt` |
| Guarded Noun edits | `Noun.update` refuses to remove a field another Noun, Verb or [Workflow](/business/nouns/workflow) still reads |