@@ -108,6 +108,10 @@ fn default_include_uncommitted() -> bool {
108108 true
109109}
110110
111+ fn default_true ( ) -> bool {
112+ true
113+ }
114+
111115impl Default for DiffConfig {
112116 fn default ( ) -> Self {
113117 Self {
@@ -132,6 +136,9 @@ pub struct LlmConfig {
132136 /// Precedence: key_cmd > key > env vars.
133137 #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
134138 pub key : Option < String > ,
139+ /// Whether LLM annotations are enabled (default: true).
140+ #[ serde( default = "default_true" ) ]
141+ pub annotations_enabled : bool ,
135142 /// Optional LLM refinement pass configuration.
136143 #[ serde( default ) ]
137144 pub refinement : RefinementConfig ,
@@ -145,8 +152,8 @@ pub struct LlmConfig {
145152/// refine again if score improved, up to `max_iterations`.
146153#[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
147154pub struct RefinementConfig {
148- /// Whether refinement is enabled (default: false ).
149- #[ serde( default ) ]
155+ /// Whether refinement is enabled (default: true ).
156+ #[ serde( default = "default_true" ) ]
150157 pub enabled : bool ,
151158 /// Provider for refinement (can differ from annotation provider).
152159 #[ serde( default ) ]
@@ -170,7 +177,7 @@ fn default_max_iterations() -> u32 {
170177impl Default for RefinementConfig {
171178 fn default ( ) -> Self {
172179 Self {
173- enabled : false ,
180+ enabled : true ,
174181 provider : None ,
175182 model : None ,
176183 key_cmd : None ,
@@ -186,6 +193,7 @@ impl Default for LlmConfig {
186193 model : None ,
187194 key_cmd : None ,
188195 key : None ,
196+ annotations_enabled : true ,
189197 refinement : RefinementConfig :: default ( ) ,
190198 }
191199 }
@@ -954,7 +962,7 @@ events = ["src/handlers/events/**/*.ts"]
954962 #[ test]
955963 fn test_refinement_config_defaults ( ) {
956964 let config = DiffcoreConfig :: default ( ) ;
957- assert ! ( ! config. llm. refinement. enabled) ;
965+ assert ! ( config. llm. refinement. enabled) ;
958966 assert_eq ! ( config. llm. refinement. provider, None ) ;
959967 assert_eq ! ( config. llm. refinement. model, None ) ;
960968 assert_eq ! ( config. llm. refinement. key_cmd, None ) ;
@@ -981,13 +989,13 @@ max_iterations = 3
981989 }
982990
983991 #[ test]
984- fn test_refinement_disabled_by_default ( ) {
992+ fn test_refinement_enabled_by_default ( ) {
985993 let toml_str = r#"
986994[llm]
987995provider = "anthropic"
988996"# ;
989997 let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
990- assert ! ( ! config. llm. refinement. enabled) ;
998+ assert ! ( config. llm. refinement. enabled) ;
991999 assert_eq ! ( config. llm. refinement. max_iterations, 1 ) ;
9921000 }
9931001
@@ -1149,4 +1157,167 @@ domain = "src/services/**"
11491157 }
11501158 }
11511159 }
1160+
1161+ // ── Annotations Enabled Tests ──
1162+
1163+ #[ test]
1164+ fn test_annotations_enabled_defaults_true ( ) {
1165+ let config = DiffcoreConfig :: default ( ) ;
1166+ assert ! ( config. llm. annotations_enabled) ;
1167+ }
1168+
1169+ #[ test]
1170+ fn test_annotations_enabled_serde_default_true ( ) {
1171+ // When annotations_enabled is missing from TOML, it should default to true
1172+ let toml_str = r#"
1173+ [llm]
1174+ provider = "anthropic"
1175+ "# ;
1176+ let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
1177+ assert ! ( config. llm. annotations_enabled) ;
1178+ }
1179+
1180+ #[ test]
1181+ fn test_annotations_enabled_explicit_false ( ) {
1182+ let toml_str = r#"
1183+ [llm]
1184+ provider = "anthropic"
1185+ annotations_enabled = false
1186+ "# ;
1187+ let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
1188+ assert ! ( !config. llm. annotations_enabled) ;
1189+ }
1190+
1191+ #[ test]
1192+ fn test_annotations_enabled_explicit_true ( ) {
1193+ let toml_str = r#"
1194+ [llm]
1195+ provider = "anthropic"
1196+ annotations_enabled = true
1197+ "# ;
1198+ let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
1199+ assert ! ( config. llm. annotations_enabled) ;
1200+ }
1201+
1202+ #[ test]
1203+ fn test_annotations_enabled_roundtrip ( ) {
1204+ let mut config = DiffcoreConfig :: default ( ) ;
1205+ config. llm . annotations_enabled = false ;
1206+
1207+ let toml_str = toml:: to_string_pretty ( & config) . unwrap ( ) ;
1208+ let back = DiffcoreConfig :: from_str ( & toml_str) . unwrap ( ) ;
1209+ assert ! ( !back. llm. annotations_enabled) ;
1210+ }
1211+
1212+ #[ test]
1213+ fn test_annotations_enabled_json_roundtrip ( ) {
1214+ let config = LlmConfig {
1215+ annotations_enabled : false ,
1216+ ..Default :: default ( )
1217+ } ;
1218+ let json = serde_json:: to_string ( & config) . unwrap ( ) ;
1219+ let back: LlmConfig = serde_json:: from_str ( & json) . unwrap ( ) ;
1220+ assert ! ( !back. annotations_enabled) ;
1221+ }
1222+
1223+ #[ test]
1224+ fn test_refinement_enabled_defaults_true_in_llm_config ( ) {
1225+ let config = LlmConfig :: default ( ) ;
1226+ assert ! ( config. refinement. enabled) ;
1227+ }
1228+
1229+ #[ test]
1230+ fn test_refinement_enabled_explicit_false_overrides_default ( ) {
1231+ let toml_str = r#"
1232+ [llm.refinement]
1233+ enabled = false
1234+ "# ;
1235+ let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
1236+ assert ! ( !config. llm. refinement. enabled) ;
1237+ }
1238+
1239+ #[ test]
1240+ fn test_both_defaults_true_on_empty_config ( ) {
1241+ let config = DiffcoreConfig :: default ( ) ;
1242+ assert ! ( config. llm. annotations_enabled, "annotations should default to true" ) ;
1243+ assert ! ( config. llm. refinement. enabled, "refinement should default to true" ) ;
1244+ }
1245+
1246+ #[ test]
1247+ fn test_both_defaults_true_on_minimal_toml ( ) {
1248+ let toml_str = "" ;
1249+ let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
1250+ assert ! ( config. llm. annotations_enabled, "annotations should default to true" ) ;
1251+ assert ! ( config. llm. refinement. enabled, "refinement should default to true" ) ;
1252+ }
1253+
1254+ #[ test]
1255+ fn test_annotations_and_refinement_independent ( ) {
1256+ // Can enable one and disable the other
1257+ let toml_str = r#"
1258+ [llm]
1259+ annotations_enabled = false
1260+
1261+ [llm.refinement]
1262+ enabled = true
1263+ "# ;
1264+ let config = DiffcoreConfig :: from_str ( toml_str) . unwrap ( ) ;
1265+ assert ! ( !config. llm. annotations_enabled) ;
1266+ assert ! ( config. llm. refinement. enabled) ;
1267+
1268+ let toml_str2 = r#"
1269+ [llm]
1270+ annotations_enabled = true
1271+
1272+ [llm.refinement]
1273+ enabled = false
1274+ "# ;
1275+ let config2 = DiffcoreConfig :: from_str ( toml_str2) . unwrap ( ) ;
1276+ assert ! ( config2. llm. annotations_enabled) ;
1277+ assert ! ( !config2. llm. refinement. enabled) ;
1278+ }
1279+
1280+ #[ test]
1281+ fn test_global_defaults_merge_with_annotations ( ) {
1282+ // Test that global config merge still works with annotations_enabled
1283+ let mut local = DiffcoreConfig :: from_str ( r#"
1284+ [llm]
1285+ annotations_enabled = false
1286+ "# ) . unwrap ( ) ;
1287+ let global = DiffcoreConfig :: from_str ( r#"
1288+ [llm]
1289+ provider = "anthropic"
1290+
1291+ [llm.refinement]
1292+ enabled = true
1293+ provider = "openai"
1294+ "# ) . unwrap ( ) ;
1295+
1296+ local. apply_global_llm_defaults ( & global) ;
1297+
1298+ // Local explicit false should be preserved
1299+ assert ! ( !local. llm. annotations_enabled) ;
1300+ // Global provider should fill in missing local
1301+ assert_eq ! ( local. llm. provider, Some ( "anthropic" . to_string( ) ) ) ;
1302+ // Refinement from either local (default true) or global should be true
1303+ assert ! ( local. llm. refinement. enabled) ;
1304+ }
1305+
1306+ #[ test]
1307+ fn test_save_global_roundtrip_annotations_enabled ( ) {
1308+ // Test that annotations_enabled survives save_global / load_global cycle
1309+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
1310+ std:: env:: set_var ( "DIFFCORE_GLOBAL_CONFIG_DIR" , dir. path ( ) . to_str ( ) . unwrap ( ) ) ;
1311+
1312+ let mut config = DiffcoreConfig :: default ( ) ;
1313+ config. llm . annotations_enabled = false ;
1314+ config. llm . refinement . enabled = false ;
1315+ config. save_global ( ) . unwrap ( ) ;
1316+
1317+ let loaded = DiffcoreConfig :: load_global ( ) . unwrap ( ) ;
1318+ assert ! ( !loaded. llm. annotations_enabled, "annotations_enabled should survive save/load" ) ;
1319+ assert ! ( !loaded. llm. refinement. enabled, "refinement.enabled should survive save/load" ) ;
1320+
1321+ std:: env:: remove_var ( "DIFFCORE_GLOBAL_CONFIG_DIR" ) ;
1322+ }
11521323}
0 commit comments