Expand description
The blob engine: coven’s single owner of a blob’s whole durability lifecycle.
coven syncs opaque encrypted blobs referenced by DB rows. By default it owns
the cloud layout (the content-addressed {namespace}/{ab}/{cd}/{id}) and
encryption; the host decides which rows carry blobs, where their plaintext
lives locally, and how each is scoped for encryption. A home configured for
the unobfuscated blob-path scheme instead stores each blob at the consumer’s
readable BlobRef::cloud_path so the bucket is browsable.
§The coven concept tree
A blob has two declared properties — Provenance (its Local story) and
CacheFill (its Remote story) — and one state, locality, flipped by the
transitions. The cache is a mechanism that serves Remote blobs; it is not a
kind of blob.
A blob the host declares with:
provenance — its LOCAL story: where the bytes live when Local, and the
Remote→Local path requirement
├─ user-provided the user's file at a path; coven references it.
│ Remote→Local writes the bytes back to a user file → NEEDS A PATH.
└─ host-provided bae hands coven the data; coven keeps it in its local store.
Remote→Local restores it to the local store → no path.
cache fill — its REMOTE story: how a device gets the bytes when the release is
Remote. A cache-mechanism setting; applies to ANY blob, regardless of
provenance, once it is Remote.
├─ CacheEager fetched into the cache on pull, with the SQL row (covers)
└─ CacheLazy fetched into the cache on first read (audio — big, fetch what you play)
and a current state:
locality
├─ Local bytes on-device — the user's path (user-provided) or coven's local store (host-provided)
└─ Remote bytes in the cloud; each device's local copy is a CACHE copy, filled
per `cache fill`, kept-or-evicted per `pin`
namespace (bucket) the blob's category — release_files · covers · artist_images
transitions
├─ Local → Remote upload the bytes; now cache-distributed to every device per cache fill
└─ Remote → Local bring the bytes back to a local file — path required iff user-provided
cache budget per-NAMESPACE size limit; each namespace evicts independently, so
evicting release_files (big) never touches covers (small reserved slice)
pin keep one specific Remote blob's cache copy from eviction (e.g. a
release the user pinned for offline)§The cache vs local files
The cache holds local copies of Remote blobs (filled per cache fill,
evicted per budget unless pinned). It is segmented by namespace: each
namespace has its own configurable cache budget and evicts independently, so
evicting release_files (big) never touches covers (a small reserved slice). A
CacheEager cover that falls out of its namespace budget shows a placeholder
until the next read re-fetches it — covers are not pinned. A Local blob is not
in the cache: a user-provided Local blob is the user’s file at its path (an
external ref); a host-provided Local blob is in coven’s local store, whose
paths and file operations are owned by coven_foundation::store_dir::StoreDir. The cache is the mechanism for remoteness — so
CacheEager/CacheLazy/pin/budget describe a blob only while it is Remote, never
while it is Local.
§The engine’s halves
This module is the engine; its halves move a blob through its lifecycle:
blob::cache— the device-local cache for Remote blobs: bytes on disk keyed by exact locator hash, with the folder a file lives in as the only retention truth (storage/pinned/protected,storage/cache/evictable). Reads — one-shot whole, which checks the plaintext against the row’s hash because it reads every byte anyway, or an opened stream whose ranges each cost their own bytes: a positioned read of a local file, or the sealed chunks covering the range fetched from the cloud object and opened — plus pin/unpin, clear, and budget eviction.coven_foundation::store_dir::StoreDir— coven’s own copy of a host-provided Local blob, instorage/local/<namespace>/<id>. Never evicted; the budget sweep never walks it.blob::upload— the cloud-write half: drain the durable upload queue, sealing each blob under its scope and writing it to the cloud with coalesced progress, so a local-only blob becomes uploaded. The sync cycle calls the drain each round before it pushes.blob::delete— the cloud-delete half: turn a queued deletion into a signed cloud tombstone, hold the blob for a convergence grace so a lagging peer isn’t stranded, then GC the blob once the grace has passed. The sync cycle drains tombstones and runs the GC each round after it pulls.
The types below (BlobRef, BlobScope, Provenance,
CacheFill, BlobTransitionObserver) are the vocabulary both halves and
the host speak. Which rows carry blobs is not a runtime callback but a per-table
declaration (crate::synced_schema::BlobDecl) coven resolves into a
the database’s BlobDecls each cycle to derive the blob set itself.
coven also owns the two locality transitions (blob::transition): make_remote
(Local → Remote: upload the bytes, then flip the gate) and make_local
(Remote → Local: bring each blob back to a local file, then retract). The
The upload drain advances the durable make-Remote intent after every exact
object lands. The Store publication activates the resulting gate change;
hosts observe both handoffs through the durable cloud-outbox query.
Modules§
Structs§
- BlobRef
- A blob a row references: its cloud identity, encryption scope, and the two
declared properties (
provenance+fill). coven derives it from the row’s declared columns (crate::synced_schema::BlobDecl) via the database’sBlobDecls. Where its bytes live depends on its locality and provenance: a user-provided Local blob is the user’s file at its path; a host-provided Local blob is in coven’s local store (storage/local/<namespace>/<id>); a Remote blob’s device-local copy is a cache copy (storage/pinned/<namespace>/<locator-hash>/storage/cache/<namespace>/<locator-hash>, built from the validated namespace + exact locator hash — seeblob::cache). - Content
Hasher - An incremental SHA-256 over a blob’s plaintext, so the streaming download path
verifies a blob’s content hash without holding the whole plaintext in memory:
feed each decrypted chunk to
update, callfinish, and compare the returned digest with the row’s hash before committing the bytes to the cache. The hex-encoded digest matchescontent_hashover the same bytes. - Deferred
Local Blob Disposition Error - Deferred
Local Blob Drop - RowBlob
Ref - One exact blob-bearing row version. A reference becomes stale when the live row stamp or any declared blob value changes.
- Transfer
Limits - How many blob transfers coven runs at once in each of its two transfer loops:
the upload drain and the pin/download loop. An
open-time blob-engine tunable the host sets on the builder,
carried on the
Databasealongside the other open-time blob config and read back by each loop, which holds&Database.
Enums§
- Blob
Opening Authority - Blob
Opening Authority Error - Blob
Replacement - A blob’s replacement story: whether the row carrying it may ever be repointed at
a different blob. Orthogonal to
ProvenanceandCacheFill; a blob declares all three. - Blob
Scope - Which key encrypts a blob, as a host names it on a
BlobRef. - Cache
Fill - A blob’s Remote story: how a device gets the bytes once the blob is Remote.
A cache-mechanism setting — it describes a blob only while Remote — that applies
to ANY blob regardless of
Provenance. Orthogonal to provenance; a blob declares both. - Deferred
Local Blob Disposition - Provenance
- A blob’s Local story: where its bytes live while the blob is Local, and
whether bringing it back from Remote needs a destination path. Orthogonal to
CacheFill(the Remote story) — a blob declares both. - RowBlob
Authority - The authority state that determines where one row version’s blob lives.
A remote-audience blob remains
PendingRemotewhile its verified plaintext is local and no cloud object has been created;Remotecarries the exact package authority needed to open its committed object. - RowBlob
RefError
Constants§
- BLOB_
TOMBSTONE_ GRACE - The default convergence window a host gets if it configures none: how long a
deleted blob is kept after its tombstone is written, before a GC pass
reclaims it. The host overrides it on the coven builder; the writer’s
tombstone collection evaluates whatever grace it is handed against the
tombstone’s
deleted_at.
Traits§
- Blob
Transition Observer - Notified about coven’s blob transitions, for host-specific bookkeeping and UI: per-blob upload progress while a make_remote uploads, per-blob materialize progress while a make_local copies files back, and the synchronous make-local completion the host turns into its own UI event.
Functions§
- cloud_
path_ names_ blob - Whether the readable
cloud_patha consumer supplied names the blobblob_id— what coven requires of aReplaceableblob’s key on a browsable home, and what a hashed key gets for free by carrying the id itself. - content_
hash - The content hash a blob-bearing row carries: the lowercase-hex SHA-256 of the blob’s plaintext bytes, computed at import and stored in the row’s blob columns alongside the declared size. The row is carried in a signed changeset (and in a signed snapshot), so this hash is signed by the row’s author — that is what makes it authoritative: on download coven hashes the decrypted plaintext and requires equality with the row’s hash, so the bytes are pinned by the author, not by the cloud key they happened to arrive under. A host computes this over a blob’s plaintext at import and writes it into the row’s declared hash column, the same way it writes the plaintext length into the size column.
- locator_
describes_ row - locator_
is_ this_ rows_ upload - Whether
locatordescribes exactly the row version it was minted for.