use std::io::Write;
use codelore_lib::Options;
use codelore_lib::calibration::{
CALIBRATION_FORMAT_VERSION, CalibrationArtifact, LanguageTable, MetricQuantiles,
QUANTILE_POINTS, Stratum,
};
use codelore_lib::facts::FactsDb;
use codelore_lib::provenance::Manifest;
use codelore_lib::repo::GixRepo;
fn zero_quantiles() -> Vec<f64> {
vec![0.0; QUANTILE_POINTS]
}
fn test_calib_artifact() -> CalibrationArtifact {
CalibrationArtifact {
format_version: CALIBRATION_FORMAT_VERSION,
corpus_vintage: "test-vintage-2026-07".to_string(),
generated_at: "2026-07-12T00:00:00Z".to_string(),
repos_included: 1,
repos_attempted: 1,
languages: vec![LanguageTable {
language: "rust".to_string(),
sample_functions: 4_000,
strata: vec![Stratum {
sloc_min: 0,
sloc_max: u64::MAX,
metrics: vec![MetricQuantiles {
metric: "cyclomatic".to_string(),
quantiles: zero_quantiles(),
}],
}],
}],
repo_metrics: None,
}
}
fn write_temp_artifact(art: &CalibrationArtifact) -> tempfile::TempPath {
let mut f = tempfile::Builder::new()
.prefix("provenance_test_calib")
.suffix(".calib.json")
.tempfile()
.expect("create temp artifact");
let bytes = serde_json::to_vec(art).expect("serialize artifact");
f.write_all(&bytes).expect("write artifact");
f.into_temp_path()
}
#[test]
fn manifest_captures_basic_fields() {
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 manifest = Manifest::capture(&db, &opts, "revisions").expect("capture");
assert!(
!manifest.codelore_version.is_empty(),
"codelore_version should be populated"
);
assert_eq!(manifest.analysis, "revisions");
assert_eq!(manifest.min_revs, 1);
let json = manifest.to_json().expect("json");
assert!(json.contains("\"analysis\""));
assert!(json.contains("\"codelore_version\""));
}
#[test]
fn manifest_captures_reproducibility_fields() {
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 m = Manifest::capture(&db, &opts, "revisions").expect("capture");
assert_eq!(m.schema_version, 2);
assert_eq!(
m.head_sha.len(),
40,
"head_sha must be the 40-char SHA, got {} chars: {:?}",
m.head_sha.len(),
m.head_sha,
);
assert_eq!(
m.cache_key_hash.len(),
64,
"cache_key_hash must be 64 hex chars (SHA-256), got {} chars",
m.cache_key_hash.len(),
);
assert!(
m.cache_key_hash.chars().all(|c| c.is_ascii_hexdigit()),
"cache_key_hash must be hex-encoded",
);
assert!(!m.rust_version.is_empty());
assert_ne!(
m.target_triple, "unknown",
"target_triple unknown — extend the cfg!() ladder in provenance/mod.rs",
);
for crate_name in [
"tree-sitter",
"tree-sitter-rust",
"tree-sitter-python",
"tree-sitter-java",
"tree-sitter-javascript",
"tree-sitter-typescript",
] {
let pin = m
.grammars
.get(crate_name)
.unwrap_or_else(|| panic!("grammar pin missing: {crate_name}"));
assert!(
!pin.is_empty(),
"grammar pin for {crate_name} must not be empty",
);
}
let json = m.to_json().expect("json");
for field in [
"\"schema_version\"",
"\"head_sha\"",
"\"cache_key_hash\"",
"\"rust_version\"",
"\"target_triple\"",
"\"grammars\"",
] {
assert!(
json.contains(field),
"serialized manifest missing field {field}",
);
}
}
#[test]
fn manifest_corpus_vintage_is_embedded_world_without_calibration() {
let embedded = codelore_lib::calibration::embedded_world()
.expect("the embedded world corpus must be active for this test");
let embedded_vintage = embedded.corpus_vintage.clone();
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,
calibration: None,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let m = Manifest::capture(&db, &opts, "code-health").expect("capture");
assert_eq!(
m.corpus_vintage.as_deref(),
Some(embedded_vintage.as_str()),
"corpus_vintage must be the embedded world vintage when no --calibration is passed"
);
let json = m.to_json().expect("json");
assert!(
json.contains("\"corpus_vintage\""),
"corpus_vintage must be present in JSON when the embedded world is active"
);
assert!(
json.contains(&embedded_vintage),
"JSON must carry the embedded world vintage string"
);
}
#[test]
fn manifest_corpus_vintage_present_with_calibration_file() {
let art = test_calib_artifact();
let artifact_path = write_temp_artifact(&art);
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,
calibration: Some(artifact_path.to_path_buf()),
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let m = Manifest::capture(&db, &opts, "code-health").expect("capture");
assert_eq!(
m.corpus_vintage.as_deref(),
Some("test-vintage-2026-07"),
"corpus_vintage must match the artifact's corpus_vintage field"
);
let json = m.to_json().expect("json");
assert!(
json.contains("\"corpus_vintage\""),
"corpus_vintage must be present in JSON when Some"
);
assert!(
json.contains("test-vintage-2026-07"),
"JSON must carry the vintage string"
);
}
#[test]
fn active_vintage_and_lens_share_one_resolution_seam() {
let art = test_calib_artifact();
let artifact_path = write_temp_artifact(&art);
let with_file = Options {
calibration: Some(artifact_path.to_path_buf()),
..Options::default()
};
let resolved = codelore_lib::calibration::load_active_artifact(&with_file)
.expect("resolve")
.expect("a --calibration file must resolve to an artifact");
assert_eq!(
resolved.corpus_vintage, "test-vintage-2026-07",
"the lens resolves the artifact whose vintage the stamp records"
);
assert_eq!(
codelore_lib::calibration::active_vintage(&with_file).expect("vintage"),
Some("test-vintage-2026-07".to_string()),
"active_vintage must be the same artifact's vintage, via the shared seam"
);
let embedded_vintage = codelore_lib::calibration::embedded_world()
.expect("embedded world corpus must be active")
.corpus_vintage
.clone();
let no_override = Options::default();
let resolved = codelore_lib::calibration::load_active_artifact(&no_override)
.expect("resolve")
.expect("with no --calibration the seam resolves to the embedded world");
assert_eq!(
resolved.corpus_vintage, embedded_vintage,
"branch 2 resolves the embedded world corpus"
);
assert_eq!(
codelore_lib::calibration::active_vintage(&no_override).expect("vintage"),
Some(embedded_vintage),
"active_vintage agrees with the seam on the embedded world vintage"
);
}
#[test]
fn manifest_defect_vintage_present_iff_defect_calibration_active() {
use codelore_lib::defect_calibration::{
DEFECT_FORMAT_VERSION, DefectArtifact, MiningStats, OracleConfig, TuningDecision,
ValidationMetrics, repo_identity, save,
};
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 plain = Options {
repo_path: tiny.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &plain).expect("ingest");
let m = Manifest::capture(&db, &plain, "code-health").expect("capture");
assert!(
m.defect_vintage.is_none(),
"defect_vintage must be None without --defect-calibration"
);
assert!(
!m.to_json().expect("json").contains("\"defect_vintage\""),
"defect_vintage must be omitted from JSON when None"
);
let art = DefectArtifact {
format_version: DEFECT_FORMAT_VERSION,
repo_identity: repo_identity(tiny.dir.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: codelore_lib::defect_calibration::validate::default_weights(),
tuning: TuningDecision::DefaultsKept {
reason: "test".to_string(),
auc_validation_default: None,
auc_validation_tuned: None,
},
};
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("defects.calib.json");
save(&art, &path).expect("save");
let flagged = Options {
defect_calibration: Some(path),
..plain
};
let m = Manifest::capture(&db, &flagged, "code-health").expect("capture");
assert_eq!(
m.defect_vintage.as_deref(),
Some("defects-2026-07-16"),
"defect_vintage must match the artifact's vintage field"
);
assert!(
m.to_json().expect("json").contains("\"defect_vintage\""),
"defect_vintage must be present in JSON when Some"
);
}