ralph_workflow/git_helpers/repo/diff_review.rs
1/// The level of truncation applied to a diff for review.
2///
3/// This enum tracks how much a diff has been abbreviated and determines
4/// what instructions should be given to the reviewer agent.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
6pub enum DiffTruncationLevel {
7 /// No truncation - full diff is included
8 #[default]
9 Full,
10 /// Diff was semantically truncated - high-priority files shown, instruction to explore
11 Abbreviated,
12 /// Only file paths listed - instruction to explore each file's diff
13 FileList,
14 /// File list was abbreviated - instruction to explore and discover files
15 FileListAbbreviated,
16}
17
18/// The result of diff truncation for review purposes.
19///
20/// Contains both the potentially-truncated content and metadata about
21/// what truncation was applied, along with version context information.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct DiffReviewContent {
24 /// The content to include in the review prompt
25 pub content: String,
26 /// The level of truncation applied
27 pub truncation_level: DiffTruncationLevel,
28 /// Total number of files in the full diff (for context in messages)
29 pub total_file_count: usize,
30 /// Number of files shown in the abbreviated content (if applicable)
31 pub shown_file_count: Option<usize>,
32 /// The OID (commit SHA) that this diff is compared against (baseline)
33 pub baseline_oid: Option<String>,
34 /// Short form (first 8 chars) of the baseline OID for display
35 pub baseline_short: Option<String>,
36 /// Description of what the baseline represents (e.g., "review_baseline", "start_commit")
37 pub baseline_description: String,
38}
39
40impl DiffReviewContent {
41 /// Generate a human-readable header describing the diff's version context.
42 ///
43 /// This header is meant to be included at the beginning of the diff content
44 /// to provide clarity about what state of the code the diff represents.
45 ///
46 /// # Returns
47 ///
48 /// A formatted string like:
49 /// ```text
50 /// Diff Context: Compared against review_baseline abc12345
51 /// Current state: Working directory (includes unstaged changes)
52 /// ```
53 ///
54 /// If no baseline information is available, returns a generic message.
55 pub fn format_context_header(&self) -> String {
56 let mut lines = Vec::new();
57
58 if let Some(short) = &self.baseline_short {
59 lines.push(format!(
60 "Diff Context: Compared against {} {}",
61 self.baseline_description, short
62 ));
63 } else {
64 lines.push("Diff Context: Version information not available".to_string());
65 }
66
67 // Add information about truncation if applicable
68 match self.truncation_level {
69 DiffTruncationLevel::Full => {
70 // No truncation - full diff
71 }
72 DiffTruncationLevel::Abbreviated => {
73 lines.push(format!(
74 "Note: Diff abbreviated - {}/{} files shown",
75 self.shown_file_count.unwrap_or(0),
76 self.total_file_count
77 ));
78 }
79 DiffTruncationLevel::FileList => {
80 lines.push(format!(
81 "Note: Only file list shown - {} files changed",
82 self.total_file_count
83 ));
84 }
85 DiffTruncationLevel::FileListAbbreviated => {
86 lines.push(format!(
87 "Note: File list abbreviated - {}/{} files shown",
88 self.shown_file_count.unwrap_or(0),
89 self.total_file_count
90 ));
91 }
92 }
93
94 if lines.is_empty() {
95 String::new()
96 } else {
97 format!("{}\n", lines.join("\n"))
98 }
99 }
100}