aptu_core/config/
review.rs1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Deserialize, Serialize, Clone)]
21#[serde(default)]
22pub struct ReviewConfig {
23 pub max_prompt_chars: usize,
25 pub max_full_content_files: usize,
27 pub max_chars_per_file: usize,
29 pub max_diff_chars: usize,
31 pub max_patch_chars_per_file: usize,
33 #[serde(default = "default_max_instructions_chars")]
35 pub max_instructions_chars: usize,
36 #[serde(default)]
38 pub instructions_file: Option<String>,
39 #[serde(default = "default_min_budget_for_call_graph")]
49 pub min_budget_for_call_graph: usize,
50 #[serde(default = "default_max_dep_release_chars")]
52 pub max_dep_release_chars: usize,
53 #[serde(default = "default_max_dep_packages")]
55 pub max_dep_packages: usize,
56}
57
58fn default_max_instructions_chars() -> usize {
59 1_500
60}
61
62fn default_min_budget_for_call_graph() -> usize {
63 20_000
64}
65
66fn default_max_dep_release_chars() -> usize {
67 2_000
68}
69
70fn default_max_dep_packages() -> usize {
71 3
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_validate_consistency_ok() {
80 let config = ReviewConfig::default();
81 let warnings = config.validate_consistency();
82 assert!(
83 warnings.is_empty(),
84 "default config should produce no warnings: {warnings:?}"
85 );
86 }
87
88 #[test]
89 fn test_validate_consistency_threshold_equals_max() {
90 let config = ReviewConfig {
91 min_budget_for_call_graph: 120_000,
92 max_prompt_chars: 120_000,
93 ..ReviewConfig::default()
94 };
95 let warnings = config.validate_consistency();
96 assert_eq!(warnings.len(), 1, "should produce exactly 1 warning");
97 assert!(
98 warnings[0].contains("call_graph will never be built"),
99 "warning should indicate call_graph is never built: {}",
100 warnings[0]
101 );
102 }
103
104 #[test]
105 fn test_validate_consistency_threshold_over_half() {
106 let config = ReviewConfig {
107 min_budget_for_call_graph: 80_000,
108 max_prompt_chars: 120_000,
109 ..ReviewConfig::default()
110 };
111 let warnings = config.validate_consistency();
112 assert_eq!(warnings.len(), 1, "should produce exactly 1 warning");
113 assert!(
114 warnings[0].contains("only be built for the largest diffs"),
115 "warning should indicate call_graph rarely enables: {}",
116 warnings[0]
117 );
118 }
119
120 #[test]
121 fn test_default_max_patch_chars_per_file() {
122 let config = ReviewConfig::default();
123 assert_eq!(
124 config.max_patch_chars_per_file, 25_000,
125 "default max_patch_chars_per_file should be 25_000"
126 );
127 }
128}
129
130impl Default for ReviewConfig {
131 fn default() -> Self {
132 Self {
133 max_prompt_chars: 120_000,
134 max_full_content_files: 10,
135 max_chars_per_file: 32_000,
136 max_diff_chars: 200_000,
137 max_patch_chars_per_file: 25_000,
138 max_instructions_chars: 1_500,
139 instructions_file: None,
140 min_budget_for_call_graph: 20_000,
141 max_dep_release_chars: 2_000,
142 max_dep_packages: 3,
143 }
144 }
145}
146
147impl ReviewConfig {
148 #[must_use]
153 pub fn validate_consistency(&self) -> Vec<String> {
154 let mut warnings = Vec::new();
155
156 if self.min_budget_for_call_graph >= self.max_prompt_chars {
160 warnings.push(format!(
161 "min_budget_for_call_graph ({}) >= max_prompt_chars ({}): call_graph will never be built; call_graph is enabled only when budget_remaining > min_budget_for_call_graph",
162 self.min_budget_for_call_graph, self.max_prompt_chars
163 ));
164 }
165 else if self.min_budget_for_call_graph > self.max_prompt_chars / 2 {
168 warnings.push(format!(
169 "min_budget_for_call_graph ({}) exceeds half of max_prompt_chars ({}): call_graph will only be built for the largest diffs; consider lowering the threshold",
170 self.min_budget_for_call_graph, self.max_prompt_chars
171 ));
172 }
173
174 warnings
175 }
176}