A moderate-intensity sweep of the workspace: dead code, duplicates, placeholders, stale comments, and the correctness bugs found along the way.
Bugs fixed #
- atpmcp
create_record_cidhashed$link/$bytesas plain maps, so it returned the wrong CID for any record carrying a blob. - atproto-attestation signed the same wrong encoding. The attested "content CID" was not the record's CID, and a proof record's strongRef could have named a CID no repository holds. Breaking for signatures over records with a blob, link or bytes; verification accepts the old encoding for a transition period.
- atproto-oauth-service-token minted a
kidthe workspace's own verifier refused. - atproto-pds-admin
takedown apply/liftsent a bodyupdateSubjectStatusno longer accepts, and mis-encoded non-ASCII query values. - PLC chain validation could not replay a
creategenesis — five-year-old DIDs failed to resolve. - Repository commit signatures are now verified on load.
- P-384 attestations could not be signed; a real service-auth token was pasted in source and in
--help.
Removals #
- fjall per-actor store, never built or deployed.
PDS_STORAGE_PROFILE=fjallnow refuses at boot rather than serving a deployment's repositories as empty. - The per-actor outbox, unwritten since the firehose moved to the accounts database.
- The legacy SQLite-direct paths in the PDS; the public-realm backend is mandatory.
- The legacy identity/record CLIs (use
atpdid/atpcid) and the atproto-client XRPC CLIs (useatpxrpc). - Unused
pubitems, never-produced error variants, dead features and stale lint allows.
Features and consolidation #
- Blob bytes in object storage.
PDS_BLOB_STORE_URLselects S3, GCS, Azure or a local directory throughobject_store, replacing the unwired AWS-SDK backend. Only bytes move; therepo_blobinventory stays in SQLite, so reference counting,listBlobs, takedowns and GC are unchanged. Existing blobs move in the background withPDS_BLOB_STORE_MIGRATE_LOCAL. Drops theRUSTSEC-2026-0253audit exception. --metrics-bindbinds a real listener. It previously decided only whether/metricswas mounted on the public router, with the address discarded.- One NSID rule (
atproto_record::nsid), strict everywhere, replacing four validators that disagreed. Breaking: a space type or collection with a hyphen or leading digit in its name segment is now refused. - Space tokens verify as JWS (
AnyS), matching every other JWS verifier here. Deliberate divergence from the reference, documented at the call site. - One DID resolver, one lexicon resolver, one service-auth minter, one CID helper set, one set of test fixtures.
Migrations #
Three new actor migrations run on next boot: drop the outbox table, add repo_blob.external, drop an unused index (confirmed with EXPLAIN QUERY PLAN).
Verification #
cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings (default and --all-features), and cargo test --workspace --no-fail-fast all clean, plus the CI lean step and the release feature check. The object-storage suite was also run against MinIO under podman.
Out of scope #
The Postgres accounts backend (unfinished work, untouched), atproto-oauth-dioxus, and ranged/streamed getBlob. Follow-up filed: atproto-crates#22h3, gate atproto-lexicon's resolver behind a feature so its validation half is lean.