//! CRDT state layer — manages pipeline state as a conflict-free replicated document backed by SQLite. //! //! The CRDT document is the primary source of truth for pipeline item //! metadata (stage, name, agent, etc.). CRDT ops are persisted to SQLite so //! state survives restarts. The filesystem `.huskies/work/` directories are //! still updated as a secondary output for backwards compatibility. //! //! Stage transitions detected by `write_item()` are broadcast as [`CrdtEvent`]s //! so subscribers (auto-assign, WebSocket, notifications) can react without //! polling the filesystem. #![allow(unused_imports, dead_code)] use std::collections::HashMap; /// A vector clock mapping node IDs (hex-encoded Ed25519 pubkeys) to the count /// of ops seen from that node. Used for delta sync — a connecting peer sends /// its clock so the other side can compute which ops are missing. pub type VectorClock = HashMap; mod ops; mod presence; mod read; mod state; mod types; mod write; pub use ops::{all_ops_json, apply_remote_op, ops_since, our_vector_clock, subscribe_ops}; pub use presence::{ is_claimed_by_us, our_node_id, read_all_node_presence, release_claim, sign_challenge, sign_versioned_challenge, write_claim, write_node_metadata, write_node_presence, }; pub use read::{ CrdtItemDump, CrdtStateDump, check_archived_deps_crdt, check_unmet_deps_crdt, dep_is_archived_crdt, dep_is_done_crdt, dump_crdt_state, evict_item, read_all_items, read_item, }; pub use state::init; pub use types::{ CrdtEvent, NodePresenceCrdt, NodePresenceView, PipelineDoc, PipelineItemCrdt, PipelineItemView, subscribe, }; pub use write::{ migrate_names_from_slugs, migrate_story_ids_to_numeric, name_from_story_id, write_item, }; #[cfg(test)] pub use state::init_for_test; pub(crate) use state::{ALL_OPS, VECTOR_CLOCK}; /// Hex-encode a byte slice (no external dep needed). pub(crate) mod hex { pub fn encode(bytes: &[u8]) -> String { bytes.iter().map(|b| format!("{b:02x}")).collect() } }