ATrium adoption evaluation #
This document records which ATrium components CPDS should compose, which responsibilities remain CPDS-owned, and the evidence required before an ATrium-backed path is considered production-ready. It is a dated evaluation of the crates published as of 2026-08-22, not a permanent endorsement of every future release.
Implementation notes were reconciled with the working tree on 2026-09-05,
including public applyWrites and the shared cpds-protocol crate. Package
release, dependency-count, and advisory findings below remain historical
2026-08-22 evidence; rerun the dependency acceptance gate for a current claim.
For the present source layout, use the repository guide.
The objective is a smaller PDS, not merely fewer local files. CPDS should use ATrium where it implements stable AT Protocol machinery and delete equivalent custom code after parity is proven. CPDS must still own server policy, persistence, transaction boundaries, resource limits, recovery, and operational behavior. A dependency is not a substitute for validating untrusted input.
Evaluated baseline #
The evaluated packages are from the ATrium workspace:
| Package | Version | Intended CPDS use | Decision |
|---|---|---|---|
atrium-api |
0.25.8 | Generated Lexicon request, response, union, and syntax types | Adopt incrementally |
atrium-crypto |
0.1.3 | AT Protocol key encoding, low-S signing, and signature verification | Adopted for service keys, Spaces, and public repo commits |
atrium-repo |
0.1.8 | Repository-v3 commits, MST operations, block-store traits, and CAR support | Adopted behind CPDS storage adapters and fixture gates |
atrium-identity |
0.1.9 | DID/handle resolver composition and bidirectional identity resolution | Adopted selectively behind hardened CPDS transports |
atrium-xrpc |
0.12.4 | Shared XRPC HTTP and error primitives used by generated types and clients | Use transitively or in adapters; not as an Axum server framework |
atrium-oauth |
0.1.7 | Profile-complete OAuth client behavior | Use in the end-to-end client harness only |
All evaluated packages are MIT licensed and declare Rust 1.85 as their minimum supported Rust version. CPDS declares Rust 1.88, so the current releases do not raise its MSRV. Their 2025-12 and 2026-03 releases demonstrate recent workspace maintenance, but the pre-1.0 repository, crypto, identity, and OAuth packages still require exact version pins, narrow adapters, and an explicit upgrade review.
atrium-api defaults to its agent and Bluesky namespace features. CPDS should
use default-features = false unless a required generated type proves otherwise.
The core com.atproto types remain available without enabling the client agent
or application namespaces. This avoids making a client SDK or the full Bluesky
schema surface part of the server architecture.
The dependency impact is acceptable only in stages. atrium-crypto reuses
CPDS's existing RustCrypto curves and multibase stack, though ATrium's current
thiserror 1 constraint coexists with CPDS's thiserror 2. Even with its own
default features disabled, atrium-api 0.25.8 unavoidably enables
atrium-common's Moka-based async cache graph in addition to atrium-xrpc,
chrono, langtag, regex, IPLD, and trait-variant; atrium-common exposes
no feature switch to remove that unused cache machinery. CPDS accepts that
cost only because the generated types will replace wire code across the public
repository API, not for isolated identifier validation. atrium-repo
additionally needs async streams, futures, Tokio I/O compatibility, and
unsigned varints. atrium-identity keeps its optional Hickory 0.24 DoH feature
disabled because it centralizes queries at a configured DoH service and would
add a second, older Hickory graph. CPDS instead pins Hickory Resolver 0.26.1
with system DNS and Tokio support. This adoption adds 26 locked packages,
including platform-specific DNS configuration and Rand 0.10, but no second TLS
stack; Hickory's Rust 1.88 floor matches CPDS. atrium-oauth
adds JOSE, concurrent-map, and Rand 0.8 packages, so it belongs in the
federation test harness rather than the production server; its default TLS
client feature should be disabled in favor of an injected test transport. The
actual resolved duplicates and enabled features must be measured in each
adoption commit, not inferred from these manifests.
Package decisions #
atrium-api: canonical protocol boundary #
Adopt generated types for standard com.atproto endpoints instead of
maintaining parallel Serde structs and string validators. In particular, the
generated record APIs already express bounded NSIDs, DIDs/handles, record keys,
CIDs, optional validation, compare-and-swap inputs, commit metadata, and
Lexicon-defined error variants that the current public handlers omit.
Axum handlers remain thin CPDS adapters: deserialize an ATrium input, authorize it, convert it into a validated domain command, and convert the domain result back to the generated output. ATrium wire types must not leak into database tables or become the repository service's policy model.
Acceptance evidence:
- JSON and query-string fixtures from the canonical Lexicons round-trip through the selected generated types;
- existing clients continue to receive the exact standard field names, optional fields, bounds, content types, and error names;
- default features remain disabled and the dependency tree contains no unused application namespaces or client runtime;
- each migrated endpoint deletes its superseded local wire structs and syntax checks in the same commit when no other caller needs them.
Adoption record for 0.25.8 (reviewed 2026-08-22): the crate is pinned exactly,
uses no default features, declares MIT and Rust 1.85, and comes from the active
ATrium workspace. The generated getSession shape matches the canonical
Lexicon at bluesky-social/atproto
d6296a1cfdb40a773319cb59061300e4e8e52f26; its DID and handle parsers reject
malformed or oversized identifiers, optional fields are omitted, and unknown
extension fields round-trip through Object::extra_data. CPDS validates
configured identifiers at startup and treats invalid persisted identifiers as
storage corruption rather than emitting non-conformant output.
The generated Unknown type rejects floats at the HTTP boundary, but 0.25.8's
generic JSON deserializer retains $link and $bytes objects as ordinary
maps. Passing that value directly to a DAG-CBOR serializer therefore encodes a
map and base64 string instead of CBOR tag 42 and a byte string. Its generic
TryFromUnknown helper also contains internal unwrap calls. CPDS does not use
that helper for untrusted records. A small fallible adapter recognizes only the
specified single-key special objects, reuses ATrium's CidLink and typed
BlobRef, enforces the blessed CIDv1/codec/SHA-256 forms and resource bounds,
and passes the resulting serializable value to atrium-repo. Repository reads
reuse ATrium's DataModel; startup re-encodes that native value to compare the
canonical bytes, including UTF-8 byte strings that untagged Serde inference can
misclassify as text. $type is still checked against the collection and
rejected data becomes InvalidRequest; malformed stored records are storage
corruption. Per-Lexicon schema validation remains separate: validate=true is
rejected instead of falsely claiming it, while successful unvalidated writes
report validationStatus: unknown.
That pure adapter now lives in cpds-protocol and is shared directly by public
repositories and Space CAR exports. Neither feature imports the other feature's
service implementation to encode records.
The adapter accepts every valid and rejects every invalid schema-independent
fixture in the official, implementation-neutral atproto-interop-tests
data-model set at commit 056e5741bb330757205d6b16db5266fffcae937b. Its
byte output and record CIDs also match every canonical encoding fixture,
including nested Unicode, native links, bytes, and blobs. CPDS negative tests
add unsafe numeric forms, excessive nesting, and CIDs outside the blessed set.
HTTP integration proves links and bytes retain the AT Protocol JSON
representation, and startup verification reads their native repository blocks.
The exact upstream fixtures are pinned with provenance, this adds no package,
and CPDS's MSRV is unchanged.
ATrium's Tid, Did, Handle, Nsid, RecordKey, and AtIdentifier
parsers match every corresponding valid and invalid syntax vector in the same
official fixture commit; CPDS pins those vectors at its delegated syntax and
production-identity boundaries. The sets cover maximum lengths,
percent-encoded and real DID methods, punycode/onion and RFC handle corner
cases, collection segment rules, the full record-key alphabet, case rules,
invalid path/query/fragment forms, IP addresses, labels, methods, and lengths.
Datetime matches the official lexical and semantic vectors except that
0.25.8 accepts 0000-01-01T00:00:00+01:00, whose offset normalizes before the
minimum year-zero instant. CPDS retains ATrium's parser and adds that one
ordering guard. Language likewise supplies the BCP 47 grammar, but its
langtag 0.3 dependency accepts case-insensitive duplicate variant and
extension-singleton subtags. Its public parsed-component accessors also panic
for short valid tags, so CPDS does not expose them to untrusted input; a small
post-parse scan enforces only the RFC uniqueness rules. The standalone fixture
commit still labels jaja and JA invalid, but the current Lexicon
specification requires well-formed rather than registry-valid tags and the
canonical atproto fixture
now comments out those two cases. CPDS follows the current specification and
canonical fixture while retaining the exact older vectors to detect the
documented difference.
The upstream CID syntax set cannot be used as the same kind of semantic
acceptance gate. It labels permissive
multibase strings such as
mBcDxtdWx0aWhhc2g+ valid at the syntax layer, while atrium-api deliberately
delegates to ipld-core's semantic CID parser and rejects that value as an
invalid multihash. The current AT Protocol data-model specification is stricter
still for interoperable links, requiring its blessed CIDv1 forms. CPDS therefore
does not replace the semantic parser with a fixture-only regular expression or
weaken the record-link checks. Generic CID syntax fixture coverage remains open
until the lexical-versus-semantic contract is clarified upstream. Generic URI
and AT URI fixture coverage also remains open because atrium-api does not
currently expose corresponding parsers. Native record-link fixtures and CPDS
negative tests remain the production gate.
An OSV query of the complete lockfile found RUSTSEC-2026-0253 in lru 0.16.4,
which atrium-common constrains for wasm only. CPDS does not target wasm; both
the aarch64-apple-darwin and x86_64-unknown-linux-gnu graphs exclude lru,
and separate OSV checks of the native graphs returned no advisories. The native
graph has no packages with missing license metadata and uses permissive
MIT/Apache/BSD/ISC/Zlib/Unicode/CDLA/CC0/Unlicense combinations. A future wasm
target is blocked until ATrium permits patched lru >= 0.18.2. Upgrade
atrium-api when a reviewed release models the current describeServer
blobUploadLimit field, removes the target-only advisory, or materially reduces
the mandatory atrium-common graph; re-run the full acceptance gate then.
atrium-crypto: AT Protocol signing boundary #
Adopt its P-256 and secp256k1 did:key parsing, key formatting, low-S signing,
and strict verification for repository commits and AT Protocol service keys. It
uses the same RustCrypto ecdsa, k256, and p256 families already used by
CPDS, so it centralizes protocol-specific encoding and malleability rules rather
than replacing the underlying audited primitives.
The strict verifier rejects high-S and DER-encoded signatures by default and
ships the AT Protocol signature fixture set for both supported curves. The
permissive verifier mode must not be used on federation boundaries. CPDS may
continue using direct RustCrypto APIs for JOSE operations that atrium-crypto
does not model, but should not retain duplicate multikey or repository-signature
code.
Acceptance evidence:
- CPDS runs the pinned upstream valid, high-S, and DER signature vectors in its own interoperability suite with recorded provenance;
- generated signatures match the raw 64-byte, SHA-256, low-S AT Protocol form;
- malformed multibase, wrong multicodec, wrong curve, short/long signature, and mutated-message tests fail closed without panics;
- key material is not copied or logged beyond what the API requires, and the production secret-loading boundary remains CPDS-owned.
atrium-repo: repository mechanism, not persistence policy #
Adopt its repository-v3 commit encoding, MST, typed/raw record operations, block-store traits, extraction, and CAR primitives after interoperability tests prove byte-for-byte output. Implement its async block-store traits over a CPDS-owned SQLite transaction so record blocks, MST blocks, signed commit, repository head, operation rows, and outbox event succeed or roll back together.
The current crate intentionally separates signing from commit construction,
which is useful for CPDS key custody. It also explicitly opens repositories
without verifying the commit signature. Repository::open therefore must never
be CPDS's trust decision: resolve the identity, verify the commit signature,
validate version/DID/revision/previous-link invariants, and enforce resource
limits before accepting imported or remote data.
The bundled CAR reader verifies SHA-256 blocks, but currently allocates lengths
declared by the input, accepts unsupported block hash algorithms without
verification, and treats an unexpected EOF while reading the next frame as a
normal end of archive. CPDS must place byte/block/depth limits around CAR input
and either harden those conditions upstream or use a bounded import adapter.
Several MST internal invariant failures use panic!/unwrap; fuzz and corrupt
block tests must demonstrate that attacker-controlled repository data cannot
reach them before the reader is exposed publicly.
Acceptance evidence:
- official MST, DAG-CBOR, CID, commit, and CAR fixtures match byte for byte;
- randomized operation sequences match the reference implementation's roots and survive create/open/export/import cycles;
- corrupt blocks, cycles, invalid key ordering, invalid hashes, truncated CARs, oversized lengths, excessive blocks, unsupported hashes, and bad signatures return bounded errors rather than panicking or exhausting resources;
- repository mutations use a real SQLite transaction through the ATrium block-store adapter and pass rollback, compare-and-swap, concurrency, restart, and clock-rollback tests;
- any local MST, commit, block, or CAR implementation superseded by the adapter is removed rather than retained as a second production path.
Adoption record for 0.1.8 (reviewed 2026-08-22): the crate is pinned exactly,
declares MIT and Rust 1.85, and was published from ATrium commit
1762e5bcf00fb2a038fa4a94777acdd9cb6d4b70 on 2026-03-25. Its MST output
matches the empty, eleven-record, twelve-record, and post-delete root CIDs in
the official TypeScript reference suite at the pinned AT Protocol commit. It
also matches all six official firehose commit-proof fixtures: pre/post roots
for single and multi-operation merge/split cases, plus the exact proof set
formed by newly written blocks that remain reachable from the final root. This
proves the public Tree API is a conformant basis for atomic applyWrites even
though Repository does not expose a batch builder; CPDS wraps the final root
in exactly one signed commit and transaction. Its block-store
traits are a useful composition boundary, but DiffBlockStore
records writes after forwarding them and is not an atomic staging layer. CPDS
therefore stages content-addressed writes in memory, filters a legacy backfill
to ATrium's reachable export, and inserts each incremental write batch, record
index, head, operation, and outbox event in one SQLite transaction. Commit-event
proof membership is the intersection of staged writes and the final root's
reachable blocks, excluding transient blocks from earlier operations in a batch.
The source review also found boundaries that CPDS must enforce. Repository and
MST open operations explicitly trust stored structure and do not verify commit
signatures, version, DID, revision, key ordering, depth, or resource bounds.
Some malformed graphs can reach panic!, assert!, or unwrap invariants;
record reads assert the DAG-CBOR codec. The CAR reader trusts declared lengths
for allocation, treats an unexpected EOF at the next frame as clean end of
input, and does not verify unsupported hash algorithms. Until a bounded
validator proves those conditions safe, CPDS uses atrium-repo only to
construct locally authorized repositories. Its SQLite adapter verifies block
hashes before any ATrium read, and raw repository/CAR readers remain unexposed
to remote input.
Full public export now composes Repository::export_into with ATrium's CAR v1
writer over CPDS's verified local block store. CPDS verifies the signed head
before traversal and wraps the writer in a 64 MiB hard bound; the router applies
the expensive-endpoint peer limit. The interoperability test reopens only this
locally generated response with ATrium, checks the declared commit root and
signature, and reads a record through the exported MST. This does not relax the
remote-input quarantine above. ATrium's export currently deduplicates through a
hash set, so block order is arbitrary; the current repository specification
permits arbitrary order while describing commit-first pre-order traversal as a
future streaming preference. Incremental since export uses CPDS's durable
per-commit block membership to select revisions newer than the requested TID
while keeping the current signed head as the CAR root, matching the reference
reader's layered-CAR contract. It fails closed across legacy rows whose exact
membership was not recorded. An interoperability test layers the incremental
archive over a prior full export and reads both old and new records through
ATrium.
Record-level sync similarly composes Repository::get_raw for existence and
Repository::extract_raw_into for the signed MST proof. Its endpoint test
confirms the proof resolves the requested record at the declared current root
and omits an unrelated record block, keeping CPDS out of proof construction and
preventing the public response from disclosing unrelated values.
Repository::add_raw and update_raw correctly preserve serializable native
CID and byte values, but plain serde_json::Value cannot express them to a
non-human-readable serializer. CPDS therefore passes only the small
schema-independent adapter described under atrium-api; ATrium remains the
sole repository/MST writer and CPDS does not maintain a parallel block encoder.
Block sync uses ATrium's reachable repository export as the authorization set,
then reads only requested members through the CID-verifying SQLite adapter and
writes them with CarStore. This is necessary because CPDS's content-addressed
block table is shared across repositories, unlike the per-account store used by
the reference PDS. Requests are bounded to 1,000 CIDs and the CAR has an empty
roots array, matching the current reference implementation. Repeated XRPC query
keys are parsed with pinned serde_html_form 0.2.8, already present and used by
atrium-xrpc, so the direct dependency adds no package or parallel query stack.
Public and permissioned blob listing now share one recursive scanner built on
ATrium's BlobRef parser. It accepts both the current typed representation and
ATrium's read-only legacy representation, canonicalizes valid CIDs, ignores
malformed lookalikes, and replaces the previous hand-written Spaces-only blob
shape checks. Public listing derives only from current repository records (or
paths changed after since), so it does not disclose unattached uploads.
Record create and put use the same parser as a stricter write boundary: only
the current typed representation is accepted, and its CID, MIME type, and size
must match metadata already uploaded by that repository owner.
Repository streaming reuses atrium-api's generated subscribeRepos message,
identity, account, commit, sync, operation, DID, handle, TID, datetime,
CID-link, and byte-string models.
ATrium does not currently provide a Rust server-side event-stream encoder, so
the CPDS HTTP adapter owns only the specified transport boundary: one binary
WebSocket frame containing a small {op, t} DAG-CBOR header followed by the
generated payload without $type. This matches the official event-stream
encoder at AT Protocol source commit
d6296a1cfdb40a773319cb59061300e4e8e52f26. Axum's existing ws feature adds
tokio-tungstenite 0.29, tungstenite 0.29, and SHA-1 only for the standard
WebSocket upgrade; their Rust 1.63/1.71 floors are below CPDS's Rust 1.88 MSRV
and their MIT/Apache licensing stays within policy. CPDS retains stream
admission, backpressure, cursor, persistence, and shutdown policy because those
are server responsibilities rather than AT Protocol data-model machinery.
The first repository transaction persists identity, active-account, and commit
events in the order recommended by the
sync specification on one sequence. CPDS
now includes the canonical stored account handle: local mode derives it from the
validated local document, while production verifies both public directions
before accepting the first write. Existing retained events remain immutable.
Later user lifecycle changes reuse generated activateAccount,
deactivateAccount, getSession, getRepoStatus, listRepos, and
subscribeRepos shapes. ATrium supplies the evolving Lexicon wire models,
while CPDS retains account policy, atomic status/outbox persistence, visibility
decisions, and concurrency gates because those are PDS server responsibilities.
The end-to-end test decodes status/session/list responses and retained
#account events through ATrium before and after reactivation.
The durable window is configurable and pruned atomically with commits. A stale
cursor receives ATrium's generated #info model with the Lexicon-defined
OutdatedCursor name, while incremental CAR export rejects history older than
the same boundary. listRepos and
listReposByCollection likewise use generated
ATrium parameters, repository models, DID/CID/TID fields, and the reference PDS
time/DID cursor. The collection variant applies the generated canonical NSID to
CPDS's current record index rather than reimplementing repository discovery
models.
describeRepo and listMissingBlobs use generated ATrium output models; the
latter and listBlobs query schema-v6 reference indexes populated by the same
ATrium typed/legacy blob scanner. Public and Space mutations update their index
in the record transaction, migrations backfill them, and startup recomputes them
to fail closed on drift. A real WebSocket relay consumer opens commit CARs
through ATrium, verifies the signed root, and resolves the announced MST record
before accepting an event. A recovery variant forces the durable cursor outside
retention, consumes the generated OutdatedCursor information event, opens a
full getRepo CAR through ATrium, verifies its signed head and every current
record, then resumes live and validates the next inductive commit.
The resolved graph reuses CPDS's existing ATrium API, CID, IPLD, DAG-CBOR,
Serde, SHA-256, Tokio, and Tokio-util packages. Its incremental packages are
atrium-repo, async-stream, the futures facade/I/O/channel features, and
unsigned-varint's futures support; it introduces no second CID, CBOR, crypto,
or async runtime. All resolved packages have license metadata and remain in the
documented permissive license set. A complete-lockfile OSV check still finds
only the documented wasm-only lru 0.16.4 advisory, while both supported native
target graphs (aarch64-apple-darwin and x86_64-unknown-linux-gnu) are clean.
atrium-identity: resolution with CPDS network policy #
CPDS now uses ATrium's common resolver for did:plc, well-known resolver for
HTTPS handles, generated DID/handle/document types, and XRPC HTTP trait. It
keeps direct DNS TXT selection because ATrium's DNS resolver returns the first
matching record rather than rejecting conflicting valid DIDs as the handle
specification requires. The canonical
resolveHandle Lexicon
intentionally performs only the forward lookup, while CPDS startup separately
applies the bidirectional trust check. The shared service also replaced the
parallel remote DID fetches used by Space signing-key and service resolution.
CPDS must provide the outbound transports and cache. Those adapters own DNS and HTTP timeouts, maximum response sizes, redirect behavior, TLS, allowed schemes and ports, IP-range/SSRF rejection, PLC endpoint configuration, positive and negative cache TTLs, concurrency bounds, and metrics. Resolver success is not enough: CPDS verifies document identity and applies caller-specific trust rules, including signing-key type/controller, service identifier/URL, and bidirectional handle-DID correspondence.
The local document does not require a network resolver. CPDS constructs and
validates both local and fetched DID documents with atrium-api::did_doc, uses
the generated type's PDS/signing-key helpers at startup, and requires a
production did:web authority to equal the public origin. This removed the
parallel DID document wire structs and remote Space fetch paths while retaining
CPDS's fetch policy. The production transport uses credential-free public HTTPS,
deployment system DNS with private/reserved answers denied, three redirects,
five-second connects, ten-second requests, 256 KiB responses, and bounded
positive/negative DNS caching. Version 0.1.9's WebDidResolver
interpolates the complete did:web method identifier as a hostname, so it does
not replace CPDS's small path-bearing, percent-decoded did:web URL mapping.
ATrium's higher-level identity resolver also treats a document with no
alsoKnownAs as acceptable; CPDS explicitly requires the exact at:// backlink
for its production trust decision.
Production periodically reuses this same resolver boundary. CPDS persists only
confirmed invalidity as the AT Protocol special value handle.invalid, appends
the generated #identity stream model through its existing durable outbox, and
restores the configured handle after a confirmed recovery. Transient resolver
failures retain the last confirmed state. This policy and persistence remain
CPDS-owned because ATrium provides resolution and wire models, not PDS hosting
lifecycle orchestration.
Acceptance evidence:
- pure negative tests cover DNS noise/duplicates/conflicts, unsafe identity
URLs,
did:webroot/path/port mapping, and missing/wrong/exact backlinks; - an injected
IdentityNetworkcontract proves DNS precedence, HTTPS fallback only for absence/transport failure, terminal conflicts, document-ID matching, bidirectional trust, and invalidation/recovery behavior independently of public network state; - generated-route and Space integration tests cover local handle resolution and reuse of the shared DID boundary;
- a fully local fake DNS/HTTPS/PLC service must still cover both successful methods and their precedence;
- private, loopback, link-local, redirected, oversized, slow, malformed, and mismatched responses fail according to explicit local/production policy;
- cached results honor bounds and expiry and cannot bypass bidirectional verification;
- superseded remote fetch and document-parsing paths are deleted; the small
conflict, backlink, and
did:webconformance adapters remain until upstream provides equivalent behavior with negative coverage.
atrium-xrpc and atrium-oauth: narrower roles #
atrium-xrpc defines client-side request/response/error and HTTP traits. It is
useful under atrium-api, resolver transports, and test clients, but it does not
provide Axum routing, server authorization, request limits, or CPDS transaction
semantics. CPDS should keep direct Axum handlers rather than build a second
server abstraction.
atrium-oauth is an OAuth client library. It can drive the local discovery,
PAR, DPoP, authorization, token, refresh, revocation, and authenticated-XRPC
end-to-end test. It does not replace the PDS authorization server. CPDS retains
server metadata, client registration policy, PAR/session storage, DPoP nonce and
replay state, token rotation, consent, revocation, and security headers.
Dependency acceptance gate #
Before each new ATrium dependency or version is committed:
- Pin the reviewed version in
Cargo.tomlandCargo.lock; disable default features and enable only features exercised by CPDS. - Confirm its declared MSRV is no higher than CPDS's, its license is allowed, and its release/changelog/repository show active maintenance.
- Review its public API and relevant source for trust assumptions, panics, unchecked allocation, permissive compatibility modes, network behavior, and secret handling.
- Run
cargo tree -dandcargo tree -e features; avoid a second crypto, async, HTTP, CID, CBOR, or Serde stack unless the benefit is explicit. - Run the repository's dependency advisory and license policy. A missing audit tool is a failed release gate, not evidence of no advisories.
- Add official fixture and CPDS negative tests before routing production data through the component.
- Put unstable ATrium APIs behind one small adapter owned by the relevant CPDS domain, then delete superseded custom code after parity is established.
- Record the exact upstream version, fixture commit, enabled features, known limitations, and upgrade trigger in the commit or test provenance file.
ATrium upgrades are reviewed changes, not automated version bumps. Re-run the source review, dependency tree, advisory check, official fixtures, negative tests, and federation harness before accepting one.
Planned adoption order #
- Complete: pinned
atrium-crypto, official signature fixtures, and removal of duplicate AT Protocol multikey and low-S signing/verification code while retaining JOSE-specific RustCrypto use. - Complete for the implemented standard surface: pinned
atrium-apiwithout default features; migratedcom.atproto.server.getSession,com.atproto.repo.createRecord,com.atproto.repo.deleteRecord,com.atproto.repo.getRecord,com.atproto.repo.listRecords,com.atproto.repo.uploadBlob, andcom.atproto.sync.getBlob, plus account configuration syntax, to generated wire and identifier types. The migrations removed CPDS's parallel blob reference structs, correctedgetBlobto require a DID rather than the previously accepted handle, enforce data-model-safe record JSON, support current-record CID selection, implement reference-compatible before/after rkey pagination, and enforcedeleteRecord.swapRecordatomically in SQLite. The canonicaldescribeServerLexicon atd6296a1cfdb40a773319cb59061300e4e8e52f26includesblobUploadLimit, which 0.25.8 does not yet model explicitly, so that endpoint remains local pending a compatible release or a deliberately tested extension-field adapter. CPDS's remaining DID, NSID, record-key, and TID validators now delegate directly to the generated ATrium syntax types; the superseded handwritten grammar and length logic has been removed. Local and fetched DID documents pluslistRepos,listReposByCollection,describeRepo, andlistMissingBlobsresponses use canonical ATrium models instead of CPDS-owned wire structs. Blob discovery reuses ATrium's current and legacy reference scanner and persists its result as atomically maintained, startup-verified public and Space indexes. Schema v6 durably stages object publication and uses those indexes to transactionally claim aged orphans before bounded, crash-resumable object deletion. - Complete for create/update/delete and atomic batches: a CPDS SQLite staging adapter composes
atrium-repofor signed repository-v3 commits, passes the pinned reference roots, returns commit metadata, enforces commit/record swaps, and atomically publishes blocks, head, index, operation, and outbox state. Ordered publicapplyWritesuses one final signed commit and the same transaction. Before binding, CPDS uses ATrium's MST entry stream and repository reads to verify the signed head, every reachable record block, and exact parity with its SQL record index; routine readiness remains a bounded adapter check. ATrium 0.1.8 exposes only single-operation builders that advance the commit when finalized; it has no public batch builder. CPDS composes its public MSTTreeAPI for the ordered operations and signs the final root once. The pinned commit-proof vectors guard ATrium's root/proof behavior; CPDS service, SQL rollback, and HTTP tests guard the surrounding batch transaction. - Complete for local full and incremental export: bounded ATrium CAR export, signed-head verification, and versioned historical block selection are live. Add a hardened bounded import adapter before enabling remote repository ingestion.
- Complete for user account lifecycle and commit/sync transport: generated
ATrium subscription models, durable inductive metadata, signed CAR slices,
legacy
#syncrecovery, and bounded binary WebSocket delivery are live. On-disk recovery is proven by replaying a committed event and receiving the next live event after restart. Configurable retained windows and generated#info/OutdatedCursorrecovery are live. The initial identity/account/commit sequence is decoded from a real WebSocket through generated ATrium types before and after restart. A relay-consumer test verifies streamed CAR roots, signatures, and MST records through ATrium. A forced slow-consumer test proves bounded disconnect and durable cursor replay without adding a parallel stream implementation. The explicit relay operation likewise reuses ATrium's generatedrequestCrawlinput while CPDS owns origin policy, deadlines, retries, logs, and process status. Relay-style gap repair through a full ATrium-opened CAR and subsequent live commit is also proven. One combined fake relay now receives the real crawl request, validates the served DID/handle pair and signing key, repairs the expired cursor, and verifies the next live commit. Durable user activation/deactivation now reports through generated status/session/list models, gates content and writes, and emits generated#accountevents. The CPDS-owned offline operator path reuses that atomic transition/event machinery for host states and verifies storage around the action. Add DID-document lifecycle, secure account erasure, and crawl metrics. - Extend the adopted
atrium-identityboundary with fake DNS/HTTPS/PLC wire services and cache/latency metrics. Periodic invalid-handle/recovery events, the deterministic resolver port, and the orchestration-policy contract are complete; retain only the reviewed conflict, backlink, and conformantdid:webadapters that upstream does not provide. - Use
atrium-oauthin the profile-complete local client harness while the CPDS authorization-server implementation remains explicit.
This order can yield to a smaller prerequisite, but CPDS must not introduce a second long-lived implementation of the same AT Protocol mechanism.