Docs Menu

Specs

spec/05-content-model.md · shown exactly as it appears in the repository

05: Content Model

Status: Draft, v0.1. License: This text is CC-BY-4.0; the field names, enum values, and other machine-readable schema elements defined here are also MPL-2.0. See LICENSE-DOCS and LICENSE.

Overview

Content is any object shared between connections (e.g. a photo, a message, a membership record) typed by its isA descriptor. What content types exist, and how each is categorized for access control, isn't fixed by the protocol: each domain declares its own content model, including which of its types are subbable, subbable-related, unshareable, or subscription-unrelated (see 04-access-control.md's subLabel section). Two domains may categorize structurally similar content completely differently. This chapter defines the fields every content item carries regardless of domain, and the mechanism a domain uses to declare its own content model, not any specific domain's actual content types.

The content envelope

Every content item, regardless of domain, carries a baseline shape:

Field Purpose
ck The content's own unique key.
isA Its content type.
version Incremented on every update; used to discard stale/duplicate updates (see 06-propagation.md).
receivedFromCxnId Which connection this content came from, or 'me' if it's the party's own. Determines ownership (below).
originDOS How many hops this content was originally allowed to propagate; originDOS minus remainingDOS gives hops traveled so far.
remainingDOS Hops still remaining; decremented on every further share. Content with none remaining is never shared again (see 06-propagation.md).
created When the content item was first created.
updated When the content item was most recently updated.

Relationship descriptors

A content item declares its relationships to other content and to connections explicitly, rather than requiring those relationships to be derived by traversing the data graph at the moment they're needed:

  • Parent pointer: {parentIsA}CK (e.g. groupCK on a member): a direct, single-slot "this belongs to that" reference.
  • Content-reliance: reliesOn{IsA}CK (e.g. reliesOnMemberCK): a denormalized reference to another content item this one depends on, used so a cascading delete can match directly instead of walking a multi-hop chain to re-derive the relationship. A content type MAY declare as many of these as its dependency graph needs; there's no protocol-imposed limit.
  • Connection-reliance: reliesOnCxnId (and as many further slots as needed, e.g. reliesOnSecondaryCxnId): the same denormalization applied to a connection instead of another content item, so that deleting a connection can efficiently find everything that depends on it.

Shareable vs. local descriptors

Not every field on a content item travels with it when shared. An implementation MUST strip, before transmission: receivedFromCxnId, any database-internal identifier (e.g. _id), and every connection-reliance descriptor (reliesOnCxnId and its further slots). A cxnId MUST NOT leave the party that holds it, the same non-linkability guarantee from 00-overview.md, extended to any field referencing one. A domain MAY additionally declare its own fields as local-only (e.g. isSubscribed, fileSize), stripped the same way. Content-reliance descriptors (reliesOn{IsA}CK) are not stripped: they reference another content item's ck, which the receiver needs to reconstruct the same dependency graph on its own side.

Registering a domain's content model

A domain's content model is its own to define; different domains may define it completely differently.

Schema registration and validation

A domain registers a schema for each content type, declaring required fields, mutually-exclusive field groups, at-least-one-of field groups, and allowed values for specific fields. An implementation MUST validate content against its registered schema before saving; invalid content MUST NOT be persisted.

Labeling for access control

Separately, a domain registers how its content types map onto the subLabel categories from 04-access-control.md: which types are subbable, subbable-related, unshareable, or subscription-unrelated, and how to derive a piece of content's parent for the subbable-related case. This is distinct from schema validation above: it drives access-control labeling, not content-shape validation.

Domain identifier and namespace

A domain's wire identifier (the domain field carried in every envelope, e.g. bonafide.pools) and the internal namespace its schema and content validator register under are related but not identical: an implementation MUST derive the namespace from the identifier's final dot-separated segment (bonafide.pools → pools). Both the schema and the content validator (above) register under this derived namespace, not the full dotted identifier.

Ownership and mutation

A content item has exactly one owner: the party whose receivedFromCxnId is 'me'. An implementation MUST reject any attempt to locally create, update, or delete content not owned by the local party; only the owner may originate a mutation. Content received from a peer is written through a separate path (governed by the shareSequence/version ordering rules in 06-propagation.md, not this ownership check). A receiving party MUST NOT treat its own local edits to received content as an authoritative mutation anyone else needs to honor: only the domain's local-only descriptors (above) may be freely changed locally.