Records as content-addressed signed data
Every artifact in idiolect is an ATProto record. A record is:
- a JSON object,
- with a
$typefield naming a lexicon, - stored at a
(did, collection, rkey)triple, - content-addressed by its CID,
- signed by the publishing repo's signing key.
The substrate is documented in the ATProto spec. This chapter covers the properties idiolect relies on.
Properties idiolect relies on
1. Records are signed
Every commit is signed by the repo's signing key. A consumer fetching a record can verify the signature against the repo head and the head against the canonical PLC directory entry. idiolect's trust model is rooted in those signatures: a verification record is only as trustworthy as its signer.
The runtime does not re-validate signatures on every read. The shipped path is:
sequenceDiagram
Consumer->>PDS: getRecord(uri)
PDS-->>Consumer: { value, cid, signed_commit }
Consumer->>PLC: resolve did
PLC-->>Consumer: signing_key
Consumer->>Consumer: verify cid against signed_commit
Consumer->>Consumer: verify signed_commit against signing_key
The verification step is what idiolect-identity plus the
VerifyingResolver in idiolect-lens give you. Cache the
resolved signing key, re-fetch only on cache miss, and treat a
mismatch as a hard error.
2. Records are content-addressed
A record's CID is derived from its canonical bytes. Two records
with the same content have the same CID. The CID is what the lens
record's object_hash field carries, and what the
VerifyingResolver checks before instantiating a lens. A
malicious upstream cannot serve a different lens under the same
at-uri without changing the CID, and the CID change is observable.
3. Records compose by reference
A record can reference another record by at-uri or by strongRef
(at-uri + CID). A strongRef is content-addressed, so the
reference points at exactly one byte sequence. An at-uri is a
mutable pointer.
idiolect uses strongRef for evidence (belief.evidence,
correction.encounter, verification.lens) and at-uri for
queries that should follow updates (recommendation.lensPath,
dialect.entries[].vocab). The choice in each lexicon is
deliberate; see the per-lexicon reference for the rationale.
4. Records survive PDS migration
ATProto's identity layer (PLC plus did:web) lets a repo move
between PDSes without changing its did. A record fetched by
at-uri after a PDS migration goes through one extra DID-resolve
hop and arrives at the new PDS. idiolect's runtime path goes
through idiolect-identity for every fetch; PDS migration is
transparent.
Properties idiolect adds on top
5. Lexicon validation at the boundary
Every shipped record kind validates against its lexicon at parse
time. A field that violates a format, maxLength, or
required constraint fails to deserialize before any business
logic runs. The boundary is exactly where you want it.
6. Family-typed dispatch
The codegen-emitted family modules (idiolect_records::IdiolectFamily)
let consumers be generic over the family. A firehose handler that
takes a RecordHandler<F: RecordFamily> filters out-of-family
commits before decode. The crate-level reference covers
OrFamily<F1, F2> for composing families.
7. Open enums
Every enum-shaped field is an open enum: known values are typed
constants, unknown values fall through to Other(String), and the
sibling *Vocab field points at a dev.idiolect.vocab record
where unknown values resolve. This is what lets two communities
extend the same field without a centralized governance step. See
Open enums and vocabularies.
8. Internal records do not federate
Runtime state that should not federate (firehose cursors, OAuth
tokens) uses the same panproto schema apparatus, but under a
sibling dev.idiolect.internal.* namespace. Conformant firehose
consumers skip the prefix; the data still travels through the
same runtime as a public record, just out of band.
What ATProto does not give you
- A schema language. ATProto Lexicon is a constrained type language; it does not cover lens algebra, schema diffs, or optic classification. Those live in panproto, which idiolect embeds.
- A migration story. Lexicon revision is wire-compatible by policy, not by tooling. The lexicon-evolution policy fills the gap; see Lexicon evolution policy.
- A vocabulary registry. Open-enum slugs need a published
knowledge graph to resolve; ATProto does not ship one. The
dev.idiolect.vocabrecord is where the resolution lives.