refactor: split crdt_state.rs into 6 sub-modules with co-located tests

The 2122-line crdt_state.rs is split into a sub-module directory:

- types.rs: CRDT/view types + CrdtEvent (247 lines)
- state.rs: CrdtState struct, statics, init, apply_and_persist (531 lines)
- ops.rs: sync API + apply_remote_op + delta-sync tests (455 lines)
- write.rs: write_item + bug_511 test (273 lines)
- read.rs: read API + dump + dep helpers (469 lines)
- presence.rs: node identity + claim API + heartbeat (176 lines)
- mod.rs: doc, sub-module decls, re-exports, hex helper (53 lines)

Tests are co-located with the code they primarily exercise per Rust convention.

No behaviour change. All 26 crdt_state tests pass; full suite green
(2635 tests with --test-threads=1).
This commit is contained in:
dave
2026-04-26 20:54:15 +00:00
parent 8bdaabd06c
commit 23e22ba49c
8 changed files with 2228 additions and 2122 deletions
+53
View File
@@ -0,0 +1,53 @@
//! 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.
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<String, u64>;
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,
write_claim, 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::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()
}
}