memory-search --seen: show current and previous seen sets separately

Instead of merging both into one flat list, display them as distinct
sections so it's clear what was surfaced in this context vs what
came from before compaction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kent Overstreet 2026-03-22 16:27:52 -04:00
parent 134f7308e3
commit e50d43bbf0

View file

@ -737,56 +737,43 @@ fn show_seen() {
println!("Pending chunks: {}", pending); println!("Pending chunks: {}", pending);
} }
// Read seen file in insertion order (append-only file) let returned = load_returned(&state_dir, session_id);
let seen_path = state_dir.join(format!("seen-{}", session_id)); let returned_set: HashSet<_> = returned.iter().cloned().collect();
let seen_lines: Vec<String> = fs::read_to_string(&seen_path)
let print_seen_file = |label: &str, path: &std::path::Path| {
let lines: Vec<String> = fs::read_to_string(path)
.unwrap_or_default() .unwrap_or_default()
.lines() .lines()
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(); .collect();
if lines.is_empty() { return; }
let returned = load_returned(&state_dir, session_id); let context_keys: Vec<_> = lines.iter()
let returned_set: HashSet<_> = returned.iter().cloned().collect();
// Count context-loaded vs search-returned
let context_keys: Vec<_> = seen_lines.iter()
.map(|l| parse_seen_line(l).to_string()) .map(|l| parse_seen_line(l).to_string())
.filter(|k| !returned_set.contains(k)) .filter(|k| !returned_set.contains(k))
.collect(); .collect();
let search_keys: Vec<_> = seen_lines.iter() let search_keys: Vec<_> = lines.iter()
.map(|l| parse_seen_line(l).to_string()) .map(|l| parse_seen_line(l).to_string())
.filter(|k| returned_set.contains(k)) .filter(|k| returned_set.contains(k))
.collect(); .collect();
println!("\nSeen set ({} total):", seen_lines.len()); println!("\n{} ({} total):", label, lines.len());
if !context_keys.is_empty() { if !context_keys.is_empty() {
println!(" Context-loaded ({}):", context_keys.len()); println!(" Context-loaded ({}):", context_keys.len());
for key in &context_keys { for key in &context_keys { println!(" {}", key); }
println!(" {}", key);
}
} }
if !search_keys.is_empty() { if !search_keys.is_empty() {
println!(" Search-returned ({}):", search_keys.len()); println!(" Search-returned ({}):", search_keys.len());
for key in &search_keys { for key in &search_keys { println!(" {}", key); }
println!(" {}", key);
}
} }
};
// Show returned keys that aren't in the seen set (bug indicator) let current_path = state_dir.join(format!("seen-{}", session_id));
let seen_key_set: HashSet<_> = seen_lines.iter() let prev_path = state_dir.join(format!("seen-prev-{}", session_id));
.map(|l| parse_seen_line(l).to_string())
.collect(); print_seen_file("Current seen set", &current_path);
let orphan_returned: Vec<_> = returned.iter() print_seen_file("Previous seen set (pre-compaction)", &prev_path);
.filter(|k| !seen_key_set.contains(k.as_str()))
.collect();
if !orphan_returned.is_empty() {
println!("\n WARNING: {} returned keys not in seen set (pre-compaction?):",
orphan_returned.len());
for key in &orphan_returned {
println!(" {}", key);
}
}
} }
fn cleanup_stale_files(dir: &Path, max_age: Duration) { fn cleanup_stale_files(dir: &Path, max_age: Duration) {