mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-05 08:10:39 +00:00
fix(resume): validate checkpoint before cleanup and clear progress.jsonl
Two issues in the resume cleanup logic: 1. progress.jsonl was not in the stale artifact list, so attach and logs would replay the previous attempt's events before the new run. Added it to the cleanup list. 2. Cleanup ran before validating the checkpoint was parseable. A crash during the original run can leave a truncated checkpoint.json that passes exists() but fails to parse. We now load and parse the checkpoint first; if it's corrupt we bail with the old conclusion and failure evidence intact. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
25b9d24d9e
commit
4c6b846fb9
1 changed files with 14 additions and 4 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::bail;
|
||||
use clap::Args;
|
||||
use fabro_util::terminal::Styles;
|
||||
use fabro_workflows::records::RunRecord;
|
||||
use fabro_workflows::records::{Checkpoint, RunRecord};
|
||||
use fabro_workflows::run_status::RunStatus;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
|
|
@ -29,9 +29,18 @@ pub async fn resume_command(args: ResumeArgs, styles: &'static Styles) -> anyhow
|
|||
}
|
||||
let run_id = RunRecord::load(&run_dir)?.run_id;
|
||||
|
||||
if !run_dir.join("checkpoint.json").exists() {
|
||||
bail!("no checkpoint found — nothing to resume");
|
||||
}
|
||||
// Validate checkpoint is parseable before touching any state.
|
||||
// A crash during the original run can leave a truncated file;
|
||||
// we must not destroy the old conclusion/failure evidence and
|
||||
// only then discover the checkpoint is corrupt.
|
||||
let cp_path = run_dir.join("checkpoint.json");
|
||||
Checkpoint::load(&cp_path).map_err(|e| {
|
||||
if cp_path.exists() {
|
||||
anyhow::anyhow!("checkpoint.json is corrupt — cannot resume: {e}")
|
||||
} else {
|
||||
anyhow::anyhow!("no checkpoint found — nothing to resume")
|
||||
}
|
||||
})?;
|
||||
|
||||
// Guard against resuming a live run
|
||||
if is_pid_alive(&run_dir.join("run.pid")) {
|
||||
|
|
@ -48,6 +57,7 @@ pub async fn resume_command(args: ResumeArgs, styles: &'static Styles) -> anyhow
|
|||
"interview_request.claim",
|
||||
"detach.log",
|
||||
"run.pid",
|
||||
"progress.jsonl",
|
||||
] {
|
||||
let _ = std::fs::remove_file(run_dir.join(name));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue