ralph_workflow/cli/reducer/
state_reduction.rs1use super::event::CliEvent;
7use super::state::{CliState, PresetType};
8
9#[must_use]
29pub fn reduce(state: CliState, event: CliEvent) -> CliState {
30 match event {
31 CliEvent::VerbositySet { level } => CliState {
33 verbosity: Some(level),
34 ..state
35 },
36 CliEvent::QuietModeEnabled => CliState {
37 quiet_mode: true,
38 ..state
39 },
40 CliEvent::FullModeEnabled => CliState {
41 full_mode: true,
42 ..state
43 },
44 CliEvent::DebugModeEnabled => CliState {
45 debug_mode: true,
46 ..state
47 },
48
49 CliEvent::QuickPresetApplied => CliState {
51 preset_applied: Some(PresetType::Quick),
52 ..state
53 },
54 CliEvent::RapidPresetApplied => CliState {
55 preset_applied: Some(PresetType::Rapid),
56 ..state
57 },
58 CliEvent::LongPresetApplied => CliState {
59 preset_applied: Some(PresetType::Long),
60 ..state
61 },
62 CliEvent::StandardPresetApplied => CliState {
63 preset_applied: Some(PresetType::Standard),
64 ..state
65 },
66 CliEvent::ThoroughPresetApplied => CliState {
67 preset_applied: Some(PresetType::Thorough),
68 ..state
69 },
70
71 CliEvent::DeveloperItersSet { value } => CliState {
73 developer_iters: Some(value),
74 ..state
75 },
76 CliEvent::ReviewerReviewsSet { value } => CliState {
77 reviewer_reviews: Some(value),
78 ..state
79 },
80
81 CliEvent::DeveloperAgentSet { agent } => CliState {
83 developer_agent: Some(agent),
84 ..state
85 },
86 CliEvent::ReviewerAgentSet { agent } => CliState {
87 reviewer_agent: Some(agent),
88 ..state
89 },
90 CliEvent::DeveloperModelSet { model } => CliState {
91 developer_model: Some(model),
92 ..state
93 },
94 CliEvent::ReviewerModelSet { model } => CliState {
95 reviewer_model: Some(model),
96 ..state
97 },
98 CliEvent::DeveloperProviderSet { provider } => CliState {
99 developer_provider: Some(provider),
100 ..state
101 },
102 CliEvent::ReviewerProviderSet { provider } => CliState {
103 reviewer_provider: Some(provider),
104 ..state
105 },
106 CliEvent::ReviewerJsonParserSet { parser } => CliState {
107 reviewer_json_parser: Some(parser),
108 ..state
109 },
110
111 CliEvent::IsolationModeDisabled => CliState {
113 isolation_mode: Some(false),
114 ..state
115 },
116 CliEvent::ReviewDepthSet { depth } => CliState {
117 review_depth: Some(depth),
118 ..state
119 },
120 CliEvent::GitUserNameSet { name } => CliState {
121 git_user_name: Some(name),
122 ..state
123 },
124 CliEvent::GitUserEmailSet { email } => CliState {
125 git_user_email: Some(email),
126 ..state
127 },
128 CliEvent::StreamingMetricsEnabled => CliState {
129 streaming_metrics: true,
130 ..state
131 },
132
133 CliEvent::AgentPresetSet { preset } => CliState {
135 agent_preset: Some(preset),
136 ..state
137 },
138
139 CliEvent::CliProcessingComplete => CliState {
141 complete: true,
142 ..state
143 },
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_reduce_verbosity_set() {
153 let state = CliState::initial();
154 let new_state = reduce(state, CliEvent::VerbositySet { level: 3 });
155 assert_eq!(new_state.verbosity, Some(3));
156 }
157
158 #[test]
159 fn test_reduce_quiet_mode() {
160 let state = CliState::initial();
161 let new_state = reduce(state, CliEvent::QuietModeEnabled);
162 assert!(new_state.quiet_mode);
163 }
164
165 #[test]
166 fn test_reduce_preset_quick() {
167 let state = CliState::initial();
168 let new_state = reduce(state, CliEvent::QuickPresetApplied);
169 assert_eq!(new_state.preset_applied, Some(PresetType::Quick));
170 assert_eq!(new_state.resolved_developer_iters(99), 1);
171 assert_eq!(new_state.resolved_reviewer_reviews(99), 1);
172 }
173
174 #[test]
175 fn test_reduce_preset_long() {
176 let state = CliState::initial();
177 let new_state = reduce(state, CliEvent::LongPresetApplied);
178 assert_eq!(new_state.preset_applied, Some(PresetType::Long));
179 assert_eq!(new_state.resolved_developer_iters(99), 15);
180 assert_eq!(new_state.resolved_reviewer_reviews(99), 10);
181 }
182
183 #[test]
184 fn test_reduce_preset_standard() {
185 let state = CliState::initial();
186 let new_state = reduce(state, CliEvent::StandardPresetApplied);
187 assert_eq!(new_state.preset_applied, Some(PresetType::Standard));
188 assert_eq!(new_state.resolved_developer_iters(99), 5);
189 assert_eq!(new_state.resolved_reviewer_reviews(99), 2);
190 }
191
192 #[test]
193 fn test_reduce_preset_thorough() {
194 let state = CliState::initial();
195 let new_state = reduce(state, CliEvent::ThoroughPresetApplied);
196 assert_eq!(new_state.preset_applied, Some(PresetType::Thorough));
197 assert_eq!(new_state.resolved_developer_iters(99), 10);
198 assert_eq!(new_state.resolved_reviewer_reviews(99), 5);
199 }
200
201 #[test]
202 fn test_reduce_preset_last_wins() {
203 let state = CliState::initial();
204 let state = reduce(state, CliEvent::QuickPresetApplied);
206 let state = reduce(state, CliEvent::LongPresetApplied);
207
208 assert_eq!(state.preset_applied, Some(PresetType::Long));
210 assert_eq!(state.resolved_developer_iters(99), 15);
211 }
212
213 #[test]
214 fn test_reduce_explicit_iters_override_preset() {
215 let state = CliState::initial();
216 let state = reduce(state, CliEvent::QuickPresetApplied);
218 let state = reduce(state, CliEvent::DeveloperItersSet { value: 7 });
220 let state = reduce(state, CliEvent::ReviewerReviewsSet { value: 3 });
221
222 assert_eq!(state.resolved_developer_iters(99), 7);
224 assert_eq!(state.resolved_reviewer_reviews(99), 3);
225 }
226
227 #[test]
228 fn test_reduce_developer_agent() {
229 let state = CliState::initial();
230 let new_state = reduce(
231 state,
232 CliEvent::DeveloperAgentSet {
233 agent: "claude".to_string(),
234 },
235 );
236 assert_eq!(new_state.developer_agent, Some("claude".to_string()));
237 }
238
239 #[test]
240 fn test_reduce_isolation_mode_disabled() {
241 let state = CliState::initial();
242 let new_state = reduce(state, CliEvent::IsolationModeDisabled);
243 assert_eq!(new_state.isolation_mode, Some(false));
244 }
245
246 #[test]
247 fn test_reduce_streaming_metrics() {
248 let state = CliState::initial();
249 let new_state = reduce(state, CliEvent::StreamingMetricsEnabled);
250 assert!(new_state.streaming_metrics);
251 }
252
253 #[test]
254 fn test_reduce_complete() {
255 let state = CliState::initial();
256 let new_state = reduce(state, CliEvent::CliProcessingComplete);
257 assert!(new_state.complete);
258 }
259
260 #[test]
261 fn test_reduce_preserves_unrelated_fields() {
262 let mut state = CliState::initial();
263 state.developer_agent = Some("existing".to_string());
264
265 let new_state = reduce(state, CliEvent::QuietModeEnabled);
267
268 assert!(new_state.quiet_mode);
269 assert_eq!(new_state.developer_agent, Some("existing".to_string()));
270 }
271
272 #[test]
273 fn test_full_event_sequence() {
274 let events = vec![
275 CliEvent::ThoroughPresetApplied,
276 CliEvent::DeveloperAgentSet {
277 agent: "opencode".to_string(),
278 },
279 CliEvent::ReviewerAgentSet {
280 agent: "claude".to_string(),
281 },
282 CliEvent::DebugModeEnabled,
283 CliEvent::StreamingMetricsEnabled,
284 CliEvent::CliProcessingComplete,
285 ];
286
287 let mut state = CliState::initial();
288 for event in events {
289 state = reduce(state, event);
290 }
291
292 assert!(state.complete);
293 assert!(state.debug_mode);
294 assert!(state.streaming_metrics);
295 assert_eq!(state.preset_applied, Some(PresetType::Thorough));
296 assert_eq!(state.developer_agent, Some("opencode".to_string()));
297 assert_eq!(state.reviewer_agent, Some("claude".to_string()));
298 assert_eq!(state.resolved_developer_iters(5), 10);
299 assert_eq!(state.resolved_reviewer_reviews(2), 5);
300 }
301}