Skip to content

Module Map

Draft

This map answers one question: for a given piece of code, which design doc owns its contract and what tier validates it. It says nothing about whether a surface is built — that is the slice tracker’s job, and keeping the answer in one place is what stops this map going stale. To learn whether something exists today, find its slice: rg 'S-C16' SLICES.md.

CrateOwnership
capsule-coreCryptography (including the MLS album authority), canonical CBOR, validation, CRDTs, sidecars, backup, lifecycle, client filesystem, local SQLite and vector index, import scan/plan/execute, culling, LQIP, share and drop crypto, aggregated federation views, ML orchestration
capsule-serverThe Kynos REST/OpenAPI application — see Server Modules
capsule-sdkThe Spargen-generated REST client plus the orchestration over it Capsule owns: auth and session refresh, the resumable upload state machine, sync, recovery, protocol-version negotiation, LAN peering
capsule-wireThe response taxonomy shared by server and SDK. Framework-free by construction: serde is its only dependency, so neither side’s transport choices reach the other
capsule-wasmThe browser sealing surface capsule-web loads — share-link open and guest-drop sealing over capsule-core with default features off. Built by mise run build-wasm; never committed
capsule-i18n + xtask::i18nCanonical ICU catalogs, runtime localization, generated platform catalogs
capsule-core-ffiUniFFI bindings for native Swift and Kotlin consumers, on one UniFFI version across both surfaces
capsule-core-swift, capsule-core-kotlinPer-platform harnesses that link the compiled core over those bindings, and the HardwareSigner implementations (Secure Enclave, StrongBox)
capsule-cli + its entity/migration cratesLocal CLI behavior and its SQLite persistence; network commands ride the SDK
capsule-webThe browser client: the guest-drop and share-link viewer surfaces, over capsule-wasm
capsule-swift, capsule-androidThe native applications
capsule-visionModel-evaluation notebooks; no shipped source

GraphQL and gRPC are retired transports and no compatibility surface will be restored (ADR-0001). Review-only sources live under legacy-review/: they are not Cargo packages and have no validation status until rewritten against their owning contracts.

ModuleOwning designValidation
crypto::{primitives,keys,encryption,provenance,verify_asset}Cryptography and AuthorizationUnit vectors, negative cases, smoke
crypto::authorityKeys — Write Authority InterfaceUnit; epoch-ledger round trip
crypto::authority::openmls_authorityMLS and MLS ResilienceUnit and smoke; protocol round trip
cborMetadataCanonical-byte vectors; cross-language conformance
validationValidationPure invariant unit tests
backupBackup and RecoveryUnit and smoke
lifecycleOrganization and ProvenanceUnit and smoke; signed write path
library::{init,open,rebuild,scrub,cache,lock,paths,receipts,auth_gate}Client Filesystem and MaintenanceUnit and smoke
library::{space,storage_verify}Import Pipeline and Storage VerificationUnit boundary and release-gate tests
import::{scan,scanner,planner,group,special,scope,default_album,importers,streaming,upload,executor,progress}Import PipelineUnit; the executor’s media half waits on capsule-core::media
drop, sharingWeb Upload and Share LinksUnit and KAT; sealing round trips cross-language against capsule-wasm
cullingOrganization — CullingUnit; filtered views and reject sweep
federationFederationUnit; aggregated album view over authority fixtures
ml::{registry,orchestrator,regen,runner}AIUnit determinism; the real inference runner is post-v1
cohortAuthenticationUnit determinism
metadata, sidecarMetadataUnit determinism and round trips
dbClient FilesystemUnit SQLite operations; vector index over sqlite-vec
domain, modelsOrganization, MetadataClosed-enum and model unit tests

OpenMLS and the inference engines are implementation dependencies; Capsule retains the application protocols, schemas, provenance, and policy. Peering is the SDK’s, not the core’s — it is a transport between two clients, and the artifact it moves is the backup container.

capsule-server is one Kynos REST/OpenAPI application composed from cohesive internal modules, not separate public transports or microservices. Route modules under routes/ carry the HTTP surface; the modules below carry the behavior behind it.

ModuleContract ownerRequired validation
auth, enrollment, directoryAuthentication and Device EnrollmentUnit plus Postgres/Valkey adapter parity
uploadUpload ProtocolState-machine property tests, adapter parity, smoke and E2E
blob, serveServer FilesystemSharded-layout round-trip and full-store enumeration, range, corruption, crash, quarantine tests
verify, attestationStorage VerificationReceipt chain continuity, nonce echo, verdict-over-the-same-read tests
gc, scrubFilesystem — MaintenanceRefcount mark-and-sweep, retention purge, read-only integrity scrub
syncDownload and SyncCursor, monotonicity, pagination and range-resume tests
albumAuthorization and VersioningLifecycle-write authorization, chain advance, upgrade ceremony
shareShare LinksCapability and expiry tests
drop, escrowWeb Upload and Backup and RecoveryDrop-session validation, adoption, escrow store/replace
federationFederationCapability, compartmentalization and pull-path tests
quota, moderationQuota and ModerationUnit plus policy smoke tests
storeServer Filesystem — Required ServicesOne conformance suite every adapter runs, which is what lets the in-memory double be trusted
problem, limits, bodyAPI Surfaces — Rejection MappingCoded-problem bodies, body-size limits, header census on every route

The server owns its content-addressed blob implementation behind a Capsule-defined backend trait. The E2EE-aware resumable protocol also stays in Capsule. Authentication state and upload state use separate typed ports; no generic CAS, transfer, or TTL library is introduced.

BoundaryDecision
REST clientSpargen-generated Rust from a checked-in OpenAPI 3.2 document
SDK workflowsCapsule-owned authentication, upload, sync, recovery, and protocol-version orchestration
Workspace verbs over FFIThe capsule_sdk UniFFI namespace exposes the workspace surface apps need — enroll/open (including a hardware-signer constructor), albums, seal and import, verify, sync-apply, master-key escrow, and device-directory publish. Orchestration and shape only: each verb is one call into capsule-core, which keeps every cryptographic step, and the capsule_core namespace never shares a binary with it
MediaRawshift performs detection, decode/encode, metadata normalization, derivatives, previews, and video work, consumed through capsule-core::media
LQIPCapsule imports Chromahash 0.7.1 directly; Rawshift has no Chromahash responsibility
Import commitCapsule applies privacy policy, creates sidecars/provenance, encrypts, signs, and commits normalized media results
AlertsAlert classes and trigger predicates live in capsule-core::notify so every platform evaluates one decision function; scheduling and presentation are native per client. See Notifications

These are the intended complexity boundaries. A dependency is not added to an active manifest until the named acceptance gaps are verified with contract fixtures or a minimal spike.

LibraryScope Capsule delegatesAcceptance gaps Capsule must verify
KynosHTTP runtime, REST routing, middleware composition, OpenAPI 3.1 and 3.2 emission, limits, shutdown, observabilityStreaming request/response bodies, cancellation and backpressure; deterministic schema output; custom protocol/error headers on every response; middleware ordering; test harnesses without live infrastructure
SpargenRust client generation from the checked-in Kynos OpenAPI contractOpenAPI 3.1 and 3.2 compatibility; streaming upload/range download; opaque binary bodies; stable error-code mapping; auth and protocol headers; supported Rust targets; deterministic generation and version-compatibility checks
RawshiftMedia detection, decoding/encoding, metadata normalization, derivatives, previews, and video processingRequired format/codec matrix; bounded memory and concurrency; cancellation/progress; malformed-input isolation; deterministic orientation/color/HDR behavior; normalized metadata provenance; mobile/desktop targets; no Chromahash API
Chromahash 0.7.1LQIP encode/decode only, imported directly by CapsuleDeterministic output; wide-gamut/HDR fixtures; decoder fallback behavior; supported FFI targets. The pin and the retired ThumbHash decision are Dependencies
OpenMLSMLS protocol and cryptographic state transitionsRequired cipher suites and credential model; deterministic persistence/restore; external signer integration; epoch/exporter behavior; cross-platform size/performance; Capsule-owned album policy and provenance stay outside it
PostgreSQL driver/ORM (sea-orm/sqlx-postgres)The durable server records: the asset index, the account cluster, the device-cohort map, the quota ledger and the library’s remaining rows. Not the two typed state ports — a Postgres-resident session table is rejected as a second implementation of one contractTransactions needed for finalization, row locking, migration strategy, cancellation, typed error mapping, tracing, and adapter conformance — all discharged for the first four adapters, whose suites run against the deterministic double and against a container under CAPSULE_TEST_POSTGRES=1. Migrations are applied by a separate binary and serve refuses to boot against a schema it was not built for
redis-rsRequired Valkey adapters for AuthStateStore, UploadSessionStore and the ceremony stores — the volatile half, and the only production adapter any of them getsAtomic compare/update and expiry primitives required by each port; cluster behavior; cancellation/timeouts; tracing; behavioural parity with the in-memory double under one conformance suite — parity is what lets that double be trusted in tests, not a claim that Valkey is substitutable. Parity with the PostgreSQL adapters is not a goal, because no port has both
RustCrypto, ciborium, rusqlite, sqlite-vec, UniFFI, wasm-bindgenExisting crypto primitives, canonical serialization, local catalog and vector index, native bindings, and the browser boundaryContinue vectors, canonical-byte tests, migration tests, and binding smoke tests; these libraries do not own Capsule protocols or schemas

Explicit non-dependencies: no generic CAS crate, object_store, resumable-transfer library, generic TTL/CAS library, GraphQL/gRPC stack, or in-repository media codec stack. Reconsider extraction only after a product-neutral interface has two real consumers and removes more audit surface than it adds.

The E2E surface is bounded: adding a test here means adding it to the relevant doc’s Validation section and justifying why the cross-module surface is irreducible. Each case must remain backed primarily by unit and adapter-contract tests. Cases are numbered so that code can name the case it covers (rg "E2E case N"), and slices in the repo-root SLICES.md reference these numbers.

  1. Auth → sync → client-side library query. Sign in → access token → the sync feed returns the account’s album entries → the client applies them and a local library.sqlite query lists the expected albums (rich queries are client-side per API Surfaces).
  2. Full import + upload + finalize. Local scan → plan → execute → upload session → finalize → blob present at its content address and the index row marked uploaded.
  3. Sync feed pickup. Upload from device A → device B’s feed advances → device B fetches the metadata blob and, per scope, the original.
  4. Federation cross-server pull. Alice on home.tld shares to Bob on other.tld → capability token → Bob’s server pulls metadata and blobs → Bob’s client renders.
  5. LAN peering A→B. Two devices on one LAN; discovery → TLS handshake → delta-scoped artifact → restore on the receiver → byte-equal libraries.
  6. Backup → restore on a fresh device. Export a full backup → bootstrap a new device via passphrase and escrow → import the backup → assert every asset present and verifiable.
  7. Full lifecycle. Create → metadata update → trash → restore → re-delete → hard purge after retention. The provenance chain advances through every transition and the server refuses purge before retention_until.
  8. Album upgrade ceremony. Multi-member album; an admin initiates the upgrade → quiesce → drain → tombstone → fork → queued writes replay. Includes one resume-from-crash mid-ceremony.
  9. Cross-version protocol gate. A client whose protocol_version falls outside the server’s range attempts an upload, receives 426, and the UI surfaces an actionable error.
  10. Model regen after version bump. Bump the canonical model version; assert stale embeddings are excluded from queries; background regen produces fresh embeddings; queries return correct results afterwards. Entirely within capsule-core::ml and the capsule-core::db vector index, so it is unaffected by the server rebuild.
  11. Server crash mid-finalization. Inject a crash between the blob rename and the Postgres transaction commit; restart; assert the session moves to FailedProcessing cleanly, with no orphaned blob and no zombie pending row.
  12. Cross-device enrollment. Device A authorizes new device B over a verified channel (enrollment code plus safety-code check) → B generates hardware keys → A cross-signs B into the device directory → B joins each album’s MLS group → B’s library matches A’s. Includes one MITM-on-relay abort.
  13. Web drop → adopt. A browser/WASM client seals a drop to an upload link → the provisioning user’s native client decapsulates, rewraps the key under the album AMK, and adopts it in place → the asset appears in the library and verify_asset-accepts on a second device. The only case exercising the web/WASM client and the wrapped-key path.