Skip to main content

zero_session/
lib.rs

1//! SQLite-backed session persistence.
2//!
3//! One database per operator partition, WAL-journalled. Every
4//! operator input and every dispatcher output is written on the
5//! hot path so a crash preserves full replay (spec v2.1 §9).
6//!
7//! This crate deliberately does NOT persist operator-state events
8//! — those live on the engine host (see ADR-016). The tables here
9//! are CLI-local: conversation log and journey milestones.
10
11#![allow(clippy::module_name_repetitions)]
12
13pub mod event;
14pub mod store;
15pub mod wrap;
16
17use thiserror::Error;
18
19pub use event::{EventKind, SessionRow, StoredEvent};
20pub use store::Store;
21pub use wrap::{CommandCount, EventCounts, WrapReport};
22
23#[derive(Debug, Error)]
24pub enum SessionError {
25    #[error("sqlite: {0}")]
26    Sql(#[from] rusqlite::Error),
27    #[error("migration: {0}")]
28    Migration(String),
29    #[error("serialize: {0}")]
30    Serde(#[from] serde_json::Error),
31    #[error("io: {0}")]
32    Io(#[from] std::io::Error),
33}
34
35/// Milestone key constants. Keep them as `&'static str` here so a
36/// typo-prone string literal never leaks into consumers.
37pub mod milestones {
38    /// The honest-welcome has been shown at least once.
39    pub const WELCOME_SHOWN: &str = "welcome_shown";
40    /// ISO-8601 timestamp of the operator's first live trade, set
41    /// once and then never rewritten. Drives the first-live-trade
42    /// ceremony.
43    pub const FIRST_LIVE_TRADE_AT: &str = "first_live_trade_at";
44    /// Last time the daily wrap was rendered to the operator.
45    pub const LAST_DAILY_WRAP_AT: &str = "last_daily_wrap_at";
46}