use HashSet for orphan edge dedup, fix redundant type qualification

Replace O(n²) Vec::contains + sort/dedup with O(n) HashSet for orphan
node tracking in health_report(). Use imported HashMap type instead of
fully-qualified std::collections::HashMap.
This commit is contained in:
ProofOfConcept 2026-03-08 21:43:58 -04:00
parent 92f3ba5acf
commit 0a35a17fad

View file

@ -607,25 +607,20 @@ pub fn health_report(graph: &Graph, store: &Store) -> String {
// Orphan edges: relations referencing non-existent nodes
let mut orphan_edges = 0usize;
let mut orphan_sources: Vec<String> = Vec::new();
let mut orphan_targets: Vec<String> = Vec::new();
let mut missing_nodes: HashSet<String> = HashSet::new();
for rel in &store.relations {
if rel.deleted { continue; }
let s_missing = !store.nodes.contains_key(&rel.source_key);
let t_missing = !store.nodes.contains_key(&rel.target_key);
if s_missing || t_missing {
orphan_edges += 1;
if s_missing && !orphan_sources.contains(&rel.source_key) {
orphan_sources.push(rel.source_key.clone());
}
if t_missing && !orphan_targets.contains(&rel.target_key) {
orphan_targets.push(rel.target_key.clone());
}
if s_missing { missing_nodes.insert(rel.source_key.clone()); }
if t_missing { missing_nodes.insert(rel.target_key.clone()); }
}
}
// NodeType breakdown
let mut type_counts: std::collections::HashMap<&str, usize> = std::collections::HashMap::new();
let mut type_counts: HashMap<&str, usize> = HashMap::new();
for node in store.nodes.values() {
let label = match node.node_type {
crate::store::NodeType::EpisodicSession => "episodic",
@ -690,18 +685,16 @@ Types: semantic={semantic} episodic={episodic} daily={daily} weekly={weekly} mon
if orphan_edges == 0 {
report.push_str("\n\nBroken links: 0");
} else {
let mut all_missing: Vec<String> = orphan_sources;
all_missing.extend(orphan_targets);
all_missing.sort();
all_missing.dedup();
report.push_str(&format!(
"\n\nBroken links: {} edges reference {} missing nodes",
orphan_edges, all_missing.len()));
for key in all_missing.iter().take(10) {
orphan_edges, missing_nodes.len()));
let mut sorted: Vec<_> = missing_nodes.iter().collect();
sorted.sort();
for key in sorted.iter().take(10) {
report.push_str(&format!("\n - {}", key));
}
if all_missing.len() > 10 {
report.push_str(&format!("\n ... and {} more", all_missing.len() - 10));
if sorted.len() > 10 {
report.push_str(&format!("\n ... and {} more", sorted.len() - 10));
}
}