返回 DeepSeek-TUI-2026
coherence.rs
根目录 / crates / tui / src / core / coherence.rs
1 //! Plain-language session coherence state derived from capacity events.
2
3 use serde::{Deserialize, Serialize};
4
5 use crate::core::capacity::{GuardrailAction, RiskBand};
6
7 /// User-facing coherence ladder for session health.
8 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9 #[serde(rename_all = "snake_case")]
10 pub enum CoherenceState {
11 #[default]
12 Healthy,
13 GettingCrowded,
14 RefreshingContext,
15 VerifyingRecentWork,
16 ResettingPlan,
17 }
18
19 impl CoherenceState {
20 #[must_use]
21 pub fn label(self) -> &'static str {
22 match self {
23 Self::Healthy => "healthy",
24 Self::GettingCrowded => "getting crowded",
25 Self::RefreshingContext => "refreshing context",
26 Self::VerifyingRecentWork => "verifying recent work",
27 Self::ResettingPlan => "resetting plan",
28 }
29 }
30
31 #[must_use]
32 pub fn description(self) -> &'static str {
33 match self {
34 Self::Healthy => "The session is stable and focused.",
35 Self::GettingCrowded => "The session is approaching context pressure.",
36 Self::RefreshingContext => "The engine is refreshing context before continuing.",
37 Self::VerifyingRecentWork => {
38 "The engine is checking recent tool results before continuing."
39 }
40 Self::ResettingPlan => {
41 "The engine is rebuilding from canonical context and replanning."
42 }
43 }
44 }
45 }
46
47 /// Synthetic input to the coherence reducer.
48 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
49 pub enum CoherenceSignal {
50 CapacityDecision {
51 risk_band: RiskBand,
52 action: GuardrailAction,
53 cooldown_blocked: bool,
54 },
55 CapacityIntervention {
56 action: GuardrailAction,
57 },
58 CompactionStarted,
59 CompactionCompleted,
60 CompactionFailed,
61 }
62
63 /// Pure transition function for the plain-language coherence ladder.
64 #[must_use]
65 pub fn next_coherence_state(current: CoherenceState, signal: CoherenceSignal) -> CoherenceState {
66 match signal {
67 CoherenceSignal::CompactionStarted => CoherenceState::RefreshingContext,
68 CoherenceSignal::CompactionCompleted => CoherenceState::Healthy,
69 CoherenceSignal::CompactionFailed => CoherenceState::GettingCrowded,
70 CoherenceSignal::CapacityIntervention { action }
71 | CoherenceSignal::CapacityDecision { action, .. } => match action {
72 GuardrailAction::NoIntervention => match signal {
73 CoherenceSignal::CapacityDecision {
74 risk_band,
75 cooldown_blocked,
76 ..
77 } => {
78 if cooldown_blocked {
79 return current;
80 }
81 match risk_band {
82 RiskBand::Low => CoherenceState::Healthy,
83 RiskBand::Medium | RiskBand::High => CoherenceState::GettingCrowded,
84 }
85 }
86 _ => current,
87 },
88 GuardrailAction::TargetedContextRefresh => CoherenceState::RefreshingContext,
89 GuardrailAction::VerifyWithToolReplay => CoherenceState::VerifyingRecentWork,
90 GuardrailAction::VerifyAndReplan => CoherenceState::ResettingPlan,
91 },
92 }
93 }
94
95 #[cfg(test)]
96 mod tests {
97 use super::*;
98
99 #[test]
100 fn synthetic_capacity_event_log_drives_plain_language_ladder() {
101 let log = [
102 CoherenceSignal::CapacityDecision {
103 risk_band: RiskBand::Low,
104 action: GuardrailAction::NoIntervention,
105 cooldown_blocked: false,
106 },
107 CoherenceSignal::CapacityDecision {
108 risk_band: RiskBand::Medium,
109 action: GuardrailAction::NoIntervention,
110 cooldown_blocked: false,
111 },
112 CoherenceSignal::CapacityDecision {
113 risk_band: RiskBand::Medium,
114 action: GuardrailAction::TargetedContextRefresh,
115 cooldown_blocked: false,
116 },
117 CoherenceSignal::CompactionCompleted,
118 CoherenceSignal::CapacityDecision {
119 risk_band: RiskBand::High,
120 action: GuardrailAction::VerifyWithToolReplay,
121 cooldown_blocked: false,
122 },
123 CoherenceSignal::CapacityDecision {
124 risk_band: RiskBand::High,
125 action: GuardrailAction::VerifyAndReplan,
126 cooldown_blocked: false,
127 },
128 ];
129
130 let mut state = CoherenceState::Healthy;
131 let mut states = Vec::new();
132 for signal in log {
133 state = next_coherence_state(state, signal);
134 states.push(state);
135 }
136
137 assert_eq!(
138 states,
139 vec![
140 CoherenceState::Healthy,
141 CoherenceState::GettingCrowded,
142 CoherenceState::RefreshingContext,
143 CoherenceState::Healthy,
144 CoherenceState::VerifyingRecentWork,
145 CoherenceState::ResettingPlan,
146 ]
147 );
148 }
149 }
150
150 lines RUST