1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! Orchestration logic for determining next effect.
//!
//! This module implements the **pure orchestration layer** that derives effects from state.
//! The orchestrator is a critical component of the reducer architecture that bridges
//! state transitions with effect execution.
//!
//! # Pure Function Contract
//!
//! All orchestration functions are **PURE**:
//! - Input: `&PipelineState` (immutable reference to current state)
//! - Output: `Effect` (intention to perform side effects)
//! - No I/O operations (no filesystem, network, environment access)
//! - No side effects (no logging, no mutations, no hidden state)
//! - Deterministic: same state always produces same effect
//!
//! # Architecture Flow
//!
//! ```text
//! State → determine_next_effect() → Effect → Handler → Event → Reducer → State
//! ^^^^^^^^^^^^^^^^^^^^^^
//! Pure orchestration (this module)
//! ```
//!
//! The orchestrator examines state and derives the next effect:
//! 1. Check for pending recovery operations (continuation cleanup, loop recovery)
//! 2. Check for retry/fallback conditions (XSD retry, agent retry)
//! 3. Determine normal phase progression effect
//!
//! # Decision Priority
//!
//! Orchestration checks conditions in priority order:
//! 1. **Recovery**: Continuation cleanup, loop recovery
//! 2. **Retry**: XSD retry pending, same-agent retry pending
//! 3. **Continuation**: Agent requested continuation
//! 4. **Normal**: Phase-specific progression
//! 5. **Transition**: Advance to next phase
//!
//! # Testing Strategy
//!
//! Orchestrators are pure functions - test them without mocks:
//!
//! ```ignore
//! #[test]
//! fn test_xsd_retry_pending_derives_cleanup_effect() {
//! let state = PipelineState {
//! continuation: ContinuationState {
//! xsd_retry_pending: true,
//! ..Default::default()
//! },
//! ..test_state()
//! };
//!
//! let effect = determine_next_effect(&state);
//!
//! assert!(matches!(effect, Effect::CleanupRequiredFiles { files } if files.iter().any(|f| f.contains("development_result.xml")));
//! }
//! ```
//!
//! See [`tests`] module for comprehensive orchestration tests.
use ;
use ;
use crate;
use determine_next_effect_for_phase;
include!;
/// Returns true if recovery state is active (dev-fix occurred and we transitioned back).
///
/// Recovery state is considered active when:
/// - `dev_fix_attempt_count` > 0 (at least one recovery attempt)
/// - `recovery_escalation_level` > 0 (escalation level set)
/// - `previous_phase` is `AwaitingDevFix` (just transitioned back from recovery)
///
/// When recovery state is active and a phase completes successfully (e.g., Planning
/// validates, Development completes), the orchestration should emit `RecoverySucceeded`
/// to clear the recovery tracking fields and resume normal operation.
pub const