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
change wmwqsuuyovlxomxoprzoplxuonukksys
commit ada85786f6890990d2ee8b2e4e4a341e39effc71
author Alpha Chen <alpha@kejadlen.dev>
date
parent xvxyqusv
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),