use super::EnrichResult;
use crate::CodememEngine;
use codemem_core::{CodememError, NodeKind};
use serde_json::json;
use std::collections::HashMap;
impl CodememEngine {
pub fn enrich_performance(
&self,
top: usize,
namespace: Option<&str>,
) -> Result<EnrichResult, CodememError> {
let all_nodes;
let mut coupling_data: Vec<(String, String, usize)> = Vec::new();
let mut high_coupling_count = 0;
let layers: Vec<Vec<String>>;
let mut file_pagerank: Vec<(String, String, f64)> = Vec::new();
{
let graph = self.lock_graph()?;
all_nodes = graph.get_all_nodes();
for node in &all_nodes {
let degree = graph.get_edges(&node.id).map(|e| e.len()).unwrap_or(0);
coupling_data.push((node.id.clone(), node.label.clone(), degree));
if degree > self.config.enrichment.perf_min_coupling_degree {
high_coupling_count += 1;
}
}
layers = graph.topological_layers();
for node in &all_nodes {
if node.kind == NodeKind::File {
let pr = graph.get_pagerank(&node.id);
if pr > 0.0 {
file_pagerank.push((node.id.clone(), node.label.clone(), pr));
}
}
}
}
let max_depth = layers.len();
file_pagerank.sort_by(|a, b| b.2.partial_cmp(&a.2).unwrap_or(std::cmp::Ordering::Equal));
let mut file_symbol_counts: HashMap<String, usize> = HashMap::new();
for node in &all_nodes {
match node.kind {
NodeKind::Function
| NodeKind::Method
| NodeKind::Class
| NodeKind::Interface
| NodeKind::Type => {
if let Some(file_path) = node.payload.get("file_path").and_then(|v| v.as_str())
{
*file_symbol_counts.entry(file_path.to_string()).or_default() += 1;
}
}
_ => {}
}
}
{
let mut graph = self.lock_graph()?;
for (node_id, _label, degree) in &coupling_data {
if let Ok(Some(mut node)) = graph.get_node(node_id) {
node.payload.insert("coupling_score".into(), json!(degree));
let _ = graph.add_node(node);
}
}
for (layer_idx, layer) in layers.iter().enumerate() {
for node_id in layer {
if let Ok(Some(mut node)) = graph.get_node(node_id) {
node.payload
.insert("dependency_layer".into(), json!(layer_idx));
let _ = graph.add_node(node);
}
}
}
for (node_id, _label, rank) in file_pagerank.iter().take(top) {
if let Ok(Some(mut node)) = graph.get_node(node_id) {
node.payload
.insert("critical_path_rank".into(), json!(rank));
let _ = graph.add_node(node);
}
}
for (file_path, sym_count) in &file_symbol_counts {
let node_id = format!("file:{file_path}");
if let Ok(Some(mut node)) = graph.get_node(&node_id) {
node.payload.insert("symbol_count".into(), json!(sym_count));
let _ = graph.add_node(node);
}
}
}
let mut insights_stored = 0;
coupling_data.sort_by(|a, b| b.2.cmp(&a.2));
for (node_id, label, degree) in coupling_data.iter().take(top) {
if *degree > self.config.enrichment.perf_min_coupling_degree {
let content = format!(
"High coupling: {} has {} dependencies — refactoring risk",
label, degree
);
if self
.store_insight(
&content,
"performance",
&["coupling"],
0.7,
namespace,
std::slice::from_ref(node_id),
)
.is_some()
{
insights_stored += 1;
}
}
}
if max_depth > 5 {
let content = format!(
"Deep dependency chain: {} layers — impacts build and test times",
max_depth
);
if self
.store_insight(
&content,
"performance",
&["dependency-depth"],
0.6,
namespace,
&[],
)
.is_some()
{
insights_stored += 1;
}
}
if let Some((node_id, label, _)) = file_pagerank.first() {
let content = format!(
"Critical bottleneck: {} — highest centrality file, changes cascade widely",
label
);
if self
.store_insight(
&content,
"performance",
&["critical-path"],
0.8,
namespace,
std::slice::from_ref(node_id),
)
.is_some()
{
insights_stored += 1;
}
}
let mut complex_files: Vec<_> = file_symbol_counts.iter().collect();
complex_files.sort_by(|a, b| b.1.cmp(a.1));
for (file_path, sym_count) in complex_files.iter().take(top) {
if **sym_count > self.config.enrichment.perf_min_symbol_count {
let content = format!("Complex file: {} — {} symbols", file_path, sym_count);
if self
.store_insight(
&content,
"performance",
&["complexity"],
0.5,
namespace,
&[format!("file:{file_path}")],
)
.is_some()
{
insights_stored += 1;
}
}
}
self.save_index();
let critical_files: Vec<_> = file_pagerank
.iter()
.take(top)
.map(|(_, label, score)| json!({"file": label, "pagerank": score}))
.collect();
Ok(EnrichResult {
insights_stored,
details: json!({
"high_coupling_count": high_coupling_count,
"max_depth": max_depth,
"critical_files": critical_files,
"insights_stored": insights_stored,
}),
})
}
}