# 2. Operations ## 2.1 The envelope Every operation is a JSON object with exactly these members (plus optional `x_*` extension members, see `05-versioning-errors-extensibility.md` §3). Missing required members, unknown members, or wrong types are `ERR_SCHEMA`. | Member | Type | Req | Meaning | |---|---|---|---| | `v` | string | ✔ | Protocol version. MUST be `"omp/0.2"` in this version (`ERR_VERSION` otherwise). | | `type` | string | ✔ | One of the seven type names below. | | `log` | identity ID | ✔ | The identity whose log this operation belongs to (the *subject log*). | | `author` | key ID | ✔ | The key that signed this operation. | | `seq` | integer | ✔ | Per-(log, author) sequence number, starting at 1, incrementing by exactly 1. | | `prev` | op ID or `null` | ✔ | Operation ID of this author's previous operation in this log. MUST be `null` iff `seq` is 1. | | `deps` | array of op IDs | ✔ | Causal dependencies: operation IDs (any author, same log) this author had applied when creating this operation. MAY be empty. SHOULD be the current heads (frontier) only. Duplicates, or the value of `prev`, MUST NOT appear (`ERR_SCHEMA`). | | `lc` | integer | ✔ | Lamport clock. MUST be strictly greater than the `lc` of the operation referenced by `prev` and of every operation in `deps`; MUST be ≥ 1 (`ERR_CLOCK`). | | `ts` | timestamp | ✔ | Advisory wall-clock creation time (§1.3 of the encoding spec). | | `body` | object | ✔ | Type-specific payload, defined per type below. | | `sig` | signature | ✔ | Ed25519 signature over the preimage (§1.4 of the encoding spec). | Notes: - `prev` + `seq` give each author a **hash chain** (tamper-evident, gap-evident). - `deps` makes the whole multi-author log a **Merkle DAG**, which is what gives OMP deterministic merge and verifiable causality (`03-log-and-merge.md`). - An operation references other operations **only by operation ID**. Referencing an operation the verifier does not (yet) have is not an error: the operation is **deferred** (`DEFER_MISSING_DEP`) until the referenced operation arrives. ### 2.1.1 Reference type rules Several bodies reference targets that MUST be of a particular type. A verifier that holds the referenced operation MUST check its `type` and reject with `ERR_REF` on mismatch. The referenced operation MUST belong to the same `log` (`ERR_REF`). --- ## 2.2 `evidence-ingest` Registers a piece of raw evidence. Raw bytes live in the node's content-addressed blob store, *outside* the log; the log records only the hash, so logs can sync without leaking evidence content, and evidence can be destroyed (GDPR-style) without breaking the chain. ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `source` | string | ✔ | Source registry value: `calendar`, `notes`, `photos`, `messages`, `contacts`, `app-activity`; or an extension source matching `^x-[a-z0-9-]+$`. | | `adapter` | string | ✔ | Adapter identifier and version, e.g. `"omp-ical/0.2"`. ≤128 chars. | | `media_type` | string | ✔ | RFC 6838 media type of the raw bytes, e.g. `"text/calendar"`. ≤128 chars. | | `content_hash` | content hash | ✔ | `sha256:` hash of the raw evidence bytes. | | `size` | integer | ✔ | Length of the raw evidence bytes. ≥ 0. | | `captured_at` | timestamp | – | When the evidence was originally captured/created at the source. | | `summary` | string | – | Short human-readable label (≤512). MUST NOT be relied on for derivation. | | `inline_b64` | string | – | The raw bytes themselves, base64url unpadded, permitted only when decoded length ≤ 4096. If present: `sha256(decode(inline_b64))` MUST equal `content_hash` and decoded length MUST equal `size` (`ERR_REF` on mismatch). | Two ingests of identical bytes (same `content_hash`) are permitted (e.g. the same file seen on two devices); derived state keys evidence by `content_hash` where dedup matters, but each ingest is its own operation with its own provenance. ## 2.3 `claim-assert` Asserts a derived claim about a subject, with provenance and confidence. The claim is identified forever by this operation's `op_id`. ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `subject` | identity ID | ✔ | Who the claim is about. In this version MUST equal the envelope `log` (`ERR_REF` otherwise); cross-subject claims are reserved. | | `predicate` | string | ✔ | Dot-namespaced predicate, regex `^[a-z0-9_]+(\.[a-z0-9_]+)*$`, ≤128 chars. The `omp.*` namespace is reserved for the core ontology; everything else is open. | | `object` | any JSON value | ✔ | The claim's value. Subject to OMP-CJ (integers only) and the 8192-byte limit. | | `confidence_ppm` | integer | ✔ | Confidence in parts-per-million: 0…1000000 inclusive (`ERR_RANGE`). | | `method` | string | ✔ | Identifier of the rule/model/human action that produced this claim, e.g. `"rule:weekly-event/1"`, `"model:local-llm/3"`, `"user-statement"`. ≤128. | | `derived_from` | array | ✔ | Provenance edges (below). MAY be empty only for ground-truth assertions (`method` SHOULD then be `"user-statement"`); derivation engines MUST populate it. | | `valid_from` | timestamp | – | Claim validity window start (advisory). | | `valid_until` | timestamp | – | Claim validity window end (advisory). | Each `derived_from` element is an object: | Member | Type | Req | Meaning | |---|---|---|---| | `op` | op ID | ✔ | The referenced operation. | | `kind` | string | ✔ | `"evidence"` (target MUST be `evidence-ingest`), `"claim"` (target MUST be `claim-assert`), or `"inference"` (target MUST be `inference-call`). Mismatch is `ERR_REF`. | `derived_from` is the **derivation graph**: it is what makes corrections cascade (`03-log-and-merge.md` §7). Elements MUST be unique by `op` (`ERR_SCHEMA`). Provenance references SHOULD also appear in `deps` (directly or transitively) so that causality covers derivation; a verifier MUST defer (not reject) a claim whose `derived_from` targets are unknown. ## 2.4 `correction` Supersedes an existing claim. The canonical pattern for "fix a claim" is two operations: first `claim-assert` the corrected claim, then `correction` pointing the old claim at the new one. ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `target` | op ID | ✔ | MUST reference a `claim-assert` in the same log (`ERR_REF`). MUST NOT equal `replacement`. | | `replacement` | op ID | – | MUST reference a `claim-assert` in the same log if present (`ERR_REF`). The claim that supersedes the target. Omitted when the claim is simply withdrawn without replacement. | | `reason` | string | – | Human-readable reason, ≤2048. | Effects (normative details in `03-log-and-merge.md` §6–7): the target claim's status becomes `superseded`; downstream claims deriving from it become `tainted`. ## 2.5 `refutation` The user (or an authorized agent) marks a claim **false** or a piece of evidence **invalid**. Stronger than correction: a refuted claim is not merely outdated, it is asserted to be wrong, and verifiers MUST treat it (and its taint cascade) as unusable for derivation and for sharing. ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `target` | op ID | ✔ | MUST reference a `claim-assert` or an `evidence-ingest` in the same log (`ERR_REF`). | | `reason` | string | – | ≤2048. | Refutation of evidence is the mechanism behind "this calendar import was garbage": every claim deriving (transitively) from that evidence becomes `tainted`. ## 2.6 `permission-grant` Grants a capability over a scoped slice of the graph to a key or identity. Grants are the *only* source of authority other than the identity root key. Used both for **sharing** (read/infer caps to third parties) and for **device authorization** (author cap to the user's own device keys) — see `04-keys-and-capabilities.md`. ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `grantee` | key ID or identity ID | ✔ | Who receives the capability. | | `caps` | array of strings | ✔ | Non-empty set (unique, sorted ascending — unsorted is `ERR_CANONICAL`-adjacent but checked as `ERR_SCHEMA`) drawn from: `"author"`, `"delegate"`, `"infer"`, `"read"`. Unknown caps are `ERR_SCHEMA`. | | `scope` | object | ✔ | Scope object (below). | | `expires_at` | timestamp | – | Grant expiry (advisory cutoff applied at evaluation time, `04-…` §4.4). | | `max_depth` | integer | – | Maximum further delegation depth, 0…8. Default 0 (no re-delegation) — and re-delegation additionally requires the `delegate` cap. | | `note` | string | – | ≤2048. | `scope` object: | Member | Type | Req | Meaning | |---|---|---|---| | `predicates` | array of strings | ✔ | Non-empty list of predicate patterns. A pattern is a predicate, optionally ending in a final `*` label (e.g. `"omp.schedule.*"`) which matches any non-empty suffix of labels. `"*"` alone matches everything. | | `provenance` | string | ✔ | How much provenance the grantee may see: `"none"` (claims only), `"ids"` (derivation edges as opaque op IDs), `"full"` (transitive provenance including evidence operations — not evidence *content*, which is never in the log). | | `ops` | array of strings | – | For `author` caps: which operation types the grantee may author, e.g. `["inference-call"]`. Absent means all types. Values MUST be valid type names, unique, sorted. | | `min_confidence_ppm` | integer | – | Read scope includes only claims with confidence ≥ this value. 0…1000000. | ## 2.7 `revocation` Mechanically revokes a grant. Permanent: a revoked grant can never be reinstated (issue a new grant instead). ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `target` | op ID | ✔ | MUST reference a `permission-grant` in the same log (`ERR_REF`). | | `reason` | string | – | ≤2048. | Who may revoke, and what happens to operations authored under a revoked grant, is defined normatively in `04-keys-and-capabilities.md` §4.5–4.6. ## 2.8 `inference-call` Records that an inference was executed over user data: which inputs, by what model, under what authority. This is the audit trail behind "what do you know about me and **why**" and behind delegated access accounting. Nodes MUST record an `inference-call` for every model invocation that consumes log-derived data, before or atomically with asserting any claims derived from it. ### Body | Member | Type | Req | Meaning | |---|---|---|---| | `purpose` | string | ✔ | Human-readable purpose, ≤512. | | `model` | object | ✔ | `{ "id": string (req, ≤128), "version": string (≤64), "provider": string (≤128), "digest": content hash }` — `version`, `provider`, `digest` optional. Unknown members `ERR_SCHEMA`. | | `inputs` | array of op IDs | ✔ | The operations (claims/evidence/inference outputs) provided to the model. MAY be empty (e.g. cold-start prompt). Unique. Each referenced op MUST be `evidence-ingest`, `claim-assert`, or `inference-call` (`ERR_REF`). | | `request_hash` | content hash | ✔ | Hash of the exact serialized request (prompt/context) bytes. The bytes themselves are blob-store material, never in the log. | | `response_hash` | content hash | – | Hash of the raw response bytes, when retained. | | `grant` | op ID | – | The `permission-grant` under which this call was authorized. REQUIRED when the author's authority is a scoped grant rather than root/device authority (`04-…` §4.3); MUST reference a `permission-grant` (`ERR_REF`). | Claims produced from a model call reference it with `derived_from[].kind = "inference"`, which transitively links the claim to the model, the inputs, and (via `grant`) the authority — the full "why". --- ## 2.9 Member ordering quick reference (canonical form) Because members are sorted, the envelope always serializes in this order: ``` author, body, deps, lc, log, prev, seq, sig, ts, type, v ``` (`x_*` extension members, if any, sort after `v` at the top level, and wherever they fall alphabetically inside `body`.) Body member orderings are likewise fixed by sorting; the worked examples in `06-worked-examples.md` show full byte layouts.