use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(default)]
pub struct ReviewConfig {
pub max_prompt_chars: usize,
pub max_full_content_files: usize,
pub max_chars_per_file: usize,
pub max_diff_chars: usize,
pub max_patch_chars_per_file: usize,
#[serde(default = "default_max_instructions_chars")]
pub max_instructions_chars: usize,
#[serde(default)]
pub instructions_file: Option<String>,
#[serde(default = "default_min_budget_for_call_graph")]
pub min_budget_for_call_graph: usize,
#[serde(default = "default_max_dep_release_chars")]
pub max_dep_release_chars: usize,
#[serde(default = "default_max_dep_packages")]
pub max_dep_packages: usize,
}
fn default_max_instructions_chars() -> usize {
1_500
}
fn default_min_budget_for_call_graph() -> usize {
20_000
}
fn default_max_dep_release_chars() -> usize {
2_000
}
fn default_max_dep_packages() -> usize {
3
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_consistency_ok() {
let config = ReviewConfig::default();
let warnings = config.validate_consistency();
assert!(
warnings.is_empty(),
"default config should produce no warnings: {:?}",
warnings
);
}
#[test]
fn test_validate_consistency_threshold_equals_max() {
let config = ReviewConfig {
min_budget_for_call_graph: 120_000,
max_prompt_chars: 120_000,
..ReviewConfig::default()
};
let warnings = config.validate_consistency();
assert_eq!(warnings.len(), 1, "should produce exactly 1 warning");
assert!(
warnings[0].contains("call_graph will never be built"),
"warning should indicate call_graph is never built: {}",
warnings[0]
);
}
#[test]
fn test_validate_consistency_threshold_over_half() {
let config = ReviewConfig {
min_budget_for_call_graph: 80_000,
max_prompt_chars: 120_000,
..ReviewConfig::default()
};
let warnings = config.validate_consistency();
assert_eq!(warnings.len(), 1, "should produce exactly 1 warning");
assert!(
warnings[0].contains("only be built for the largest diffs"),
"warning should indicate call_graph rarely enables: {}",
warnings[0]
);
}
}
impl Default for ReviewConfig {
fn default() -> Self {
Self {
max_prompt_chars: 120_000,
max_full_content_files: 10,
max_chars_per_file: 16_000,
max_diff_chars: 200_000,
max_patch_chars_per_file: 10_000,
max_instructions_chars: 1_500,
instructions_file: None,
min_budget_for_call_graph: 20_000,
max_dep_release_chars: 2_000,
max_dep_packages: 3,
}
}
}
impl ReviewConfig {
#[must_use]
pub fn validate_consistency(&self) -> Vec<String> {
let mut warnings = Vec::new();
if self.min_budget_for_call_graph >= self.max_prompt_chars {
warnings.push(format!(
"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",
self.min_budget_for_call_graph, self.max_prompt_chars
));
}
else if self.min_budget_for_call_graph > self.max_prompt_chars / 2 {
warnings.push(format!(
"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",
self.min_budget_for_call_graph, self.max_prompt_chars
));
}
warnings
}
}