Use a dedicated error variant for invalid run transitions
Synthesizing an io::Error::InvalidInput conflated a logic error
with I/O failure. Add Error::InvalidTransition with the from/to
states so the caller and diagnostics reflect what actually went
wrong.
Assisted-by: Claude Opus 4.7 (1M context) via Claude Code
diff --git a/src/ci/run.rs b/src/ci/run.rs
index ef89f99..7e7fa4a 100644
--- a/src/ci/run.rs
+++ b/src/ci/run.rs
@@ -258,10 +258,10 @@ impl Run {
(Pending, Active) | (Pending, Complete) | (Active, Complete) | (Active, Failed)
);
if !allowed {
- return Err(Error::Io(std::io::Error::new(
- std::io::ErrorKind::InvalidInput,
- format!("invalid run transition: {:?} -> {:?}", self.state, to),
- )));
+ return Err(Error::InvalidTransition {
+ from: self.state,
+ to,
+ });
}
let src = self.path();
diff --git a/src/error.rs b/src/error.rs
index f4aa52b..8fda8b8 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,6 +1,6 @@
use miette::Diagnostic;
-use crate::ci::ValidationError;
+use crate::ci::{RunState, ValidationError};
use crate::fennel::FennelError;
#[derive(Debug, thiserror::Error, Diagnostic)]
@@ -26,6 +26,9 @@ pub enum Error {
#[related]
Validation(Vec<ValidationError>),
+ #[error("invalid run transition: {from:?} -> {to:?}")]
+ InvalidTransition { from: RunState, to: RunState },
+
#[error("git error: {0}")]
Git(String),