Skip to main content

lean_ctx/core/
delivered_ranges.rs

1//! Cross-read deduplication engine (#1313).
2//!
3//! Tracks which line ranges of each file have already been delivered
4//! to the agent in this session. On subsequent overlapping reads,
5//! only novel (not-yet-delivered) lines are emitted.
6
7use std::collections::HashMap;
8use std::path::PathBuf;
9use std::sync::{Mutex, PoisonError};
10
11static GLOBAL: Mutex<Option<DeliveredRanges>> = Mutex::new(None);
12
13/// Access the global delivered-ranges tracker.
14pub fn global() -> std::sync::MutexGuard<'static, Option<DeliveredRanges>> {
15    GLOBAL.lock().unwrap_or_else(PoisonError::into_inner)
16}
17
18/// Sorted, non-overlapping intervals of 1-based line numbers.
19#[derive(Debug, Clone, Default)]
20pub struct IntervalSet {
21    intervals: Vec<(usize, usize)>,
22}
23
24impl IntervalSet {
25    /// Mark lines `start..=end` as delivered.
26    pub fn insert(&mut self, start: usize, end: usize) {
27        if start > end {
28            return;
29        }
30        self.intervals.push((start, end));
31        self.merge();
32    }
33
34    /// Returns line numbers in `start..=end` that have NOT been delivered.
35    pub fn novel_lines(&self, start: usize, end: usize) -> Vec<(usize, usize)> {
36        if start > end {
37            return Vec::new();
38        }
39        let mut novel = Vec::new();
40        let mut cursor = start;
41
42        for &(ds, de) in &self.intervals {
43            if ds > cursor {
44                novel.push((cursor, ds.min(end + 1) - 1));
45            }
46            if de >= cursor {
47                cursor = de + 1;
48            }
49            if cursor > end {
50                break;
51            }
52        }
53
54        if cursor <= end {
55            novel.push((cursor, end));
56        }
57
58        novel
59    }
60
61    /// Fraction of `start..=end` that is already delivered.
62    pub fn overlap_fraction(&self, start: usize, end: usize) -> f64 {
63        if start > end {
64            return 0.0;
65        }
66        let total = (end - start + 1) as f64;
67        let delivered: usize = self
68            .intervals
69            .iter()
70            .map(|&(ds, de)| {
71                let overlap_start = ds.max(start);
72                let overlap_end = de.min(end);
73                if overlap_start <= overlap_end {
74                    overlap_end - overlap_start + 1
75                } else {
76                    0
77                }
78            })
79            .sum();
80        delivered as f64 / total
81    }
82
83    fn merge(&mut self) {
84        self.intervals.sort_by_key(|&(s, _)| s);
85        let mut merged: Vec<(usize, usize)> = Vec::new();
86        for (s, e) in self.intervals.drain(..) {
87            if let Some(last) = merged.last_mut()
88                && s <= last.1 + 1
89            {
90                last.1 = last.1.max(e);
91                continue;
92            }
93            merged.push((s, e));
94        }
95        self.intervals = merged;
96    }
97}
98
99/// Session-scoped tracker of delivered line ranges per file.
100#[derive(Debug, Clone, Default)]
101pub struct DeliveredRanges {
102    files: HashMap<PathBuf, IntervalSet>,
103}
104
105impl DeliveredRanges {
106    pub fn new() -> Self {
107        Self::default()
108    }
109
110    /// Record that lines `start..=end` of `path` have been delivered.
111    pub fn record(&mut self, path: &str, start: usize, end: usize) {
112        self.files
113            .entry(PathBuf::from(path))
114            .or_default()
115            .insert(start, end);
116    }
117
118    /// Get novel (not-yet-delivered) line ranges for a read request.
119    pub fn novel_ranges(&self, path: &str, start: usize, end: usize) -> Vec<(usize, usize)> {
120        match self.files.get(&PathBuf::from(path)) {
121            Some(set) => set.novel_lines(start, end),
122            None => vec![(start, end)],
123        }
124    }
125
126    /// Fraction of the requested range already delivered.
127    pub fn overlap_fraction(&self, path: &str, start: usize, end: usize) -> f64 {
128        match self.files.get(&PathBuf::from(path)) {
129            Some(set) => set.overlap_fraction(start, end),
130            None => 0.0,
131        }
132    }
133
134    /// Record a full-file delivery (all lines).
135    pub fn record_full(&mut self, path: &str, line_count: usize) {
136        if line_count > 0 {
137            self.record(path, 1, line_count);
138        }
139    }
140
141    /// Reset tracking for a specific file (e.g., after modification).
142    pub fn invalidate(&mut self, path: &str) {
143        self.files.remove(&PathBuf::from(path));
144    }
145
146    pub fn reset(&mut self) {
147        self.files.clear();
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154
155    #[test]
156    fn interval_set_insert_and_merge() {
157        let mut set = IntervalSet::default();
158        set.insert(1, 10);
159        set.insert(15, 20);
160        set.insert(8, 17);
161        assert_eq!(set.intervals, vec![(1, 20)]);
162    }
163
164    #[test]
165    fn interval_set_novel_lines() {
166        let mut set = IntervalSet::default();
167        set.insert(1, 50);
168        set.insert(80, 100);
169
170        let novel = set.novel_lines(40, 90);
171        assert_eq!(novel, vec![(51, 79)]);
172    }
173
174    #[test]
175    fn interval_set_all_novel_when_empty() {
176        let set = IntervalSet::default();
177        assert_eq!(set.novel_lines(1, 100), vec![(1, 100)]);
178    }
179
180    #[test]
181    fn interval_set_nothing_novel_when_fully_covered() {
182        let mut set = IntervalSet::default();
183        set.insert(1, 200);
184        assert!(set.novel_lines(50, 150).is_empty());
185    }
186
187    #[test]
188    fn overlap_fraction_partial() {
189        let mut set = IntervalSet::default();
190        set.insert(1, 50);
191        let frac = set.overlap_fraction(1, 100);
192        assert!((frac - 0.5).abs() < 0.01);
193    }
194
195    #[test]
196    fn overlap_fraction_zero_when_empty() {
197        let set = IntervalSet::default();
198        assert_eq!(set.overlap_fraction(1, 100), 0.0);
199    }
200
201    #[test]
202    fn delivered_ranges_record_and_query() {
203        let mut dr = DeliveredRanges::new();
204        dr.record("src/db.py", 1, 100);
205
206        let novel = dr.novel_ranges("src/db.py", 50, 200);
207        assert_eq!(novel, vec![(101, 200)]);
208
209        let overlap = dr.overlap_fraction("src/db.py", 50, 200);
210        assert!((overlap - 50.0 / 151.0).abs() < 0.01);
211    }
212
213    #[test]
214    fn delivered_ranges_full_file() {
215        let mut dr = DeliveredRanges::new();
216        dr.record_full("src/main.rs", 500);
217        assert!(dr.novel_ranges("src/main.rs", 1, 500).is_empty());
218        assert_eq!(dr.overlap_fraction("src/main.rs", 1, 500), 1.0);
219    }
220
221    #[test]
222    fn delivered_ranges_invalidate() {
223        let mut dr = DeliveredRanges::new();
224        dr.record_full("src/lib.rs", 100);
225        dr.invalidate("src/lib.rs");
226        assert_eq!(dr.novel_ranges("src/lib.rs", 1, 100), vec![(1, 100)]);
227    }
228
229    #[test]
230    fn delivered_ranges_evaluation_scenario() {
231        let mut dr = DeliveredRanges::new();
232
233        dr.record("src/db.py", 1, 100);
234        let novel = dr.novel_ranges("src/db.py", 50, 200);
235        assert_eq!(novel, vec![(101, 200)]);
236        dr.record("src/db.py", 101, 200);
237
238        let novel = dr.novel_ranges("src/db.py", 80, 180);
239        assert!(novel.is_empty(), "third read should be fully deduplicated");
240    }
241}