9.1 KiB
9.1 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||
|---|---|---|---|---|---|---|---|---|---|---|
| mem-engine-foundations | Mem engine — crate scaffold, `MemStore::new()`, guarded state core, wake routing | completed | moderate | medium | component | implementation |
|
Description
The mem engine's foundations (wave 6 — ADR-024):
a new workspace member alkstore-mem and the state core every later
task builds on.
- Crate + manifest: workspace member per
ADR-024 §1 —
dependencies are
alkstore(versioned path pin per ADR-017 §4.1, matching the other engines' manifests) plus tokio restricted to the wasm-supported subset (sync + time only). No driver dependencies.thiserrorvia core; no other crates.io surface. - Constructor:
MemStore::new()— engine-native, no connection string, no file path (the one documented exception to the core-contract open prose, amended by ADR-024 §4). Eachnew()yields a fully isolated instance sharing nothing (the suite factory's isolation contract); teardown is drop. NoPgOpts-equivalent opts struct exists — nothing to configure (if a knob surfaces during the wave,MemOptswith..Default::default()follows the family opts pattern; not assumed now). - Guarded per-mechanism state core: the store instance is the
state — per-mechanism structures (queues+jobs, dead letters,
streams+offsets, locks, schedules) behind the family's locking
discipline (parking_lot short-held internal locks per AGENTS
convention 3; tokio primitives for cross-await coordination).
Layout is module-per-file under
src/, mirroring the other engines. Subsequent mechanism tasks own their tables' shapes; this task owns the shared scaffolding: the guarded-state container idiom, name validation at entry (sameInvalidName/ReservedNamerules as every other engine — reserved prefix__alkstore_, the one reserved string__alkstore_listener_reconnected__unused here but still rejected), and the wake-routing substrate (in-process channels; a mechanism registers its commit-ordered wake source, receivers attach per channel). - Wake substrate shape: no batching boundary exists — wakes
deliver at the commit boundary directly to each open receiver,
per-subscriber FIFO by commit order (engine-mem.md §Architecture;
coalescing not applicable). The routing core lives here; the
listen()/WakeReceiversurface lives inmem-engine-notify-listen. - Clock posture: every timestamp (unix-seconds stamps, visibility deadlines, TTLs, scheduler boundaries) reads the process clock — there is no server clock to defer to. Keep the clock behind one internal accessor so tests can observe timestamps deterministically the same way the SQL engines' row shapes do.
The Store trait impl itself is ADR-007-shaped and lands in
mem-engine-seam-tx (the tx overlay is the load-bearing half);
this task lands everything up to the trait boundary.
Acceptance Criteria
alkstore-memis a workspace member compiling clean; manifest dependency surface is core + tokio (sync + time) onlyMemStore::new()constructs; two instances share nothing (pinned by a unit test)- The guarded state core, validation rules, wake-routing substrate, and clock accessor exist with unit pins
cargo check --target wasm32-unknown-unknown -p alkstore-memclean from this task onward (tokio subset discipline enforced here, not retro-fitted)- Workspace gates green (
cargo build,cargo test, clippy-D warnings, fmt)
References
- docs/architecture/decisions/024-mem-engine.md §1/§4
- docs/architecture/engine-mem.md §Identity and posture, §Architecture
- docs/architecture/core-contract.md §Naming / reserved namespace
- tasks/pg-engine-schema.md (the wave-4 rhythm this wave mirrors — its "foundations first" slot)
Notes
Filled by implementation agent, 2026-10-10.
- parking_lot rejected — the ADR won the manifest. The
description's prose named "parking_lot short-held internal locks
per AGENTS convention 3", but ADR-024 §1 and the acceptance
criterion pin the manifest to core + tokio (sync + time) only.
The guarded-state container uses plain
std::sync::Mutex(wasm-fine, no crates.io surface) behind aGuardtrait whoseguard()folds poisoning intointo_inner— structurally unreachable anyway, since no guard is ever held across an.awaitor user-provided code; tokio primitives (mpscunbounded) are the cross-await coordination. Downstream mechanism tasks follow this idiom (state::Guard). - Guarded-state shapes deliberately empty —
state.rscarries the container plus named empty per-mechanism sections (QueueState= jobs + dead letters,StreamState= log + offsets,LockState= TTL registry,ScheduleState= schedule table); each mechanism task owns its section's actual shape. - Wake substrate API shape (
wakes.rs):WakeBus::attach(channel) -> WakeFeed(one unbounded mpsc feed per subscriber; attach lands under the registry guard, so attach-after-commit no-replay is structural),fire_commit_wakes(channels)is the commit-ordered wake source's entry point (mechanisms fire at the commit boundary; the guard makes bump + per-channel fanout one operation — per-subscriber FIFO by commit order, never coalesced),close()is the engine-drop path (MemStore'sDropcalls it; senders live only in the bus, so a drop disconnects every feed regardless of who holds one), andcommit_watermark()is acfg(test)ordering observable only — never contract surface.WakeFeed::rx()exposes the raw mpsc receiver; the consumer-visibleWakeReceiverbridge (recv/try_recv/recv_timeout forms) ismem-engine-notify-listen's surface over this primitive. - Clock (
clock.rs): one accessorClock::unix_now()readsstd::time::SystemTime(process clock only, per engine-mem.md);freeze/advance/unfreezeare thecfg(test)deterministic observation seam.MemStore::clock()cfg(test)accessor. - Validation carries no new rule —
validation.rsis the pin module only (empty/whitespace-only →InvalidName, reserved prefix →ReservedName,RESERVED_LISTENER_RECONNECTEDrejected even though unused here); every future mem entry point routes through core'svalidate_shared_name/validate_local_namedirectly, same as the SQL engines. - Scaffold dead-code posture: targeted
#[allow(dead_code)]on the not-yet-wired scaffold surfaces (thewakesmodule, the emptyStatesections,MemStore'sstate/clockfields,Clock::unix_now) so clippy-D warningsstays green with the gate before consumers exist — the mechanism tasks own using (and thereby exhausting) these allows. - No
MemStore::close()— ADR-024 §4 says teardown is drop; there is no explicit close form (the sqlite/pg engines'closeis connection machinery). Ifmem-engine-integrationwants one for symmetry, that is the place to decide. - tokio
timefeature is pinned but currently unexercised — no mem code reads tokio time yet (lock TTLs and scheduler boundaries are their tasks' consumers); the manifest carries it per this task's description so the wasm-subset discipline is enforced at birth rather than widened later.
Summary
Filled on completion, 2026-10-10.
Landed alkstore-mem as the fourth workspace member — crate scaffold
- manifest (deps:
alkstorepath pin per ADR-017 §4.1 + tokiosync/timeonly; dev-deps tokiort/macros), five modules (store,state,wakes,clock,validation), re-exported fromlib.rswhose crate docs carry the ADR-016 posture statement (honest-ephemeral, full contract v1, wasm32-compile-clean identity).MemStore::new()implements the engine-native isolated-constructor contract (ADR-024 §4): new guarded state core, wake bus, and clock per open, teardown = drop drivingWakeBus::close(). Unit pins: 16 tests — two-instances-share-nothing (Arc pointer identity + behavioral: frozen clock on one instance leaves the other's process time intact; a fire through one instance's bus never reaches the other's feed), guarded-state section independence/relock, wake routing (channel-scoped per-subscriber delivery + foreign-channel silence, per-commit-notify never coalesced, watermark-ordered FIFO, attach-after-commit no-replay, close disconnects every live feed + inert post-close fire, dropped feed detaches), engine-drop closes open feeds, clock determinism (freeze/advance/unfreeze), validation pins (4). Verified:cargo build, workspacecargo testgreen (pg 124 lib / 25 suite / 9 schema, sqlite 191 lib / 25 suite, core 25, suite harness 3, mem 17), clippy--all-targets -D warningsclean,cargo fmt --checkclean, andcargo check --target wasm32-unknown-unknown -p alkstore-memclean — the wave-6 wasm gate starts green from this task onward.