Files
alkstore/alkstore-sqlite/src/seam.rs
T
glm-5.3-flash 7d400906f5 SQLite engine open: SqliteOpts, connection architecture, spawn_blocking seam posture (task sqlite-engine-open-opts)
- SqliteOpts (poll_interval: Option<Duration>, None = 1 ms shipping
  default ADR-023 §4; max_readers, DEFAULT_MAX_READERS = 8; opts
  exemption from non_exhaustive per ADR-017 §3)
- open(path, opts) -> Box<dyn Store>: writer slot, reader pool,
  SharedUpdateWatcher with fallible spawn mapped W-2-style into
  Error::Database; plain-path posture (ADR-023 §3) pinned by test
- Substrate delta D-30: open_conn_bootstrapped — every connection
  (writer and pooled readers) carries the full bootstrap surface
  (pragmas, notify, alkstore functions, schema) per engine-sqlite.md;
  lineage opened readers pragmas-only. Registered in PROVENANCE.md
- spawn_blocking seam helper + error mappings (string/rusqlite ->
  Database, source chains preserved); helper cfg(test)-gated until
  sqlite-engine-seam-tx wires the trait impls
- Store trait stubbed with Database errors (no panics); close()/Drop
  join the watcher, clear subscribers (death-guard), close pool+writer
- 15 new tests (open boot, watcher fanout/death-close, cadence
  accounting, plain-path literal filename, :memory:, pool bounding,
  drop teardown, seam smoke incl. panic mapping); gates green
2026-10-08 11:25:16 +00:00

46 lines
1.9 KiB
Rust

//! The `spawn_blocking` seam (ADR-003, ADR-007) and the error
//! mapping — the two engine-wide postures established here that every
//! later mechanism task reuses.
//!
//! - Every engine call round-trips a blocking thread: rusqlite
//! connections are not `Send`-across-await, and the sync substrate
//! bridges at the trait seam (the family REQ-TTY-01 posture).
//! - Substrate errors map into the contract taxonomy's opaque
//! [`Error::Database`](alkstore::Error) fallback with the source
//! chain preserved (ADR-008 §5). No panics cross the seam: a panic
//! inside a bridged closure is the `JoinError` arm's `Database`
//! mapping, family-standard no-panics discipline maintained.
use alkstore::Error;
/// The blocking bridge every trait method's substrate round trip goes
/// through. Private: the seam is engine-internal — consumers meet it
/// only through the async trait surface. `cfg(test)`-gated until the
/// seam task (`sqlite-engine-seam-tx`) wires the trait impls; the
/// helper's shape and error path are pinned by this wave's smoke test.
#[cfg(test)]
pub(crate) async fn blocking<T, F>(f: F) -> Result<T, Error>
where
T: Send + 'static,
F: FnOnce() -> Result<T, Error> + Send + 'static,
{
match tokio::task::spawn_blocking(f).await {
Ok(result) => result,
Err(e) => Err(database_error(format!("blocking task failed: {e}"))),
}
}
/// Map a substrate string failure into the contract taxonomy. The
/// substrate is contract-blind — its fallible API surfaces strings
/// (the W-2 spawn posture, ADR-012 §4); the engine layer owns the
/// mapping, ADR-012 §2.
pub(crate) fn database_error(message: impl Into<String>) -> Error {
Error::database(std::io::Error::other(message.into()))
}
/// Map a `rusqlite::Error` into the contract taxonomy, source chain
/// preserved (ADR-008 §5 — no engine-specific variants minted).
pub(crate) fn sqlite_error(e: rusqlite::Error) -> Error {
Error::database(e)
}