@@ -521,10 +521,6 @@ pub fn stats_from_authorship_log(
521521 prompt_record. agent_id. tool, prompt_record. agent_id. model
522522 ) ;
523523 let tool_stats = commit_stats. tool_model_breakdown . entry ( key) . or_default ( ) ;
524- tool_stats. ai_additions += std:: cmp:: min (
525- prompt_record. total_additions ,
526- prompt_record. overriden_lines + prompt_record. accepted_lines ,
527- ) ;
528524 tool_stats. total_ai_additions += prompt_record. total_additions ;
529525 tool_stats. total_ai_deletions += prompt_record. total_deletions ;
530526 tool_stats. mixed_additions += prompt_record. overriden_lines ;
@@ -544,6 +540,11 @@ pub fn stats_from_authorship_log(
544540 commit_stats. mixed_additions + commit_stats. ai_accepted ,
545541 git_diff_added_lines,
546542 ) ;
543+
544+ // Calculate ai_additions for each tool following the same contract: ai_additions = ai_accepted + mixed_additions
545+ for tool_stats in commit_stats. tool_model_breakdown . values_mut ( ) {
546+ tool_stats. ai_additions = tool_stats. ai_accepted + tool_stats. mixed_additions ;
547+ }
547548 }
548549
549550 // Human additions are the difference between total git diff and AI accepted lines (ensure non-negative)
@@ -564,7 +565,8 @@ pub fn stats_for_commit_stats(
564565 // Step 1: get the diff between this commit and its parent ON refname (if more than one parent)
565566 // If initial than everything is additions
566567 // We want the count here git shows +111 -55
567- let ( git_diff_added_lines, git_diff_deleted_lines) = get_git_diff_stats ( repo, commit_sha, ignore_patterns) ?;
568+ let ( git_diff_added_lines, git_diff_deleted_lines) =
569+ get_git_diff_stats ( repo, commit_sha, ignore_patterns) ?;
568570
569571 // Step 2: get the authorship log for this commit
570572 let authorship_log = get_authorship ( repo, & commit_sha) ;
@@ -578,7 +580,11 @@ pub fn stats_for_commit_stats(
578580}
579581
580582/// Get git diff statistics between commit and its parent
581- pub fn get_git_diff_stats ( repo : & Repository , commit_sha : & str , ignore_patterns : & [ String ] ) -> Result < ( u32 , u32 ) , GitAiError > {
583+ pub fn get_git_diff_stats (
584+ repo : & Repository ,
585+ commit_sha : & str ,
586+ ignore_patterns : & [ String ] ,
587+ ) -> Result < ( u32 , u32 ) , GitAiError > {
582588 // Use git show --numstat to get diff statistics
583589 let mut args = repo. global_args_for_exec ( ) ;
584590 args. push ( "show" . to_string ( ) ) ;
@@ -993,7 +999,9 @@ mod tests {
993999 let tmp_repo = TmpRepo :: new ( ) . unwrap ( ) ;
9941000
9951001 // Initial commit
996- tmp_repo. write_file ( "src/main.rs" , "fn main() {}\n " , true ) . unwrap ( ) ;
1002+ tmp_repo
1003+ . write_file ( "src/main.rs" , "fn main() {}\n " , true )
1004+ . unwrap ( ) ;
9971005 tmp_repo
9981006 . trigger_checkpoint_with_author ( "test_user" )
9991007 . unwrap ( ) ;
@@ -1014,12 +1022,14 @@ mod tests {
10141022 let head_sha = tmp_repo. get_head_commit_sha ( ) . unwrap ( ) ;
10151023
10161024 // Test WITHOUT ignore - should count lockfile
1017- let stats_with_lockfile = stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & [ ] ) . unwrap ( ) ;
1025+ let stats_with_lockfile =
1026+ stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & [ ] ) . unwrap ( ) ;
10181027 assert_eq ! ( stats_with_lockfile. git_diff_added_lines, 1001 ) ; // 1 source + 1000 lockfile
10191028
10201029 // Test WITH ignore - should exclude lockfile
10211030 let ignore_patterns = vec ! [ "Cargo.lock" . to_string( ) ] ;
1022- let stats_without_lockfile = stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & ignore_patterns) . unwrap ( ) ;
1031+ let stats_without_lockfile =
1032+ stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & ignore_patterns) . unwrap ( ) ;
10231033 assert_eq ! ( stats_without_lockfile. git_diff_added_lines, 1 ) ; // Only 1 source line
10241034 assert_eq ! ( stats_without_lockfile. ai_additions, 1 ) ;
10251035 }
@@ -1029,7 +1039,9 @@ mod tests {
10291039 let tmp_repo = TmpRepo :: new ( ) . unwrap ( ) ;
10301040
10311041 // Initial commit
1032- tmp_repo. write_file ( "README.md" , "# Project\n " , true ) . unwrap ( ) ;
1042+ tmp_repo
1043+ . write_file ( "README.md" , "# Project\n " , true )
1044+ . unwrap ( ) ;
10331045 tmp_repo
10341046 . trigger_checkpoint_with_author ( "test_user" )
10351047 . unwrap ( ) ;
@@ -1065,7 +1077,8 @@ mod tests {
10651077 "package-lock.json" . to_string( ) ,
10661078 "yarn.lock" . to_string( ) ,
10671079 ] ;
1068- let stats_filtered = stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & ignore_patterns) . unwrap ( ) ;
1080+ let stats_filtered =
1081+ stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & ignore_patterns) . unwrap ( ) ;
10691082 assert_eq ! ( stats_filtered. git_diff_added_lines, 1 ) ;
10701083 assert_eq ! ( stats_filtered. human_additions, 1 ) ;
10711084 }
@@ -1075,7 +1088,9 @@ mod tests {
10751088 let tmp_repo = TmpRepo :: new ( ) . unwrap ( ) ;
10761089
10771090 // Initial commit
1078- tmp_repo. write_file ( "src/lib.rs" , "pub fn foo() {}\n " , true ) . unwrap ( ) ;
1091+ tmp_repo
1092+ . write_file ( "src/lib.rs" , "pub fn foo() {}\n " , true )
1093+ . unwrap ( ) ;
10791094 tmp_repo
10801095 . trigger_checkpoint_with_author ( "test_user" )
10811096 . unwrap ( ) ;
@@ -1098,7 +1113,8 @@ mod tests {
10981113
10991114 // Test WITH ignore - shows 0 lines (lockfile-only commit)
11001115 let ignore_patterns = vec ! [ "Cargo.lock" . to_string( ) ] ;
1101- let stats_without = stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & ignore_patterns) . unwrap ( ) ;
1116+ let stats_without =
1117+ stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & ignore_patterns) . unwrap ( ) ;
11021118 assert_eq ! ( stats_without. git_diff_added_lines, 0 ) ;
11031119 assert_eq ! ( stats_without. ai_additions, 0 ) ;
11041120 assert_eq ! ( stats_without. human_additions, 0 ) ;
@@ -1137,7 +1153,9 @@ mod tests {
11371153 let tmp_repo = TmpRepo :: new ( ) . unwrap ( ) ;
11381154
11391155 // Initial commit
1140- tmp_repo. write_file ( "src/lib.rs" , "pub fn foo() {}\n " , true ) . unwrap ( ) ;
1156+ tmp_repo
1157+ . write_file ( "src/lib.rs" , "pub fn foo() {}\n " , true )
1158+ . unwrap ( ) ;
11411159 tmp_repo
11421160 . trigger_checkpoint_with_author ( "test_user" )
11431161 . unwrap ( ) ;
@@ -1154,10 +1172,18 @@ mod tests {
11541172 . write_file ( "package-lock.json" , "{}\n " . repeat ( 500 ) . as_str ( ) , true )
11551173 . unwrap ( ) ;
11561174 tmp_repo
1157- . write_file ( "api.generated.ts" , "// generated\n " . repeat ( 300 ) . as_str ( ) , true )
1175+ . write_file (
1176+ "api.generated.ts" ,
1177+ "// generated\n " . repeat ( 300 ) . as_str ( ) ,
1178+ true ,
1179+ )
11581180 . unwrap ( ) ;
11591181 tmp_repo
1160- . write_file ( "schema.generated.js" , "// schema\n " . repeat ( 200 ) . as_str ( ) , true )
1182+ . write_file (
1183+ "schema.generated.js" ,
1184+ "// schema\n " . repeat ( 200 ) . as_str ( ) ,
1185+ true ,
1186+ )
11611187 . unwrap ( ) ;
11621188 tmp_repo
11631189 . trigger_checkpoint_with_ai ( "Claude" , Some ( "claude-3-sonnet" ) , Some ( "cursor" ) )
@@ -1172,11 +1198,12 @@ mod tests {
11721198
11731199 // Test WITH glob patterns - only source code (1 line)
11741200 let glob_patterns = vec ! [
1175- "*.lock" . to_string( ) , // Matches Cargo.lock
1176- "*lock.json" . to_string( ) , // Matches package-lock.json
1177- "*.generated.*" . to_string( ) , // Matches *.generated.ts, *.generated.js
1201+ "*.lock" . to_string( ) , // Matches Cargo.lock
1202+ "*lock.json" . to_string( ) , // Matches package-lock.json
1203+ "*.generated.*" . to_string( ) , // Matches *.generated.ts, *.generated.js
11781204 ] ;
1179- let stats_filtered = stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & glob_patterns) . unwrap ( ) ;
1205+ let stats_filtered =
1206+ stats_for_commit_stats ( & tmp_repo. gitai_repo ( ) , & head_sha, & glob_patterns) . unwrap ( ) ;
11801207 assert_eq ! ( stats_filtered. git_diff_added_lines, 1 ) ;
11811208 assert_eq ! ( stats_filtered. ai_additions, 1 ) ;
11821209 }
0 commit comments