From 5e9574fc149a06414b9d817f83fbafa2e805aea2 Mon Sep 17 00:00:00 2001 From: Noah Gift Date: Mon, 12 Oct 2026 04:38:55 +0200 Subject: [PATCH 1/2] fix(core): f32_bits_tests reads its ECE fixture at run time, so the published crate compiles src/metrics/f32_bits_tests.rs did include_str! of scripts/setfit_fixtures/claims_stats/ece_top_label_cases.json, a file outside aprender-core, so the packaged .crate could not compile the lib's unit tests (scripts/package_tarball_build.sh red). It now reads the file through provable_contracts::workspace_file_or_skip!, the shared rule test_support already uses: in tree a missing file panics; out of tree the ECE half prints a named SKIP and the f1 half still runs. The frozen snapshot table is unchanged. Refs #5171 Agent: aprender-wmainred Co-Authored-By: Claude Opus 5.5 --- .../src/metrics/f32_bits_tests.rs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/aprender-core/src/metrics/f32_bits_tests.rs b/crates/aprender-core/src/metrics/f32_bits_tests.rs index 8c1639ec5a..f8f736722d 100644 --- a/crates/aprender-core/src/metrics/f32_bits_tests.rs +++ b/crates/aprender-core/src/metrics/f32_bits_tests.rs @@ -18,8 +18,10 @@ use super::classification::{f1_score, Average}; use crate::calibration::expected_calibration_error_top_label; -const ECE_FIXTURES: &str = - include_str!("../../../../scripts/setfit_fixtures/claims_stats/ece_top_label_cases.json"); +/// The frozen ECE cases: a workspace file outside this crate, so it is read at RUN time +/// (`provable_contracts::workspace_file_or_skip!`, #4130/#4175). An `include_str!` of it kept the +/// published .crate from compiling this module (#5171). +const ECE_FIXTURES: &str = "scripts/setfit_fixtures/claims_stats/ece_top_label_cases.json"; /// Seeded random cases in the snapshot. const N_RANDOM: u64 = 24; @@ -175,9 +177,11 @@ fn f1_inputs() -> Vec<(String, Vec, Vec)> { out } -/// Every top-label ECE input in snapshot order: `(name, probs, k, labels, bins)`. -fn ece_inputs() -> Vec<(String, Vec, usize, Vec, usize)> { - let doc: serde_json::Value = serde_json::from_str(ECE_FIXTURES).expect("fixture JSON parses"); +/// Every top-label ECE input in snapshot order: `(name, probs, k, labels, bins)`. `None` (after a +/// named SKIP) only out of tree; in tree a missing fixture panics. +fn ece_inputs(test: &str) -> Option, usize, Vec, usize)>> { + let text = provable_contracts::workspace_file_or_skip!(test, ECE_FIXTURES)?; + let doc: serde_json::Value = serde_json::from_str(&text).expect("fixture JSON parses"); let mut out = Vec::new(); for case in doc["cases"].as_array().expect("cases array") { let rows = case["probabilities"].as_array().expect("probabilities"); @@ -208,7 +212,7 @@ fn ece_inputs() -> Vec<(String, Vec, usize, Vec, usize)> { let c = random_case(i); out.push((format!("rand_{i:02}"), c.probs, c.k, c.y_true, RANDOM_BINS)); } - out + Some(out) } fn f1_bits(y_true: &[usize], y_pred: &[usize]) -> [u32; 3] { @@ -345,7 +349,9 @@ fn f32_metrics_are_bit_identical_to_the_frozen_snapshot() { } } - let ece = ece_inputs(); + let Some(ece) = ece_inputs("f32_metrics_are_bit_identical_to_the_frozen_snapshot") else { + return; + }; assert_eq!( ece.len(), ECE_SNAPSHOT.len(), @@ -381,7 +387,7 @@ fn print_f32_snapshot() { } println!("];"); println!("const ECE_SNAPSHOT: &[(&str, u32)] = &["); - for (name, probs, k, labels, bins) in ece_inputs() { + for (name, probs, k, labels, bins) in ece_inputs("print_f32_snapshot").unwrap_or_default() { let bits = expected_calibration_error_top_label(&probs, k, &labels, bins).to_bits(); println!(" (\"{name}\", {bits:#010x}),"); } From 9939c9c4fce91aa64557b3f8bf097b6f305a3f52 Mon Sep 17 00:00:00 2001 From: Noah Gift Date: Mon, 12 Oct 2026 05:14:18 +0200 Subject: [PATCH 2/2] test(metrics): read the ECE fixture through a test_support fn so the shrink report counts the skip (#5171) The tarball shrink report counts skip sites by `*_or_skip(` calls; the macro form `workspace_file_or_skip!(` did not match, so the new out-of-tree skip was invisible to the line that is meant to show every place a published test surface shrinks. Same rule, same panic in tree; only the call form changes. Refs #5171 Agent: aprender-wmainred Co-Authored-By: Claude Opus 5.5 --- crates/aprender-core/src/metrics/f32_bits_tests.rs | 4 ++-- crates/aprender-core/src/test_support.rs | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/aprender-core/src/metrics/f32_bits_tests.rs b/crates/aprender-core/src/metrics/f32_bits_tests.rs index f8f736722d..a355658da0 100644 --- a/crates/aprender-core/src/metrics/f32_bits_tests.rs +++ b/crates/aprender-core/src/metrics/f32_bits_tests.rs @@ -19,7 +19,7 @@ use super::classification::{f1_score, Average}; use crate::calibration::expected_calibration_error_top_label; /// The frozen ECE cases: a workspace file outside this crate, so it is read at RUN time -/// (`provable_contracts::workspace_file_or_skip!`, #4130/#4175). An `include_str!` of it kept the +/// (`crate::test_support::workspace_fixture_or_skip`, #4130/#4175). An `include_str!` of it kept the /// published .crate from compiling this module (#5171). const ECE_FIXTURES: &str = "scripts/setfit_fixtures/claims_stats/ece_top_label_cases.json"; @@ -180,7 +180,7 @@ fn f1_inputs() -> Vec<(String, Vec, Vec)> { /// Every top-label ECE input in snapshot order: `(name, probs, k, labels, bins)`. `None` (after a /// named SKIP) only out of tree; in tree a missing fixture panics. fn ece_inputs(test: &str) -> Option, usize, Vec, usize)>> { - let text = provable_contracts::workspace_file_or_skip!(test, ECE_FIXTURES)?; + let text = crate::test_support::workspace_fixture_or_skip(test, ECE_FIXTURES)?; let doc: serde_json::Value = serde_json::from_str(&text).expect("fixture JSON parses"); let mut out = Vec::new(); for case in doc["cases"].as_array().expect("cases array") { diff --git a/crates/aprender-core/src/test_support.rs b/crates/aprender-core/src/test_support.rs index e5a5ef6f7e..f0cd760345 100644 --- a/crates/aprender-core/src/test_support.rs +++ b/crates/aprender-core/src/test_support.rs @@ -14,6 +14,13 @@ pub(crate) fn workspace_contract_or_skip(test: &str, rel: &str) -> Option Option { + provable_contracts::workspace_file_or_skip!(test, rel) +} + #[cfg(test)] mod tests { /// The real workspace resolves: this build IS in tree, so the helper must find the contract.