mem engine integration — the suite's third column lands, born pinned: StoreFactory implemented for the mem engine (alkstore-mem/tests/contract_suite.rs — a fresh MemStore::new() per open, teardown = drop, unit-struct factory with no external backing) and all 25 rows wired under the current-thread flavor (every test explicitly flavor = "current_thread" — the no-spawn_blocking posture proven by the flavor the column runs under, grep re-verified clean): the 24 engine-shared mechanism rows + mem's new PayloadTooLarge non-occurrence arm row (payload_too_large_never_produced_on_mem — properties.rs, stamped ADR-016 §5 + ADR-024 §3, just-past-2-MiB payload, exported from the suite lib; the SQLite/pg rows untouched — a suite-side class-4 addition, recorded in the task Notes). Column green first run (13 s), zero red rows — no mem defects, no row wobbles, no class-1 escalation owed. Full-surface wiring + crate posture/wasm-identity docs verified as landed by the seam/foundations tasks — zero production code changed. engine-mem.md frontmatter: draft → implementation-complete (stable flip stays with the review gate). Task file: status completed, 6 acceptance boxes ticked, Notes (incl. the wasm on-target scope-out's named collapse condition: a wasm-bindgen-test adapter crate, deliberately not an OQ) + Summary filled. Verified: cargo build; workspace cargo test green (core 25, suite harness 3, mem 100 lib + 25 suite, sqlite 191 + 25, pg 124 + 25 + 9); clippy --all-targets -D warnings clean; cargo fmt --check clean; cargo check --target wasm32-unknown-unknown -p alkstore-mem clean
This commit is contained in:
1 parent
47ac6f7739
commit
76c06e42a9
7 files changed
+354
-19
No files matched your search
Generated
+1
@@ -26,6 +26,7 @@ name = "alkstore-mem"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alkstore",
|
"alkstore",
|
||||||
|
"alkstore-contract-suite",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ pub use properties::{
|
|||||||
duration_refusal_on_non_positive_ttl, enqueue_opts_resolution, extent_clamp_semantics,
|
duration_refusal_on_non_positive_ttl, enqueue_opts_resolution, extent_clamp_semantics,
|
||||||
in_tx_reads_see_own_writes, job_handle_validity_predicate, lock_ttl_expiry_and_reacquisition,
|
in_tx_reads_see_own_writes, job_handle_validity_predicate, lock_ttl_expiry_and_reacquisition,
|
||||||
name_validation_rejects_empty_and_reserved, outbox_enqueue_tx_commit_atomicity,
|
name_validation_rejects_empty_and_reserved, outbox_enqueue_tx_commit_atomicity,
|
||||||
payload_round_trip_stores_exact_encoding, payload_too_large_never_produced_on_sqlite,
|
payload_round_trip_stores_exact_encoding, payload_too_large_never_produced_on_mem,
|
||||||
payload_too_large_produced_on_pg, publish_with_key_tx_commit_atomicity,
|
payload_too_large_never_produced_on_sqlite, payload_too_large_produced_on_pg,
|
||||||
queue_depth_reclaim_and_dead_letter, receiver_close_and_save_arms, scheduler_boundary_fires,
|
publish_with_key_tx_commit_atomicity, queue_depth_reclaim_and_dead_letter,
|
||||||
scheduler_bounded_catchup, scheduler_leadership_discipline, stream_ordering_equivalence,
|
receiver_close_and_save_arms, scheduler_boundary_fires, scheduler_bounded_catchup,
|
||||||
sweep_no_stranded_rows, trim_to_semantics, wake_receiver_shapes,
|
scheduler_leadership_discipline, stream_ordering_equivalence, sweep_no_stranded_rows,
|
||||||
with_tx_panicking_closure_rolls_back,
|
trim_to_semantics, wake_receiver_shapes, with_tx_panicking_closure_rolls_back,
|
||||||
};
|
};
|
||||||
@@ -772,6 +772,32 @@ pub async fn payload_too_large_never_produced_on_sqlite(factory: &dyn StoreFacto
|
|||||||
factory.teardown().await.expect("factory teardown");
|
factory.teardown().await.expect("factory teardown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// **`PayloadTooLarge` occurrence asymmetry — the mem arm** — the mem
|
||||||
|
/// engine never produces the variant at any payload size (no
|
||||||
|
/// notification limit; the wake delivers the channel alone — the
|
||||||
|
/// notify transport stores nothing), the same non-occurrence posture
|
||||||
|
/// as SQLite's arm, born pinned as mem's column of the row
|
||||||
|
/// ([ADR-024](../../docs/architecture/decisions/024-mem-engine.md)
|
||||||
|
/// §3's classification pins mem wiring this arm). The row drives an
|
||||||
|
/// oversized payload — just past the 2 MiB mark the tx seam's mem
|
||||||
|
/// unit pins — through the store's notify path and asserts success.
|
||||||
|
///
|
||||||
|
/// Contract stamp: ADR-016 §5 (the occurrence asymmetry — the
|
||||||
|
/// non-occurrence arm wiring on mem); ADR-024 §3 (mem's posture in
|
||||||
|
/// the classification); ADR-008 §5 (universal variant, no
|
||||||
|
/// engine-specific growth).
|
||||||
|
pub async fn payload_too_large_never_produced_on_mem(factory: &dyn StoreFactory) {
|
||||||
|
let store = factory.open().await.expect("factory opens a store");
|
||||||
|
|
||||||
|
let big = "x".repeat(2 * 1024 * 1024 + 1);
|
||||||
|
store
|
||||||
|
.notify("big", json!({"blob": big}))
|
||||||
|
.await
|
||||||
|
.expect("mem notify has no payload limit at any size");
|
||||||
|
|
||||||
|
factory.teardown().await.expect("factory teardown");
|
||||||
|
}
|
||||||
|
|
||||||
/// **Drop = rollback, no-ghosts** — a transaction handle dropped
|
/// **Drop = rollback, no-ghosts** — a transaction handle dropped
|
||||||
/// before commit rolls its writes back through RAII: job rows, stream
|
/// before commit rolls its writes back through RAII: job rows, stream
|
||||||
/// events, notifies, and offset saves all leave no residue the
|
/// events, notifies, and offset saves all leave no residue the
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ serde_json = "1"
|
|||||||
tokio = { version = "1", features = ["sync", "time"] }
|
tokio = { version = "1", features = ["sync", "time"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
alkstore-contract-suite = { path = "../alkstore-contract-suite" }
|
||||||
tokio = { version = "1", features = ["rt", "macros"] }
|
tokio = { version = "1", features = ["rt", "macros"] }
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
//! The suite-driving test target: the mem engine's third backlog
|
||||||
|
//! column (ADR-022's factory reused verbatim — the rows live in
|
||||||
|
//! `alkstore-contract-suite`, this target is the executor that runs
|
||||||
|
//! them against the mem factory; the born-pinned posture per
|
||||||
|
//! ADR-024 §5 — the engine lands against the finished suite).
|
||||||
|
//!
|
||||||
|
//! The factory: a fresh `MemStore::new()` per `open` — distinct
|
||||||
|
//! engine instances sharing nothing (ADR-024 §4's isolation rule,
|
||||||
|
//! exactly the factory's isolation contract). Teardown is drop — the
|
||||||
|
//! store handle itself *is* the backing store, so the holder's drop
|
||||||
|
//! is the whole teardown; a teardown call has nothing external to
|
||||||
|
//! dispose of and is trivially idempotent.
|
||||||
|
//!
|
||||||
|
//! Flavor: every test runs under the **current-thread** runtime —
|
||||||
|
//! the current-thread-clean posture of the engine's internals
|
||||||
|
//! (no `spawn_blocking` anywhere) proven by the flavor the rows
|
||||||
|
//! actually run under ([ADR-024](../../docs/architecture/decisions/024-mem-engine.md)
|
||||||
|
//! §5). A blocking call inside a row or inside the engine would
|
||||||
|
//! stall this flavor into a hang, not pass.
|
||||||
|
|
||||||
|
use alkstore::{BoxedFuture, Result, Store};
|
||||||
|
use alkstore_contract_suite::StoreFactory;
|
||||||
|
use alkstore_mem::MemStore;
|
||||||
|
|
||||||
|
/// The mem suite factory: a fresh isolated engine instance per
|
||||||
|
/// `open`, teardown = drop (the consumer holds the handle; an
|
||||||
|
/// explicit teardown call is the trivial no-op — nothing exists
|
||||||
|
/// outside the instance to dispose of).
|
||||||
|
struct MemFactory;
|
||||||
|
|
||||||
|
impl StoreFactory for MemFactory {
|
||||||
|
fn open(&self) -> BoxedFuture<'_, Result<Box<dyn Store>>> {
|
||||||
|
Box::pin(async move { Ok(Box::new(MemStore::new()) as Box<dyn Store>) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teardown(&self) -> BoxedFuture<'_, Result<()>> {
|
||||||
|
Box::pin(async move { Ok(()) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod rows {
|
||||||
|
use alkstore_contract_suite::properties::{
|
||||||
|
backoff_curve_equivalence, concurrent_try_lock_loser_is_a_value,
|
||||||
|
drop_rollback_leaves_no_ghosts, duration_refusal_on_non_positive_ttl,
|
||||||
|
enqueue_opts_resolution, extent_clamp_semantics, in_tx_reads_see_own_writes,
|
||||||
|
job_handle_validity_predicate, lock_ttl_expiry_and_reacquisition,
|
||||||
|
name_validation_rejects_empty_and_reserved, outbox_enqueue_tx_commit_atomicity,
|
||||||
|
payload_round_trip_stores_exact_encoding, payload_too_large_never_produced_on_mem,
|
||||||
|
publish_with_key_tx_commit_atomicity, queue_depth_reclaim_and_dead_letter,
|
||||||
|
receiver_close_and_save_arms, scheduler_boundary_fires, scheduler_bounded_catchup,
|
||||||
|
scheduler_leadership_discipline, stream_ordering_equivalence, sweep_no_stranded_rows,
|
||||||
|
trim_to_semantics, wake_receiver_shapes, with_tx_panicking_closure_rolls_back,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::MemFactory;
|
||||||
|
|
||||||
|
fn factory() -> MemFactory {
|
||||||
|
MemFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_name_validation_rejects_empty_and_reserved() {
|
||||||
|
name_validation_rejects_empty_and_reserved(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_extent_clamp_semantics() {
|
||||||
|
extent_clamp_semantics(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_duration_refusal_on_non_positive_ttl() {
|
||||||
|
duration_refusal_on_non_positive_ttl(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_lock_ttl_expiry_and_reacquisition() {
|
||||||
|
lock_ttl_expiry_and_reacquisition(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_concurrent_try_lock_loser_is_a_value() {
|
||||||
|
concurrent_try_lock_loser_is_a_value(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_payload_round_trip_stores_exact_encoding() {
|
||||||
|
payload_round_trip_stores_exact_encoding(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_payload_too_large_never_produced_on_mem() {
|
||||||
|
payload_too_large_never_produced_on_mem(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_drop_rollback_leaves_no_ghosts() {
|
||||||
|
drop_rollback_leaves_no_ghosts(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_in_tx_reads_see_own_writes() {
|
||||||
|
in_tx_reads_see_own_writes(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_enqueue_opts_resolution() {
|
||||||
|
enqueue_opts_resolution(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_backoff_curve_equivalence() {
|
||||||
|
backoff_curve_equivalence(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_receiver_close_and_save_arms() {
|
||||||
|
receiver_close_and_save_arms(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_job_handle_validity_predicate() {
|
||||||
|
job_handle_validity_predicate(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_queue_depth_reclaim_and_dead_letter() {
|
||||||
|
queue_depth_reclaim_and_dead_letter(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_sweep_no_stranded_rows() {
|
||||||
|
sweep_no_stranded_rows(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_scheduler_boundary_fires() {
|
||||||
|
scheduler_boundary_fires(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_scheduler_bounded_catchup() {
|
||||||
|
scheduler_bounded_catchup(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_scheduler_leadership_discipline() {
|
||||||
|
scheduler_leadership_discipline(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_outbox_enqueue_tx_commit_atomicity() {
|
||||||
|
outbox_enqueue_tx_commit_atomicity(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_publish_with_key_tx_commit_atomicity() {
|
||||||
|
publish_with_key_tx_commit_atomicity(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_stream_ordering_equivalence() {
|
||||||
|
stream_ordering_equivalence(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_trim_to_semantics() {
|
||||||
|
trim_to_semantics(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_wake_receiver_shapes() {
|
||||||
|
wake_receiver_shapes(&factory()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn row_with_tx_panicking_closure_rolls_back() {
|
||||||
|
with_tx_panicking_closure_rolls_back(&factory()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod factory_shape {
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use alkstore_contract_suite::StoreFactory;
|
||||||
|
|
||||||
|
use super::MemFactory;
|
||||||
|
|
||||||
|
/// ADR-022's factory contract, verbatim on the mem engine: every
|
||||||
|
/// open yield is isolated (distinct `MemStore::new()` instances
|
||||||
|
/// sharing nothing — proved behaviorally, a row one store lands
|
||||||
|
/// being invisible to the other) and teardown is idempotent per
|
||||||
|
/// instance; a failing assertion early-exit (the panic path)
|
||||||
|
/// leaves teardown safe against the abandoned store — for mem the
|
||||||
|
/// abandoned store simply drops with the test's frame.
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn opens_are_isolated_and_teardown_is_idempotent() {
|
||||||
|
let factory = MemFactory;
|
||||||
|
|
||||||
|
let a = factory.open().await.unwrap();
|
||||||
|
let b = factory.open().await.unwrap();
|
||||||
|
|
||||||
|
let sa = a.stream("iso").await.unwrap();
|
||||||
|
let event_offset = sa.publish(json!({"iso": true})).await.unwrap();
|
||||||
|
assert!(event_offset > 0);
|
||||||
|
let sb = b.stream("iso").await.unwrap();
|
||||||
|
let seen = sb.read_since(0, 100).await.unwrap();
|
||||||
|
assert!(
|
||||||
|
seen.is_empty(),
|
||||||
|
"two opens must never share rows — b saw {seen:?}"
|
||||||
|
);
|
||||||
|
drop(sa);
|
||||||
|
drop(sb);
|
||||||
|
drop(a);
|
||||||
|
drop(b);
|
||||||
|
|
||||||
|
factory.teardown().await.unwrap();
|
||||||
|
factory.teardown().await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
---
|
---
|
||||||
status: draft
|
status: implementation-complete
|
||||||
last_updated: 2026-10-10 (initial spec — ADR-024 adopted the mem
|
last_updated: 2026-10-10 (the wave-6 wave landed: the full surface
|
||||||
engine as wave 6; implementation pending, spec grows with the wave's
|
wired over guarded state, the suite's third `StoreFactory` column
|
||||||
decomposition)
|
green on the host under the current-thread flavor, the wasm32
|
||||||
|
compile gate clean — the review gate holds the stable flip)
|
||||||
---
|
---
|
||||||
|
|
||||||
# Mem engine
|
# Mem engine
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: mem-engine-integration
|
id: mem-engine-integration
|
||||||
name: Mem engine — integration (full-surface wiring, suite third column, wasm32 acceptance)
|
name: Mem engine — integration (full-surface wiring, suite third column, wasm32 acceptance)
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [mem-engine-notify-listen, mem-engine-streams, mem-engine-queues, mem-engine-locks, mem-engine-scheduler-outbox, mem-engine-seam-tx, suite-harness-current-thread]
|
depends_on: [mem-engine-notify-listen, mem-engine-streams, mem-engine-queues, mem-engine-locks, mem-engine-scheduler-outbox, mem-engine-seam-tx, suite-harness-current-thread]
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: medium
|
risk: medium
|
||||||
@@ -53,18 +53,18 @@ factory):
|
|||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- [ ] `StoreFactory` implemented for the mem engine; the third suite
|
- [x] `StoreFactory` implemented for the mem engine; the third suite
|
||||||
column wired and **green on the host** (same row set per the
|
column wired and **green on the host** (same row set per the
|
||||||
wiring table above)
|
wiring table above)
|
||||||
- [ ] The column runs under the current-thread flavor; no blocking
|
- [x] The column runs under the current-thread flavor; no blocking
|
||||||
calls in mem internals (grep-verified)
|
calls in mem internals (grep-verified)
|
||||||
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
|
- [x] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
|
||||||
clean
|
clean
|
||||||
- [ ] `engine-mem.md` updated from `draft`-initial to
|
- [x] `engine-mem.md` updated from `draft`-initial to
|
||||||
implementation-complete (the spec grows with the wave per its
|
implementation-complete (the spec grows with the wave per its
|
||||||
frontmatter note); crate docs carry the posture + wasm identity
|
frontmatter note); crate docs carry the posture + wasm identity
|
||||||
- [ ] Workspace gates green; clippy `-D warnings`; fmt clean
|
- [x] Workspace gates green; clippy `-D warnings`; fmt clean
|
||||||
- [ ] The class-1 window discipline respected: any suite-row change
|
- [x] The class-1 window discipline respected: any suite-row change
|
||||||
or contract wobble surfaced to the reviewer, not silently
|
or contract wobble surfaced to the reviewer, not silently
|
||||||
patched
|
patched
|
||||||
|
|
||||||
@@ -88,8 +88,94 @@ suite surfaces one — the task owns absorbing it.
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
> To be filled by implementation agent
|
> Decisions of record the description didn't pin:
|
||||||
|
|
||||||
|
- **The full-surface wiring was already true by construction** — the
|
||||||
|
`mem-engine-seam-tx` task's whole-engine scope realized the entire
|
||||||
|
`Store`/`TxHandle`/mechanism-handle surfaces over guarded state (a
|
||||||
|
Rust trait impl is all-or-nothing per method), and the lib crate
|
||||||
|
docs already carried the ADR-016/ADR-024 posture statement and the
|
||||||
|
wasm identity line from `mem-engine-foundations`. This task
|
||||||
|
verified both rather than re-landed them: the sweep found no
|
||||||
|
`todo!`/`unimplemented!`, no `spawn_blocking`/`block_on` anywhere
|
||||||
|
in `alkstore-mem/src` (grep), and the posture/wasm-identity crate
|
||||||
|
docs in place; zero production code changed.
|
||||||
|
- **The `PayloadTooLarge` asymmetry row gained a third arm — a new
|
||||||
|
suite row, not a row edit** (ADR-017 §2 class 4 suite-side
|
||||||
|
non-event, recorded here for the review gate): the existing pair
|
||||||
|
are engine-named (`payload_too_large_never_produced_on_sqlite` /
|
||||||
|
`payload_too_large_produced_on_pg`) with "the engine-differing leg
|
||||||
|
inside" their own functions, so mem's non-occurrence posture gets
|
||||||
|
its same-shaped arm — `payload_too_large_never_produced_on_mem`,
|
||||||
|
stamped ADR-016 §5 + ADR-024 §3, driving a payload just past the
|
||||||
|
2 MiB mark the tx seam's mem unit pins (2 MiB + 1) through notify
|
||||||
|
and asserting success. The existing SQLite and pg rows are
|
||||||
|
untouched; their columns still run 25 rows each.
|
||||||
|
- **The mem column carries all 25 rows with no omissions**: the
|
||||||
|
engine-shaped arms the description lists as omit-able
|
||||||
|
(reconnect-wake, watcher-death close, watcher-cadence) never
|
||||||
|
existed as suite rows — per review-wave-5's discharge map they were
|
||||||
|
per-engine *engine-side* rows from birth (SQLite's
|
||||||
|
`poll_interval_flows_to_the_watcher_config` and the pg
|
||||||
|
reconnect-stays-open leg each pin in their own crate's tests;
|
||||||
|
receiver-close arms pin through the store-handle drop that
|
||||||
|
`receiver_close_and_save_arms` drives — the dispose carrier mem
|
||||||
|
also implements). So the classification's "omits the rows that
|
||||||
|
cannot" is trivially satisfied: there was nothing to leave out, and
|
||||||
|
the mem arm substitution keeps the column at the full 25.
|
||||||
|
- **Factory shape**: `MemFactory` is a unit struct — no per-tag
|
||||||
|
backing directory (there is no external backing; the store instance
|
||||||
|
is the state). `open` = `MemStore::new()` boxed; `teardown` = the
|
||||||
|
documented no-op `Ok(())` (the holder's drop of the handle *is* the
|
||||||
|
teardown — nothing outside the instance exists to dispose of),
|
||||||
|
idempotent trivially, safe against abandoned stores (the abandoned
|
||||||
|
box drops with the test's frame). The factory-shape pin proves
|
||||||
|
isolation behaviorally (a publish under `a` invisible to `b`) and
|
||||||
|
teardown idempotence (both calls `Ok`).
|
||||||
|
- **Current-thread flavor enforced per-test**: every
|
||||||
|
`#[tokio::test]` in the target names `flavor = "current_thread"`
|
||||||
|
explicitly — a blocking call inside a row or inside the engine
|
||||||
|
stalls the flavor into a hang, not a pass: the no-blocking posture
|
||||||
|
is proven by the flavor running, not by a grep alone.
|
||||||
|
- **The on-target wasm suite-execution scope-out's named collapse
|
||||||
|
condition** (recorded per the task description, not an OQ): a
|
||||||
|
**wasm-bindgen-test adapter crate** — the suite's rows await real
|
||||||
|
time (`past_stamp_sleep`) and drive the store through
|
||||||
|
`BoxedFuture`s; on-target execution needs a wasm-bindgen-test
|
||||||
|
runner bridging those futures and the suite's `#[tokio::test]`
|
||||||
|
executor posture, which no row demands today. Until a consumer
|
||||||
|
needs it, the wasm acceptance stays at compile-clean (green).
|
||||||
|
- **No red rows** — the center-of-mass landed green on the first
|
||||||
|
full-column run: zero mem defects surfaced and zero suite-row
|
||||||
|
wobbles found, so the class-1 amend-in-place path was never
|
||||||
|
exercised and no reviewer escalation was owed.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
> To be filled on completion
|
> Landed: the contract suite's third column —
|
||||||
|
> `alkstore-mem/tests/contract_suite.rs` — with `StoreFactory`
|
||||||
|
> implemented for the mem engine (fresh `MemStore::new()` per open,
|
||||||
|
> teardown = drop; a unit struct, no backing path), all 25 rows
|
||||||
|
> wired (the 24 engine-shared mechanism rows + mem's new
|
||||||
|
> `payload_too_large_never_produced_on_mem` arm) **under the
|
||||||
|
> current-thread flavor**, every test explicitly
|
||||||
|
> `flavor = "current_thread"` — green first run in 13 s. The suite
|
||||||
|
> addition (the new mem-arm row in `properties.rs` + its export) is
|
||||||
|
> the only suite-side change; no existing row changed.
|
||||||
|
>
|
||||||
|
> Full-surface wiring and crate docs verified as already landed by
|
||||||
|
> the seam/foundations tasks (`no todo!/unimplemented!`,
|
||||||
|
> `spawn_blocking`-free by grep, posture + wasm-identity crate docs
|
||||||
|
> in place) — zero production code changed. `engine-mem.md`
|
||||||
|
> frontmatter flipped `draft` → `implementation-complete` with the
|
||||||
|
> last_updated line recording the wave's landing; the stable flip
|
||||||
|
> stays with the review gate.
|
||||||
|
>
|
||||||
|
> Verified: workspace `cargo build` green; workspace `cargo test`
|
||||||
|
> green (core 25, suite harness 3, mem 100 lib + 25 suite, SQLite 191
|
||||||
|
> lib + 25 suite, pg 124 lib + 25 suite + 9 schema); clippy
|
||||||
|
> `--all-targets -D warnings` clean; `cargo fmt --check` clean;
|
||||||
|
> `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
|
||||||
|
> clean; the manifest's tokio subset (sync + time; dev rt/macros)
|
||||||
|
> verified — unchanged by this task beyond the
|
||||||
|
> `alkstore-contract-suite` dev-dep (test-side, host-only).
|
||||||
Reference in new issue
Block a user