crabmap 0.1.1

Rust code satellite map — index, query, and navigate your entire codebase
use crate::model::CodeGraph;
use serde_json::{Value, json};

pub fn quality(graph: &CodeGraph) -> Value {
    let stats = graph.stats();
    let definite = stats
        .by_certainty
        .get("definite")
        .copied()
        .unwrap_or_default();
    let confirmed = stats
        .by_certainty
        .get("confirmed")
        .copied()
        .unwrap_or_default();
    let inferred = stats
        .by_certainty
        .get("inferred")
        .copied()
        .unwrap_or_default();
    let possible = stats
        .by_certainty
        .get("possible")
        .copied()
        .unwrap_or_default();
    let trusted = definite + confirmed;
    let scored_edges = trusted + inferred + possible;
    let confidence = if scored_edges == 0 {
        0
    } else {
        ((trusted * 100) + (inferred * 55) + (possible * 25)) / scored_edges
    };
    let semantic_enabled = graph
        .semantic
        .as_ref()
        .map(|info| info.enabled)
        .unwrap_or_default();
    let mir_enabled = graph
        .mir
        .as_ref()
        .map(|info| info.enabled)
        .unwrap_or_default();
    json!({
        "kind": "quality",
        "score": confidence,
        "interpretation": quality_label(confidence),
        "stats": stats,
        "trusted_edges": trusted,
        "uncertain_edges": inferred + possible,
        "warnings": graph.warnings,
        "recommendations": quality_recommendations(graph, confidence, semantic_enabled, mir_enabled, possible)
    })
}

fn quality_label(score: usize) -> &'static str {
    match score {
        85..=100 => "high",
        65..=84 => "medium",
        1..=64 => "low",
        _ => "empty",
    }
}

fn quality_recommendations(
    graph: &CodeGraph,
    score: usize,
    semantic_enabled: bool,
    mir_enabled: bool,
    possible: usize,
) -> Vec<String> {
    let mut items = Vec::new();
    if !semantic_enabled {
        items.push(
            "Run `index --semantic` to confirm more call edges with rust-analyzer.".to_string(),
        );
    }
    if !mir_enabled {
        items.push("Run `index --mir` when lowered call confirmation matters.".to_string());
    }
    if possible > graph.edges.len().saturating_div(10).max(1) {
        items.push(
            "Many edges are possible dispatch candidates; treat trait-call paths as hypotheses."
                .to_string(),
        );
    }
    if !graph.warnings.is_empty() {
        items.push("Inspect warnings before trusting missing or sparse regions.".to_string());
    }
    if score < 65 {
        items.push(
            "Use source reads for final confirmation; this graph has a low confidence score."
                .to_string(),
        );
    }
    items
}