Migrated from Method backlog
This issue was created from a legacy filesystem backlog card. GitHub Issues are now the live work tracker; repository docs remain Method evidence.
Source backlog: docs/method/backlog/cool-ideas/PLATFORM_deep-storage-api-evolution.md
Original lane: cool-ideas
Original legend: PLATFORM
Original backlog card
Milestone: Deep Storage | Priority: P2
Status: active cool idea. crates/echo-cas exists with BlobStore and
MemoryTier; the current trait still returns Arc<[u8]> and explicitly notes
that bytes::Bytes, disk, cold, and async tiers are future work. No
DiskTier, TieredStore, AsyncBlobStore, BlobMeta, or StoreStats
implementation exists yet.
API Evolution
Modernize the BlobStore trait for async usage, bytes::Bytes payloads, and enumeration support.
T-5-4-1: Arc<[u8]> to bytes::Bytes migration
User Story: As a developer, I want the BlobStore API to use bytes::Bytes instead of Arc<[u8]> so that zero-copy slicing and network buffer integration are possible.
Requirements:
- R1: Change
BlobStore::get return type from Option<Arc<[u8]>> to Option<bytes::Bytes>.
- R2: Update
MemoryTier internal storage from HashMap<BlobHash, Arc<[u8]>> to HashMap<BlobHash, bytes::Bytes>.
- R3: Update
DiskTier to return Bytes::from(vec) on read.
- R4: Preserve all existing semantics (dedup, pin, budget tracking).
- R5: Add
bytes = "1" dependency to echo-cas.
Acceptance Criteria:
Definition of Done:
Scope: Return type migration, internal storage migration, downstream compile
fixes.
Out of Scope: Streaming reads. Associated type generics. Async.
Test Plan:
- Goldens: Existing golden tests unaffected (hash values unchanged).
- Failures: N/A (type change, not behavioral).
- Edges:
Bytes from get after the original put data is dropped (refcount correctness).
- Fuzz/Stress: 100,000 put/get cycles, verify no memory leaks via peak RSS measurement.
Blocked By: none
Blocking: T-5-4-2
Est. Hours: 4h
Expected Complexity: ~80 LoC (mostly type signature changes)
T-5-4-2: AsyncBlobStore trait
User Story: As a developer, I want an async variant of BlobStore so that disk and network tiers can perform non-blocking I/O.
Requirements:
- R1: Define
AsyncBlobStore trait with async fn variants of all BlobStore methods.
- R2: Provide a blanket
AsyncBlobStore impl for any T: BlobStore + Send + Sync that wraps sync calls (useful for MemoryTier).
- R3:
DiskTier gets a native AsyncBlobStore impl using tokio::fs for file I/O.
- R4:
TieredStore gets an AsyncBlobStore impl that chains async get (memory sync -> disk async).
Acceptance Criteria:
Definition of Done:
Scope: AsyncBlobStore trait definition, blanket impl, DiskTier async impl,
TieredStore async impl.
Out of Scope: Async pin/unpin (remains sync for Phase 3). Async GC runner. Stream-based get.
Test Plan:
- Goldens: N/A (behavioral, not byte-exact).
- Failures: Async get on missing blob returns None. Async put_verified mismatch returns error.
- Edges: Concurrent async gets for the same hash (no deadlock). Async put during async get of same hash.
- Fuzz/Stress: Tokio multi-threaded runtime: 100 tasks doing async put/get concurrently.
Blocked By: T-5-4-1, T-5-1-2
Blocking: T-5-4-3
Est. Hours: 5h
Expected Complexity: ~200 LoC
T-5-4-3: Enumeration and metadata API
User Story: As a developer, I want to list stored blobs and query metadata so that tooling (CLI inspect, GC) can report storage state.
Requirements:
- R1: Add
fn list(&self) -> Vec<BlobHash> to BlobStore (returns hashes sorted by BlobHash -- determinism invariant from lib.rs docs).
- R2: Add
fn metadata(&self, hash: &BlobHash) -> Option<BlobMeta> where BlobMeta contains { size: u64, pinned: bool }.
- R3: Add
fn stats(&self) -> StoreStats returning { blob_count: u64, total_bytes: u64, pinned_count: u64 }.
- R4: Implement for MemoryTier, DiskTier, and TieredStore.
- R5: Add async variants to
AsyncBlobStore.
Acceptance Criteria:
Definition of Done:
Scope: list, metadata, stats methods on BlobStore + AsyncBlobStore. All tier implementations.
Out of Scope: Pagination. Filtering by size/age. serde serialization of BlobMeta (defer to need).
Test Plan:
- Goldens:
list() order for 3 known blobs matches expected sorted hex order.
- Failures:
metadata for non-existent hash returns None. list() on empty store returns empty vec.
- Edges: Store with 1 blob. Store with 10,000 blobs (DiskTier directory scan perf).
- Fuzz/Stress: Insert and remove (when removal exists) random blobs; verify
list() is always sorted and complete.
Blocked By: T-5-4-2
Blocking: none
Est. Hours: 4h
Expected Complexity: ~200 LoC
Migrated from Method backlog
This issue was created from a legacy filesystem backlog card. GitHub Issues are now the live work tracker; repository docs remain Method evidence.
Source backlog:
docs/method/backlog/cool-ideas/PLATFORM_deep-storage-api-evolution.mdOriginal lane:
cool-ideasOriginal legend:
PLATFORMOriginal backlog card
API Evolution
Modernize the
BlobStoretrait for async usage,bytes::Bytespayloads, and enumeration support.T-5-4-1: Arc<[u8]> to bytes::Bytes migration
User Story: As a developer, I want the BlobStore API to use
bytes::Bytesinstead ofArc<[u8]>so that zero-copy slicing and network buffer integration are possible.Requirements:
BlobStore::getreturn type fromOption<Arc<[u8]>>toOption<bytes::Bytes>.MemoryTierinternal storage fromHashMap<BlobHash, Arc<[u8]>>toHashMap<BlobHash, bytes::Bytes>.DiskTierto returnBytes::from(vec)on read.bytes = "1"dependency to echo-cas.Acceptance Criteria:
Bytesfromgetcan be sliced without copying (bytes.slice(..)).Definition of Done:
Scope: Return type migration, internal storage migration, downstream compile
fixes.
Out of Scope: Streaming reads. Associated type generics. Async.
Test Plan:
Bytesfromgetafter the originalputdata is dropped (refcount correctness).Blocked By: none
Blocking: T-5-4-2
Est. Hours: 4h
Expected Complexity: ~80 LoC (mostly type signature changes)
T-5-4-2: AsyncBlobStore trait
User Story: As a developer, I want an async variant of BlobStore so that disk and network tiers can perform non-blocking I/O.
Requirements:
AsyncBlobStoretrait withasync fnvariants of allBlobStoremethods.AsyncBlobStoreimpl for anyT: BlobStore + Send + Syncthat wraps sync calls (useful for MemoryTier).DiskTiergets a nativeAsyncBlobStoreimpl usingtokio::fsfor file I/O.TieredStoregets anAsyncBlobStoreimpl that chains async get (memory sync -> disk async).Acceptance Criteria:
MemoryTieris usable asAsyncBlobStorevia the blanket impl.DiskTier::getdoes not block the tokio runtime (usestokio::fs::read).TieredStoreasync get properly promotes on disk hit.Definition of Done:
Scope: AsyncBlobStore trait definition, blanket impl, DiskTier async impl,
TieredStore async impl.
Out of Scope: Async pin/unpin (remains sync for Phase 3). Async GC runner. Stream-based get.
Test Plan:
Blocked By: T-5-4-1, T-5-1-2
Blocking: T-5-4-3
Est. Hours: 5h
Expected Complexity: ~200 LoC
T-5-4-3: Enumeration and metadata API
User Story: As a developer, I want to list stored blobs and query metadata so that tooling (CLI inspect, GC) can report storage state.
Requirements:
fn list(&self) -> Vec<BlobHash>toBlobStore(returns hashes sorted byBlobHash-- determinism invariant from lib.rs docs).fn metadata(&self, hash: &BlobHash) -> Option<BlobMeta>whereBlobMetacontains{ size: u64, pinned: bool }.fn stats(&self) -> StoreStatsreturning{ blob_count: u64, total_bytes: u64, pinned_count: u64 }.AsyncBlobStore.Acceptance Criteria:
list()returns hashes in ascending byte order.metadatafor a pinned blob returnspinned: true.stats().blob_countmatcheslist().len().list()scans the directory tree and returns all stored hashes.Definition of Done:
Scope: list, metadata, stats methods on BlobStore + AsyncBlobStore. All tier implementations.
Out of Scope: Pagination. Filtering by size/age. serde serialization of BlobMeta (defer to need).
Test Plan:
list()order for 3 known blobs matches expected sorted hex order.metadatafor non-existent hash returnsNone.list()on empty store returns empty vec.list()is always sorted and complete.Blocked By: T-5-4-2
Blocking: none
Est. Hours: 4h
Expected Complexity: ~200 LoC