Simplify status.txt implementation: reduce boilerplate and fix double read

- Add StatusInfo::simple() helper to eliminate repeated 4-field constructions
- Eliminate double read of status.txt in scan_runs() by calling read_status()
  once and branching on Unknown vs non-Unknown
- Use write_status_file() consistently in engine.rs instead of raw fs::write

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-15 16:18:27 -04:00
parent 047c2c4fef
commit c2c351c472
No known key found for this signature in database
2 changed files with 39 additions and 51 deletions

View file

@ -182,9 +182,27 @@ pub fn scan_runs(base: &Path) -> Result<Vec<RunInfo>> {
.map(|s| s.trim().to_string())
.unwrap_or_else(|_| dir_name.clone());
if read_status_file(&path).is_some() {
let si = read_status(&path);
if matches!(si.status, RunStatus::Unknown) {
// True orphan — no manifest, no status.txt
runs.push(RunInfo {
run_id,
dir_name,
workflow_name: "[no manifest]".to_string(),
workflow_slug: None,
status: si.status,
start_time: mtime,
labels: HashMap::new(),
duration_ms: None,
total_cost: None,
host_repo_path: None,
start_time_dt: mtime_dt,
end_time: None,
path,
is_orphan: true,
});
} else {
// Has status.txt → run is initializing, not an orphan
let si = read_status(&path);
runs.push(RunInfo {
run_id,
dir_name,
@ -201,24 +219,6 @@ pub fn scan_runs(base: &Path) -> Result<Vec<RunInfo>> {
path,
is_orphan: false,
});
} else {
// True orphan — no manifest, no status.txt
runs.push(RunInfo {
run_id,
dir_name,
workflow_name: "[no manifest]".to_string(),
workflow_slug: None,
status: RunStatus::Unknown,
start_time: mtime,
labels: HashMap::new(),
duration_ms: None,
total_cost: None,
host_repo_path: None,
start_time_dt: mtime_dt,
end_time: None,
path,
is_orphan: true,
});
}
}
}
@ -235,6 +235,17 @@ struct StatusInfo {
total_cost: Option<f64>,
}
impl StatusInfo {
fn simple(status: RunStatus) -> Self {
Self {
status,
end_time: None,
duration_ms: None,
total_cost: None,
}
}
}
/// Write the run lifecycle status to `status.txt` (best-effort).
pub fn write_status_file(run_dir: &Path, status: &str) {
let _ = std::fs::write(run_dir.join("status.txt"), status);
@ -260,42 +271,19 @@ fn read_status(run_dir: &Path) -> StatusInfo {
// 2. status.txt — explicit lifecycle tracking
if let Some(status_str) = read_status_file(run_dir) {
return match status_str.as_str() {
"starting" | "running" => StatusInfo {
status: RunStatus::Running,
end_time: None,
duration_ms: None,
total_cost: None,
},
"starting" | "running" => StatusInfo::simple(RunStatus::Running),
// concluded without conclusion.json → treat as failed
"concluded" => StatusInfo {
status: RunStatus::Concluded(crate::outcome::StageStatus::Fail),
end_time: None,
duration_ms: None,
total_cost: None,
},
_ => StatusInfo {
status: RunStatus::Unknown,
end_time: None,
duration_ms: None,
total_cost: None,
},
"concluded" => {
StatusInfo::simple(RunStatus::Concluded(crate::outcome::StageStatus::Fail))
}
_ => StatusInfo::simple(RunStatus::Unknown),
};
}
// 3. Legacy fallback: run.pid exists → Running
if run_dir.join("run.pid").exists() {
return StatusInfo {
status: RunStatus::Running,
end_time: None,
duration_ms: None,
total_cost: None,
};
}
StatusInfo {
status: RunStatus::Unknown,
end_time: None,
duration_ms: None,
total_cost: None,
return StatusInfo::simple(RunStatus::Running);
}
StatusInfo::simple(RunStatus::Unknown)
}
/// Which run statuses to include in filtered results.

View file

@ -1251,7 +1251,7 @@ impl WorkflowRunEngine {
// Write manifest.json (spec 5.6)
let manifest = write_manifest(&config.run_dir, graph, config);
let _ = std::fs::write(config.run_dir.join("status.txt"), "running");
crate::cli::runs::write_status_file(&config.run_dir, "running");
// Initialize metadata branch for git-native checkpoint storage (best-effort)
if let (Some(_), Some(ref repo_path)) = (&config.meta_branch, &config.host_repo_path) {