ralph_workflow/reducer/event/lifecycle.rs
1//! Pipeline lifecycle events (start, stop, resume).
2//!
3//! These events control the overall pipeline execution lifecycle,
4//! distinct from phase-specific transitions.
5
6use serde::{Deserialize, Serialize};
7
8/// Pipeline lifecycle events (start, stop, resume).
9///
10/// These events control the overall pipeline execution lifecycle,
11/// distinct from phase-specific transitions. Use these for:
12///
13/// - Starting or resuming a pipeline run
14/// - Completing a successful pipeline execution
15///
16/// # When to Use
17///
18/// - `Started`: When a fresh pipeline run begins
19/// - `Resumed`: When resuming from a checkpoint
20/// - `Completed`: When all phases complete successfully
21///
22/// # ⚠️ FROZEN - DO NOT ADD VARIANTS ⚠️
23///
24/// This enum is **FROZEN**. Adding new variants is **PROHIBITED**.
25///
26/// ## Why is this frozen?
27///
28/// Lifecycle events control pipeline flow (start/stop/completion). Allowing effect
29/// handlers to emit new lifecycle events would violate the core architectural principle:
30/// **handlers describe what happened; reducers decide what happens next.**
31///
32/// ## What to do instead
33///
34/// If you need to express new observations or failures:
35///
36/// 1. **Reuse existing phase/category events** - Use `PlanningEvent`, `DevelopmentEvent`,
37/// `ReviewEvent`, `CommitEvent`, etc. to describe what happened within that phase.
38/// Example: `PlanningEvent::PlanXmlMissing` instead of creating a generic "Aborted" event.
39///
40/// 2. **Return errors from the event loop** - For truly unrecoverable failures (permission
41/// errors, invariant violations), return `Err` from the effect handler. The outer runner
42/// will handle termination, not the reducer.
43///
44/// 3. **Handle in orchestration** - Some conditions don't need events at all and can be
45/// handled in the effect handler or runner logic.
46///
47/// ## Enforcement
48///
49/// The freeze policy is enforced by the `lifecycle_event_is_frozen` test in the parent module,
50/// which will fail to compile if new variants are added. This is intentional.
51#[derive(Clone, Serialize, Deserialize, Debug)]
52pub enum LifecycleEvent {
53 /// Pipeline execution started fresh (not from checkpoint).
54 Started,
55 /// Pipeline execution resumed from a previous state.
56 Resumed {
57 /// Whether this resume is from a persisted checkpoint.
58 from_checkpoint: bool,
59 },
60 /// Pipeline execution completed successfully.
61 Completed,
62 /// Gitignore entries ensured in the repository.
63 GitignoreEntriesEnsured {
64 /// Entries that were added to .gitignore.
65 added: Vec<String>,
66 /// Entries that were already present.
67 existing: Vec<String>,
68 /// Whether .gitignore was created.
69 created: bool,
70 },
71}