Skip to main content

bones_core/crdt/
trace.rs

1use serde::{Deserialize, Serialize};
2
3/// Tie-break stage that produced a strict LWW winner.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5pub enum TieBreakStep {
6    ItcCausal,
7    WallTimestamp,
8    AgentId,
9    EventHash,
10    Equal,
11}
12
13/// Structured trace payload for a single LWW merge decision.
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15pub struct MergeTrace {
16    pub field: String,
17    pub values: (String, String),
18    pub winner: String,
19    pub step: TieBreakStep,
20    pub correlation_id: String,
21    pub enabled: bool,
22}
23
24impl MergeTrace {
25    #[must_use]
26    pub const fn disabled() -> Self {
27        Self {
28            field: String::new(),
29            values: (String::new(), String::new()),
30            winner: String::new(),
31            step: TieBreakStep::Equal,
32            correlation_id: String::new(),
33            enabled: false,
34        }
35    }
36}
37
38/// Runtime toggle for merge tracing.
39///
40/// Enabled when either:
41/// - `BONES_DEBUG_MERGE=1|true|yes|on`
42/// - `BONES_LOG` contains `debug` or `trace`
43#[must_use]
44pub fn merge_tracing_enabled() -> bool {
45    let debug_merge = std::env::var("BONES_DEBUG_MERGE").ok().is_some_and(|v| {
46        let lowered = v.trim().to_ascii_lowercase();
47        matches!(lowered.as_str(), "1" | "true" | "yes" | "on")
48    });
49
50    if debug_merge {
51        return true;
52    }
53
54    std::env::var("BONES_LOG").ok().is_some_and(|v| {
55        let lowered = v.to_ascii_lowercase();
56        lowered.contains("debug") || lowered.contains("trace")
57    })
58}