Agora Record v1¶
Source schema: doc/schemas/agora-record.v1.schema.json
Machine-readable schema for a signed, content-addressed, topic-addressed record ingested by an Agora topic relay. The envelope is backend-neutral and intentionally opaque about topic-key shape: the substrate does not type, parse, or split topic/key. Resource identity (proposal 026) is reachable through the optional record/about field and is never used as the primary key.
Governing Basis¶
doc/project/40-proposals/035-agora-topic-addressed-record-relay.mddoc/project/40-proposals/026-resource-opinions-and-discussion-surfaces.mddoc/project/40-proposals/024-capability-passports-and-network-ledger-delegation.mddoc/project/40-proposals/032-key-delegation-passports.mddoc/project/40-proposals/013-whisper-social-signal-exchange.md
Project Lineage¶
Requirements¶
doc/project/50-requirements/requirements-006-node-networking-mvp.mddoc/project/50-requirements/requirements-010-middleware-executor.mddoc/project/50-requirements/requirements-011-dator-arca-contracts.md
Stories¶
doc/project/30-stories/story-001-swarm-node-onboarding.mddoc/project/30-stories/story-004-pod-client-onboarding.mddoc/project/30-stories/story-005-whisper-rumor-intake.mddoc/project/30-stories/story-006-buyer-node-components.mddoc/project/30-stories/story-006-voluntary-swarm-exchange.mddoc/project/30-stories/story-007-settlement-capable-node.md
Fields¶
| Field | Required | Shape | Description |
|---|---|---|---|
schema |
yes |
const: agora-record.v1 |
Schema discriminator. MUST be the literal string agora-record.v1. |
record/id |
yes |
string | Content-addressed identifier of this record. Computed by the Orbiplex canonical sha256_base64url helper: sha256: followed by the unpadded base64url (RFC 4648 section 5) encoding of sha256(canonicalize(payload)), where payload is the record with record/id, signature, relay/received-at, relay/id, and relay/hops removed. Two records with the same canonical payload MUST yield the same record/id on every relay. |
record/kind |
yes |
string | Role label of this record. Application-visible discriminator used by query APIs and kind contracts. Examples: opinion, comment, annotation, public-log, whisper-durable. The substrate accepts any well-formed kind; it MAY mark unknown kinds as non-indexable until a kind contract is registered. |
topic/key |
yes |
string | Opaque topic identifier. The substrate MUST NOT parse, split, or type this value. Canonicalization rules: Unicode NFC, no control characters (C0/C1/DEL), no leading or trailing whitespace, non-empty, at most 512 bytes after UTF-8 encoding. Applications choose their own naming conventions (namespace-prefixed paths, content-derived identifiers, human-readable channel names). Topic keys derived from external resource identity are a convention of the record-kind contract, not a rule of the substrate. |
author/participant-id |
yes |
string | Participant identity or application-layer nym identity of the record author. Participant-authored records verify directly against the participant key or an explicit delegation proof. Nym-authored records MUST carry author/nym-proof, and the record signature verifies against the nym key certified by that proof. |
author/nym-proof |
no |
ref: nym-authorship-proof.v1.schema.json |
Inline-first proof for nym-authored records. Required when author/participant-id starts with nym:did:key: and forbidden by the core verifier for participant-authored records. The proof context MUST match topic/key, record/kind, content/schema, and any relevant disclosure scope. |
authored/at |
yes |
string | Wall-clock timestamp asserted by the author at the moment of record creation. Relays enforce a clock skew window (default ±10 minutes) at ingest; out-of-window records are flagged and temporarily excluded from live query results. |
content/schema |
yes |
string | Identifier of the schema that describes the inner content payload. MUST follow the {slug}.v{n} shape. Examples: plain-comment.v1, public-log-entry.v1, resource-opinion.v1. The substrate does not require content/schema to be pre-registered; unknown schemas are stored and served but MAY be treated as opaque by indexers. |
content |
yes |
object | Payload object conforming to the schema named by content/schema. Kind contracts define field-level validation; the substrate performs envelope-level validation only. |
record/about |
no |
array | Optional secondary-index references to external subjects this record is about. Each entry follows the resource identity model from proposal 026. MUST NOT be used by the substrate to derive topic/key. A kind contract MAY require one or more entries for specific record kinds. |
record/parent |
no |
string | Optional parent record reference (reply, annotation, successor). MUST resolve to a record under the same topic/key. A record that references an as-yet-unknown parent is flagged dangling until the parent appears. |
record/supersedes |
no |
string | Optional prior record reference that this record revises or replaces. MUST resolve to a record under the same topic/key authored by the same author/participant-id, unless a kind contract explicitly relaxes the author constraint. |
record/policy |
no |
string | Optional policy record reference. For comment threads this SHOULD point to an Agora record with record/kind = thread-policy and content/schema = comment-thread-policy.v1. The policy record is part of domain authorization and is signed like any other Agora record; the substrate only validates the reference shape. |
record/tags |
no |
array | Optional short free-form tags for application-level grouping. The substrate does not interpret tag semantics. |
record/lang |
no |
string | Optional BCP 47 language tag describing the natural-language contents of the record. Informational only. |
relay/received-at |
no |
string | Wall-clock timestamp stamped by the relay that first ingested the record. MUST NOT appear in the payload the author signs. Stripped before record/id computation and signature verification. |
relay/id |
no |
string | Identifier of the relay that first ingested the record. MUST NOT appear in the payload the author signs. Stripped before record/id computation and signature verification. |
relay/hops |
no |
integer | Relay-local hop count stamped by relay implementations. The field is transport metadata, not author content: it MUST NOT appear in the payload the author signs and is stripped before record/id computation and signature verification. |
signature |
yes |
ref: #/$defs/signature |
Ed25519 signature over the canonical payload of this record with signature, relay/received-at, relay/id, and relay/hops removed. Direct participant signatures verify with the participant key embedded in author/participant-id. Direct nym signatures verify with the nym key embedded in author/participant-id and require a verifier-usable author/nym-proof. Delegated signatures carry key/public (the proxy signing key) and key/delegation (an inline proof from proposal 032); verifiers first check the Ed25519 signature with key/public, then validate the delegation proof. Note that record/id is INCLUDED in the signed payload: the signature explicitly binds the content-address. record/id itself is a separate hash computed over a different canonical payload that additionally excludes record/id. |
Definitions¶
| Definition | Shape | Description |
|---|---|---|
signature |
object | |
delegationProof |
object | Compact bearer credential copied from a key-delegation.v1 artifact and embedded beside a proxy-key signature. The full semantics live in proposal 032; Agora treats this as an inline proof for delegated record signing. |
Conditional Rules¶
Rule 1¶
When:
{
"properties": {
"author/participant-id": {
"pattern": "^nym:did:key:"
}
},
"required": [
"author/participant-id"
]
}
Then:
{
"required": [
"author/nym-proof"
]
}
Field Semantics¶
schema¶
- Required:
yes - Shape: const:
agora-record.v1
Schema discriminator. MUST be the literal string agora-record.v1.
record/id¶
- Required:
yes - Shape: string
Content-addressed identifier of this record. Computed by the Orbiplex canonical sha256_base64url helper: sha256: followed by the unpadded base64url (RFC 4648 section 5) encoding of sha256(canonicalize(payload)), where payload is the record with record/id, signature, relay/received-at, relay/id, and relay/hops removed. Two records with the same canonical payload MUST yield the same record/id on every relay.
Maintainer note: Canonicalization rules (key sorting, number normalization, Unicode NFC) are defined by the orbiplex-agora-core library and MUST match across implementations. The sha256:<base64url-no-pad> shape matches the convention already used by node/capability/src/lib.rs::sha256_base64url for signed artifacts and passport hashes.
record/kind¶
- Required:
yes - Shape: string
Role label of this record. Application-visible discriminator used by query APIs and kind contracts. Examples: opinion, comment, annotation, public-log, whisper-durable. The substrate accepts any well-formed kind; it MAY mark unknown kinds as non-indexable until a kind contract is registered.
topic/key¶
- Required:
yes - Shape: string
Opaque topic identifier. The substrate MUST NOT parse, split, or type this value. Canonicalization rules: Unicode NFC, no control characters (C0/C1/DEL), no leading or trailing whitespace, non-empty, at most 512 bytes after UTF-8 encoding. Applications choose their own naming conventions (namespace-prefixed paths, content-derived identifiers, human-readable channel names). Topic keys derived from external resource identity are a convention of the record-kind contract, not a rule of the substrate.
Maintainer note: The ^\S(.*\S)?$ pattern rejects leading and trailing whitespace. Unicode NFC normalization and the byte-length bound are enforced by orbiplex-agora-core since JSON Schema cannot express them directly.
author/participant-id¶
- Required:
yes - Shape: string
Participant identity or application-layer nym identity of the record author. Participant-authored records verify directly against the participant key or an explicit delegation proof. Nym-authored records MUST carry author/nym-proof, and the record signature verifies against the nym key certified by that proof.
author/nym-proof¶
- Required:
no - Shape: ref:
nym-authorship-proof.v1.schema.json
Inline-first proof for nym-authored records. Required when author/participant-id starts with nym:did:key: and forbidden by the core verifier for participant-authored records. The proof context MUST match topic/key, record/kind, content/schema, and any relevant disclosure scope.
authored/at¶
- Required:
yes - Shape: string
Wall-clock timestamp asserted by the author at the moment of record creation. Relays enforce a clock skew window (default ±10 minutes) at ingest; out-of-window records are flagged and temporarily excluded from live query results.
content/schema¶
- Required:
yes - Shape: string
Identifier of the schema that describes the inner content payload. MUST follow the {slug}.v{n} shape. Examples: plain-comment.v1, public-log-entry.v1, resource-opinion.v1. The substrate does not require content/schema to be pre-registered; unknown schemas are stored and served but MAY be treated as opaque by indexers.
content¶
- Required:
yes - Shape: object
Payload object conforming to the schema named by content/schema. Kind contracts define field-level validation; the substrate performs envelope-level validation only.
record/about¶
- Required:
no - Shape: array
Optional secondary-index references to external subjects this record is about. Each entry follows the resource identity model from proposal 026. MUST NOT be used by the substrate to derive topic/key. A kind contract MAY require one or more entries for specific record kinds.
record/parent¶
- Required:
no - Shape: string
Optional parent record reference (reply, annotation, successor). MUST resolve to a record under the same topic/key. A record that references an as-yet-unknown parent is flagged dangling until the parent appears.
record/supersedes¶
- Required:
no - Shape: string
Optional prior record reference that this record revises or replaces. MUST resolve to a record under the same topic/key authored by the same author/participant-id, unless a kind contract explicitly relaxes the author constraint.
record/policy¶
- Required:
no - Shape: string
Optional policy record reference. For comment threads this SHOULD point to an Agora record with record/kind = thread-policy and content/schema = comment-thread-policy.v1. The policy record is part of domain authorization and is signed like any other Agora record; the substrate only validates the reference shape.
record/tags¶
- Required:
no - Shape: array
Optional short free-form tags for application-level grouping. The substrate does not interpret tag semantics.
record/lang¶
- Required:
no - Shape: string
Optional BCP 47 language tag describing the natural-language contents of the record. Informational only.
relay/received-at¶
- Required:
no - Shape: string
Wall-clock timestamp stamped by the relay that first ingested the record. MUST NOT appear in the payload the author signs. Stripped before record/id computation and signature verification.
relay/id¶
- Required:
no - Shape: string
Identifier of the relay that first ingested the record. MUST NOT appear in the payload the author signs. Stripped before record/id computation and signature verification.
relay/hops¶
- Required:
no - Shape: integer
Relay-local hop count stamped by relay implementations. The field is transport metadata, not author content: it MUST NOT appear in the payload the author signs and is stripped before record/id computation and signature verification.
signature¶
- Required:
yes - Shape: ref:
#/$defs/signature
Ed25519 signature over the canonical payload of this record with signature, relay/received-at, relay/id, and relay/hops removed. Direct participant signatures verify with the participant key embedded in author/participant-id. Direct nym signatures verify with the nym key embedded in author/participant-id and require a verifier-usable author/nym-proof. Delegated signatures carry key/public (the proxy signing key) and key/delegation (an inline proof from proposal 032); verifiers first check the Ed25519 signature with key/public, then validate the delegation proof. Note that record/id is INCLUDED in the signed payload: the signature explicitly binds the content-address. record/id itself is a separate hash computed over a different canonical payload that additionally excludes record/id.
Maintainer note: Two distinct canonical payloads are used in this schema: (1) the record/id payload excludes record/id + signature + relay fields; (2) the signature payload excludes only signature + relay fields and keeps record/id. This matches the Matrix event-signing pattern where event_id is embedded in the signed content and gives wider cross-transport compatibility.
Definition Semantics¶
$defs.signature¶
- Shape: object
$defs.delegationProof¶
- Shape: object
Compact bearer credential copied from a key-delegation.v1 artifact and embedded beside a proxy-key signature. The full semantics live in proposal 032; Agora treats this as an inline proof for delegated record signing.