Files
alkblobs/tasks/store-read-paths.md
T
glm-5.3-flash 6bce301c55 docs(tasks): decompose wave 2 — mem + local engines, facade, in-process GC, first suite columns
Nine tasks against the wave-1 contract surface as reviewed (no
amendments from the gate):

- engine-mem / engine-local (parallel, dependency-free): the two
  engines; local owns the stage-hygiene exact-count tests and the
  Drop-cancellation story the wave-1 review recorded
- store-construction: the Store type, constructor modes, size-threshold
  dispatch; binds the conformance factory's Store associated type
- store-read-paths ∥ gc-protocol: read ops with the ADR-012 §6.1
  fall-through rule; the ADR-005 in-process protocol (pins, liveness,
  delete windows, abort-as-data, GcRefuse with the full protection set)
- store-put-paths: the two put paths behind one signature, ADR-003's
  three numbered rules, pin-before-publish, Batch, kv-only rejection
- suite-column-mem → suite-column-local: the reference column, then the
  dual-tier dispatch-coverage shape mirroring it
- review-wave-2: the gate (facade/dispatch/GC vs ADR-003/005/012)

Verification: dependency graph validated (all ids resolve, no cycles,
topological order clean); docs-only change.

Refs: docs/plans/implementation.md §Wave 2
2026-10-11 21:39:28 +00:00

4.1 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
store-read-paths Store read paths — get/stat/read_range/has/list with dispatch fall-through pending
store-construction
moderate medium component implementation
wave-2
facade
read-path

Description

Implement the facade's read-side ops on the Store type (store-api.md §Read path, §Lifecycle), behind the dispatch seam from store-construction. Direct delete is not here — it lands in gc-protocol with its arbitration.

  • The fall-through general rule (ADR-012 §6.1; POC #1 finding 6): every key-addressed op consults the kv tier first, then the large tier. get/stat/has/read_range/list all follow it.
  • get(key) → Option<(len, stream)>: small tier returns a bounded read; large tier streams. The per-engine cursor shapes stay hidden behind the crate-internal ReadCursor the store core drives (ADR-010 §1) — named design point: the public stream type that wraps the cursor (the facade's (len, stream) shape is uniform across tiers; the cursor is never exposed). A miss on both tiers is None — get never carries Error::Missing (ADR-012 §6.5 ruling 5; the error module's behavioral-enforcement note lands here).
  • stat(key) → Option<EntryMeta>: the cheap probe riding the trait's size method — length plus algorithm, never a content load (ADR-008's size discipline). Fall-through per the general rule.
  • read_range(key, range) → (slice, slice_digest): slice plus the out-of-band SHA-256 slice digest (ADR-006, fixed by convention — composed through the cursor's read_range seam). Err(Missing) on a both-tier miss. Range reads fall through tiers exactly as get does.
  • has(key) → bool: the pure existence probe (ADR-008's has discipline) — a size-probe under the fall-through rule; absent on both tiers is false; virgin-store reads are no-ops.
  • list() → stream of keys: whole-pool enumeration, complete by contract. Named design point: the return shape — store-api.md says "stream of keys"; decide Vec vs stream (the sweep consumes the same enumeration crate-internally) and record it.
  • Verification posture on get (named design point): ADR-006's whole-blob verification vs the slice-digest-only reading — where the store core's hash-check actually fires on the read path (kv materialized reads are verifiable cheaply; large streaming reads ride per-range slice digests). Pin the reading against ADR-006's text and record it for the review gate.
  • KeyInvalid at the boundary: typed Key conversion happens at the store boundary only (ADR-002/003) — malformed key bytes on any read op reject with Error::KeyInvalid, never a guess; engines never see typed keys.

Acceptance Criteria

  • get/stat/read_range/has/list implemented with the fall-through general rule (kv first, then large), unit-tested including the both-tier-miss shapes (None vs Err(Missing) per op)
  • The public stream type decided and recorded; engine cursors never leak into the public surface
  • stat never fetches content (rides size); EntryMeta carries len + algorithm
  • read_range returns slice + SHA-256 slice digest per the ADR-006 convention; verification-on-get posture decided and recorded
  • Malformed key bytes reject with KeyInvalid at the facade boundary on every key-addressed op
  • cargo test green; cargo test --features mem and cargo test --all-features green; clippy/fmt gates green

References

  • docs/architecture/store-api.md (§Read path, §Lifecycle, §Error model)
  • docs/architecture/backends-and-dispatch.md (§Size-threshold dispatch — get fall-through)
  • docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §6.1/§6.5
  • docs/architecture/decisions/006-verification-posture-and-transfer-encoding.md
  • docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md (size discipline)
  • src/backend.rs (the ReadCursor seam this drives)

Notes

To be filled by implementation agent

Summary

To be filled on completion