Skip to main content

ralph_workflow/reducer/
mod.rs

1//! Reducer-based pipeline architecture.
2//!
3//! This module implements the event-sourced reducer architecture.
4//! It provides:
5//! - Pure state reduction with explicit event transitions
6//! - Immutable pipeline state that doubles as checkpoint
7//! - Event log for debugging and replay
8//! - Effect handlers for side effects (git operations, agent execution)
9//!
10//! # Single Source of Truth
11//!
12//! The reducer state is the **single source of truth** for all pipeline decisions:
13//!
14//! - **Phase transitions**: Only happen via reducer events, never via file checks
15//! - **Agent selection**: Determined by `state.agent_chain`, not config lookups
16//! - **Agent fallback**: Triggered by reducer events (`AgentFallbackTriggered`, `AgentInvocationFailed`)
17//! - **XSD retry**: Tracked in `ContinuationState.xsd_retry_count` / `ContinuationState.xsd_retry_pending`, not hidden logic
18//! - **Pipeline completion**: Determined by `state.phase == Complete`, not file existence
19//!
20//! **Invariant**: No phase module or effect handler makes control-flow decisions.
21//! All decisions happen via events processed by [`reduce`], which returns new state.
22//!
23//! All effects are determined by [`determine_next_effect`], a pure function of state.
24//! No external file checks or configuration lookups influence effect determination.
25//!
26//! # Key Types
27//!
28//! - [`PipelineState`] - Immutable state representing current pipeline progress
29//! - [`PipelineEvent`] - Events that trigger state transitions
30//! - [`reduce`] - Pure function: `(State, Event) → State`
31//! - [`determine_next_effect`] - Pure function: `State → Effect`
32//! - [`EffectHandler`] - Trait for executing effects (impure operations)
33//!
34//! See also: [`CODE_STYLE.md`](https://codeberg.org/mistlight/RalphWithReviewer/src/branch/main/CODE_STYLE.md)
35//! for the architecture overview.
36//!
37//! # Architecture
38//!
39//! ```text
40//! ┌──────────────────────────────────────────────────┐
41//! │                     Pipeline State                        │
42//! │  (immutable: phase, iteration, agent_chain, history)     │
43//! └──────────────────────────────────────────────────┘
44//!                           │
45//!                           ▼
46//! ┌──────────────────────────────────────────────────┐
47//! │                        Reducer                            │
48//! │       fn reduce(state: State, event: Event) -> State     │
49//! │                   [Pure, no side effects]                │
50//! └──────────────────────────────────────────────────┘
51//!                           ▲
52//!                           │
53//! ┌──────────────────────────────────────────────────┐
54//! │                        Events                             │
55//! │  DevelopmentIterationCompleted | AgentFailed |           │
56//! │  ReviewPassCompleted | RebaseSucceeded | ...             │
57//! └──────────────────────────────────────────────────┘
58//!                           ▲
59//!                           │
60//! ┌──────────────────────────────────────────────────┐
61//! │                   Effect Handlers                         │
62//! │  (Agent execution, file I/O, git operations)             │
63//! │       [Side effects isolated here]                       │
64//! └──────────────────────────────────────────────────┘
65//! ```
66//!
67//! # Quick Start
68//!
69//! Run pipeline with reducer:
70//!
71//! ```ignore
72//! use ralph_workflow::reducer::{run_event_loop, PipelineState};
73//!
74//! let state = PipelineState::initial(developer_iters, reviewer_reviews);
75//! let result = run_event_loop(&mut phase_ctx, Some(state), Default::default())?;
76//! ```
77//!
78//! # State Inspection
79//!
80//! Inspect pipeline state at any point:
81//!
82//! ```ignore
83//! println!("Current phase: {}", state.phase);
84//! println!("Iteration: {}/{}", state.iteration, state.total_iterations);
85//! println!("Current agent: {:?}", state.agent_chain.current_agent());
86//! ```
87//!
88//! # Event Replay
89//!
90//! Replay events from log:
91//!
92//! ```ignore
93//! let final_state = events.into_iter()
94//!     .fold(initial_state, |s, e| reduce(s, e));
95//! ```
96//!
97//! # Testing Strategy
98//!
99//! The reducer architecture is designed for extensive testability:
100//!
101//! ## Unit Tests
102//!
103//! - **Pure reducer**: `reduce()` function has no side effects, 100% testable
104//! - **State transitions**: Each event → state transition tested in state_reduction.rs tests
105//! - **Agent chain**: Fallback logic tested via AgentChainState methods
106//! - **Error classification**: All error kinds tested in fault_tolerant_executor.rs
107//!
108//! ## Integration Tests
109//!
110//! - **State machine**: Real pipeline execution verifies correct phase transitions
111//! - **Event replay**: Event logs can reproduce final state deterministically
112//!
113//! # Testing Reducer Purity
114//!
115//! Reducer is easy to test - pure function with no side effects:
116//!
117//! ```ignore
118//! #[test]
119//! fn test_agent_fallback() {
120//!     let state = create_test_state();
121//!     let event = PipelineEvent::AgentInvocationFailed { ... };
122//!     let new_state = reduce(state, event);
123//!     assert_eq!(new_state.agent_chain.current_agent_index, 1);
124//! }
125//! ```
126//!
127//! # Running Tests
128//!
129//! ```bash
130//! # Unit tests only
131//! cargo test -p ralph-workflow --lib --all-features
132//!
133//! # Integration tests
134//! cargo test -p ralph-workflow-tests --all-targets
135//!
136//! # With coverage
137//! cargo test -p ralph-workflow --lib --all-features -- --nocapture
138//! ```
139
140pub mod effect;
141pub mod event;
142pub mod fault_tolerant_executor;
143pub mod handler;
144#[cfg(any(test, feature = "test-utils"))]
145pub mod mock_effect_handler;
146pub mod orchestration;
147#[cfg(test)]
148mod orchestration_tests;
149pub mod prompt_inputs;
150pub mod state;
151pub mod state_reduction;
152pub mod ui_event;
153
154#[cfg(test)]
155mod tests;
156
157pub use effect::{EffectHandler, EffectResult};
158pub use event::PipelineEvent;
159pub use handler::MainEffectHandler;
160pub use orchestration::{compute_effect_fingerprint, determine_next_effect};
161pub use state::PipelineState;
162pub use state_reduction::reduce;
163pub use ui_event::UIEvent;
164
165// Re-export CheckpointTrigger for external use
166pub use event::CheckpointTrigger;
167
168// Re-export category enums for external use
169pub use event::{
170    AgentEvent, CommitEvent, DevelopmentEvent, LifecycleEvent, PlanningEvent, RebaseEvent,
171    ReviewEvent,
172};