use super::scan::ProjectHealth;
use crate::core::bm25_index::ChunkKind;
use crate::core::consolidation::{self, ConsolidationArtifacts, PrunePrior};
use crate::core::content_chunk::ContentChunk;
use crate::core::graph_index::IndexEdge;
use crate::core::knowledge_provider_extract::ExtractedFact;
const URI_SCHEME: &str = "health://";
const RESOURCE: &str = "complexity";
const EDGE_KIND: &str = "health_hotspot";
const FACT_CATEGORY: &str = "code_health";
const FACT_CONFIDENCE: f32 = 0.9;
const MAX_PG_HOTSPOT_EDGES: usize = 200;
fn hotspot_uri(item_id: &str) -> String {
format!("{URI_SCHEME}{RESOURCE}/{item_id}")
}
fn item_id(file: &str, symbol: &str) -> String {
format!("{file}#{symbol}")
}
pub fn build_artifacts(health: &ProjectHealth) -> ConsolidationArtifacts {
let mut artifacts = ConsolidationArtifacts::default();
for h in &health.score.hotspots {
let id = item_id(&h.file, &h.symbol);
let title = format!("{} (cc={})", h.symbol, h.cognitive);
let content = format!(
"Code-health hotspot: function `{}` in {} (line {}) has cognitive \
complexity {}, above the navigability threshold. High-complexity \
functions cost more tokens to read and edit safely; consider \
extracting nested logic.",
h.symbol, h.file, h.line, h.cognitive
);
artifacts.bm25_chunks.push(ContentChunk::from_provider(
"health",
RESOURCE,
&id,
&title,
ChunkKind::Other,
content,
vec![h.file.clone()],
Some(serde_json::json!({
"file": h.file,
"symbol": h.symbol,
"line": h.line,
"cognitive": h.cognitive,
})),
));
artifacts.facts.push(ExtractedFact {
category: FACT_CATEGORY.to_string(),
key: id,
value: format!("cognitive complexity {} (line {})", h.cognitive, h.line),
confidence: FACT_CONFIDENCE,
});
}
for h in pg_hotspots(health) {
artifacts.edges.push(IndexEdge {
from: h.file.clone(),
to: hotspot_uri(&item_id(&h.file, &h.symbol)),
kind: EDGE_KIND.to_string(),
weight: h.cognitive as f32,
});
}
artifacts
}
fn pg_hotspots(health: &ProjectHealth) -> Vec<super::Hotspot> {
let mut all: Vec<super::Hotspot> = if health.files.is_empty() {
health.score.hotspots.clone()
} else {
health
.files
.iter()
.flat_map(|f| f.hotspots.iter().cloned())
.collect()
};
all.sort_by(|a, b| {
b.cognitive
.cmp(&a.cognitive)
.then_with(|| a.file.cmp(&b.file))
.then_with(|| a.line.cmp(&b.line))
});
all.truncate(MAX_PG_HOTSPOT_EDGES);
all
}
pub fn hotspot_cc(root: &str, symbol: &str) -> Option<u32> {
let pg = crate::core::property_graph::CodeGraph::open(root).ok()?;
pg.all_cross_source_edges()
.iter()
.filter(|e| e.kind == EDGE_KIND)
.filter_map(|e| {
let sym = e.to.rsplit('#').next()?;
(sym == symbol).then_some(e.weight.round() as u32)
})
.max()
}
fn prune_spec() -> PrunePrior {
PrunePrior {
bm25_prefix: Some(URI_SCHEME.to_string()),
edge_kind: Some(EDGE_KIND.to_string()),
fact_category: Some(FACT_CATEGORY.to_string()),
}
}
pub fn apply(root: &str, health: &ProjectHealth) {
let artifacts = build_artifacts(health);
consolidation::apply_artifacts_to_stores(&artifacts, root, &prune_spec());
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::core::code_health::score::{Hotspot, NavigabilityScore};
use crate::core::knowledge::ProjectKnowledge;
use crate::core::property_graph::CodeGraph;
fn score_with(hotspots: Vec<Hotspot>) -> NavigabilityScore {
NavigabilityScore {
score: 80,
total_functions: 10,
over_threshold: hotspots.len(),
worst_cognitive: hotspots.iter().map(|h| h.cognitive).max().unwrap_or(0),
import_cycles: 0,
estimated_waste_usd: 0.0,
hotspots,
}
}
fn health_with(hotspots: Vec<Hotspot>) -> ProjectHealth {
ProjectHealth {
score: score_with(hotspots),
files: Vec::new(),
naming_count: 0,
}
}
fn hotspot(file: &str, symbol: &str, line: usize, cognitive: u32) -> Hotspot {
Hotspot {
file: file.to_string(),
symbol: symbol.to_string(),
line,
cognitive,
}
}
#[test]
fn build_emits_triplet_per_hotspot() {
let health = health_with(vec![
hotspot("src/a.rs", "big", 10, 22),
hotspot("src/b.rs", "huge", 5, 31),
]);
let a = build_artifacts(&health);
assert_eq!(a.bm25_chunks.len(), 2);
assert_eq!(a.edges.len(), 2);
assert_eq!(a.facts.len(), 2);
assert!(a.bm25_chunks[0].file_path.starts_with(URI_SCHEME));
assert_eq!(
a.bm25_chunks[0].file_path,
"health://complexity/src/a.rs#big"
);
assert_eq!(a.facts[0].category, FACT_CATEGORY);
assert_eq!(a.facts[0].key, "src/a.rs#big");
assert_eq!(a.edges[0].weight, 31.0, "worst hotspot edge first");
let edge_a = a.edges.iter().find(|e| e.from == "src/a.rs").unwrap();
assert_eq!(edge_a.kind, EDGE_KIND);
assert_eq!(edge_a.weight, 22.0);
assert_eq!(edge_a.to, "health://complexity/src/a.rs#big");
}
#[test]
fn build_clean_project_is_empty() {
let a = build_artifacts(&health_with(Vec::new()));
assert!(a.bm25_chunks.is_empty());
assert!(a.edges.is_empty());
assert!(a.facts.is_empty());
}
#[test]
fn build_is_deterministic() {
let health = health_with(vec![
hotspot("src/a.rs", "big", 10, 22),
hotspot("src/b.rs", "huge", 5, 31),
]);
let first = build_artifacts(&health);
let second = build_artifacts(&health);
let paths = |a: &ConsolidationArtifacts| {
a.bm25_chunks
.iter()
.map(|c| c.file_path.clone())
.collect::<Vec<_>>()
};
assert_eq!(paths(&first), paths(&second));
assert_eq!(
first
.facts
.iter()
.map(|f| f.value.clone())
.collect::<Vec<_>>(),
second
.facts
.iter()
.map(|f| f.value.clone())
.collect::<Vec<_>>(),
);
}
#[test]
fn apply_then_clean_prunes_every_store() {
let _iso = crate::core::data_dir::isolated_data_dir();
let dir = tempfile::tempdir().unwrap();
let root = dir.path().to_str().unwrap();
std::fs::write(dir.path().join("lib.rs"), "pub fn ok() {}\n").unwrap();
apply(root, &health_with(vec![hotspot("src/a.rs", "big", 10, 22)]));
let pg = CodeGraph::open(root).unwrap();
assert_eq!(
pg.all_cross_source_edges()
.iter()
.filter(|e| e.kind == EDGE_KIND)
.count(),
1,
"hotspot edge written"
);
let knowledge = ProjectKnowledge::load(root).unwrap();
assert_eq!(
knowledge
.facts
.iter()
.filter(|f| f.category == FACT_CATEGORY)
.count(),
1,
"hotspot fact written"
);
apply(root, &health_with(Vec::new()));
let pg = CodeGraph::open(root).unwrap();
assert_eq!(
pg.all_cross_source_edges()
.iter()
.filter(|e| e.kind == EDGE_KIND)
.count(),
0,
"resolved hotspot edge pruned"
);
let knowledge = ProjectKnowledge::load(root).unwrap();
assert_eq!(
knowledge
.facts
.iter()
.filter(|f| f.category == FACT_CATEGORY)
.count(),
0,
"resolved hotspot fact pruned"
);
}
fn file_report(hotspots: Vec<Hotspot>) -> crate::core::code_health::scan::FileReport {
crate::core::code_health::scan::FileReport {
file: hotspots.first().map(|h| h.file.clone()).unwrap_or_default(),
total_functions: hotspots.len(),
over_threshold: hotspots.len(),
worst_cognitive: hotspots.iter().map(|h| h.cognitive).max().unwrap_or(0),
hotspots,
naming: Vec::new(),
wasted_tokens: 0,
}
}
#[test]
fn pg_edges_cover_all_over_threshold_not_just_score() {
let top = hotspot("src/a.rs", "worst", 1, 40);
let health = ProjectHealth {
score: score_with(vec![top.clone()]),
files: vec![
file_report(vec![top, hotspot("src/a.rs", "mid", 20, 25)]),
file_report(vec![hotspot("src/b.rs", "low", 3, 18)]),
],
naming_count: 0,
};
let a = build_artifacts(&health);
assert_eq!(a.bm25_chunks.len(), 1, "BM25 follows the bounded score");
assert_eq!(a.facts.len(), 1, "facts follow the bounded score");
assert_eq!(
a.edges.len(),
3,
"edges cover every over-threshold function"
);
assert_eq!(a.edges[0].weight, 40.0, "worst-first");
}
#[test]
fn hotspot_cc_reads_back_persisted_edge() {
let dir = tempfile::tempdir().unwrap();
let root = dir.path().to_str().unwrap();
std::fs::write(dir.path().join("lib.rs"), "pub fn ok() {}\n").unwrap();
apply(root, &health_with(vec![hotspot("src/a.rs", "big", 10, 22)]));
assert_eq!(hotspot_cc(root, "big"), Some(22));
assert_eq!(hotspot_cc(root, "not_a_hotspot"), None);
}
}