8. Provenance and logs
Every stored value says where it came from (chapter 1.9). This chapter says how sources are assigned, how ownership moves, how disagreements are kept, and how the full history lives in each owner's signed log.
8.1 Origin #
origin records how a value was first established, and it never changes.
| Origin | Means | Assigned by |
|---|---|---|
observed |
read off a real instance | a contract whose origin is observed (a form at the bench, OCR of a photo, a scale) |
declared |
its maker or a person said so | a form (the default), a maker's feed |
derived |
a rule computed it | the engine, for fills, derivations and rollups (chapter 6.4) |
reported |
a catalog says so, origin unknown | a receive contract (the default) |
- A value that arrives with its own source (from another owner's data, chapter 7.8) keeps that source's
origin. Otherwise it takes the contract's. - Rule or contract? A value that can be produced again from the record's own values, with the same
answer, is
derivedby a rule; it can be dropped and rebuilt. A value that can't (AI text, a price from comparables, a drawn SKU) came through a contract, carries that contract's origin, and is irreplaceable, so it is kept. - A migration never becomes a value's origin or owner (8.6).
8.2 Owner and adopting #
owner is who controls a value now. It changes in one way: adopting (✎, "made your own"). The same verb
works at every scale.
| You adopt | From | Then |
|---|---|---|
| a produced value, by editing it | a rule | the value stops following the rule; the source gains adopted: true |
| another owner's value | that owner | owner becomes you; origin stays theirs; their later changes arrive as suggestions |
| another owner's whole record | that owner | a new record of yours, with crubal:clonedFrom linking the original |
- An adopted value doesn't update until it is given back: removing the adoption returns it to following its rule or its presenter, and the next run or update replaces it.
- A presenter's
termsmay forbid adopting (chapter 7.8). Then a consumer's edit is refused. - Strength limits adopting a produced value (chapter 6.2):
mustforbids it,shouldflags it.
8.3 Link, copy, adopt #
| You hold | Readable on its own? | Updates? | Owner |
|---|---|---|---|
| a link | no: it's their current value while they're reachable | always theirs | them |
| a copy | yes, self-contained | by the mode (chapter 7.8) | them, until adopted |
| an adopted copy | yes | no; their changes arrive as suggestions | you |
A copy is always self-contained: it holds the values and their sources, so it reads without the original.
8.4 Trust and alternatives #
When two sources disagree about a value (a conflict, chapter 9), the trust order picks the current value. The trust order is per package (chapter 11); by default a person comes first. A facet MAY override it.
The losing values are kept, in the record's alternatives, keyed by address like sources:
"alternatives": {
"title": [
{ "value": "National Lampoon's Christmas Vacation", "origin": "reported", "via": "L-55ZT" }
]
}
Each alternative is a value with its full source. An alternative becomes current only by a person's choice
or a change in the trust order, and the value it replaces becomes an alternative in turn. Suggestions
(values that land: suggestion, chapter 7.5) are kept the same way, in suggestions.
Sources stay hidden when printing in plain mode (chapter 2.6), and so do alternatives and suggestions.
8.5 The log #
Each owner keeps a log: an append-only list of entries, one per write, however many values the write touched (chapter 3.8 gives the JSON).
Every change is a transaction. An entry is the unit: it applies whole or not at all, and a store that fails partway applies nothing of it. Data entry, intake landing, a grant, a review decision and a change to a definition are each one entry with one cause. The unit is one caller's action on one record, or on the few records one operation touches (a merge, an attach); a run over many records writes one entry per record, so one refused row refuses one row (chapter 7.5). What is computed is never a transaction: projections, rule results and pending instructions are read off the state. Nor is a read, except under an emergency edge (chapter 14.13). An event in the world (a sale, a reading) is not a transaction either: it is a record of a kind with a moment facet, and the transaction is the write that records it (chapter 6.11).
- Hash-linked. Each write has a hash: the SHA-256 of its canonical form (chapter 3.9). An entry's
hash is the SHA-256 of its canonical form without
sig, with each item ofwritesreplaced by the stringsha256:and that write's hash in hex. So the entry's hash covers every write through the write's own hash, and a write can be taken out (8.5.2) without moving it.previssha256:and the previous entry's hash. The first entry of a chain has noprev. - Signed.
sigis the owner's Ed25519 signature over the entry's hash (its 32 bytes, not the hex text), written as base64url without padding, made with the key published for the owner's domain (chapter 7.8). A redacted entry carries noowner; it is checked against its chain's owner. When the owner's key is known, an entry without a validsigbreaks the chain there. - Chains. An owner MAY keep several chains, each linear (one per shard of a large store); every entry
then names its
chain. A record's writes MUST all go to one chain. - No consensus. There is no mining and no global ledger. Every record has an owner, and the owner's log is the truth for the owner's data. Anyone holding entries can check the links and signatures.
The log records effects, not causes. An entry says exactly what changed in the stored state, so the state can be rebuilt from the log alone (8.5.3). Why it changed is linked, not re-derived: the intake record, the run, the rule or the recipe.
What an entry holds: log (its ID), prev, chain (when there are several), owner, at, by
(exactly one of person, contract with run, rule, migration, instruction or take with the
presenter's entry), intake (when the write came through intake), source (the default source of its
value writes: origin, and owner and adopted when they apply; via is the entry itself), writes,
crubal (the language version, on the first entry of a chain and whenever it changes from the entry
before, chapter 11.8), and sig.
Each write is one of these:
| Write | Names | Effect |
|---|---|---|
| value | record, address, value or "removed": true, as, and source when it differs from the entry's |
as says where the value lands: current (the default), alternative, suggestion or held |
| envelope | record and one envelope member: created, of, within, wears, status, applied |
the record's envelope (chapter 1.12) |
| edge | the edge (chapter 14.3), or its ID and "removed": true |
access and relations; a lapse it causes down the grantor chain is computed, not written |
| observation | the observation document (chapter 3.8) | it is kept, beside the record it supports |
| binding | contract, ref, and record or "removed": true |
an arrival binding (chapter 9.2a) |
| review | the item, and its decision or "opened": true |
the review queue (chapters 9.5, 10.4) |
| instruction | record, its number and the instruction |
the record's instructions (chapter 10.7) |
| run | run, contract, its idempotency key, state: started, acted, failed, closed, and on started the versions of the contract, the package and the rules it uses (chapter 7.4) |
the run's state (chapter 7.5) |
| define | a member of the owner's working package (chapter 11.4) as it now stands: facet, class, rule, contract, kind, view, shape, filter, migration, permissions or ownership, in the JSON form, or its name and "retired": true; or package, the package's own settings (chapter 11.1: its trust order, prefixes, pins and thresholds) |
the definition in force from this entry on; by is the person who changed it, in the same entry as the review write when a review decision did (chapter 9.5) |
| install | the package identity and version | a package of another owner the store adopts; the restamp that follows is its own entries |
| read | record and the edge it was read under, under an emergency edge only (chapter 14.13) |
nothing; it is the record that a read happened |
Definitions are state like records: the owner's working package is what the define writes build, so a
rebuild (8.5.3) recovers the definitions in force at any entry together with the data, and replay (chapter
9.6) needs nothing outside the log. A published version of the package is a snapshot of that state (chapter
11.5).
An entry MAY carry witnessed: true (chapter 14.13); such an entry MUST NOT be redacted.
What can be computed from the log and the package versions it installs is never logged: completeness and the other rule results (chapter 6.9), projections (chapter 12.6), and whether instructions are pending.
8.5.1 Values that crossed a border #
When a value comes from another owner, the consumer's entry says so: by is {"take": "catalogTake", "from": "distributor.example/L-91AC"}. The value keeps its origin, and the presenter's entry can be checked
against the presenter's own log.
8.5.2 Redaction #
A write, or a whole hop, can be hidden without breaking the chain.
- A redacted write is replaced, inside its entry, by
{"redacted": "sha256:…"}, the hash of the write it replaces. The entry's hash is unchanged (8.5), soprevof the next entry still matches, the signature still verifies, and every write the entry kept is still checked by its own hash. - A redacted entry keeps only
log,prev,chain,sigand"redacted": "sha256:…", the hash of the full entry. Its hash is that value. This is how a whole hop is hidden when an owner shares part of a log.
What may be redacted. Only value, observation and read writes, and only in an entry that isn't witnessed (chapter 14.13). An envelope, edge, binding, review, instruction, run, define or install write is never redacted, so a rebuild (8.5.3) never meets a write to a record it hasn't seen; an entry holding one of those is redacted write by write, never whole.
Erasure is redaction applied to a person: every value write that holds their data, in every entry that holds one, is redacted, whatever else the entry holds. The entry that created their record keeps the creation and loses the values beside it, so the record's shell stays and its values are gone, and the log still proves what happened and when without saying what was written. Erasure is the owner's power (chapter 14.1), and a person's own records (14.1) are erased by them.
8.5.3 Rebuild and replay #
Two different things, never to be confused:
- Rebuild applies the log's entries, in order, to an empty store. It needs no rules, no contracts and no engine of a particular version, and it MUST give exactly the state the store had. A store MUST be able to rebuild; the state it keeps is a cache of the log. A redacted write or entry is skipped, so rebuilding gives the state without what they held, which is what erasure means.
- Replay (chapter 9.6) folds kept intake records again under the current definitions. It is new work, and it writes new entries.
8.6 Migrations and history #
A migration's write gets its own log entry, with by: {"migration": "<recipe>"}. It never changes a
value's origin or owner: a person's renamed value is still the person's, with the migration in its
history.
Values written before an owner kept a log (legacy data) get one entry for the whole backfill, with by: {"migration": "backfill"}. Their origin is what is known about them, and reported when nothing is.
8.7 Read-through values #
Values read through from an upper level or a shared part carry no source on the lower record. Their source lives where they are stored, and the log entries are the upper record's.
8.8 Record members added by this chapter #
Chapter 3.2's record gains three optional members:
| Member | JSON | Present |
|---|---|---|
alternatives |
object: address → array of {value, origin, via, owner?} |
when a conflict left a losing value |
suggestions |
the same shape | when values landed as suggestions |
held |
object: address → {value, rule?, instruction?} |
when a value is held (chapter 6.7, 10.4, 10.7): kept, out of the current values |
and the source object (chapter 3.7) gains adopted: true.