Skip to main content

ralph_workflow/reducer/event/
commit.rs

1//! Commit generation events.
2//!
3//! Events related to commit message generation, validation, and creation.
4
5use serde::{Deserialize, Serialize};
6
7/// Commit generation events.
8///
9/// Events related to commit message generation, validation, and creation.
10/// Commit generation occurs after development iterations and review fixes.
11///
12/// # State Machine
13///
14/// ```text
15/// NotStarted -> Generating -> Generated -> Committed
16///                    |              |
17///                    +--> (retry) --+
18///                    |
19///                    +--> Skipped
20/// ```
21///
22/// # Emitted By
23///
24/// - Commit generation handlers in `handler/commit/`
25/// - Commit message validation handlers
26/// - Git commit handlers
27#[derive(Clone, Serialize, Deserialize, Debug)]
28pub enum CommitEvent {
29    /// Commit message generation started.
30    GenerationStarted,
31    /// Commit diff computed for commit generation.
32    ///
33    /// Emitted after preparing the diff that will be committed. The reducer
34    /// uses the `empty` flag to decide whether to skip commit creation.
35    DiffPrepared {
36        /// True when the diff is empty.
37        empty: bool,
38        /// Content identifier (sha256 hex) of the prepared diff content.
39        ///
40        /// This is used to guard against reusing stale materialized inputs when the
41        /// diff content changes across checkpoints or retries.
42        content_id_sha256: String,
43    },
44    /// Commit diff computation failed.
45    DiffFailed {
46        /// The error message for the diff failure.
47        error: String,
48    },
49    /// Commit diff is no longer available and must be recomputed.
50    ///
51    /// This is used for recoverability when `.agent/tmp` artifacts are cleaned between
52    /// checkpoints or when required diff files go missing during resume.
53    DiffInvalidated {
54        /// Reason for invalidation.
55        reason: String,
56    },
57    /// Commit prompt prepared for a commit attempt.
58    PromptPrepared {
59        /// The attempt number.
60        attempt: u32,
61    },
62    /// Commit agent invoked for a commit attempt.
63    AgentInvoked {
64        /// The attempt number.
65        attempt: u32,
66    },
67    /// Commit message XML extracted for a commit attempt.
68    CommitXmlExtracted {
69        /// The attempt number.
70        attempt: u32,
71    },
72    /// Commit message XML missing for a commit attempt.
73    CommitXmlMissing {
74        /// The attempt number.
75        attempt: u32,
76    },
77    /// Commit message XML validated successfully.
78    CommitXmlValidated {
79        /// The generated commit message.
80        message: String,
81        /// The attempt number.
82        attempt: u32,
83        /// Optional list of files to selectively commit.
84        ///
85        /// Empty means commit all changed files.
86        /// Defaults to empty for backward compatibility with old checkpoints.
87        #[serde(default)]
88        files: Vec<String>,
89        /// Files excluded from this commit with documented reasons.
90        ///
91        /// Audit/observability metadata only — does not affect commit execution.
92        /// Defaults to empty for backward compatibility with old checkpoints.
93        #[serde(default)]
94        excluded_files: Vec<crate::reducer::state::pipeline::ExcludedFile>,
95    },
96    /// Commit message XML validation failed.
97    CommitXmlValidationFailed {
98        /// The reason for validation failure.
99        reason: String,
100        /// The attempt number.
101        attempt: u32,
102    },
103    /// Commit message XML archived.
104    CommitXmlArchived {
105        /// The attempt number.
106        attempt: u32,
107    },
108    /// Commit message XML cleaned before invoking the commit agent.
109    CommitXmlCleaned {
110        /// The attempt number.
111        attempt: u32,
112    },
113    /// Commit message was generated.
114    MessageGenerated {
115        /// The generated commit message.
116        message: String,
117        /// The attempt number.
118        attempt: u32,
119    },
120    /// Commit message validation failed.
121    MessageValidationFailed {
122        /// The reason for validation failure.
123        reason: String,
124        /// The attempt number that failed.
125        attempt: u32,
126    },
127    /// Commit was created successfully.
128    Created {
129        /// The commit hash.
130        hash: String,
131        /// The commit message used.
132        message: String,
133    },
134
135    // === Cloud mode git remote operations (emitted only when cloud mode is enabled) ===
136    /// Git authentication configured successfully for remote operations.
137    GitAuthConfigured,
138
139    /// Push to remote completed successfully.
140    PushCompleted {
141        remote: String,
142        branch: String,
143        commit_sha: String,
144    },
145
146    /// Push to remote failed.
147    PushFailed {
148        remote: String,
149        branch: String,
150        error: String,
151    },
152
153    /// Pull request created successfully.
154    PullRequestCreated { url: String, number: u32 },
155
156    /// Pull request creation failed.
157    PullRequestFailed { error: String },
158    /// Commit generation failed completely.
159    GenerationFailed {
160        /// The reason for failure.
161        reason: String,
162    },
163    /// Commit was skipped (e.g., no changes to commit).
164    Skipped {
165        /// The reason for skipping.
166        reason: String,
167    },
168
169    /// Pre-termination commit safety check completed successfully.
170    ///
171    /// Emitted after `Effect::CheckUncommittedChangesBeforeTermination` when the
172    /// working directory is clean, allowing termination to proceed.
173    PreTerminationSafetyCheckPassed,
174
175    /// Pre-termination commit safety check detected uncommitted changes.
176    ///
177    /// This is not a terminal error: the reducer must route back through the
178    /// commit phase so the changes are committed (or explicitly skipped).
179    PreTerminationUncommittedChangesDetected {
180        /// Number of lines in `git status --porcelain` output.
181        file_count: usize,
182    },
183
184    /// Residual uncommitted files detected after a selective commit pass.
185    ///
186    /// When `pass == 1`, triggers an automatic second commit pass.
187    /// When `pass == 2`, the files are carried forward to the next cycle.
188    ResidualFilesFound {
189        /// Repo-relative paths of remaining dirty files.
190        files: Vec<String>,
191        /// Which pass just completed (1 = first pass, 2 = second pass).
192        pass: u8,
193    },
194
195    /// No residual uncommitted files detected after a commit pass.
196    ///
197    /// Pipeline may proceed normally; working tree is clean.
198    ResidualFilesNone,
199}