//! Durable and Matrix-facing data types for the foundation phase.
use serde::{Deserialize, Serialize};
/// Represents one normalized Matrix text message in an invocation's context.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MatrixMessage {
/// Matrix event ID that identifies this message.
pub event_id: String,
/// Matrix room ID containing this message.
pub room_id: String,
/// Stable Matrix user ID of the author.
pub sender_id: String,
/// Matrix server timestamp for chronological ordering.
pub timestamp_ms: u64,
/// Normalized text with meaningful formatting represented safely.
pub body: String,
/// Rich-reply target, when present.
pub reply_to_event_id: Option<String>,
}
/// Identifies one candidate Matrix event that may invoke Lisa.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct InvocationCandidate {
/// Matrix event ID that uniquely identifies the invocation.
pub event_id: String,
/// Matrix room ID containing the event.
pub room_id: String,
/// Matrix user ID that sent the event.
pub sender_id: String,
/// Server timestamp recorded for ordering and diagnosis.
pub received_at_ms: u64,
/// Original Matrix event retained only until classification completes.
pub raw_event_json: String,
/// Deterministic Matrix transaction ID for Lisa's reply.
pub matrix_txn_id: String,
}
/// Describes the durable stage of an invocation.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InvocationStatus {
/// The event awaits classification or processing.
Candidate,
/// A worker owns the event until its lease expires.
Processing,
/// The event cannot invoke Lisa.
Ignored,
/// A fixed reply payload is ready for idempotent Matrix delivery.
ReadyToSend,
/// Matrix accepted the reply and its event ID was recorded.
Sent,
}
impl InvocationStatus {
/// Returns the SQLite representation of this status.
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Candidate => "candidate",
Self::Processing => "processing",
Self::Ignored => "ignored",
Self::ReadyToSend => "ready_to_send",
Self::Sent => "sent",
}
}
/// Parses a durable invocation status.
pub fn parse(value: &str) -> Result<Self, String> {
match value {
"candidate" => Ok(Self::Candidate),
"processing" => Ok(Self::Processing),
"ignored" => Ok(Self::Ignored),
"ready_to_send" => Ok(Self::ReadyToSend),
"sent" => Ok(Self::Sent),
_ => Err(format!("unknown invocation status {value:?}")),
}
}
}
/// Holds a durable invocation row exposed to workers.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InvocationRecord {
/// Matrix event ID that identifies the invocation.
pub event_id: String,
/// Matrix room ID containing the invocation.
pub room_id: String,
/// Matrix user ID that sent the invocation.
pub sender_id: String,
/// Server timestamp recorded for ordering.
pub received_at_ms: u64,
/// Current durable lifecycle state.
pub status: InvocationStatus,
/// Stored Matrix event JSON, absent after a terminal state.
pub raw_event_json: Option<String>,
/// Exact reply JSON persisted before delivery.
pub response_json: Option<String>,
/// Deterministic Matrix transaction ID.
pub matrix_txn_id: String,
/// Matrix event ID of Lisa's accepted reply.
pub sent_event_id: Option<String>,
/// Number of times a worker has acquired the invocation.
pub attempt_count: u32,
/// Time after which the row may be processed again.
pub available_at_ms: u64,
/// Stable non-sensitive error code for operators.
pub last_error_code: Option<String>,
}
/// Holds Lisa's persisted controlled-sync position.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SyncState {
/// Indicates whether the historical first-sync baseline was recorded.
pub initialized: bool,
/// Matrix next-batch token, if an initial sync has completed.
pub next_batch: Option<String>,
}
/// Summarizes non-sensitive durable work for a local operator health check.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HealthSnapshot
{
/// Number of accepted candidates not currently leased by a worker.
pub candidate_count: u64,
/// Number of replies durably awaiting Matrix delivery.
pub ready_to_send_count: u64,
/// Age in milliseconds of the oldest reply awaiting delivery.
pub oldest_ready_age_ms: Option<u64>,
}