use std::io::Write as _;
use codelore_lib::Options;
use codelore_lib::analyses::code_health::run_code_health;
use codelore_lib::calibration::{
CALIBRATION_FORMAT_VERSION, CalibrationArtifact, LanguageTable, MetricQuantiles,
QUANTILE_POINTS, Stratum,
};
use codelore_lib::facts::FactsDb;
use codelore_lib::repo::GixRepo;
#[test]
fn code_health_for_tiny_repo() {
let tiny = codelore_lib::test_support::tiny_repo::build();
let repo = GixRepo::open(tiny.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_health(&db, &opts).expect("run");
assert!(!rows.is_empty(), "should produce ≥1 row");
for row in &rows {
assert!(
row.score >= 0.0 && row.score <= 100.0,
"score should be in [0, 100], got {} for {}",
row.score,
row.path
);
assert!(
row.cognitive >= 0.0,
"cognitive should be >= 0, got {} for {}",
row.cognitive,
row.path
);
}
}
#[test]
fn code_health_ranks_least_healthy_first() {
let tiny = codelore_lib::test_support::tiny_repo::build();
let repo = GixRepo::open(tiny.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_health(&db, &opts).expect("run");
for w in rows.windows(2) {
assert!(
w[0].score <= w[1].score,
"expected ascending score order, got {} > {}",
w[0].score,
w[1].score
);
}
}
#[test]
fn code_health_penalizes_churn() {
let tiny = codelore_lib::test_support::tiny_repo::build();
let repo = GixRepo::open(tiny.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_health(&db, &opts).expect("run");
let m = rows
.iter()
.find(|r| r.path == "src/main.rs")
.expect("src/main.rs should be scored");
let l = rows
.iter()
.find(|r| r.path == "src/lib.rs")
.expect("src/lib.rs should be scored");
assert!(
m.score <= l.score,
"src/main.rs (4 commits) should rank <= src/lib.rs (1 commit) in code health, got main={} lib={}",
m.score,
l.score
);
}
#[test]
fn code_health_reports_band_and_percentile() {
let tiny = codelore_lib::test_support::tiny_repo::build();
let repo = codelore_lib::repo::GixRepo::open(tiny.dir.path()).expect("open");
let db = codelore_lib::facts::FactsDb::new_in_memory().expect("db");
let opts = codelore_lib::Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..codelore_lib::Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = codelore_lib::analyses::code_health::run_code_health(&db, &opts).expect("run");
assert!(!rows.is_empty());
for row in &rows {
assert!(
(0.0..=1.0).contains(&row.percentile),
"percentile in [0,1]: {}",
row.percentile
);
assert!(
matches!(row.band.as_str(), "red" | "yellow" | "green"),
"band must be red|yellow|green, got {}",
row.band
);
assert!(
(0.0..=1.0).contains(&row.structural_risk),
"structural_risk in [0,1]: {}",
row.structural_risk
);
}
}
#[test]
fn biomarkers_flag_complex_functions() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let _ = run_code_health(&db, &opts).expect("run");
let count: i64 = db
.query_row("SELECT COUNT(*) FROM code_health_biomarkers_v1", [], |r| {
r.get(0)
})
.expect("query biomarkers");
assert!(
count >= 1,
"biomarker_repo should produce >=1 biomarker row"
);
let bad: i64 = db
.query_row(
"SELECT COUNT(*) FROM code_health_biomarkers_v1 WHERE intensity < 0.0 OR intensity > 1.0",
[], |r| r.get(0),
)
.expect("query range");
assert_eq!(bad, 0, "all intensities must be in [0,1]");
}
#[test]
fn tiny_language_cohort_is_not_pinned_to_red() {
const STRUCTURAL_IN: &str = "smell IN \
('complex-method','large-method','deep-nesting','many-args','complex-conditional')";
let structural_count = |db: &FactsDb| -> i64 {
db.query_row(
&format!("SELECT COUNT(*) FROM code_health_biomarkers_v1 WHERE {STRUCTURAL_IN}"),
[],
|r| r.get(0),
)
.expect("count structural biomarker rows")
};
let tiny = codelore_lib::test_support::tiny_repo::build();
let repo = GixRepo::open(tiny.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let _ = run_code_health(&db, &opts).expect("run tiny");
assert_eq!(
structural_count(&db),
0,
"a below-floor language cohort must yield no per-language structural biomarkers"
);
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo2 = GixRepo::open(fx.dir.path()).expect("open");
let db2 = FactsDb::new_in_memory().expect("db");
let opts2 = biomarker_opts(fx.dir.path());
db2.ingest(&repo2, &opts2).expect("ingest");
let _ = run_code_health(&db2, &opts2).expect("run biomarker");
assert!(
structural_count(&db2) >= 1,
"an at-floor language cohort must still produce per-language structural biomarkers"
);
}
#[test]
fn coupling_becomes_shotgun_surgery_biomarker() {
let repo_fx = codelore_lib::test_support::differential_repo::build();
let repo = codelore_lib::repo::GixRepo::open(repo_fx.dir.path()).expect("open");
let db = codelore_lib::facts::FactsDb::new_in_memory().expect("db");
let opts =
codelore_lib::test_support::permissive_coupling_opts(repo_fx.dir.path().to_path_buf());
db.ingest(&repo, &opts).expect("ingest");
let _ = codelore_lib::analyses::code_health::run_code_health(&db, &opts).expect("run");
let n: i64 = db
.query_row(
"SELECT COUNT(*) FROM code_health_biomarkers_v1 WHERE smell = 'shotgun-surgery'",
[],
|r| r.get(0),
)
.expect("query");
assert!(
n >= 1,
"a coupling-heavy repo should yield shotgun-surgery biomarkers"
);
}
#[test]
fn structural_risk_rewards_multiple_cooccurring_smells() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_health(&db, &opts).expect("run");
let dup = rows
.iter()
.find(|r| r.path.ends_with("dup_a.rs"))
.expect("dup_a scored");
let trivial = rows
.iter()
.find(|r| r.path.ends_with("trivial.rs"))
.expect("trivial scored");
assert!(
dup.structural_risk > trivial.structural_risk,
"a file with several co-occurring smells (dup_a={}) must have higher structural_risk than a smell-free file (trivial={})",
dup.structural_risk,
trivial.structural_risk
);
}
#[test]
fn code_health_v2_is_deterministic() {
let tiny = codelore_lib::test_support::tiny_repo::build();
let repo = codelore_lib::repo::GixRepo::open(tiny.dir.path()).expect("open");
let opts = codelore_lib::Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..codelore_lib::Options::default()
};
let run = || {
let db = codelore_lib::facts::FactsDb::new_in_memory().expect("db");
db.ingest(&repo, &opts).expect("ingest");
codelore_lib::analyses::code_health::run_code_health(&db, &opts).expect("run")
};
let a = run();
let b = run();
assert_eq!(a.len(), b.len());
for (x, y) in a.iter().zip(b.iter()) {
assert_eq!(x.path, y.path);
assert!((x.score - y.score).abs() < 1e-9, "score must be stable");
assert_eq!(x.band, y.band, "band must be stable");
}
}
#[test]
fn code_health_score_invariant_under_rows_limit() {
let diff_repo = codelore_lib::test_support::differential_repo::build();
let repo = GixRepo::open(diff_repo.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts_unlimited = Options {
repo_path: diff_repo.dir.path().to_path_buf(),
min_revs: 1,
fisher_significance: 1.0,
rows_limit: None,
..Options::default()
};
db.ingest(&repo, &opts_unlimited).expect("ingest");
let baseline = run_code_health(&db, &opts_unlimited).expect("baseline");
assert!(baseline.len() >= 2, "need ≥2 rows to test truncation");
let opts_capped = Options {
rows_limit: Some(2),
..opts_unlimited.clone()
};
let capped = run_code_health(&db, &opts_capped).expect("capped");
assert!(capped.len() <= 2, "rows_limit=2 should truncate output");
for row in &capped {
let baseline_row = baseline
.iter()
.find(|b| b.path == row.path)
.expect("capped path must be in baseline");
assert!(
(row.score - baseline_row.score).abs() < 1e-9,
"score drift for {}: capped={} baseline={} — rows_limit leaked into centrality?",
row.path,
row.score,
baseline_row.score
);
}
}
fn biomarker_opts(dir: &std::path::Path) -> Options {
Options {
repo_path: dir.to_path_buf(),
min_revs: 1,
fisher_significance: 1.0,
min_shared_revs: 1,
min_coupling_pct: 0,
max_coupling_pct: 100,
..Options::default()
}
}
#[test]
fn code_health_structural_risk_discriminates() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_health(&db, &opts).expect("run");
assert!(rows.len() >= 5, "fixture should score several files");
let distinct: std::collections::HashSet<String> = rows
.iter()
.map(|r| format!("{:.3}", r.structural_risk))
.collect();
assert!(
distinct.len() >= 3,
"structural_risk must spread across files, got {} distinct value(s)",
distinct.len()
);
let max = rows
.iter()
.map(|r| r.structural_risk)
.fold(0.0_f64, f64::max);
let min = rows
.iter()
.map(|r| r.structural_risk)
.fold(1.0_f64, f64::min);
assert!(
max < 1.0,
"no file should saturate at the ceiling, got max={max}"
);
assert!(max - min > 0.2, "expected a real spread, got {min}..{max}");
let trivial = rows
.iter()
.find(|r| r.path.ends_with("trivial.rs"))
.expect("trivial file scored");
let complex = rows
.iter()
.find(|r| r.path.ends_with("complex.rs"))
.expect("complex file scored");
assert!(
trivial.structural_risk < complex.structural_risk,
"trivial ({}) must be less risky than complex ({})",
trivial.structural_risk,
complex.structural_risk
);
}
#[test]
fn code_health_biomarkers_fire_distinct_smells() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let _ = run_code_health(&db, &opts).expect("run");
let smells: std::collections::HashSet<String> =
codelore_lib::analyses::query::query_map_collect(
&db,
"SELECT DISTINCT smell FROM code_health_biomarkers_v1",
[],
"smells",
|r| r.get::<_, String>(0),
)
.expect("smells")
.into_iter()
.collect();
for expected in [
"complex-method",
"large-method",
"dry",
"shotgun-surgery",
"deep-nesting",
"many-args",
"complex-conditional",
] {
assert!(
smells.contains(expected),
"expected smell {expected} to fire on the fixture, got {smells:?}"
);
}
}
fn smell_intensity(db: &FactsDb, path: &str, smell: &str) -> Option<f64> {
codelore_lib::analyses::query::query_map_collect(
db,
"SELECT intensity FROM code_health_biomarkers_v1 WHERE path = ? AND smell = ?",
duckdb::params![path, smell],
"smell-intensity",
|r| r.get::<_, f64>(0),
)
.expect("query smell intensity")
.into_iter()
.next()
}
#[test]
fn deep_nesting_biomarker_fires_on_nested_file() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let _ = run_code_health(&db, &opts).expect("run");
let intensity = smell_intensity(&db, "src/nested.rs", "deep-nesting")
.expect("nested.rs should carry a deep-nesting biomarker row");
assert!(
intensity > 0.0,
"deep-nesting intensity for src/nested.rs must be > 0, got {intensity}"
);
}
#[test]
fn many_args_biomarker_fires_on_many_args_file() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let _ = run_code_health(&db, &opts).expect("run");
let intensity = smell_intensity(&db, "src/many_args.rs", "many-args")
.expect("many_args.rs should carry a many-args biomarker row");
assert!(
intensity > 0.0,
"many-args intensity for src/many_args.rs must be > 0, got {intensity}"
);
}
#[test]
fn complex_conditional_biomarker_fires_on_conditional_file() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let _ = run_code_health(&db, &opts).expect("run");
let intensity = smell_intensity(&db, "src/conditional.rs", "complex-conditional")
.expect("conditional.rs should carry a complex-conditional biomarker row");
assert!(
intensity > 0.0,
"complex-conditional intensity for src/conditional.rs must be > 0, got {intensity}"
);
}
#[test]
fn code_health_csv_column_contract() {
let rows = vec![codelore_lib::analyses::code_health::CodeHealthRow {
path: "src/x.rs".to_string(),
cognitive: 12.0,
score: 88.5,
structural_risk: 0.3,
percentile: 0.5,
band: "yellow".to_string(),
corpus_percentile: None,
beyond_corpus: false,
corpus_percentile_ci_low: None,
corpus_percentile_ci_high: None,
}];
let mut buf: Vec<u8> = Vec::new();
codelore_lib::output::csv::write_code_health_csv(&rows, &mut buf).expect("csv");
let out = String::from_utf8(buf).expect("utf8");
assert_eq!(
out.lines().next().unwrap(),
"entity,cognitive,score,structural_risk,percentile,band,corpus-pct,corpus-pct-ci-low,corpus-pct-ci-high"
);
assert!(
out.lines().nth(1).unwrap().starts_with("src/x.rs,"),
"data row should carry the path"
);
}
#[test]
fn code_health_csv_corpus_pct_populated_and_none() {
use codelore_lib::analyses::code_health::CodeHealthRow;
let make = |cp: Option<f64>, bc: bool| CodeHealthRow {
path: "f.rs".into(),
cognitive: 1.0,
score: 50.0,
structural_risk: 0.1,
percentile: 0.2,
band: "green".into(),
corpus_percentile: cp,
beyond_corpus: bc,
corpus_percentile_ci_low: cp.map(|_| 0.61),
corpus_percentile_ci_high: cp.map(|_| 0.90),
};
let rows = vec![
make(Some(0.75), false),
make(Some(1.0), true),
make(None, false),
];
let mut buf: Vec<u8> = Vec::new();
codelore_lib::output::csv::write_code_health_csv(&rows, &mut buf).expect("csv");
let csv = String::from_utf8(buf).expect("utf8");
let lines: Vec<&str> = csv.lines().collect();
assert!(
lines[0].ends_with(",corpus-pct,corpus-pct-ci-low,corpus-pct-ci-high"),
"header must end with the corpus-pct + CI columns: {}",
lines[0]
);
assert!(
lines[1].ends_with(",0.75,0.61,0.90"),
"populated row must carry corpus-pct and its CI: {}",
lines[1]
);
assert!(
lines[2].ends_with(",1.00,0.61,0.90"),
"beyond-corpus row must carry 1.00 and its CI: {}",
lines[2]
);
assert!(
lines[3].ends_with(",,,"),
"None row must emit empty corpus-pct + CI cells: {}",
lines[3]
);
}
#[test]
fn code_health_markdown_corpus_pct_column() {
use codelore_lib::analyses::code_health::CodeHealthRow;
let make = |cp: Option<f64>, bc: bool| CodeHealthRow {
path: "f.rs".into(),
cognitive: 1.0,
score: 50.0,
structural_risk: 0.1,
percentile: 0.2,
band: "green".into(),
corpus_percentile: cp,
beyond_corpus: bc,
corpus_percentile_ci_low: cp.map(|_| 0.61),
corpus_percentile_ci_high: cp.map(|_| 0.90),
};
let rows = vec![
make(Some(0.74), false),
make(Some(1.0), true),
make(None, false),
];
let mut buf: Vec<u8> = Vec::new();
codelore_lib::output::markdown::write_code_health_markdown(&rows, &mut buf).expect("md");
let md = String::from_utf8(buf).expect("utf8");
assert!(
md.contains("Corpus percentile"),
"markdown header must contain 'Corpus percentile'"
);
assert!(
md.contains("Corpus 95% CI"),
"markdown header must contain the 'Corpus 95% CI' column: {md}"
);
assert!(
md.contains("74%"),
"populated corpus_percentile 0.74 must render as 74%: {md}"
);
assert!(
md.contains("100%+"),
"beyond_corpus row must render as 100%+: {md}"
);
assert!(
md.contains("61–90%"),
"populated CI bounds 0.61/0.90 must render as 61–90%: {md}"
);
assert!(
md.contains("—"),
"None corpus_percentile must render as em-dash"
);
}
#[test]
fn scoped_no_clones_excludes_dry_and_renormalizes() {
use codelore_lib::analyses::code_health::{
CodeHealthRow, HealthScanCtx, run_code_health, run_code_health_scoped,
};
let repo = codelore_lib::test_support::biomarker_repo::build();
let gix = codelore_lib::repo::GixRepo::open(repo.dir.path()).expect("open");
let db = codelore_lib::facts::FactsDb::new_in_memory().expect("db");
let opts = codelore_lib::test_support::permissive_coupling_opts(repo.dir.path().to_path_buf());
db.ingest(&gix, &opts).expect("ingest");
let head = run_code_health(&db, &opts).expect("head");
let mut cx = HealthScanCtx::head();
cx.include_clones = false;
let no_dry = run_code_health_scoped(&db, &opts, &cx).expect("no-dry");
assert_eq!(head.len(), no_dry.len(), "same file universe");
let risk = |rows: &[CodeHealthRow], suffix: &str| -> f64 {
rows.iter()
.find(|r| r.path.ends_with(suffix))
.unwrap_or_else(|| panic!("{suffix} should be scored"))
.structural_risk
};
let big_head = risk(&head, "big.rs");
let big_nodry = risk(&no_dry, "big.rs");
assert!(
big_head > 0.0,
"big.rs must carry a non-DRY smell for this check"
);
assert!(
(big_nodry - big_head / 0.88).abs() < 1e-6,
"renorm: big.rs no-clones risk {big_nodry} must equal HEAD {big_head} / 0.88"
);
let dup_head = risk(&head, "dup_a.rs");
let dup_nodry = risk(&no_dry, "dup_a.rs");
assert!(
dup_nodry < dup_head - 1e-6,
"DRY excluded: dup_a.rs no-clones risk {dup_nodry} must drop below HEAD {dup_head}"
);
for r in &no_dry {
assert!(
(0.0..=1.0).contains(&r.structural_risk),
"structural_risk out of range for {}: {}",
r.path,
r.structural_risk
);
}
}
#[test]
fn head_wrapper_equals_scoped_head_ctx() {
use codelore_lib::analyses::code_health::{
HealthScanCtx, run_code_health, run_code_health_scoped,
};
let repo = codelore_lib::test_support::biomarker_repo::build();
let gix = codelore_lib::repo::GixRepo::open(repo.dir.path()).expect("open");
let db = codelore_lib::facts::FactsDb::new_in_memory().expect("db");
let opts = codelore_lib::test_support::permissive_coupling_opts(repo.dir.path().to_path_buf());
db.ingest(&gix, &opts).expect("ingest");
let a = run_code_health(&db, &opts).expect("wrapper");
let b = run_code_health_scoped(&db, &opts, &HealthScanCtx::head()).expect("scoped-head");
assert!(!a.is_empty(), "biomarker_repo must yield scored rows");
assert_eq!(a.len(), b.len());
for (x, y) in a.iter().zip(b.iter()) {
assert_eq!(x.path, y.path);
assert!(
(x.score - y.score).abs() < 1e-12,
"score parity for {}",
x.path
);
assert!((x.structural_risk - y.structural_risk).abs() < 1e-12);
assert_eq!(x.band, y.band);
}
}
#[test]
fn scoped_history_cutoff_limits_churn_and_coupling() {
use codelore_lib::analyses::code_health::{HealthScanCtx, run_code_health_scoped};
let repo = codelore_lib::test_support::biomarker_repo::build();
let gix = codelore_lib::repo::GixRepo::open(repo.dir.path()).expect("open");
let db = codelore_lib::facts::FactsDb::new_in_memory().expect("db");
let opts = codelore_lib::test_support::permissive_coupling_opts(repo.dir.path().to_path_buf());
db.ingest(&gix, &opts).expect("ingest");
let full = run_code_health_scoped(&db, &opts, &HealthScanCtx::head()).expect("full");
let mut cx = HealthScanCtx::head();
cx.history_cutoff = Some("2026-06-03T23:59:59Z".to_string());
let cut = run_code_health_scoped(&db, &opts, &cx).expect("cutoff");
assert!(!cut.is_empty(), "cutoff scan must yield rows");
for r in &cut {
assert!(
(0.0..=100.0).contains(&r.score),
"score in [0,100] for {}: {}",
r.path,
r.score
);
}
let full_by: std::collections::HashMap<_, _> =
full.iter().map(|r| (r.path.clone(), r.score)).collect();
let moved = cut.iter().any(|r| {
full_by
.get(&r.path)
.is_none_or(|f| (r.score - f).abs() > 1e-9)
});
assert!(
moved,
"history cutoff must change at least one file's score vs full history"
);
}
#[test]
fn code_health_band_matches_thresholds() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = biomarker_opts(fx.dir.path());
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_health(&db, &opts).expect("run");
assert!(!rows.is_empty());
for r in &rows {
let expected = if r.structural_risk >= 0.55 {
"red"
} else if r.structural_risk >= 0.28 {
"yellow"
} else {
"green"
};
assert_eq!(
r.band, expected,
"band {} != expected {} for structural_risk {}",
r.band, expected, r.structural_risk
);
}
}
#[allow(clippy::cast_precision_loss)]
fn linear_quantiles(min: f64, max: f64) -> Vec<f64> {
let last = (QUANTILE_POINTS - 1) as f64;
(0..QUANTILE_POINTS)
.map(|i| min + (max - min) * (i as f64) / last)
.collect()
}
fn ramp_artifact(languages: &[&str]) -> CalibrationArtifact {
let metrics = ["cyclomatic", "cognitive", "sloc", "nargs", "max_nesting"];
CalibrationArtifact {
format_version: CALIBRATION_FORMAT_VERSION,
corpus_vintage: "test-ramp".to_string(),
generated_at: "2026-07-12T00:00:00Z".to_string(),
repos_included: 2,
repos_attempted: 2,
languages: languages
.iter()
.map(|lang| LanguageTable {
language: (*lang).to_string(),
sample_functions: 4_000,
strata: vec![Stratum {
sloc_min: 0,
sloc_max: u64::MAX,
metrics: metrics
.iter()
.map(|m| MetricQuantiles {
metric: (*m).to_string(),
quantiles: linear_quantiles(0.0, 1000.0),
})
.collect(),
}],
})
.collect(),
repo_metrics: None,
}
}
fn write_calibration(art: &CalibrationArtifact) -> tempfile::TempPath {
let mut f = tempfile::Builder::new()
.prefix("code-health-calib")
.suffix(".calib.json")
.tempfile()
.expect("create temp artifact");
f.write_all(&serde_json::to_vec(art).expect("serialize"))
.expect("write artifact");
f.into_temp_path()
}
#[test]
fn corpus_lens_is_additive_over_shipped_fields() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let run = |calibration: Option<std::path::PathBuf>| {
let db = FactsDb::new_in_memory().expect("db");
db.ingest(&repo, &biomarker_opts(fx.dir.path()))
.expect("ingest");
let opts = Options {
calibration,
..biomarker_opts(fx.dir.path())
};
run_code_health(&db, &opts).expect("run")
};
let calib = write_calibration(&ramp_artifact(&["rust"]));
let without = run(None);
let with = run(Some(calib.to_path_buf()));
assert!(!without.is_empty(), "fixture must yield scored rows");
assert_eq!(
without.len(),
with.len(),
"the corpus pass must not add or drop rows"
);
let shipped = |row: &codelore_lib::analyses::code_health::CodeHealthRow| -> serde_json::Value {
let mut v = serde_json::to_value(row).expect("serialize row");
let obj = v.as_object_mut().expect("row is an object");
obj.remove("corpus_percentile");
obj.remove("beyond_corpus");
obj.remove("corpus_percentile_ci_low");
obj.remove("corpus_percentile_ci_high");
v
};
for (a, b) in without.iter().zip(with.iter()) {
assert_eq!(
shipped(a),
shipped(b),
"corpus calibration perturbed a shipped field for {}",
a.path
);
}
assert!(
with.iter().any(|r| r.corpus_percentile.is_some()),
"the covering rust artifact must populate corpus_percentile on ≥1 rust file"
);
}
#[test]
fn corpus_lens_populates_covered_language_and_skips_others() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
db.ingest(&repo, &biomarker_opts(fx.dir.path()))
.expect("ingest");
let rust_calib = write_calibration(&ramp_artifact(&["rust"]));
let covered = {
let opts = Options {
calibration: Some(rust_calib.to_path_buf()),
..biomarker_opts(fx.dir.path())
};
run_code_health(&db, &opts).expect("run covered")
};
let rust_rows: Vec<_> = covered
.iter()
.filter(|r| {
codelore_lib::complexity::Tier1Language::from_path(&r.path)
== Some(codelore_lib::complexity::Tier1Language::Rust)
})
.collect();
assert!(!rust_rows.is_empty(), "fixture is rust");
for r in &rust_rows {
let p = r
.corpus_percentile
.unwrap_or_else(|| panic!("rust file {} must carry a corpus percentile", r.path));
assert!(
(0.0..=1.0).contains(&p),
"corpus percentile in [0,1] for {}: {p}",
r.path
);
}
let py_calib = write_calibration(&ramp_artifact(&["python"]));
let uncovered = {
let opts = Options {
calibration: Some(py_calib.to_path_buf()),
..biomarker_opts(fx.dir.path())
};
run_code_health(&db, &opts).expect("run uncovered")
};
for r in &uncovered {
assert!(
r.corpus_percentile.is_none() && !r.beyond_corpus,
"a rust file must get None from a python-only artifact, got {:?} for {}",
r.corpus_percentile,
r.path
);
}
}
fn write_defect_artifact(
dir: &std::path::Path,
repo_path: &std::path::Path,
weights: Vec<(String, f64)>,
) -> std::path::PathBuf {
use codelore_lib::defect_calibration::{
DEFECT_FORMAT_VERSION, DefectArtifact, MiningStats, OracleConfig, TuningDecision,
ValidationMetrics, repo_identity, save,
};
let art = DefectArtifact {
format_version: DEFECT_FORMAT_VERSION,
repo_identity: repo_identity(repo_path),
head_at_mining: "0".repeat(40),
vintage: "defects-2026-07-16".to_string(),
generated_at: "2026-07-16T00:00:00Z".to_string(),
oracle: OracleConfig::default(),
mining: MiningStats::default(),
validation: ValidationMetrics::default(),
weights,
tuning: TuningDecision::Applied {
auc_train: 0.7,
auc_validation_default: 0.6,
auc_validation_tuned: 0.7,
},
};
let path = dir.join("defects.calib.json");
save(&art, &path).expect("save artifact");
path
}
#[test]
fn defect_calibration_with_default_weights_is_byte_identical() {
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: fx.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let baseline = run_code_health(&db, &opts).expect("run without artifact");
let art_dir = tempfile::tempdir().expect("tempdir");
let path = write_defect_artifact(
art_dir.path(),
fx.dir.path(),
codelore_lib::defect_calibration::validate::default_weights(),
);
let flagged_opts = Options {
defect_calibration: Some(path),
..opts
};
let flagged = run_code_health(&db, &flagged_opts).expect("run with default-weights artifact");
assert_eq!(
serde_json::to_string(&baseline).expect("json"),
serde_json::to_string(&flagged).expect("json"),
"an artifact carrying the default weights must leave output byte-identical"
);
}
#[test]
fn defect_calibration_shifted_weights_apply_and_match_the_rust_side_prediction() {
use codelore_lib::defect_calibration::validate::{
capture_intensities, structural_risk_from_intensities,
};
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: fx.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let baseline = run_code_health(&db, &opts).expect("baseline run");
let shifted: Vec<(String, f64)> = codelore_lib::defect_calibration::validate::default_weights()
.into_iter()
.map(|(name, w)| match name.as_str() {
"complex-method" => (name, w + 0.11),
"god-class" => (name, w - 0.11),
_ => (name, w),
})
.collect();
let art_dir = tempfile::tempdir().expect("tempdir");
let path = write_defect_artifact(art_dir.path(), fx.dir.path(), shifted.clone());
let flagged_opts = Options {
defect_calibration: Some(path),
..opts
};
let tuned = run_code_health(&db, &flagged_opts).expect("tuned run");
let intensities = capture_intensities(&db).expect("capture intensities");
assert_ne!(
serde_json::to_string(&baseline).expect("json"),
serde_json::to_string(&tuned).expect("json"),
"a genuinely shifted weight set must change the output"
);
let mut parity_checked = 0usize;
for row in &tuned {
let Some(intens) = intensities.get(&row.path) else {
continue;
};
let predicted = structural_risk_from_intensities(&shifted, intens);
assert!(
(row.structural_risk - predicted).abs() < 1e-9,
"SQL risk {} diverges from Rust-side prediction {} for {}",
row.structural_risk,
predicted,
row.path
);
parity_checked += 1;
}
assert!(
parity_checked > 0,
"at least one scored file must have captured intensities for the parity loop to bite"
);
}
#[test]
fn defect_calibration_foreign_artifact_errors_unless_explicitly_allowed() {
use codelore_lib::defect_calibration::{
DEFECT_FORMAT_VERSION, DefectArtifact, MiningStats, OracleConfig, TuningDecision,
ValidationMetrics, save,
};
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: fx.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let baseline = run_code_health(&db, &opts).expect("baseline run");
let shifted: Vec<(String, f64)> = codelore_lib::defect_calibration::validate::default_weights()
.into_iter()
.map(|(name, w)| match name.as_str() {
"complex-method" => (name, w + 0.11),
"god-class" => (name, w - 0.11),
_ => (name, w),
})
.collect();
let art = DefectArtifact {
format_version: DEFECT_FORMAT_VERSION,
repo_identity: "0".repeat(64), head_at_mining: "0".repeat(40),
vintage: "defects-2026-07-16".to_string(),
generated_at: "2026-07-16T00:00:00Z".to_string(),
oracle: OracleConfig::default(),
mining: MiningStats::default(),
validation: ValidationMetrics::default(),
weights: shifted,
tuning: TuningDecision::DefaultsKept {
reason: "test".to_string(),
auc_validation_default: None,
auc_validation_tuned: None,
},
};
let art_dir = tempfile::tempdir().expect("tempdir");
let path = art_dir.path().join("defects.calib.json");
save(&art, &path).expect("save artifact");
let foreign_opts = Options {
defect_calibration: Some(path.clone()),
..opts.clone()
};
let err = run_code_health(&db, &foreign_opts).expect_err("foreign artifact must hard-error");
assert!(
format!("{err}").contains("different repository"),
"error must name the mismatch: {err}"
);
let allowed_opts = Options {
defect_calibration: Some(path),
allow_foreign_calibration: true,
..opts
};
let rows = run_code_health(&db, &allowed_opts).expect("allow-foreign must apply");
assert_ne!(
serde_json::to_string(&baseline).expect("json"),
serde_json::to_string(&rows).expect("json"),
"with the escape hatch the foreign artifact's shifted weights must actually apply"
);
}
#[test]
fn defect_calibration_recomputes_the_no_dry_scale_from_the_tuned_dry_weight() {
use codelore_lib::analyses::code_health::{HealthScanCtx, run_code_health_scoped};
use codelore_lib::defect_calibration::validate::capture_intensities;
let fx = codelore_lib::test_support::biomarker_repo::build();
let repo = GixRepo::open(fx.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = Options {
repo_path: fx.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let tuned: Vec<(String, f64)> = codelore_lib::defect_calibration::validate::default_weights()
.into_iter()
.map(|(name, w)| match name.as_str() {
"dry" => (name, w + 0.12),
"complex-method" => (name, w - 0.12),
_ => (name, w),
})
.collect();
let dry_weight = 0.24;
let art_dir = tempfile::tempdir().expect("tempdir");
let path = write_defect_artifact(art_dir.path(), fx.dir.path(), tuned.clone());
let flagged_opts = Options {
defect_calibration: Some(path),
..opts
};
let cx = HealthScanCtx {
include_clones: false,
..HealthScanCtx::head()
};
let rows = run_code_health_scoped(&db, &flagged_opts, &cx).expect("scoped run");
let intensities = capture_intensities(&db).expect("capture intensities");
let mut checked = 0usize;
for row in &rows {
let Some(intens) = intensities.get(&row.path) else {
continue;
};
let dot: f64 = tuned.iter().zip(intens).map(|((_, w), i)| w * i).sum();
let expected = (dot / (1.0 - dry_weight)).min(1.0);
assert!(
(row.structural_risk - expected).abs() < 1e-9,
"no-DRY risk {} diverges from tuned-divisor prediction {} for {}",
row.structural_risk,
expected,
row.path
);
checked += 1;
}
assert!(
checked > 0,
"at least one scored file must have captured intensities for the divisor check to bite"
);
}