alkstore 0.1.0

The alkstore contract crate: one reactive store trait surface — notify, streams, durable queues, TTL locks, outbox, scheduler — implemented by the alkstore-sqlite/-postgres/-mem engine crates; no driver dependencies
Documentation
//! The durable stream subscription receiver (ADR-008 §8; ADR-021 §5;
//! ADR-019 §6).
//!
//! Explicit saves only — no `save_every`, no save-on-drop (the
//! auto-checkpoint ambiguity is not inherited); checkpointing is the
//! consumer's call.

use crate::Result;
use crate::future::BoxedFuture;
use crate::stream::StreamEvent;

/// The durable stream subscription handle `StreamHandle::subscribe`
/// returns.
///
/// # Close and error arms (ADR-021 §5)
///
/// `recv()`'s `Err` arm carries `Database` only — payloads cross
/// raw, and `Codec` lives at `payload_as<T>` on the yielded
/// [`StreamEvent`]; `Closed` is the `None` arm by construction. Close
/// is terminal; what causes it is the documented engine asymmetry
/// (SQLite: watcher death; Postgres: engine shutdown — reconnect
/// wakes arrive on the receiver). A closed receiver never reopens;
/// recovery is a fresh `subscribe(consumer)` resuming from the saved
/// offset. No `recv_timeout` exists here — deliberate absence (a
/// stream consumer's steady state is wake-driven re-read; polling
/// needs are served by `try_recv` and the offset-anchored
/// `read_since`).
pub trait EventReceiver: Send {
    /// Wait for the next event. `None` = the stream receiver closed
    /// (terminal). `Some(Err(...))` carries `Database` only.
    fn recv<'a>(&'a mut self) -> BoxedFuture<'a, Option<Result<StreamEvent>>>;

    /// Poll without waiting. `Ok(None)` = no event pending right now;
    /// `Err` carries `Database` or `Closed` (closed source).
    fn try_recv(&mut self) -> Result<Option<StreamEvent>>;

    /// Offset-anchored read from the stream, independent of this
    /// receiver's position (saved checkpoints do not gate reads —
    /// replay is a read concern).
    fn read_since<'a>(
        &'a mut self,
        offset: i64,
        limit: i64,
    ) -> BoxedFuture<'a, Result<Vec<StreamEvent>>>;

    /// Checkpoint the last-yielded event's offset through the same
    /// monotone op the direct `save_offset` form uses — the forms
    /// interleave freely and cannot regress one another (ADR-019 §6).
    /// A save before any event has been yielded is a no-op (the
    /// stored checkpoint untouched). The `Err` arm carries `Database`
    /// only (ADR-021 §5).
    fn save_offset(&mut self) -> Result<()>;

    /// The receiver's current offset (the last-yielded event's
    /// offset), used when a consumer wants to interleave the direct
    /// save form with the receiver's position. Before any event has
    /// yielded it reads 0 — the no-yield sentinel, not the consumer's
    /// stored checkpoint (the checkpoint gates the feed's start; the
    /// first `recv`/`try_recv` observation is the first move;
    /// annotated 2026-10-11, review-004 item 12).
    fn offset(&self) -> i64;
}