From f36ec7aab4b86fc9c1d23d2f9450383c61a0a4a1 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 7 Mar 2026 17:29:32 -0500 Subject: [PATCH] Replace git_author_name/email parameter pairs with GitAuthor struct Consolidates the two separate String parameters (git_author_name, git_author_email) threaded through ~10 function signatures into a single GitAuthor struct with Default providing "arc"/"arc@local". Also quotes git config values in parallel.rs shell commands. Co-Authored-By: Claude Opus 4.6 --- crates/arc-api/src/serve.rs | 10 +- crates/arc-api/src/server.rs | 20 +- crates/arc-cli/src/main.rs | 21 +- crates/arc-workflows/src/cli/run.rs | 14 +- crates/arc-workflows/src/engine.rs | 157 +++----- crates/arc-workflows/src/git.rs | 67 ++-- .../arc-workflows/src/handler/manager_loop.rs | 3 +- crates/arc-workflows/src/handler/parallel.rs | 13 +- .../tests/daytona_integration.rs | 18 +- crates/arc-workflows/tests/integration.rs | 336 ++++++------------ 10 files changed, 250 insertions(+), 409 deletions(-) diff --git a/crates/arc-api/src/serve.rs b/crates/arc-api/src/serve.rs index 75eda9d0e..e821b6b4a 100644 --- a/crates/arc-api/src/serve.rs +++ b/crates/arc-api/src/serve.rs @@ -136,14 +136,14 @@ pub async fn serve_command(args: ServeArgs, styles: &'static Styles) -> anyhow:: (auth_mode, client_auth, max_concurrent_runs) }; - let (git_author_name, git_author_email) = { + let git_author = { let cfg = shared_config.read().expect("config lock poisoned"); - ( - cfg.git.author.name.clone().unwrap_or_else(|| "arc".into()), - cfg.git.author.email.clone().unwrap_or_else(|| "arc@local".into()), + arc_workflows::git::GitAuthor::from_options( + cfg.git.author.name.clone(), + cfg.git.author.email.clone(), ) }; - let state = crate::server::create_app_state_with_options(db, factory, dry_run_mode, max_concurrent_runs, git_author_name, git_author_email); + let state = crate::server::create_app_state_with_options(db, factory, dry_run_mode, max_concurrent_runs, git_author); crate::server::spawn_scheduler(Arc::clone(&state)); let router = build_router(state, auth_mode); diff --git a/crates/arc-api/src/server.rs b/crates/arc-api/src/server.rs index dd860004d..1a8c3c0cd 100644 --- a/crates/arc-api/src/server.rs +++ b/crates/arc-api/src/server.rs @@ -106,8 +106,7 @@ pub struct AppState { max_concurrent_runs: usize, scheduler_notify: tokio::sync::Notify, pub hook_config: arc_workflows::hook::HookConfig, - git_author_name: String, - git_author_email: String, + git_author: arc_workflows::git::GitAuthor, } /// Build the axum Router with all run endpoints. @@ -367,7 +366,7 @@ pub fn create_app_state( db: sqlx::SqlitePool, registry_factory: impl Fn(Arc) -> HandlerRegistry + Send + Sync + 'static, ) -> Arc { - create_app_state_with_options(db, registry_factory, false, 5, "arc".into(), "arc@local".into()) + create_app_state_with_options(db, registry_factory, false, 5, arc_workflows::git::GitAuthor::default()) } /// Create an `AppState` with the given database pool, registry factory, dry-run flag, and concurrency limit. @@ -376,8 +375,7 @@ pub fn create_app_state_with_options( registry_factory: impl Fn(Arc) -> HandlerRegistry + Send + Sync + 'static, dry_run: bool, max_concurrent_runs: usize, - git_author_name: String, - git_author_email: String, + git_author: arc_workflows::git::GitAuthor, ) -> Arc { Arc::new(AppState { runs: Mutex::new(HashMap::new()), @@ -388,8 +386,7 @@ pub fn create_app_state_with_options( max_concurrent_runs, scheduler_notify: tokio::sync::Notify::new(), hook_config: arc_workflows::hook::HookConfig::default(), - git_author_name, - git_author_email, + git_author, }) } @@ -585,8 +582,7 @@ async fn execute_run(state: Arc, run_id: String) { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: state.git_author_name.clone(), - git_author_email: state.git_author_email.clone(), + git_author: state.git_author.clone(), }; let result = tokio::select! { @@ -1143,7 +1139,7 @@ mod tests { #[tokio::test] async fn test_model_dry_run_returns_ok() { - let state = create_app_state_with_options(test_db().await, test_registry, true, 5, "arc".into(), "arc@local".into()); + let state = create_app_state_with_options(test_db().await, test_registry, true, 5, arc_workflows::git::GitAuthor::default()); let app = build_router(state, AuthMode::Disabled); let req = Request::builder() @@ -1163,7 +1159,7 @@ mod tests { #[tokio::test] async fn test_model_dry_run_unknown_returns_404() { - let state = create_app_state_with_options(test_db().await, test_registry, true, 5, "arc".into(), "arc@local".into()); + let state = create_app_state_with_options(test_db().await, test_registry, true, 5, arc_workflows::git::GitAuthor::default()); let app = build_router(state, AuthMode::Disabled); let req = Request::builder() @@ -1844,7 +1840,7 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn concurrency_limit_respected() { - let state = create_app_state_with_options(test_db().await, test_registry, false, 1, "arc".into(), "arc@local".into()); + let state = create_app_state_with_options(test_db().await, test_registry, false, 1, arc_workflows::git::GitAuthor::default()); let app = test_app_with_scheduler(state); // Submit two runs with max_concurrent_runs=1 diff --git a/crates/arc-cli/src/main.rs b/crates/arc-cli/src/main.rs index cae73040f..7ff9f783a 100644 --- a/crates/arc-cli/src/main.rs +++ b/crates/arc-cli/src/main.rs @@ -183,24 +183,21 @@ async fn main() -> Result<()> { let github_app = build_github_app_credentials(&server_config); let cli_author = cli_config.git.as_ref().map(|g| &g.author); - let git_author_name = cli_author - .and_then(|a| a.name.as_deref()) - .or(server_config.git.author.name.as_deref()) - .unwrap_or("arc") - .to_string(); - let git_author_email = cli_author - .and_then(|a| a.email.as_deref()) - .or(server_config.git.author.email.as_deref()) - .unwrap_or("arc@local") - .to_string(); + let git_author = arc_workflows::git::GitAuthor::from_options( + cli_author + .and_then(|a| a.name.clone()) + .or_else(|| server_config.git.author.name.clone()), + cli_author + .and_then(|a| a.email.clone()) + .or_else(|| server_config.git.author.email.clone()), + ); arc_workflows::cli::run::run_command( args, server_config.run_defaults, styles, github_app, - git_author_name, - git_author_email, + git_author, ) .await?; } diff --git a/crates/arc-workflows/src/cli/run.rs b/crates/arc-workflows/src/cli/run.rs index eb5f0c3b6..c50cc1f2a 100644 --- a/crates/arc-workflows/src/cli/run.rs +++ b/crates/arc-workflows/src/cli/run.rs @@ -181,12 +181,11 @@ pub async fn run_command( run_defaults: RunDefaults, styles: &'static Styles, github_app: Option, - git_author_name: String, - git_author_email: String, + git_author: crate::git::GitAuthor, ) -> anyhow::Result<()> { // Handle --run-branch resume: read everything from git metadata if let Some(branch) = args.run_branch.clone() { - return run_from_branch(args, &branch, styles, git_author_name, git_author_email).await; + return run_from_branch(args, &branch, styles, git_author).await; } let workflow_path = args @@ -697,8 +696,7 @@ pub async fn run_command( .collect(), checkpoint_exclude_globs, github_app: github_app.clone(), - git_author_name, - git_author_email, + git_author, }; let run_start = Instant::now(); @@ -930,8 +928,7 @@ async fn run_from_branch( args: RunArgs, run_branch: &str, styles: &'static Styles, - git_author_name: String, - git_author_email: String, + git_author: crate::git::GitAuthor, ) -> anyhow::Result<()> { // Extract run_id from branch name: "arc/run/{run_id}" -> "{run_id}" let run_id = run_branch @@ -1068,8 +1065,7 @@ async fn run_from_branch( labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name, - git_author_email, + git_author, }; let run_start = Instant::now(); diff --git a/crates/arc-workflows/src/engine.rs b/crates/arc-workflows/src/engine.rs index 97a288828..90e5546dc 100644 --- a/crates/arc-workflows/src/engine.rs +++ b/crates/arc-workflows/src/engine.rs @@ -521,8 +521,7 @@ pub struct GitState { pub run_branch: Option, pub meta_branch: Option, pub checkpoint_exclude_globs: Vec, - pub git_author_name: String, - pub git_author_email: String, + pub git_author: crate::git::GitAuthor, } /// How git checkpointing should be performed for a workflow run. @@ -544,8 +543,7 @@ pub async fn git_checkpoint_host( completed_count: usize, shadow_sha: Option, exclude_globs: Vec, - author_name: String, - author_email: String, + author: crate::git::GitAuthor, ) -> Option { match tokio::task::spawn_blocking(move || { crate::git::checkpoint_commit( @@ -556,8 +554,7 @@ pub async fn git_checkpoint_host( completed_count, shadow_sha.as_deref(), &exclude_globs, - &author_name, - &author_email, + &author, ) }) .await @@ -593,8 +590,7 @@ pub async fn git_checkpoint_remote( completed_count: usize, shadow_sha: Option, exclude_globs: &[String], - author_name: &str, - author_email: &str, + author: &crate::git::GitAuthor, ) -> Option { // Stage everything (with optional excludes) let add_cmd = if exclude_globs.is_empty() { @@ -646,7 +642,9 @@ pub async fn git_checkpoint_remote( // Commit with configured identity using the message file let commit_cmd = format!( - "{GIT_REMOTE} -c user.name={author_name} -c user.email={author_email} commit --allow-empty -F /tmp/arc-commit-msg" + "{GIT_REMOTE} -c user.name={name} -c user.email={email} commit --allow-empty -F /tmp/arc-commit-msg", + name = author.name, + email = author.email, ); let commit_result = sandbox .exec_command(&commit_cmd, 30_000, None, None, None) @@ -838,10 +836,8 @@ pub struct RunConfig { pub checkpoint_exclude_globs: Vec, /// GitHub App credentials for pushing metadata branches to origin. pub github_app: Option, - /// Git author name for checkpoint commits. - pub git_author_name: String, - /// Git author email for checkpoint commits. - pub git_author_email: String, + /// Git author identity for checkpoint commits. + pub git_author: crate::git::GitAuthor, } /// The workflow run execution engine. @@ -1220,8 +1216,7 @@ impl WorkflowRunEngine { run_branch: config.run_branch.clone(), meta_branch: config.meta_branch.clone(), checkpoint_exclude_globs: config.checkpoint_exclude_globs.clone(), - git_author_name: config.git_author_name.clone(), - git_author_email: config.git_author_email.clone(), + git_author: config.git_author.clone(), })), _ => None, }; @@ -1272,11 +1267,7 @@ impl WorkflowRunEngine { None => None, }; if let Some(repo_path) = store_path { - let store = crate::git::MetadataStore::new( - repo_path, - &config.git_author_name, - &config.git_author_email, - ); + let store = crate::git::MetadataStore::new(repo_path, &config.git_author); let manifest_bytes = serde_json::to_vec_pretty(&manifest).unwrap_or_default(); let dot_source = std::fs::read(config.logs_root.join("graph.dot")).unwrap_or_default(); @@ -1900,11 +1891,7 @@ impl WorkflowRunEngine { let repo_path = match mode { GitCheckpointMode::Host(ref p) | GitCheckpointMode::Remote(ref p) => p, }; - let store = crate::git::MetadataStore::new( - repo_path, - &config.git_author_name, - &config.git_author_email, - ); + let store = crate::git::MetadataStore::new(repo_path, &config.git_author); serde_json::to_vec_pretty(&checkpoint) .ok() .and_then(|cp_json| { @@ -1953,8 +1940,7 @@ impl WorkflowRunEngine { completed_count, shadow_sha, config.checkpoint_exclude_globs.clone(), - config.git_author_name.clone(), - config.git_author_email.clone(), + config.git_author.clone(), ) .await } @@ -1967,8 +1953,7 @@ impl WorkflowRunEngine { completed_count, shadow_sha, &config.checkpoint_exclude_globs, - &config.git_author_name, - &config.git_author_email, + &config.git_author, ) .await } @@ -2836,8 +2821,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -2861,8 +2845,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); let checkpoint_path = dir.path().join("checkpoint.json"); @@ -2894,8 +2877,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -2923,8 +2905,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -2948,8 +2929,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -2986,8 +2966,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -3048,8 +3027,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3137,8 +3115,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3169,8 +3146,7 @@ mod tests { labels: HashMap::from([("env".into(), "test".into())]), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3197,8 +3173,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3225,8 +3200,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3256,8 +3230,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3415,8 +3388,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3457,8 +3429,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; engine.run(&g, &config).await.unwrap(); @@ -3517,8 +3488,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); @@ -3580,8 +3550,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; @@ -3647,8 +3616,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_ok()); @@ -3703,8 +3671,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -3760,8 +3727,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); @@ -3792,8 +3758,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -3820,8 +3785,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -3847,8 +3811,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -3887,8 +3850,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; // Set cancel after a short delay (while the slow handler is running) @@ -3964,8 +3926,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -3994,8 +3955,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4026,8 +3986,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4063,8 +4022,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4098,8 +4056,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4130,8 +4087,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4223,8 +4179,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; // The engine returns Err because the Fail outcome has no outgoing fail edge, @@ -4431,8 +4386,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4466,8 +4420,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4508,8 +4461,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4590,8 +4542,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4683,8 +4634,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let result = engine.run(&g, &config).await; assert!(result.is_err()); @@ -4753,8 +4703,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -4810,8 +4759,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let outcome = engine.run(&g, &config).await.unwrap(); assert_eq!(outcome.status, StageStatus::Success); @@ -4868,8 +4816,7 @@ mod tests { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: crate::git::GitAuthor::default(), }; let _outcome = engine.run(&g, &config).await.unwrap(); diff --git a/crates/arc-workflows/src/git.rs b/crates/arc-workflows/src/git.rs index cd2eadca2..a0a546b1f 100644 --- a/crates/arc-workflows/src/git.rs +++ b/crates/arc-workflows/src/git.rs @@ -9,6 +9,34 @@ use git2::{Repository, Signature}; use crate::checkpoint::Checkpoint; use crate::error::{ArcError, Result}; +/// Resolved git author identity for checkpoint commits. +#[derive(Debug, Clone, PartialEq)] +pub struct GitAuthor { + pub name: String, + pub email: String, +} + +impl Default for GitAuthor { + fn default() -> Self { + Self { + name: "arc".into(), + email: "arc@local".into(), + } + } +} + +impl GitAuthor { + /// Create a `GitAuthor` from optional name/email, falling back to defaults. + pub fn from_options(name: Option, email: Option) -> Self { + let defaults = Self::default(); + Self { + name: name.unwrap_or(defaults.name), + email: email.unwrap_or(defaults.email), + } + } +} + + fn git_error(msg: impl Into) -> ArcError { ArcError::engine(msg.into()) } @@ -145,8 +173,7 @@ pub fn checkpoint_commit( completed_count: usize, shadow_sha: Option<&str>, excludes: &[String], - author_name: &str, - author_email: &str, + author: &GitAuthor, ) -> Result { tracing::debug!(path = %work_dir.display(), node_id, "Creating git checkpoint commit"); // Stage everything (with optional excludes) @@ -186,8 +213,8 @@ pub fn checkpoint_commit( let message = trailerlink::format_message(&subject, "", &trailers); // Commit with configured identity (works even if user.name/email not configured) - let name_cfg = format!("user.name={author_name}"); - let email_cfg = format!("user.email={author_email}"); + let name_cfg = format!("user.name={}", author.name); + let email_cfg = format!("user.email={}", author.email); let output = git_cmd(work_dir) .args([ "-c", @@ -287,16 +314,14 @@ pub fn sanitize_ref_component(s: &str) -> String { /// (`arc/{run_id}`) so that runs can be resumed from git alone. pub struct MetadataStore { repo_path: std::path::PathBuf, - author_name: String, - author_email: String, + author: GitAuthor, } impl MetadataStore { - pub fn new(repo_path: impl Into, author_name: &str, author_email: &str) -> Self { + pub fn new(repo_path: impl Into, author: &GitAuthor) -> Self { Self { repo_path: repo_path.into(), - author_name: author_name.to_string(), - author_email: author_email.to_string(), + author: author.clone(), } } @@ -309,7 +334,7 @@ impl MetadataStore { let repo = Repository::discover(&self.repo_path) .map_err(|e| git_error(format!("failed to open repo: {e}")))?; let store = Store::new(repo); - let sig = Signature::now(&self.author_name, &self.author_email) + let sig = Signature::now(&self.author.name, &self.author.email) .map_err(|e| git_error(format!("failed to create signature: {e}")))?; Ok((store, sig)) } @@ -526,7 +551,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, &[], "arc", "arc@local").unwrap(); + checkpoint_commit(&wt, "run", "node", "ok", 1, None, &[], &GitAuthor::default()).unwrap(); let advanced_sha = head_sha(&wt).unwrap(); remove_worktree(dir.path(), &wt).unwrap(); @@ -598,7 +623,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), &[], "arc", "arc@local").unwrap(); + checkpoint_commit(&wt_path, "run1", "nodeA", "success", 3, Some(shadow_sha), &[], &GitAuthor::default()).unwrap(); assert_eq!(sha.len(), 40); assert!(sha.chars().all(|c| c.is_ascii_hexdigit())); @@ -637,7 +662,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, &[], "arc", "arc@local").unwrap(); + let sha = checkpoint_commit(&wt_path, "run2", "nodeB", "completed", 1, None, &[], &GitAuthor::default()).unwrap(); assert_eq!(sha.len(), 40); // Verify Arc-Completed trailer present but no Arc-Meta @@ -681,7 +706,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, &[], "arc", "arc@local").unwrap(); + let sha = checkpoint_commit(&wt_path, "run2", "nodeB", "completed", 0, None, &[], &GitAuthor::default()).unwrap(); assert_eq!(sha.len(), 40); remove_worktree(dir.path(), &wt_path).unwrap(); @@ -735,7 +760,7 @@ mod tests { let dir = tempfile::tempdir().unwrap(); init_repo(dir.path()); - let store = MetadataStore::new(dir.path(), "arc", "arc@local"); + let store = MetadataStore::new(dir.path(), &GitAuthor::default()); let manifest = br#"{"run_id":"RUN1","workflow_name":"test","goal":"g","start_time":"2025-01-01T00:00:00Z","node_count":2,"edge_count":1}"#; let dot = b"digraph { start -> end }"; store.init_run("RUN1", manifest, dot).unwrap(); @@ -757,7 +782,7 @@ mod tests { let dir = tempfile::tempdir().unwrap(); init_repo(dir.path()); - let store = MetadataStore::new(dir.path(), "arc", "arc@local"); + let store = MetadataStore::new(dir.path(), &GitAuthor::default()); store.init_run("RUN2", b"{}", b"digraph {}").unwrap(); let ctx = crate::context::Context::new(); @@ -792,7 +817,7 @@ mod tests { let dir = tempfile::tempdir().unwrap(); init_repo(dir.path()); - let store = MetadataStore::new(dir.path(), "arc", "arc@local"); + let store = MetadataStore::new(dir.path(), &GitAuthor::default()); store.init_run("RUN3", b"{}", b"digraph {}").unwrap(); let ctx = crate::context::Context::new(); @@ -843,7 +868,7 @@ mod tests { let dir = tempfile::tempdir().unwrap(); init_repo(dir.path()); - let store = MetadataStore::new(dir.path(), "arc", "arc@local"); + let store = MetadataStore::new(dir.path(), &GitAuthor::default()); store.init_run("RUN4", b"{}", b"digraph {}").unwrap(); let artifact_data = br#"{"large_output":"some data"}"#; @@ -966,7 +991,7 @@ mod tests { 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, "arc", "arc@local").unwrap(); + checkpoint_commit(&wt_path, "run", "node", "ok", 1, None, &excludes, &GitAuthor::default()).unwrap(); // Verify kept.txt was committed let output = Command::new("git") @@ -999,14 +1024,14 @@ mod tests { // 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, &[], "arc", "arc@local").unwrap(); + checkpoint_commit(&wt_path, "run", "setup", "ok", 0, None, &[], &GitAuthor::default()).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, "arc", "arc@local").unwrap(); + checkpoint_commit(&wt_path, "run", "step", "ok", 1, None, &excludes, &GitAuthor::default()).unwrap(); let output = Command::new("git") .args(["show", "--name-only", "--format=", "HEAD"]) diff --git a/crates/arc-workflows/src/handler/manager_loop.rs b/crates/arc-workflows/src/handler/manager_loop.rs index 2bd144776..f87f0a9e0 100644 --- a/crates/arc-workflows/src/handler/manager_loop.rs +++ b/crates/arc-workflows/src/handler/manager_loop.rs @@ -150,8 +150,7 @@ impl Handler for SubWorkflowHandler { labels: HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: git_state.as_ref().map(|gs| gs.git_author_name.clone()).unwrap_or_else(|| "arc".into()), - git_author_email: git_state.as_ref().map(|gs| gs.git_author_email.clone()).unwrap_or_else(|| "arc@local".into()), + git_author: git_state.as_ref().map(|gs| gs.git_author.clone()).unwrap_or_default(), }; // Clone parent context for child; inject parent preamble diff --git a/crates/arc-workflows/src/handler/parallel.rs b/crates/arc-workflows/src/handler/parallel.rs index 84e0e0e66..6e6cb1a76 100644 --- a/crates/arc-workflows/src/handler/parallel.rs +++ b/crates/arc-workflows/src/handler/parallel.rs @@ -244,8 +244,7 @@ impl Handler for ParallelHandler { 0, None, gs.checkpoint_exclude_globs.clone(), - gs.git_author_name.clone(), - gs.git_author_email.clone(), + gs.git_author.clone(), ) .await } @@ -258,8 +257,7 @@ impl Handler for ParallelHandler { 0, None, &gs.checkpoint_exclude_globs, - &gs.git_author_name, - &gs.git_author_email, + &gs.git_author, ) .await } @@ -401,8 +399,7 @@ impl Handler for ParallelHandler { let sem = Arc::clone(&semaphore); let has_git = git_state.is_some(); let run_id = git_state.as_ref().map(|gs| gs.run_id.clone()); - let git_author_name = git_state.as_ref().map(|gs| gs.git_author_name.clone()).unwrap_or_else(|| "arc".into()); - let git_author_email = git_state.as_ref().map(|gs| gs.git_author_email.clone()).unwrap_or_else(|| "arc@local".into()); + let git_author = git_state.as_ref().map(|gs| gs.git_author.clone()).unwrap_or_default(); let handle = tokio::spawn(async move { let _permit = sem @@ -468,7 +465,9 @@ impl Handler for ParallelHandler { if add_result.as_ref().is_ok_and(|r| r.exit_code == 0) { let msg = format!("arc({rid}): {nid} ({status_str})"); let commit_cmd = format!( - "{git_r} -c user.name={git_author_name} -c user.email={git_author_email} commit --allow-empty -m '{msg}'" + "{git_r} -c 'user.name={name}' -c 'user.email={email}' commit --allow-empty -m '{msg}'", + name = git_author.name, + email = git_author.email, ); let _ = setup .sandbox diff --git a/crates/arc-workflows/tests/daytona_integration.rs b/crates/arc-workflows/tests/daytona_integration.rs index 7f5117efa..98ddbff11 100644 --- a/crates/arc-workflows/tests/daytona_integration.rs +++ b/crates/arc-workflows/tests/daytona_integration.rs @@ -333,8 +333,7 @@ async fn daytona_pipeline_artifact_offload_and_sync() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -528,8 +527,7 @@ async fn daytona_git_checkpoint_remote_emits_events() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -712,8 +710,7 @@ async fn daytona_parallel_git_branching_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1041,8 +1038,7 @@ async fn daytona_git_checkpoint_with_shadow_branch() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1182,8 +1178,7 @@ async fn daytona_asset_collection() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1416,8 +1411,7 @@ async fn daytona_git_push_run_branch_to_origin() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine diff --git a/crates/arc-workflows/tests/integration.rs b/crates/arc-workflows/tests/integration.rs index c3dc9d739..fa695f825 100644 --- a/crates/arc-workflows/tests/integration.rs +++ b/crates/arc-workflows/tests/integration.rs @@ -201,8 +201,7 @@ async fn end_to_end_linear_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -342,8 +341,7 @@ async fn end_to_end_branching_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -467,8 +465,7 @@ async fn end_to_end_human_gate_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -580,8 +577,7 @@ async fn goal_gate_routes_to_retry_target_on_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -703,8 +699,7 @@ async fn goal_gate_routes_to_retry_target_when_present() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1013,8 +1008,7 @@ async fn retry_on_failure_then_succeed() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1090,8 +1084,7 @@ async fn pipeline_with_many_nodes() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1415,8 +1408,7 @@ async fn smoke_test_with_mock_codergen_backend() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1518,8 +1510,7 @@ async fn end_to_end_parallel_fan_out_fan_in() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1632,8 +1623,7 @@ async fn resume_from_checkpoint_completes_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -1732,8 +1722,7 @@ async fn resume_from_checkpoint_preserves_goal_gate_outcomes() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; // This should succeed because goal gate for gated_work is satisfied @@ -1777,8 +1766,7 @@ async fn graph_goal_in_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -1814,8 +1802,7 @@ async fn event_streaming_lifecycle() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -1895,8 +1882,7 @@ async fn context_flow_between_stages() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -1949,8 +1935,7 @@ async fn tool_handler_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2022,8 +2007,7 @@ async fn auto_approve_interviewer_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2060,8 +2044,7 @@ async fn codergen_without_backend_simulated() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -2166,8 +2149,7 @@ async fn branching_loop_back_on_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2254,8 +2236,7 @@ async fn human_gate_loops_back() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2313,8 +2294,7 @@ async fn scenario_ship_a_feature() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2400,8 +2380,7 @@ async fn scenario_parallel_expert_review() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2481,8 +2460,7 @@ async fn scenario_node_retries_on_retry_status() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2544,8 +2522,7 @@ async fn scenario_loop_restart_resets_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2613,8 +2590,7 @@ async fn scenario_bug_triage_router() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -2672,8 +2648,7 @@ async fn scenario_crash_recovery() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine .run_from_checkpoint(&graph, &config, &checkpoint) @@ -2782,8 +2757,7 @@ async fn manager_loop_stop_condition_satisfied_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); @@ -2860,8 +2834,7 @@ async fn manager_loop_max_cycles_exceeded_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); @@ -2997,8 +2970,7 @@ async fn conditional_branching_success_fail_paths() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -3051,8 +3023,7 @@ async fn edge_selection_condition_match_wins_over_weight() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -3099,8 +3070,7 @@ async fn edge_selection_weight_breaks_ties() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -3139,8 +3109,7 @@ async fn edge_selection_lexical_tiebreak() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -3198,8 +3167,7 @@ async fn context_updates_visible_across_nodes() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -3243,8 +3211,7 @@ async fn stylesheet_applies_model_override() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -3300,8 +3267,7 @@ async fn custom_handler_registration_and_execution() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -3372,8 +3338,7 @@ async fn integration_smoke_plan_implement_review_done() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success); @@ -3477,8 +3442,7 @@ async fn manager_loop_runs_child_engine_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -3613,8 +3577,7 @@ async fn manager_loop_context_flows_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); @@ -3688,8 +3651,7 @@ async fn manager_loop_child_dotfile_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); @@ -3803,8 +3765,7 @@ async fn graph_merge_e2e_through_engine() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -3955,8 +3916,7 @@ async fn fidelity_default_is_compact() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4013,8 +3973,7 @@ async fn fidelity_graph_default_applied() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4067,8 +4026,7 @@ async fn fidelity_node_overrides_graph_default() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4127,8 +4085,7 @@ async fn fidelity_edge_overrides_node_and_graph() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4177,8 +4134,7 @@ async fn fidelity_full_produces_empty_preamble() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4237,8 +4193,7 @@ async fn fidelity_truncate_preamble_minimal() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4310,8 +4265,7 @@ async fn fidelity_summary_low_mode() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4378,8 +4332,7 @@ async fn fidelity_summary_medium_mode() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4446,8 +4399,7 @@ async fn fidelity_summary_high_mode() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4507,8 +4459,7 @@ async fn fidelity_full_sets_thread_id_in_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4579,8 +4530,7 @@ async fn fidelity_full_nodes_share_thread_id() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4660,8 +4610,7 @@ async fn fidelity_resume_degrades_full_to_summary_high() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine .run_from_checkpoint(&graph, &config, &checkpoint) @@ -4757,8 +4706,7 @@ async fn fidelity_resume_degrade_only_affects_first_hop() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine .run_from_checkpoint(&graph, &config, &checkpoint) @@ -4841,8 +4789,7 @@ async fn fidelity_resume_no_degrade_when_not_full() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine .run_from_checkpoint(&graph, &config, &checkpoint) @@ -4884,8 +4831,7 @@ async fn fidelity_stored_in_checkpoint_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -4971,8 +4917,7 @@ async fn fidelity_precedence_multi_node_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5040,8 +4985,7 @@ async fn fidelity_compact_preamble_includes_completed_stages_and_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5117,8 +5061,7 @@ async fn fidelity_summary_low_excludes_context_values_in_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine_low .run(&graph_low, &config_low) @@ -5186,8 +5129,7 @@ async fn fidelity_summary_low_excludes_context_values_in_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine_med .run(&graph_med, &config_med) @@ -5258,8 +5200,7 @@ async fn fidelity_thread_id_fallback_to_previous_node_in_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5313,8 +5254,7 @@ async fn fidelity_thread_id_from_node_class_in_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5371,8 +5311,7 @@ async fn fidelity_edge_thread_id_override_in_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5430,8 +5369,7 @@ async fn fidelity_full_without_explicit_thread_id_uses_previous_node() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5499,8 +5437,7 @@ async fn fidelity_from_parsed_dot_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5548,8 +5485,7 @@ async fn fidelity_checkpoint_roundtrip_preserves_fidelity() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5619,8 +5555,7 @@ async fn fidelity_node_thread_id_overrides_edge_thread_id_in_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine.run(&graph, &config).await.expect("run"); @@ -5706,8 +5641,7 @@ async fn fidelity_resume_preserves_context_values_across_checkpoint() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine .run_from_checkpoint(&graph, &config, &checkpoint) @@ -5901,8 +5835,7 @@ mod real_llm { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = tokio::time::timeout( @@ -6017,8 +5950,7 @@ mod real_llm { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = tokio::time::timeout( @@ -6160,8 +6092,7 @@ mod real_llm { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = tokio::time::timeout( @@ -6269,8 +6200,7 @@ mod real_llm { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = tokio::time::timeout( @@ -6369,8 +6299,7 @@ async fn human_gate_freeform_only_routes_text() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -6504,8 +6433,7 @@ async fn human_gate_freeform_with_fixed_choice_match() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -6623,8 +6551,7 @@ async fn human_gate_freeform_fallback_on_unmatched_text() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -6756,8 +6683,7 @@ async fn human_gate_freeform_sets_allow_freeform_on_question() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -6869,8 +6795,7 @@ async fn human_gate_without_freeform_sets_allow_freeform_false() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -7130,8 +7055,7 @@ fn make_run_config(dir: &std::path::Path) -> RunConfig { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), } } @@ -8225,8 +8149,7 @@ async fn arc_e2e_with_real_llm() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -8355,8 +8278,7 @@ async fn run_fidelity_prompt_pipeline(fidelity: &str) -> String { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; engine @@ -8556,8 +8478,7 @@ async fn large_context_values_are_offloaded_to_artifact_store() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -8770,8 +8691,7 @@ async fn artifact_pointers_rewritten_for_remote_sandbox() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -8902,8 +8822,7 @@ async fn node_dir_uses_visit_count_on_revisit() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -9822,8 +9741,7 @@ async fn full_pipeline_with_cli_backend_node() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -9953,8 +9871,7 @@ async fn stylesheet_backend_property_routes_to_cli() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -10236,8 +10153,7 @@ async fn git_checkpoint_host_emits_events_and_diff_patch() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; // 5. Run pipeline @@ -10423,8 +10339,7 @@ async fn git_checkpoint_host_writes_shadow_branch() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; // 5. Run pipeline @@ -10619,8 +10534,7 @@ async fn parallel_git_branching_host_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; // 5. Run pipeline @@ -10883,8 +10797,7 @@ async fn git_checkpoint_host_skips_empty_diff_patch() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -11267,8 +11180,7 @@ async fn e2e_circuit_breaker_deterministic_self_loop() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -11316,8 +11228,7 @@ async fn e2e_circuit_breaker_custom_limit() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -11358,8 +11269,7 @@ async fn e2e_circuit_breaker_ignores_transient_failures() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -11407,8 +11317,7 @@ async fn e2e_circuit_breaker_different_reasons_separate_counters() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -11449,8 +11358,7 @@ async fn e2e_circuit_breaker_loop_restart() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -11513,8 +11421,7 @@ async fn e2e_failure_signature_persisted_in_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.unwrap(); @@ -11579,8 +11486,7 @@ async fn e2e_failure_signature_hint_overrides_reason_in_context() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let _outcome = engine.run(&graph, &config).await.unwrap(); @@ -11637,8 +11543,7 @@ async fn e2e_signature_maps_persist_in_checkpoint() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.unwrap(); @@ -11765,8 +11670,7 @@ async fn e2e_circuit_breaker_emits_events_before_abort() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -11834,8 +11738,7 @@ async fn e2e_circuit_breaker_does_not_fire_below_limit() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.unwrap(); @@ -11932,8 +11835,7 @@ async fn e2e_circuit_breaker_multi_stage_impl_verify_cycle() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12030,8 +11932,7 @@ async fn e2e_loop_restart_blocked_for_deterministic_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12072,8 +11973,7 @@ async fn e2e_loop_restart_blocked_for_structural_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12114,8 +12014,7 @@ async fn e2e_loop_restart_blocked_for_budget_exhausted_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12156,8 +12055,7 @@ async fn e2e_loop_restart_blocked_for_canceled_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12195,8 +12093,7 @@ async fn e2e_loop_restart_blocked_for_compilation_loop_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12238,8 +12135,7 @@ async fn e2e_loop_restart_allowed_for_transient_infra() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12344,8 +12240,7 @@ async fn e2e_stall_watchdog_triggers_from_dot_parsed_pipeline() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let result = engine.run(&graph, &config).await; @@ -12402,8 +12297,7 @@ async fn e2e_stall_watchdog_kept_alive_by_handler_events() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -12450,8 +12344,7 @@ async fn e2e_stall_watchdog_disabled_with_zero_timeout() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -12517,8 +12410,7 @@ async fn e2e_stall_watchdog_with_explicit_timeout_override() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let start = std::time::Instant::now(); @@ -12649,8 +12541,7 @@ async fn asset_collection_local_sandbox_success() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -12759,8 +12650,7 @@ async fn asset_collection_local_sandbox_on_failure() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -12852,8 +12742,7 @@ async fn asset_collection_docker_sandbox() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine @@ -12923,8 +12812,7 @@ async fn wait_timer_e2e() { labels: std::collections::HashMap::new(), checkpoint_exclude_globs: Vec::new(), github_app: None, - git_author_name: "arc".into(), - git_author_email: "arc@local".into(), + git_author: arc_workflows::git::GitAuthor::default(), }; let outcome = engine.run(&graph, &config).await.expect("run"); assert_eq!(outcome.status, StageStatus::Success);