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}