Ledger Record Format
Fields, identifiers, seals, and validation rules for ledger format version 0.
A ledger contains one canonical JSON record per line.
Keys are sorted by UTF-16 code unit. Numbers are integers, and insignificant whitespace is omitted.
Every field is present. Unknown times and numbers use null. Empty string fields use "".
The portable implementation is @y2/ontology.
Common fields
| Field | Type | Meaning |
|---|---|---|
v | 0 | Format version |
seq | integer | Position in the log, starting at 1, contiguous |
id | string | Record ID, with a prefix for its kind |
kind | subject, designator, observation, assertion | Record kind |
recorded_at | time | Record time, strictly increasing along the log |
prev | hex or null | Previous line hash, or null on the first line |
hash | hex | SHA-256 of the canonical line without hash |
Times are ISO 8601 in UTC with milliseconds, exactly as Date.prototype.toISOString prints them.
Records
Subject
| Field | Meaning |
|---|---|
class | person, organization, or system. A subject never changes class. |
A subject has no name. Names and identifiers arrive as designators and claims.
Designator
| Field | Meaning |
|---|---|
designator_kind | See Vocabulary |
value | The canonical string |
namespace | Platform, algorithm, registry, or exchange MIC. Empty for kinds without one. |
normalized | Case-folded for names and handles. Otherwise equal to value. |
A ledger permits one designator per (kind, namespace, normalized).
A second record with that key is rejected. The existing ID must be reused.
Observation
| Field | Meaning |
|---|---|
method | One passive method, or analyst-note |
source_grade | primary, secondary, or analytic (only for a note) |
source_url | Page URL. Required for a retrieval, optional for a note. |
archive_url | A preserved copy, or null |
retrieved_at | Retrieval time, or null on a note |
content_hash | SHA-256 of excerpt, or of an archived blob when archive_url is set |
excerpt | A quote of 1–500 characters, or null when an archive holds the content |
collector | Recording label, 1–80 characters |
cites | Observations cited by a note. Empty on a retrieval. |
Assertion
| Field | Meaning |
|---|---|
op | assert or retract |
predicate, from, to | The claim. See predicates |
qualifier | Public role on member-of. Otherwise "". |
supersedes | The current head of the claim key, or null on the key's first line |
confidence | Integer 0–100, or null on a retraction |
verification | A verification state, or null on a retraction |
valid_from, valid_to | Valid-time interval with an exclusive end. null means unknown. |
evidence_refs | 1–20 earlier observations |
note | Up to 1,000 characters of caveat |
The claim key is predicate|from|to|qualifier. Each key has exactly one chain of lines.
Identifiers
Record IDs contain a kind prefix and 24 hexadecimal digest characters. The SHA-256 input combines the record type and workspace ledger position.
| Kind | Prefix | Example |
|---|---|---|
| Subject | sbj_ | sbj_0123456789abcdef01234567 |
| Designator | dsg_ | dsg_0123456789abcdef01234567 |
| Observation | obv_ | obv_0123456789abcdef01234567 |
| Assertion | clm_ | clm_0123456789abcdef01234567 |
The offline format accepts any lowercase ID with the right prefix, such as sbj_ada in the
fictional fixtures.
Rules
Each rule has a code. The API returns codes in detail. The offline checker prints them per line.
| Code | Rule |
|---|---|
shape.* | Exact field set and field types for the kind |
format.json, format.canonical | The line is JSON in canonical form |
chain.seq, chain.prev, chain.hash | Contiguous seq, prev links the previous hash, hash matches |
chain.time, time.format | Record time strictly increases. Times use the required format. |
id.format, id.duplicate | Prefix matches the kind. IDs are unique. |
designator.* | Canonical value, correct normalization, and one record per designator key |
observation.method, observation.grade | Supported passive method. Only a note is analytic. |
observation.url, observation.time | HTTP(S) URL without userinfo. Retrieval time must not exceed record time. |
observation.note, observation.cites | Notes cite earlier observations and have no retrieval time. Retrievals cite nothing. |
observation.excerpt, observation.hash, observation.preservation | Excerpt of 1–500 characters or an archive. The hash matches the excerpt unless archived. |
assertion.endpoint | Distinct endpoints of permitted kinds. same-as and distinct-from require matching subject classes. |
assertion.qualifier | Only member-of carries a lowercase role |
assertion.chain | First claim supersedes nothing. Later claims supersede the head. Consecutive retractions are rejected. |
assertion.evidence | 1–20 distinct earlier observations |
assertion.confidence, assertion.interval | Integer confidence of 0–100. valid_from precedes valid_to. |
assertion.verification | The state is one the evidence supports (see the ladder) |
assertion.retract | A retraction clears confidence, verification, and the interval |
assertion.label | preferred-label needs a live designated-by for the same pair |
Examples
The repository supplies two valid fixtures in packages/ontology/v0/examples:
fictional.ndjsondemonstrates corrections, retractions, and disputed identity.fictional-cyber-market.ndjsondemonstrates company identifiers and supplier relationships.
The local tutorial checks the company fixture and shows its expected output.