Precheck docker availability and drop unused ContainerSession.image_tag
Surfaces a clean DockerUnavailable error when docker mode is requested
but the daemon isn't reachable, replacing the cryptic "command not
found" stderr that bubbled out of docker_build. Drops the unused
image_tag field on ContainerSession — the tag is already tracked on
ContainerRecord.

Assisted-by: Claude Opus 4.7 via Claude Code
change yyyslsxyzovtvzuvrtnqzwmkwpvrwsop
commit 62ebf6311289e3438906882029d10901d0c49d59
author Alpha Chen <alpha@kejadlen.dev>
date
parent xtsrzwzo
diff --git a/src/ci/docker.rs b/src/ci/docker.rs
index 23bd38d..040d46c 100644
--- a/src/ci/docker.rs
+++ b/src/ci/docker.rs
@@ -50,7 +50,6 @@ pub(crate) fn docker_build(dockerfile: &Path, context: &Path, tag: &str) -> Resu
 /// reconciliation handles anything that survives.
 pub(crate) struct ContainerSession {
     pub(crate) container_id: String,
-    pub(crate) image_tag: String,
     pub(crate) container_started_at: jiff::Timestamp,
 }
 
@@ -89,7 +88,6 @@ impl ContainerSession {
         let container_id = String::from_utf8_lossy(&output.stdout).trim().to_string();
         Ok(Self {
             container_id,
-            image_tag: image_tag.to_string(),
             container_started_at: jiff::Timestamp::now(),
         })
     }
@@ -172,7 +170,6 @@ mod tests {
         assert!(!session.container_id.is_empty());
         // Docker container IDs from `docker run` are 64-char SHA256 hex.
         assert_eq!(session.container_id.len(), 64, "got: {}", session.container_id);
-        assert_eq!(session.image_tag, "alpine:3.19");
         // session drops here; docker stop runs.
     }
 
diff --git a/src/ci/run.rs b/src/ci/run.rs
index 46c6a92..150f7e3 100644
--- a/src/ci/run.rs
+++ b/src/ci/run.rs
@@ -444,6 +444,10 @@ impl Run {
         match executor {
             Executor::Host => Ok(ExecutorRuntime::Host),
             Executor::Docker => {
+                if !crate::ci::docker::is_available() {
+                    return Err(Error::DockerUnavailable);
+                }
+
                 let mut record = ContainerRecord::default();
 
                 // Build phase.
diff --git a/src/error.rs b/src/error.rs
index 80478b1..3702f9b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -40,6 +40,9 @@ pub enum Error {
         source: Box<Error>,
     },
 
+    #[error("docker is not available — install docker and ensure the daemon is running")]
+    DockerUnavailable,
+
     #[error("workspace materialization failed")]
     WorkspaceMaterializationFailed {
         #[source]