feat(store): the Store facade — constructor modes, size-threshold dispatch, the factory binding

The wave-2 facade skeleton and routing (tasks/store-construction.md):
the public surface consumers program against, with the ops methods
still to land against it in store-read-paths/gc-protocol/store-put-paths.

- src/store.rs — the public `Store` type (engine-blind, ADR-007/008/
  010) over crate-internal tier enums (`KvEngine`{mem}, `LargeEngine`{
  local}): the engine-representation design point decided as concrete
  + enum dispatch, generic rejected (pub(crate) engines, no dyn);
  the three constructor modes as named constructors — `mem_only`,
  `kv_only_mem`, `dual_tier_mem_local` (the ADR-012 §6.3
  dispatch-coverage shape) — with `StoreMode` introspection; the
  write-side routing seam (`tier_for`), the read-side fall-through
  order (`kv()` then `large()`, ADR-012 §6.1), and the `GcHome`
  GC-state field; the ADR-012 §3 fleet declaration ruled deferred to
  the engine waves (nothing fleet-valid is constructible yet)
- src/dispatch.rs — the pure routing function (`route`, at-or-below
  → kv), `DEFAULT_DISPATCH_THRESHOLD` (128 KiB) exported at the
  crate root, boundary-value unit tests (exactly-at-threshold,
  degenerate tunings, purity)
- src/gc.rs — `GcHome`: the store-instance GC-state home the
  gc-protocol task fills (in-process; fleet state stays on the
  engine-state seam per ADR-010 §2/ADR-012 §4)
- tests/conformance — the wave-2 binding made as anticipated: the
  factory's `Store` associated type collapsed into the concrete
  `alkblobs::Store` (`open` vends it directly), recorded in
  factory.rs + README; the wave-1 mock probe retired, replaced by
  mem-gated binding demo factories (binding.rs) over both
  constructible shapes

Verification: `cargo test` (default), `cargo test --features mem`,
`cargo test --all-features` green (41/53/53 unit + conformance
targets green in all three shapes); `cargo clippy --all-targets
-- -D warnings` green in all three feature shapes; `cargo fmt
--check` green; `cargo doc --no-deps` adds no warnings beyond the
pre-existing private-intra-doc-links class.
This commit is contained in:
glm-5.3-flash committed 2026-10-11 22:18:32 +00:00
1 parent 856d436f81
commit 532adfa707
9 files changed
+840 -84

No files matched your search

+89 -3
View File
@@ -1,7 +1,7 @@
---
id: store-construction
name: Store facade type — constructor modes and size-threshold dispatch
status: pending
status: completed
depends_on: [engine-mem, engine-local]
scope: moderate
risk: medium
@@ -87,8 +87,94 @@ and `store-put-paths` against this type.
## Notes
> To be filled by implementation agent
- **Engine representation decided**: concrete `Store` holding two
crate-internal engine enums (`KvEngine`: mem [feature-gated];
`LargeEngine`: local [ungated]), not the generic
`Store<Kv, Large>` — the generic would leak `pub(crate)` engine
types through the public surface or force `dyn` (wave-1 design
point 3); the facade stays engine-blind (ADR-007/008/010) and the
conformance factory's binding note anticipated exactly this
collapse. Waves 3–5 slot in by adding an enum variant + a named
(feature-gated) constructor — no reshaping. Recorded in
`src/store.rs` module docs.
- **Constructor modes** land as named constructors, engines named by
the constructor (public surface can't take `pub(crate)` engine
handles): `mem_only()` / `kv_only_mem(threshold)` /
`dual_tier_mem_local(root, threshold)` (the ADR-012 §6.3
dispatch-coverage shape; fallible because the local root's creation
is I/O). Modes validate structurally (unrepresentable states
unrepresentable — dual-tier constructs the large engine itself) and
every instance carries its mode (`Store::mode() → StoreMode`,
public). The **fleet declaration (`fleet: true`, ADR-012 §3)
defers to the engine waves**: it is a constructor *error* for every
non-fleet-valid configuration, and none is constructible yet — the
ruling is recorded in store.rs docs rather than carried as a
dead-machinery flag.
- **Threshold shape**: `None`-vs-value is the mode's ruling (mem-only
= "no dispatch threshold in effect", ADR-011 §4), so the field is
always a value and mem-only's `threshold()` returns `None` by mode
branch — no unrepresentable `Option` state to `expect` away
(AGENTS convention 2). The pure function is `dispatch::route(len,
threshold)` with the pinned boundary reading **at-or-below → kv**;
`DEFAULT_DISPATCH_THRESHOLD` (128 KiB) is exported at the crate
root and constructors take the threshold explicitly (tunability
proven by tests at a non-default threshold).
- **Dispatch seam handed to the ops tasks**: write-side
`Store::tier_for(len)` (dual-tier pure routing; kv-only routes kv
for every length — the over-threshold *rejection* is the put seam's
behavior keyed off `threshold()`, ADR-012 §6.2; mem-only kv), and
read-side fall-through order as `kv()`-then-`large()` accessors
documented as ADR-012 §6.1's general rule. The engine enum's
`Backend` dispatch methods and the cursor/staging enum wrappers are
deliberately not built here — they are store-read-paths and
store-put-paths named design points (the public stream shape, the
declared-len mismatch case) and adding methods to the enums is
slotting in.
- **GC state home**: `pub(crate) struct GcHome` in `src/gc.rs`, held
as a `Store` field with a crate-internal `gc()` accessor — the
gc-protocol task fills it (pin registry, liveness sources, protect
callback, in-process window); fleet state explicitly never lands
there (ADR-010 §2 / ADR-012 §4 host rule).
- **Factory binding made and recorded**: the skeleton's `Store`
associated type is gone — `StoreFactory::open` vends the concrete
`alkblobs::Store` directly (`tests/conformance/factory.rs` + README
§The factory contract record the ruling); the wave-1 mock probe
retired, replaced by mem-gated binding demo factories
(`tests/conformance/binding.rs`) covering mem-only and the
dispatch-coverage dual-tier shape with isolation + idempotent
teardown.
- **Default-build note**: the kv engine set is empty until wave 3
(sqlite), so `Store` exists in default builds but is
unconstructible — constructors and construction tests are
`#[cfg(feature = "mem")]`; the `#![allow(dead_code)]` scope notes on
`dispatch.rs`/`store.rs` follow the house pattern and shrink as the
ops tasks land.
## Summary
> To be filled on completion
Implemented the `Store` facade skeleton in `src/store.rs`: the public
engine-blind facade type holding the two crate-internal tier enums
(`KvEngine` {mem}, `LargeEngine` {local}) per the recorded
engine-representation ruling (concrete + enum dispatch, generic
rejected), the three constructor modes as named constructors —
`mem_only()`, `kv_only_mem(threshold)`, `dual_tier_mem_local(root,
threshold)` (the ADR-012 §6.3 shape) — with `StoreMode` introspection,
the write-side routing seam (`tier_for`) composing the pure
`dispatch::route` (default 128 KiB, constructor-tunable, at-threshold →
kv), the read-side fall-through order (`kv()` then `large()`, ADR-012
§6.1), and the `GcHome` GC-state field the gc-protocol task fills
(added to `src/gc.rs`). `dispatch.rs` grew the pure routing function
plus `DEFAULT_DISPATCH_THRESHOLD` with boundary-value unit tests
(exactly-at-threshold, degenerate tunings, purity). The conformance
factory binding collapsed the `Store` associated type into the concrete
facade (recorded in `factory.rs` + the suite README); the wave-1 probe
became mem-gated binding demo factories. Tests: mem-only/kv-only/
dual-tier construction + validation, threshold tunability at a
non-default value, dispatch boundary values, factory open/teardown
lifecycle in both constructible shapes.
Verification: `cargo test` (default), `cargo test --features mem`,
`cargo test --all-features` all green; `cargo clippy --all-targets
-- -D warnings` green in all three feature shapes; `cargo fmt --check`
green; `cargo doc --no-deps` clean of new warnings beyond the
pre-existing private-intra-doc-links class.