From dcec06d1124ff6628656da59dffa3d62de581412 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Fri, 26 Jun 2026 20:16:30 -0700 Subject: [PATCH] add model name to blame --- src/commands/blame.rs | 136 ++++++++++++++---- .../checkpoint_agent/presets/mock_ai.rs | 15 +- src/commands/git_ai_handlers.rs | 35 ++++- tests/integration/blame_flags.rs | 68 +++++++++ ...attributions__initial_and_blame_merge.snap | 5 +- ...ons__initial_and_blame_merge@worktree.snap | 6 +- ...attributions_in_subsequent_checkpoint.snap | 5 +- ...ons_in_subsequent_checkpoint@worktree.snap | 6 +- ...ributions__initial_only_no_blame_data.snap | 5 +- ...__initial_only_no_blame_data@worktree.snap | 6 +- ...l_attributions__initial_wins_overlaps.snap | 3 +- ...tions__initial_wins_overlaps@worktree.snap | 3 +- ...l_attributions__partial_file_coverage.snap | 5 +- ...tions__partial_file_coverage@worktree.snap | 6 +- 14 files changed, 246 insertions(+), 58 deletions(-) diff --git a/src/commands/blame.rs b/src/commands/blame.rs index ca17fc4ae1..f64eb021a0 100644 --- a/src/commands/blame.rs +++ b/src/commands/blame.rs @@ -1,9 +1,8 @@ use crate::auth::CredentialStore; use crate::authorship::authorship_log::{HumanRecord, PromptRecord, SessionRecord}; -use crate::authorship::authorship_log_serialization::AuthorshipLog; +use crate::authorship::authorship_log_serialization::{AUTHORSHIP_LOG_VERSION, AuthorshipLog}; use crate::authorship::working_log::CheckpointKind; use crate::error::GitAiError; -use crate::git::notes_api::read_authorship_v3 as get_reference_as_authorship_log_v3; use crate::git::repository::Repository; use crate::git::repository::{exec_git, exec_git_stdin}; #[cfg(windows)] @@ -935,6 +934,43 @@ impl Repository { Ok(hunks) } + /// Batch-load v3 authorship logs for a set of commits in a handful of git + /// invocations (one `ls-tree` + batched `cat-file`) instead of one + /// `git notes show` subprocess per commit. + /// + /// Commits without a valid note are recorded as `None` so callers can cache + /// negative lookups too. Behavior mirrors `read_authorship_v3`: the schema + /// version is enforced and each log's `base_commit_sha` is aligned to the + /// commit its note is attached to. + fn load_authorship_logs_batched( + &self, + commit_shas: impl IntoIterator, + ) -> HashMap> { + let unique: Vec = commit_shas + .into_iter() + .collect::>() + .into_iter() + .collect(); + let mut cache: HashMap> = HashMap::new(); + if unique.is_empty() { + return cache; + } + + let notes = crate::git::notes_api::read_notes_batch(self, &unique).unwrap_or_default(); + for sha in unique { + let log = notes.get(&sha).and_then(|content| { + let mut log = AuthorshipLog::deserialize_from_string(content).ok()?; + if log.metadata.schema_version != AUTHORSHIP_LOG_VERSION { + return None; + } + log.metadata.base_commit_sha = sha.clone(); + Some(log) + }); + cache.insert(sha, log); + } + cache + } + /// Post-process blame hunks to populate ai_human_author from authorship logs. /// For each hunk, looks up the authorship log for its commit and finds the human_author /// from the prompt record that covers lines in the hunk. @@ -946,23 +982,21 @@ impl Repository { file_path: &str, options: &GitAiBlameOptions, ) -> Result, GitAiError> { - // Cache authorship logs by commit SHA to avoid repeated lookups - let mut commit_authorship_cache: HashMap> = HashMap::new(); + // Batch-load authorship logs for every commit in one shot to avoid one + // `git notes show` subprocess per commit. + let commit_authorship_cache = + self.load_authorship_logs_batched(hunks.iter().map(|h| h.commit_sha.clone())); // Cache for foreign prompts to avoid repeated grepping let mut foreign_prompts_cache: HashMap> = HashMap::new(); let mut result_hunks: Vec = Vec::new(); for hunk in hunks { - // Get or fetch the authorship log for this commit - let authorship_log = if let Some(cached) = commit_authorship_cache.get(&hunk.commit_sha) - { - cached.clone() - } else { - let authorship = get_reference_as_authorship_log_v3(self, &hunk.commit_sha).ok(); - commit_authorship_cache.insert(hunk.commit_sha.clone(), authorship.clone()); - authorship - }; + // Look up the pre-loaded authorship log for this commit. + let authorship_log = commit_authorship_cache + .get(&hunk.commit_sha) + .cloned() + .flatten(); // If we have an authorship log, look up human_author for each line if let Some(ref authorship_log) = authorship_log { @@ -1040,6 +1074,18 @@ impl Repository { } } +fn format_agent_author(tool: &str, model: &str) -> String { + let model = model.trim(); + if model.is_empty() || model.eq_ignore_ascii_case("unknown") { + tool.to_string() + } else { + // Strip a redundant "claude-" prefix (e.g. "claude-sonnet-4-6" -> "sonnet-4-6") + // to keep the label compact. + let model = model.strip_prefix("claude-").unwrap_or(model); + format!("{} {}", tool, model) + } +} + #[allow(clippy::type_complexity)] fn overlay_ai_authorship( repo: &Repository, @@ -1068,8 +1114,10 @@ fn overlay_ai_authorship( let mut commits_with_notes: std::collections::HashSet = std::collections::HashSet::new(); - // Group hunks by commit SHA to avoid repeated lookups - let mut commit_authorship_cache: HashMap> = HashMap::new(); + // Batch-load authorship logs for every commit in one shot to avoid one + // `git notes show` subprocess per commit. + let commit_authorship_cache = + repo.load_authorship_logs_batched(blame_hunks.iter().map(|h| h.commit_sha.clone())); // Simulated authorship logs for agent commits without notes. We keep these separate // from commit_authorship_cache so a single agent commit can be handled across multiple // blame hunks without being limited to the first hunk's line range. @@ -1077,15 +1125,11 @@ fn overlay_ai_authorship( // Cache for foreign prompts to avoid repeated grepping let mut foreign_prompts_cache: HashMap> = HashMap::new(); for hunk in blame_hunks { - // Check if we've already looked up this commit's authorship - let authorship_log = if let Some(cached) = commit_authorship_cache.get(&hunk.commit_sha) { - cached.clone() - } else { - // Try to get authorship log for this commit - let authorship = get_reference_as_authorship_log_v3(repo, &hunk.commit_sha).ok(); - commit_authorship_cache.insert(hunk.commit_sha.clone(), authorship.clone()); - authorship - }; + // Look up the pre-loaded authorship log for this commit. + let authorship_log = commit_authorship_cache + .get(&hunk.commit_sha) + .cloned() + .flatten(); // If we have AI authorship data, look up the author for lines in this hunk if let Some(ref authorship_log) = authorship_log { @@ -1131,8 +1175,13 @@ fn overlay_ai_authorship( if options.use_prompt_hashes_as_names { line_authors.insert(current_line_num, prompt_hash.clone()); } else { - line_authors - .insert(current_line_num, prompt_record.agent_id.tool.clone()); + line_authors.insert( + current_line_num, + format_agent_author( + &prompt_record.agent_id.tool, + &prompt_record.agent_id.model, + ), + ); } prompt_records.insert(prompt_hash, prompt_record.clone()); @@ -1724,7 +1773,11 @@ fn output_default_format( } else if options.show_prompt && prompt_records.contains_key(author) { let prompt = &prompt_records[author]; let short_hash = &author[..7.min(author.len())]; - format!("{} [{}]", prompt.agent_id.tool, short_hash) + format!( + "{} [{}]", + format_agent_author(&prompt.agent_id.tool, &prompt.agent_id.model), + short_hash + ) } else if options.show_email { format!("{} <{}>", author, &hunk.author_email) } else { @@ -2236,3 +2289,32 @@ fn parse_line_range(range_str: &str) -> Option<(u32, u32)> { None } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_format_agent_author_with_model() { + // A leading "claude-" is stripped to keep the label compact. + assert_eq!( + format_agent_author("claude", "claude-sonnet-4-6"), + "claude sonnet-4-6" + ); + // Non-claude models are shown verbatim. + assert_eq!(format_agent_author("cursor", "gpt-4"), "cursor gpt-4"); + // Only a leading "claude-" is stripped, not occurrences elsewhere. + assert_eq!( + format_agent_author("amp", "anthropic/claude-opus"), + "amp anthropic/claude-opus" + ); + } + + #[test] + fn test_format_agent_author_omits_unknown_or_empty_model() { + assert_eq!(format_agent_author("mock_ai", "unknown"), "mock_ai"); + assert_eq!(format_agent_author("mock_ai", "UNKNOWN"), "mock_ai"); + assert_eq!(format_agent_author("claude", ""), "claude"); + assert_eq!(format_agent_author("claude", " "), "claude"); + } +} diff --git a/src/commands/checkpoint_agent/presets/mock_ai.rs b/src/commands/checkpoint_agent/presets/mock_ai.rs index f1a207e89c..7be2547104 100644 --- a/src/commands/checkpoint_agent/presets/mock_ai.rs +++ b/src/commands/checkpoint_agent/presets/mock_ai.rs @@ -17,10 +17,11 @@ impl AgentPreset for MockAiPreset { .unwrap_or(0) ); - let (file_paths, cwd) = if hook_input.is_empty() { + let (file_paths, cwd, model) = if hook_input.is_empty() { ( vec![], std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), + "unknown".to_string(), ) } else { let data: serde_json::Value = serde_json::from_str(hook_input) @@ -42,14 +43,22 @@ impl AgentPreset for MockAiPreset { .map(PathBuf::from) .unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))); - (paths, cwd) + // Allow tests to specify a model so model-dependent behavior (e.g. blame + // displaying " ") can be exercised end-to-end. + let model = data + .get("model") + .and_then(|v| v.as_str()) + .unwrap_or("unknown") + .to_string(); + + (paths, cwd, model) }; let context = PresetContext { agent_id: AgentId { tool: "mock_ai".to_string(), id: mock_agent_id, - model: "unknown".to_string(), + model, }, external_session_id: "mock_ai_session".to_string(), trace_id: trace_id.to_string(), diff --git a/src/commands/git_ai_handlers.rs b/src/commands/git_ai_handlers.rs index 2264fcf8f6..d9a0ec3d10 100644 --- a/src/commands/git_ai_handlers.rs +++ b/src/commands/git_ai_handlers.rs @@ -1050,13 +1050,33 @@ fn synthesize_hook_input_from_cli_args(preset_name: &str, remaining_args: &[Stri match preset_name { "human" | "mock_ai" | "mock_known_human" => { let cwd = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")); - let mut paths: Vec = remaining_args + // Optional `--model ` lets the mock_ai preset attach a real model + // (e.g. for exercising blame's " " display); ignored by the + // other presets in this branch. + let mut model: Option = None; + let mut path_args: Vec<&String> = Vec::new(); + let mut i = 0usize; + while i < remaining_args.len() { + match remaining_args[i].as_str() { + "--model" if i + 1 < remaining_args.len() => { + model = Some(remaining_args[i + 1].clone()); + i += 2; + } + arg if !arg.starts_with("--") => { + path_args.push(&remaining_args[i]); + i += 1; + } + _ => { + i += 1; + } + } + } + let mut paths: Vec = path_args .iter() - .filter(|a| !a.starts_with("--")) .map(|s| { let p = std::path::Path::new(s.as_str()); if p.is_absolute() { - s.clone() + (*s).clone() } else { cwd.join(p).to_string_lossy().to_string() } @@ -1065,11 +1085,14 @@ fn synthesize_hook_input_from_cli_args(preset_name: &str, remaining_args: &[Stri if paths.is_empty() { paths = discover_dirty_files_from_status(&cwd); } - serde_json::json!({ + let mut payload = serde_json::json!({ "file_paths": paths, "cwd": cwd.to_string_lossy(), - }) - .to_string() + }); + if let Some(model) = model { + payload["model"] = serde_json::Value::String(model); + } + payload.to_string() } "known_human" => { let cwd = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")); diff --git a/tests/integration/blame_flags.rs b/tests/integration/blame_flags.rs index 649be77508..127eb4a3c7 100644 --- a/tests/integration/blame_flags.rs +++ b/tests/integration/blame_flags.rs @@ -1472,6 +1472,72 @@ fn test_blame_ai_human_author() { ); } +#[test] +fn test_blame_shows_agent_and_model() { + // Users repeatedly assumed git-ai wasn't capturing the model because blame only + // showed the agent name. Blame should now render AI lines as " ". + let repo = TestRepo::new(); + let file_path = repo.path().join("test.txt"); + + // Human baseline line, committed without AI involvement. + std::fs::write(&file_path, "Human line\n").unwrap(); + repo.stage_all_and_commit("Initial commit").unwrap(); + + // Add an AI line via mock_ai with an explicit model. + std::fs::write(&file_path, "Human line\nAI line\n").unwrap(); + repo.git_ai(&[ + "checkpoint", + "mock_ai", + "--model", + "claude-sonnet-4-6", + "test.txt", + ]) + .unwrap(); + repo.stage_all_and_commit("AI commit").unwrap(); + + let output = repo.git_ai(&["blame", "test.txt"]).unwrap(); + println!("\n[DEBUG] git-ai blame:\n{}", output); + let lines: Vec<&str> = output.lines().collect(); + + // The "claude-" prefix is stripped, so "claude-sonnet-4-6" renders as "sonnet-4-6". + assert!( + lines[1].contains("mock_ai sonnet-4-6"), + "AI line should show agent and (claude-stripped) model: {}", + lines[1] + ); + // The human line must not pick up a spurious model. + assert!( + !lines[0].contains("sonnet-4-6"), + "Human line should not show a model: {}", + lines[0] + ); +} + +#[test] +fn test_blame_omits_unknown_model() { + // When the model wasn't captured (sentinel "unknown"), blame should fall back to + // just the agent name rather than printing "mock_ai unknown". + let repo = TestRepo::new(); + let file_path = repo.path().join("test.txt"); + + std::fs::write(&file_path, "Human line\n").unwrap(); + repo.stage_all_and_commit("Initial commit").unwrap(); + + std::fs::write(&file_path, "Human line\nAI line\n").unwrap(); + // No --model => mock_ai defaults to the "unknown" sentinel. + repo.git_ai(&["checkpoint", "mock_ai", "test.txt"]).unwrap(); + repo.stage_all_and_commit("AI commit").unwrap(); + + let output = repo.git_ai(&["blame", "test.txt"]).unwrap(); + let lines: Vec<&str> = output.lines().collect(); + + assert!( + lines[1].contains("mock_ai") && !lines[1].contains("unknown"), + "AI line should show agent without an 'unknown' model: {}", + lines[1] + ); +} + crate::reuse_tests_in_worktree!( test_blame_basic_format, test_blame_line_range, @@ -1501,4 +1567,6 @@ crate::reuse_tests_in_worktree!( test_blame_without_ignore_revs_file_works_normally, test_blame_ignore_revs_with_multiple_commits, test_blame_ai_human_author, + test_blame_shows_agent_and_model, + test_blame_omits_unknown_model, ); diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge.snap b/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge.snap index fc06308fec..2876046324 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge.snap @@ -1,5 +1,6 @@ --- -source: tests/initial_attributions.rs +source: tests/integration/initial_attributions.rs +assertion_line: 295 expression: normalized --- -"COMMIT_SHA (tool1 TIMESTAMP 1) line 1\nCOMMIT_SHA (tool1 TIMESTAMP 2) line 2\nCOMMIT_SHA (tool1 TIMESTAMP 3) line 3\nCOMMIT_SHA (mock_ai TIMESTAMP 4) line 4\nCOMMIT_SHA (tool2 TIMESTAMP 5) line 5\nCOMMIT_SHA (mock_ai TIMESTAMP 6) line 6\nCOMMIT_SHA (mock_ai TIMESTAMP 7) line 7\n" +"COMMIT_SHA (tool1 model1 TIMESTAMP 1) line 1\nCOMMIT_SHA (tool1 model1 TIMESTAMP 2) line 2\nCOMMIT_SHA (tool1 model1 TIMESTAMP 3) line 3\nCOMMIT_SHA (mock_ai TIMESTAMP 4) line 4\nCOMMIT_SHA (tool2 model2 TIMESTAMP 5) line 5\nCOMMIT_SHA (mock_ai TIMESTAMP 6) line 6\nCOMMIT_SHA (mock_ai TIMESTAMP 7) line 7\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge@worktree.snap b/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge@worktree.snap index d4617a1cbf..2876046324 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge@worktree.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_and_blame_merge@worktree.snap @@ -1,6 +1,6 @@ --- -source: tests/initial_attributions.rs -assertion_line: 274 +source: tests/integration/initial_attributions.rs +assertion_line: 295 expression: normalized --- -"COMMIT_SHA (tool1 TIMESTAMP 1) line 1\nCOMMIT_SHA (tool1 TIMESTAMP 2) line 2\nCOMMIT_SHA (tool1 TIMESTAMP 3) line 3\nCOMMIT_SHA (mock_ai TIMESTAMP 4) line 4\nCOMMIT_SHA (tool2 TIMESTAMP 5) line 5\nCOMMIT_SHA (mock_ai TIMESTAMP 6) line 6\nCOMMIT_SHA (mock_ai TIMESTAMP 7) line 7\n" +"COMMIT_SHA (tool1 model1 TIMESTAMP 1) line 1\nCOMMIT_SHA (tool1 model1 TIMESTAMP 2) line 2\nCOMMIT_SHA (tool1 model1 TIMESTAMP 3) line 3\nCOMMIT_SHA (mock_ai TIMESTAMP 4) line 4\nCOMMIT_SHA (tool2 model2 TIMESTAMP 5) line 5\nCOMMIT_SHA (mock_ai TIMESTAMP 6) line 6\nCOMMIT_SHA (mock_ai TIMESTAMP 7) line 7\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint.snap b/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint.snap index 028deb69a3..4cf8dbb8bc 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint.snap @@ -1,5 +1,6 @@ --- -source: tests/initial_attributions.rs +source: tests/integration/initial_attributions.rs +assertion_line: 476 expression: normalized_b --- -"COMMIT_SHA (subsequent-tool TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (subsequent-tool TIMESTAMP 2) line 2 from INITIAL\n" +"COMMIT_SHA (subsequent-tool subsequent-model TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (subsequent-tool subsequent-model TIMESTAMP 2) line 2 from INITIAL\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint@worktree.snap b/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint@worktree.snap index 28f31ce894..4cf8dbb8bc 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint@worktree.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_attributions_in_subsequent_checkpoint@worktree.snap @@ -1,6 +1,6 @@ --- -source: tests/initial_attributions.rs -assertion_line: 443 +source: tests/integration/initial_attributions.rs +assertion_line: 476 expression: normalized_b --- -"COMMIT_SHA (subsequent-tool TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (subsequent-tool TIMESTAMP 2) line 2 from INITIAL\n" +"COMMIT_SHA (subsequent-tool subsequent-model TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (subsequent-tool subsequent-model TIMESTAMP 2) line 2 from INITIAL\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data.snap b/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data.snap index f2afb6f905..fc09c62683 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data.snap @@ -1,5 +1,6 @@ --- -source: tests/initial_attributions.rs +source: tests/integration/initial_attributions.rs +assertion_line: 116 expression: normalized --- -"COMMIT_SHA (test-tool TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (test-tool TIMESTAMP 2) line 2 from INITIAL\nCOMMIT_SHA (test-tool TIMESTAMP 3) line 3 from INITIAL\n" +"COMMIT_SHA (test-tool test-model TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (test-tool test-model TIMESTAMP 2) line 2 from INITIAL\nCOMMIT_SHA (test-tool test-model TIMESTAMP 3) line 3 from INITIAL\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data@worktree.snap b/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data@worktree.snap index 5169b586b4..fc09c62683 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data@worktree.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_only_no_blame_data@worktree.snap @@ -1,6 +1,6 @@ --- -source: tests/initial_attributions.rs -assertion_line: 111 +source: tests/integration/initial_attributions.rs +assertion_line: 116 expression: normalized --- -"COMMIT_SHA (test-tool TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (test-tool TIMESTAMP 2) line 2 from INITIAL\nCOMMIT_SHA (test-tool TIMESTAMP 3) line 3 from INITIAL\n" +"COMMIT_SHA (test-tool test-model TIMESTAMP 1) line 1 from INITIAL\nCOMMIT_SHA (test-tool test-model TIMESTAMP 2) line 2 from INITIAL\nCOMMIT_SHA (test-tool test-model TIMESTAMP 3) line 3 from INITIAL\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps.snap b/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps.snap index 34167c55d6..a40c16c57a 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps.snap @@ -1,5 +1,6 @@ --- source: tests/integration/initial_attributions.rs +assertion_line: 192 expression: normalized --- -"COMMIT_SHA (override-tool TIMESTAMP 1) line 1\nCOMMIT_SHA (override-tool TIMESTAMP 2) line 2\nCOMMIT_SHA (override-tool TIMESTAMP 3) line 3 modified\n" +"COMMIT_SHA (override-tool override-model TIMESTAMP 1) line 1\nCOMMIT_SHA (override-tool override-model TIMESTAMP 2) line 2\nCOMMIT_SHA (override-tool override-model TIMESTAMP 3) line 3 modified\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps@worktree.snap b/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps@worktree.snap index 34167c55d6..a40c16c57a 100644 --- a/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps@worktree.snap +++ b/tests/integration/snapshots/integration__initial_attributions__initial_wins_overlaps@worktree.snap @@ -1,5 +1,6 @@ --- source: tests/integration/initial_attributions.rs +assertion_line: 192 expression: normalized --- -"COMMIT_SHA (override-tool TIMESTAMP 1) line 1\nCOMMIT_SHA (override-tool TIMESTAMP 2) line 2\nCOMMIT_SHA (override-tool TIMESTAMP 3) line 3 modified\n" +"COMMIT_SHA (override-tool override-model TIMESTAMP 1) line 1\nCOMMIT_SHA (override-tool override-model TIMESTAMP 2) line 2\nCOMMIT_SHA (override-tool override-model TIMESTAMP 3) line 3 modified\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage.snap b/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage.snap index 8eb6af0e53..0a21463d29 100644 --- a/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage.snap +++ b/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage.snap @@ -1,5 +1,6 @@ --- -source: tests/initial_attributions.rs +source: tests/integration/initial_attributions.rs +assertion_line: 375 expression: normalized_a --- -"COMMIT_SHA (toolA TIMESTAMP 1) line 1 in A\nCOMMIT_SHA (toolA TIMESTAMP 2) line 2 in A\n" +"COMMIT_SHA (toolA modelA TIMESTAMP 1) line 1 in A\nCOMMIT_SHA (toolA modelA TIMESTAMP 2) line 2 in A\n" diff --git a/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage@worktree.snap b/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage@worktree.snap index ef4818d9eb..0a21463d29 100644 --- a/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage@worktree.snap +++ b/tests/integration/snapshots/integration__initial_attributions__partial_file_coverage@worktree.snap @@ -1,6 +1,6 @@ --- -source: tests/initial_attributions.rs -assertion_line: 345 +source: tests/integration/initial_attributions.rs +assertion_line: 375 expression: normalized_a --- -"COMMIT_SHA (toolA TIMESTAMP 1) line 1 in A\nCOMMIT_SHA (toolA TIMESTAMP 2) line 2 in A\n" +"COMMIT_SHA (toolA modelA TIMESTAMP 1) line 1 in A\nCOMMIT_SHA (toolA modelA TIMESTAMP 2) line 2 in A\n"