Add checkpoint exclude globs to skip bulky artifacts from git checkpoint commits

Introduces a [checkpoint] config table with exclude_globs in both run.toml
(per-run) and server.toml (defaults). Globs are merged (union + dedup) when
both are present. Non-empty excludes use git pathspec :(glob,exclude) syntax
to prevent staging matching files during checkpoint commits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-07 12:25:27 -05:00
parent 69e82a22f0
commit 314ee9be99
12 changed files with 456 additions and 9 deletions

View file

@ -969,6 +969,7 @@ mod runs {
("branch".into(), "feature/rate-limiting".into()),
])),
hooks: vec![],
checkpoint: Default::default(),
})
.unwrap()
}
@ -1088,6 +1089,7 @@ mod workflows {
("branch".into(), "main".into()),
])),
hooks: vec![],
checkpoint: Default::default(),
}),
graph: r#"digraph fix_build {
graph [
@ -1152,6 +1154,7 @@ mod workflows {
("test_framework".into(), "vitest".into()),
])),
hooks: vec![],
checkpoint: Default::default(),
}),
graph: r#"digraph implement {
graph [
@ -1228,6 +1231,7 @@ mod workflows {
("drift_threshold".into(), "warn".into()),
])),
hooks: vec![],
checkpoint: Default::default(),
}),
graph: r#"digraph sync {
graph [
@ -1293,6 +1297,7 @@ mod workflows {
("min_confidence".into(), "0.8".into()),
])),
hooks: vec![],
checkpoint: Default::default(),
}),
graph: r#"digraph expand {
graph [
@ -2680,6 +2685,7 @@ mod settings {
exe: None,
}),
vars: None,
checkpoint: Default::default(),
},
hook_config: arc_workflows::hook::HookConfig {
hooks: vec![],

View file

@ -577,6 +577,7 @@ async fn execute_run(state: Arc<AppState>, run_id: String) {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = tokio::select! {

View file

@ -446,4 +446,24 @@ matcher = "agent_loop"
let config: ServerConfig = toml::from_str(toml).unwrap();
assert!(config.hook_config.hooks.is_empty());
}
#[test]
fn parse_config_with_checkpoint_exclude_globs() {
let toml = r#"
[checkpoint]
exclude_globs = ["**/node_modules/**", "**/.cache/**"]
"#;
let config: ServerConfig = toml::from_str(toml).unwrap();
assert_eq!(
config.run_defaults.checkpoint.exclude_globs,
vec!["**/node_modules/**", "**/.cache/**"]
);
}
#[test]
fn parse_config_checkpoint_defaults_empty() {
let toml = "";
let config: ServerConfig = toml::from_str(toml).unwrap();
assert!(config.run_defaults.checkpoint.exclude_globs.is_empty());
}
}

View file

@ -666,6 +666,10 @@ pub async fn run_command(
} else {
None
};
let checkpoint_exclude_globs = run_cfg
.as_ref()
.map(|c| c.checkpoint.exclude_globs.clone())
.unwrap_or_default();
let config = RunConfig {
logs_root: logs_dir.clone(),
cancel_token: None,
@ -689,6 +693,7 @@ pub async fn run_command(
.filter_map(|s| s.split_once('='))
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect(),
checkpoint_exclude_globs,
};
let run_start = Instant::now();
@ -1054,6 +1059,7 @@ async fn run_from_branch(
run_branch: Some(run_branch.to_string()),
meta_branch,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let run_start = Instant::now();
@ -1538,6 +1544,7 @@ mod tests {
sandbox: None,
vars: None,
hooks: Vec::new(),
checkpoint: Default::default(),
};
let (model, provider) = resolve_model_provider(
Some("gpt-5.2"),
@ -1578,6 +1585,7 @@ mod tests {
sandbox: None,
vars: None,
hooks: Vec::new(),
checkpoint: Default::default(),
};
let (model, provider) = resolve_model_provider(None, None, Some(&cfg), &defaults, &graph);
assert_eq!(model, "toml-model");
@ -1653,6 +1661,7 @@ mod tests {
sandbox: None,
vars: None,
hooks: Vec::new(),
checkpoint: Default::default(),
};
let (model, provider) = resolve_model_provider(None, None, Some(&cfg), &defaults, &graph);
assert_eq!(model, "toml-model");
@ -1676,6 +1685,7 @@ mod tests {
}),
vars: None,
hooks: Vec::new(),
checkpoint: Default::default(),
};
let defaults = RunDefaults::default();
assert!(resolve_preserve_sandbox(true, Some(&cfg), &defaults));
@ -1698,6 +1708,7 @@ mod tests {
}),
vars: None,
hooks: Vec::new(),
checkpoint: Default::default(),
};
let defaults = RunDefaults {
sandbox: Some(run_config::SandboxConfig {

View file

@ -8,6 +8,12 @@ use crate::daytona_sandbox::DaytonaConfig;
const SUPPORTED_VERSION: u32 = 1;
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct CheckpointConfig {
#[serde(default)]
pub exclude_globs: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct WorkflowRunConfig {
@ -21,6 +27,8 @@ pub struct WorkflowRunConfig {
pub vars: Option<HashMap<String, String>>,
#[serde(default)]
pub hooks: Vec<crate::hook::HookDefinition>,
#[serde(default)]
pub checkpoint: CheckpointConfig,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
@ -55,6 +63,8 @@ pub struct RunDefaults {
pub setup: Option<SetupConfig>,
pub sandbox: Option<SandboxConfig>,
pub vars: Option<HashMap<String, String>>,
#[serde(default)]
pub checkpoint: CheckpointConfig,
}
impl WorkflowRunConfig {
@ -135,6 +145,15 @@ impl WorkflowRunConfig {
}
self.vars = Some(merged);
}
// Union checkpoint exclude globs from defaults and task config, dedup
if !defaults.checkpoint.exclude_globs.is_empty() {
let mut merged = defaults.checkpoint.exclude_globs.clone();
merged.extend(self.checkpoint.exclude_globs.drain(..));
merged.sort();
merged.dedup();
self.checkpoint.exclude_globs = merged;
}
}
}
@ -1237,4 +1256,118 @@ auto_stop_interval = 60
]))
);
}
#[test]
fn parse_toml_with_checkpoint_exclude_globs() {
let toml = r#"
version = 1
goal = "test"
graph = "w.dot"
[checkpoint]
exclude_globs = ["**/node_modules/**", "**/.cache/**"]
"#;
let config = parse_run_config(toml).unwrap();
assert_eq!(
config.checkpoint.exclude_globs,
vec!["**/node_modules/**", "**/.cache/**"]
);
}
#[test]
fn parse_toml_without_checkpoint_defaults_empty() {
let toml = r#"
version = 1
goal = "test"
graph = "w.dot"
"#;
let config = parse_run_config(toml).unwrap();
assert!(config.checkpoint.exclude_globs.is_empty());
}
#[test]
fn apply_defaults_unions_checkpoint_exclude_globs() {
let mut cfg = parse_run_config(
r#"
version = 1
goal = "test"
graph = "w.dot"
[checkpoint]
exclude_globs = ["**/dist/**", "**/.cache/**"]
"#,
)
.unwrap();
let defaults = RunDefaults {
checkpoint: CheckpointConfig {
exclude_globs: vec![
"**/.cache/**".into(),
"**/node_modules/**".into(),
],
},
..RunDefaults::default()
};
cfg.apply_defaults(&defaults);
assert_eq!(
cfg.checkpoint.exclude_globs,
vec!["**/.cache/**", "**/dist/**", "**/node_modules/**"]
);
}
#[test]
fn apply_defaults_checkpoint_from_defaults_only() {
let mut cfg = parse_run_config(
r#"
version = 1
goal = "test"
graph = "w.dot"
"#,
)
.unwrap();
let defaults = RunDefaults {
checkpoint: CheckpointConfig {
exclude_globs: vec!["**/node_modules/**".into()],
},
..RunDefaults::default()
};
cfg.apply_defaults(&defaults);
assert_eq!(
cfg.checkpoint.exclude_globs,
vec!["**/node_modules/**"]
);
}
#[test]
fn apply_defaults_checkpoint_from_task_only() {
let mut cfg = parse_run_config(
r#"
version = 1
goal = "test"
graph = "w.dot"
[checkpoint]
exclude_globs = ["**/dist/**"]
"#,
)
.unwrap();
let defaults = RunDefaults::default();
cfg.apply_defaults(&defaults);
assert_eq!(
cfg.checkpoint.exclude_globs,
vec!["**/dist/**"]
);
}
#[test]
fn parse_run_defaults_with_checkpoint() {
let toml = r#"
[checkpoint]
exclude_globs = ["**/node_modules/**"]
"#;
let defaults: RunDefaults = toml::from_str(toml).unwrap();
assert_eq!(
defaults.checkpoint.exclude_globs,
vec!["**/node_modules/**"]
);
}
}

View file

@ -520,6 +520,7 @@ pub struct GitState {
pub base_sha: String,
pub run_branch: Option<String>,
pub meta_branch: Option<String>,
pub checkpoint_exclude_globs: Vec<String>,
}
/// How git checkpointing should be performed for a workflow run.
@ -540,6 +541,7 @@ pub async fn git_checkpoint_host(
status: String,
completed_count: usize,
shadow_sha: Option<String>,
exclude_globs: Vec<String>,
) -> Option<String> {
match tokio::task::spawn_blocking(move || {
crate::git::checkpoint_commit(
@ -549,6 +551,7 @@ pub async fn git_checkpoint_host(
&status,
completed_count,
shadow_sha.as_deref(),
&exclude_globs,
)
})
.await
@ -583,9 +586,18 @@ pub async fn git_checkpoint_remote(
status: &str,
completed_count: usize,
shadow_sha: Option<String>,
exclude_globs: &[String],
) -> Option<String> {
// Stage everything
let add_cmd = format!("{GIT_REMOTE} add -A");
// Stage everything (with optional excludes)
let add_cmd = if exclude_globs.is_empty() {
format!("{GIT_REMOTE} add -A")
} else {
let pathspecs: Vec<String> = exclude_globs
.iter()
.map(|g| format!("':(glob,exclude){g}'"))
.collect();
format!("{GIT_REMOTE} add -A -- . {}", pathspecs.join(" "))
};
let add_result = sandbox
.exec_command(&add_cmd, 30_000, None, None, None)
.await;
@ -744,6 +756,9 @@ pub struct RunConfig {
pub meta_branch: Option<String>,
/// User-defined key-value labels for this run.
pub labels: HashMap<String, String>,
/// Glob patterns to exclude from git checkpoint staging.
#[allow(clippy::struct_field_names)]
pub checkpoint_exclude_globs: Vec<String>,
}
/// The workflow run execution engine.
@ -1121,6 +1136,7 @@ impl WorkflowRunEngine {
base_sha: base_sha.clone(),
run_branch: config.run_branch.clone(),
meta_branch: config.meta_branch.clone(),
checkpoint_exclude_globs: config.checkpoint_exclude_globs.clone(),
})),
_ => None,
};
@ -1843,6 +1859,7 @@ impl WorkflowRunEngine {
status_str,
completed_count,
shadow_sha,
config.checkpoint_exclude_globs.clone(),
)
.await
}
@ -1854,6 +1871,7 @@ impl WorkflowRunEngine {
&outcome.status.to_string(),
completed_count,
shadow_sha,
&config.checkpoint_exclude_globs,
)
.await
}
@ -2711,6 +2729,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -2732,6 +2751,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
let checkpoint_path = dir.path().join("checkpoint.json");
@ -2761,6 +2781,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -2786,6 +2807,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -2807,6 +2829,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -2841,6 +2864,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -2899,6 +2923,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -2984,6 +3009,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3012,6 +3038,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::from([("env".into(), "test".into())]),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3036,6 +3063,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3060,6 +3088,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3087,6 +3116,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3242,6 +3272,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3280,6 +3311,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&g, &config).await.unwrap();
@ -3336,6 +3368,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
@ -3395,6 +3428,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
@ -3458,6 +3492,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_ok());
@ -3510,6 +3545,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -3563,6 +3599,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
@ -3591,6 +3628,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -3615,6 +3653,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3638,6 +3677,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -3674,6 +3714,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// Set cancel after a short delay (while the slow handler is running)
@ -3747,6 +3788,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3773,6 +3815,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3801,6 +3844,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3834,6 +3878,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3865,6 +3910,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3893,6 +3939,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -3982,6 +4029,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// The engine returns Err because the Fail outcome has no outgoing fail edge,
@ -4186,6 +4234,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -4217,6 +4266,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -4255,6 +4305,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -4333,6 +4384,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -4422,6 +4474,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&g, &config).await;
assert!(result.is_err());
@ -4488,6 +4541,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -4541,6 +4595,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&g, &config).await.unwrap();
assert_eq!(outcome.status, StageStatus::Success);
@ -4595,6 +4650,7 @@ mod tests {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let _outcome = engine.run(&g, &config).await.unwrap();

View file

@ -144,11 +144,21 @@ pub fn checkpoint_commit(
status: &str,
completed_count: usize,
shadow_sha: Option<&str>,
excludes: &[String],
) -> Result<String> {
tracing::debug!(path = %work_dir.display(), node_id, "Creating git checkpoint commit");
// Stage everything
let output = git_cmd(work_dir)
.args(["add", "-A"])
// Stage everything (with optional excludes)
let mut cmd = git_cmd(work_dir);
cmd.args(["add", "-A", "--"]);
if excludes.is_empty() {
cmd.arg(".");
} else {
cmd.arg(".");
for glob in excludes {
cmd.arg(format!(":(glob,exclude){glob}"));
}
}
let output = cmd
.output()
.map_err(|e| git_error(format!("git add failed: {e}")))?;
@ -497,7 +507,7 @@ mod tests {
let wt = dir.path().join("ff-wt");
add_worktree(dir.path(), &wt, "ff-branch").unwrap();
fs::write(wt.join("new.txt"), "data").unwrap();
checkpoint_commit(&wt, "run", "node", "ok", 1, None).unwrap();
checkpoint_commit(&wt, "run", "node", "ok", 1, None, &[]).unwrap();
let advanced_sha = head_sha(&wt).unwrap();
remove_worktree(dir.path(), &wt).unwrap();
@ -569,7 +579,7 @@ mod tests {
// Simulate a shadow commit SHA
let shadow_sha = "abcdef1234567890abcdef1234567890abcdef12";
let sha =
checkpoint_commit(&wt_path, "run1", "nodeA", "success", 3, Some(shadow_sha)).unwrap();
checkpoint_commit(&wt_path, "run1", "nodeA", "success", 3, Some(shadow_sha), &[]).unwrap();
assert_eq!(sha.len(), 40);
assert!(sha.chars().all(|c| c.is_ascii_hexdigit()));
@ -608,7 +618,7 @@ mod tests {
let wt_path = dir.path().join("worktree");
add_worktree(dir.path(), &wt_path, "run-branch2").unwrap();
let sha = checkpoint_commit(&wt_path, "run2", "nodeB", "completed", 1, None).unwrap();
let sha = checkpoint_commit(&wt_path, "run2", "nodeB", "completed", 1, None, &[]).unwrap();
assert_eq!(sha.len(), 40);
// Verify Arc-Completed trailer present but no Arc-Meta
@ -652,7 +662,7 @@ mod tests {
let wt_path = dir.path().join("worktree");
add_worktree(dir.path(), &wt_path, "fallback-branch").unwrap();
let sha = checkpoint_commit(&wt_path, "run2", "nodeB", "completed", 0, None).unwrap();
let sha = checkpoint_commit(&wt_path, "run2", "nodeB", "completed", 0, None, &[]).unwrap();
assert_eq!(sha.len(), 40);
remove_worktree(dir.path(), &wt_path).unwrap();
@ -921,4 +931,79 @@ mod tests {
assert_eq!(head_sha(dir.path()).unwrap(), initial_sha);
assert!(!dir.path().join("file.txt").exists());
}
#[test]
fn checkpoint_commit_with_excludes_skips_matching_files() {
let dir = tempfile::tempdir().unwrap();
init_repo(dir.path());
create_branch(dir.path(), "excl-branch").unwrap();
let wt_path = dir.path().join("worktree");
add_worktree(dir.path(), &wt_path, "excl-branch").unwrap();
// Create files: one should be staged, one excluded
fs::write(wt_path.join("kept.txt"), "keep me").unwrap();
fs::create_dir_all(wt_path.join("node_modules/pkg")).unwrap();
fs::write(wt_path.join("node_modules/pkg/index.js"), "module").unwrap();
let excludes = vec!["**/node_modules/**".to_string()];
checkpoint_commit(&wt_path, "run", "node", "ok", 1, None, &excludes).unwrap();
// Verify kept.txt was committed
let output = Command::new("git")
.args(["show", "--name-only", "--format=", "HEAD"])
.current_dir(&wt_path)
.output()
.unwrap();
let committed_files = String::from_utf8_lossy(&output.stdout);
assert!(
committed_files.contains("kept.txt"),
"kept.txt should be committed"
);
assert!(
!committed_files.contains("node_modules"),
"node_modules should be excluded"
);
remove_worktree(dir.path(), &wt_path).unwrap();
}
#[test]
fn checkpoint_commit_with_excludes_skips_modified_tracked_files() {
let dir = tempfile::tempdir().unwrap();
init_repo(dir.path());
create_branch(dir.path(), "excl-mod-branch").unwrap();
let wt_path = dir.path().join("worktree");
add_worktree(dir.path(), &wt_path, "excl-mod-branch").unwrap();
// Create and commit a file in the excluded dir first
fs::create_dir_all(wt_path.join(".cache")).unwrap();
fs::write(wt_path.join(".cache/data.bin"), "v1").unwrap();
checkpoint_commit(&wt_path, "run", "setup", "ok", 0, None, &[]).unwrap();
// Now modify the tracked excluded file and add a new non-excluded file
fs::write(wt_path.join(".cache/data.bin"), "v2").unwrap();
fs::write(wt_path.join("result.txt"), "done").unwrap();
let excludes = vec!["**/.cache/**".to_string()];
checkpoint_commit(&wt_path, "run", "step", "ok", 1, None, &excludes).unwrap();
let output = Command::new("git")
.args(["show", "--name-only", "--format=", "HEAD"])
.current_dir(&wt_path)
.output()
.unwrap();
let committed_files = String::from_utf8_lossy(&output.stdout);
assert!(
committed_files.contains("result.txt"),
"result.txt should be committed"
);
assert!(
!committed_files.contains(".cache"),
".cache should be excluded"
);
remove_worktree(dir.path(), &wt_path).unwrap();
}
}

View file

@ -147,6 +147,7 @@ impl Handler for SubWorkflowHandler {
run_branch: None,
meta_branch: None,
labels: HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// Clone parent context for child; inject parent preamble

View file

@ -243,6 +243,7 @@ impl Handler for ParallelHandler {
"parallel_base".into(),
0,
None,
gs.checkpoint_exclude_globs.clone(),
)
.await
}
@ -254,6 +255,7 @@ impl Handler for ParallelHandler {
"parallel_base",
0,
None,
&gs.checkpoint_exclude_globs,
)
.await
}

View file

@ -331,6 +331,7 @@ async fn daytona_pipeline_artifact_offload_and_sync() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -522,6 +523,7 @@ async fn daytona_git_checkpoint_remote_emits_events() {
run_branch: Some(branch_name),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -702,6 +704,7 @@ async fn daytona_parallel_git_branching_e2e() {
run_branch: Some(branch_name),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1027,6 +1030,7 @@ async fn daytona_git_checkpoint_with_shadow_branch() {
run_branch: Some(branch_name),
meta_branch: Some(meta_branch),
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1164,6 +1168,7 @@ async fn daytona_asset_collection() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1394,6 +1399,7 @@ async fn daytona_git_push_run_branch_to_origin() {
run_branch: Some(branch_name.clone()),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine

View file

@ -199,6 +199,7 @@ async fn end_to_end_linear_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -336,6 +337,7 @@ async fn end_to_end_branching_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -457,6 +459,7 @@ async fn end_to_end_human_gate_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -566,6 +569,7 @@ async fn goal_gate_routes_to_retry_target_on_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -685,6 +689,7 @@ async fn goal_gate_routes_to_retry_target_when_present() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -991,6 +996,7 @@ async fn retry_on_failure_then_succeed() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1064,6 +1070,7 @@ async fn pipeline_with_many_nodes() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1385,6 +1392,7 @@ async fn smoke_test_with_mock_codergen_backend() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1484,6 +1492,7 @@ async fn end_to_end_parallel_fan_out_fan_in() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1594,6 +1603,7 @@ async fn resume_from_checkpoint_completes_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -1690,6 +1700,7 @@ async fn resume_from_checkpoint_preserves_goal_gate_outcomes() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// This should succeed because goal gate for gated_work is satisfied
@ -1731,6 +1742,7 @@ async fn graph_goal_in_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -1764,6 +1776,7 @@ async fn event_streaming_lifecycle() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -1841,6 +1854,7 @@ async fn context_flow_between_stages() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -1891,6 +1905,7 @@ async fn tool_handler_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -1960,6 +1975,7 @@ async fn auto_approve_interviewer_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -1994,6 +2010,7 @@ async fn codergen_without_backend_simulated() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -2096,6 +2113,7 @@ async fn branching_loop_back_on_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2180,6 +2198,7 @@ async fn human_gate_loops_back() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2235,6 +2254,7 @@ async fn scenario_ship_a_feature() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2318,6 +2338,7 @@ async fn scenario_parallel_expert_review() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2395,6 +2416,7 @@ async fn scenario_node_retries_on_retry_status() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2454,6 +2476,7 @@ async fn scenario_loop_restart_resets_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2519,6 +2542,7 @@ async fn scenario_bug_triage_router() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2574,6 +2598,7 @@ async fn scenario_crash_recovery() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
.run_from_checkpoint(&graph, &config, &checkpoint)
@ -2680,6 +2705,7 @@ async fn manager_loop_stop_condition_satisfied_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
@ -2754,6 +2780,7 @@ async fn manager_loop_max_cycles_exceeded_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
@ -2887,6 +2914,7 @@ async fn conditional_branching_success_fail_paths() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -2937,6 +2965,7 @@ async fn edge_selection_condition_match_wins_over_weight() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -2981,6 +3010,7 @@ async fn edge_selection_weight_breaks_ties() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3017,6 +3047,7 @@ async fn edge_selection_lexical_tiebreak() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3072,6 +3103,7 @@ async fn context_updates_visible_across_nodes() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3113,6 +3145,7 @@ async fn stylesheet_applies_model_override() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -3166,6 +3199,7 @@ async fn custom_handler_registration_and_execution() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3234,6 +3268,7 @@ async fn integration_smoke_plan_implement_review_done() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);
@ -3335,6 +3370,7 @@ async fn manager_loop_runs_child_engine_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -3467,6 +3503,7 @@ async fn manager_loop_context_flows_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
@ -3538,6 +3575,7 @@ async fn manager_loop_child_dotfile_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
@ -3649,6 +3687,7 @@ async fn graph_merge_e2e_through_engine() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -3797,6 +3836,7 @@ async fn fidelity_default_is_compact() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3851,6 +3891,7 @@ async fn fidelity_graph_default_applied() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3901,6 +3942,7 @@ async fn fidelity_node_overrides_graph_default() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -3957,6 +3999,7 @@ async fn fidelity_edge_overrides_node_and_graph() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4003,6 +4046,7 @@ async fn fidelity_full_produces_empty_preamble() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4059,6 +4103,7 @@ async fn fidelity_truncate_preamble_minimal() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4128,6 +4173,7 @@ async fn fidelity_summary_low_mode() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4192,6 +4238,7 @@ async fn fidelity_summary_medium_mode() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4256,6 +4303,7 @@ async fn fidelity_summary_high_mode() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4313,6 +4361,7 @@ async fn fidelity_full_sets_thread_id_in_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4381,6 +4430,7 @@ async fn fidelity_full_nodes_share_thread_id() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4458,6 +4508,7 @@ async fn fidelity_resume_degrades_full_to_summary_high() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine
.run_from_checkpoint(&graph, &config, &checkpoint)
@ -4551,6 +4602,7 @@ async fn fidelity_resume_degrade_only_affects_first_hop() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine
.run_from_checkpoint(&graph, &config, &checkpoint)
@ -4631,6 +4683,7 @@ async fn fidelity_resume_no_degrade_when_not_full() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine
.run_from_checkpoint(&graph, &config, &checkpoint)
@ -4670,6 +4723,7 @@ async fn fidelity_stored_in_checkpoint_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4753,6 +4807,7 @@ async fn fidelity_precedence_multi_node_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4818,6 +4873,7 @@ async fn fidelity_compact_preamble_includes_completed_stages_and_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -4891,6 +4947,7 @@ async fn fidelity_summary_low_excludes_context_values_in_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine_low
.run(&graph_low, &config_low)
@ -4956,6 +5013,7 @@ async fn fidelity_summary_low_excludes_context_values_in_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine_med
.run(&graph_med, &config_med)
@ -5024,6 +5082,7 @@ async fn fidelity_thread_id_fallback_to_previous_node_in_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5075,6 +5134,7 @@ async fn fidelity_thread_id_from_node_class_in_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5129,6 +5189,7 @@ async fn fidelity_edge_thread_id_override_in_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5184,6 +5245,7 @@ async fn fidelity_full_without_explicit_thread_id_uses_previous_node() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5249,6 +5311,7 @@ async fn fidelity_from_parsed_dot_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5294,6 +5357,7 @@ async fn fidelity_checkpoint_roundtrip_preserves_fidelity() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5361,6 +5425,7 @@ async fn fidelity_node_thread_id_overrides_edge_thread_id_in_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine.run(&graph, &config).await.expect("run");
@ -5444,6 +5509,7 @@ async fn fidelity_resume_preserves_context_values_across_checkpoint() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine
.run_from_checkpoint(&graph, &config, &checkpoint)
@ -5635,6 +5701,7 @@ mod real_llm {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = tokio::time::timeout(
@ -5747,6 +5814,7 @@ mod real_llm {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = tokio::time::timeout(
@ -5886,6 +5954,7 @@ mod real_llm {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = tokio::time::timeout(
@ -5991,6 +6060,7 @@ mod real_llm {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = tokio::time::timeout(
@ -6087,6 +6157,7 @@ async fn human_gate_freeform_only_routes_text() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -6218,6 +6289,7 @@ async fn human_gate_freeform_with_fixed_choice_match() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -6333,6 +6405,7 @@ async fn human_gate_freeform_fallback_on_unmatched_text() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -6462,6 +6535,7 @@ async fn human_gate_freeform_sets_allow_freeform_on_question() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -6571,6 +6645,7 @@ async fn human_gate_without_freeform_sets_allow_freeform_false() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -6828,6 +6903,7 @@ fn make_run_config(dir: &std::path::Path) -> RunConfig {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
}
}
@ -7919,6 +7995,7 @@ async fn arc_e2e_with_real_llm() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -8045,6 +8122,7 @@ async fn run_fidelity_prompt_pipeline(fidelity: &str) -> String {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
engine
@ -8242,6 +8320,7 @@ async fn large_context_values_are_offloaded_to_artifact_store() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -8452,6 +8531,7 @@ async fn artifact_pointers_rewritten_for_remote_sandbox() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -8580,6 +8660,7 @@ async fn node_dir_uses_visit_count_on_revisit() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -9496,6 +9577,7 @@ async fn full_pipeline_with_cli_backend_node() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -9623,6 +9705,7 @@ async fn stylesheet_backend_property_routes_to_cli() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -9902,6 +9985,7 @@ async fn git_checkpoint_host_emits_events_and_diff_patch() {
run_branch: Some("arc/run/test-docker".to_string()),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// 5. Run pipeline
@ -10085,6 +10169,7 @@ async fn git_checkpoint_host_writes_shadow_branch() {
run_branch: Some(format!("arc/run/{run_id}")),
meta_branch: Some(meta_branch),
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// 5. Run pipeline
@ -10277,6 +10362,7 @@ async fn parallel_git_branching_host_e2e() {
run_branch: Some(run_branch.clone()),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
// 5. Run pipeline
@ -10537,6 +10623,7 @@ async fn git_checkpoint_host_skips_empty_diff_patch() {
run_branch: Some("arc/run/empty-diff".to_string()),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -10917,6 +11004,7 @@ async fn e2e_circuit_breaker_deterministic_self_loop() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -10962,6 +11050,7 @@ async fn e2e_circuit_breaker_custom_limit() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11000,6 +11089,7 @@ async fn e2e_circuit_breaker_ignores_transient_failures() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11045,6 +11135,7 @@ async fn e2e_circuit_breaker_different_reasons_separate_counters() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11083,6 +11174,7 @@ async fn e2e_circuit_breaker_loop_restart() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11143,6 +11235,7 @@ async fn e2e_failure_signature_persisted_in_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.unwrap();
@ -11205,6 +11298,7 @@ async fn e2e_failure_signature_hint_overrides_reason_in_context() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let _outcome = engine.run(&graph, &config).await.unwrap();
@ -11259,6 +11353,7 @@ async fn e2e_signature_maps_persist_in_checkpoint() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.unwrap();
@ -11383,6 +11478,7 @@ async fn e2e_circuit_breaker_emits_events_before_abort() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11448,6 +11544,7 @@ async fn e2e_circuit_breaker_does_not_fire_below_limit() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.unwrap();
@ -11542,6 +11639,7 @@ async fn e2e_circuit_breaker_multi_stage_impl_verify_cycle() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11636,6 +11734,7 @@ async fn e2e_loop_restart_blocked_for_deterministic_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11674,6 +11773,7 @@ async fn e2e_loop_restart_blocked_for_structural_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11712,6 +11812,7 @@ async fn e2e_loop_restart_blocked_for_budget_exhausted_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11750,6 +11851,7 @@ async fn e2e_loop_restart_blocked_for_canceled_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11785,6 +11887,7 @@ async fn e2e_loop_restart_blocked_for_compilation_loop_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11824,6 +11927,7 @@ async fn e2e_loop_restart_allowed_for_transient_infra() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11926,6 +12030,7 @@ async fn e2e_stall_watchdog_triggers_from_dot_parsed_pipeline() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let result = engine.run(&graph, &config).await;
@ -11980,6 +12085,7 @@ async fn e2e_stall_watchdog_kept_alive_by_handler_events() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -12024,6 +12130,7 @@ async fn e2e_stall_watchdog_disabled_with_zero_timeout() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -12087,6 +12194,7 @@ async fn e2e_stall_watchdog_with_explicit_timeout_override() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let start = std::time::Instant::now();
@ -12215,6 +12323,7 @@ async fn asset_collection_local_sandbox_success() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -12321,6 +12430,7 @@ async fn asset_collection_local_sandbox_on_failure() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -12410,6 +12520,7 @@ async fn asset_collection_docker_sandbox() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine
@ -12477,6 +12588,7 @@ async fn wait_timer_e2e() {
run_branch: None,
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
};
let outcome = engine.run(&graph, &config).await.expect("run");
assert_eq!(outcome.status, StageStatus::Success);

View file

@ -3,3 +3,17 @@ base_url = "http://api:3000"
[feature_flags]
session_sandboxes = false
[checkpoint]
exclude_globs = [
"**/node_modules/**",
"**/.pnpm-store/**",
"**/.npm/**",
"**/.cache/**",
"**/playwright-report/**",
"**/test-results/**",
"**/.cargo-target*/**",
"**/.cargo_target*/**",
"**/.wasm-pack/**",
"**/.tmpbuild/**",
]