commit 68e9202c767c70508d294c75d6ae21b2659d4a48
parent 35c13270bdea0826cda5d9ebb345efe575082666
Author: triesap <tyson@radroots.org>
Date: Tue, 23 Jun 2026 07:39:51 +0000
coverage: enforce final sdk policy gates
- split xtask coverage policy evaluation from command orchestration\n- gate the pure xtask policy evaluator at 100 percent with branch-complete tests\n- remove duplicate wasm generation from the package check script\n- replace the xtask bootstrap exclusion with narrow command-glue exclusions
Diffstat:
6 files changed, 769 insertions(+), 532 deletions(-)
diff --git a/contracts/coverage.toml b/contracts/coverage.toml
@@ -10,14 +10,14 @@ wasm_target = "wasm32-unknown-unknown"
[report]
output = "target/sdk-coverage/summary.json"
-ignore_filename_regex = "(/target/|/\\.cargo/registry/|/Cellar/rust/|/crates/.+_bindings/|/crates/binding_model/|/crates/replica_db_wasm/src/wasm_impl.rs)"
+ignore_filename_regex = "(/target/|/\\.cargo/registry/|/Cellar/rust/|/crates/.+_bindings/|/crates/binding_model/|/crates/replica_db_wasm/src/wasm_impl.rs|/tools/xtask/src/(check|contracts|coverage|fs|generate|main|output|package_matrix|wasm)\\.rs)"
[scopes.radroots_sdk]
paths = ["crates/sdk/src/**"]
threshold = 98.0
-[scopes.xtask]
-paths = ["tools/xtask/src/**"]
+[scopes.xtask_policy]
+paths = ["tools/xtask/src/coverage_policy.rs"]
threshold = 100.0
[scopes.events_codec_wasm]
@@ -53,6 +53,16 @@ reason = "binding crates are generator-owned source facades with behavior covere
paths = ["crates/replica_db_wasm/src/wasm_impl.rs"]
reason = "temporary bootstrap exclusion for the generated-style DB wrapper forwarding file while exported snapshot policy and sync parsing behavior are covered natively"
-[exclusions.xtask_bootstrap]
-paths = ["tools/xtask/**"]
-reason = "temporary bootstrap exclusion until coverage command behavior is stable and the final gate includes xtask coverage"
+[exclusions.xtask_command_glue]
+paths = [
+ "tools/xtask/src/check.rs",
+ "tools/xtask/src/contracts.rs",
+ "tools/xtask/src/coverage.rs",
+ "tools/xtask/src/fs.rs",
+ "tools/xtask/src/generate.rs",
+ "tools/xtask/src/main.rs",
+ "tools/xtask/src/output.rs",
+ "tools/xtask/src/package_matrix.rs",
+ "tools/xtask/src/wasm.rs",
+]
+reason = "xtask command, filesystem, package-generation, and process-runner glue is validated by cargo xtask generate ts, cargo xtask generate wasm, cargo xtask check, package build/typecheck, and cargo xtask coverage run; pure coverage policy enforcement remains under the xtask_policy strict gate"
diff --git a/package.json b/package.json
@@ -5,7 +5,7 @@
"scripts": {
"generate:ts": "cargo xtask generate ts",
"generate:wasm": "cargo xtask generate wasm",
- "check": "cargo xtask generate ts && cargo xtask generate wasm && cargo xtask check && pnpm -r build && pnpm -r typecheck",
+ "check": "cargo xtask generate ts && pnpm -r build && cargo xtask check && pnpm -r typecheck",
"coverage": "cargo xtask coverage run",
"build": "pnpm -r build",
"typecheck": "pnpm -r typecheck"
diff --git a/tools/xtask/src/coverage.rs b/tools/xtask/src/coverage.rs
@@ -1,141 +1,11 @@
-use std::{collections::BTreeMap, fs, path::Path, process::Command};
+use std::{fs, path::Path, process::Command};
-use serde::Deserialize;
-
-use crate::{check, fs::workspace_root, generate, wasm};
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct CoverageContract {
- policy: CoveragePolicy,
- toolchain: CoverageToolchain,
- report: CoverageReport,
- generated: GeneratedCoveragePolicy,
- scopes: BTreeMap<String, CoverageScope>,
- exclusions: BTreeMap<String, CoverageExclusion>,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct CoveragePolicy {
- enforce: bool,
- require_regions: bool,
- require_functions: bool,
- require_lines: bool,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct CoverageToolchain {
- rust: String,
- wasm_target: String,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct CoverageReport {
- output: String,
- ignore_filename_regex: String,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct GeneratedCoveragePolicy {
- typescript: String,
- binding_crates: String,
- wasm_glue: String,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct CoverageScope {
- paths: Vec<String>,
- threshold: f64,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct CoverageExclusion {
- paths: Vec<String>,
- reason: String,
-}
-
-#[derive(Debug, Deserialize)]
-struct LlvmCovReport {
- data: Vec<LlvmCovData>,
-}
-
-#[derive(Debug, Deserialize)]
-struct LlvmCovData {
- files: Vec<LlvmCovFile>,
- totals: LlvmCovSummary,
-}
-
-#[derive(Debug, Deserialize)]
-struct LlvmCovFile {
- filename: String,
- summary: LlvmCovSummary,
-}
-
-#[derive(Debug, Deserialize)]
-struct LlvmCovSummary {
- lines: LlvmCovMetric,
- functions: LlvmCovMetric,
- regions: LlvmCovMetric,
-}
-
-#[derive(Debug, Deserialize)]
-struct LlvmCovMetric {
- count: u64,
- covered: u64,
- percent: f64,
-}
-
-#[derive(Debug, Default)]
-struct MetricAccumulator {
- count: u64,
- covered: u64,
-}
-
-impl MetricAccumulator {
- fn add(&mut self, metric: &LlvmCovMetric) {
- self.count += metric.count;
- self.covered += metric.covered;
- }
-
- fn metric(&self) -> LlvmCovMetric {
- LlvmCovMetric {
- count: self.count,
- covered: self.covered,
- percent: metric_percent(self.count, self.covered),
- }
- }
-}
-
-#[derive(Debug, Default)]
-struct SummaryAccumulator {
- lines: MetricAccumulator,
- functions: MetricAccumulator,
- regions: MetricAccumulator,
- matched_files: usize,
-}
-
-impl SummaryAccumulator {
- fn add(&mut self, summary: &LlvmCovSummary) {
- self.lines.add(&summary.lines);
- self.functions.add(&summary.functions);
- self.regions.add(&summary.regions);
- self.matched_files += 1;
- }
-
- fn summary(&self) -> LlvmCovSummary {
- LlvmCovSummary {
- lines: self.lines.metric(),
- functions: self.functions.metric(),
- regions: self.regions.metric(),
- }
- }
-}
+use crate::{
+ check,
+ coverage_policy::{CoverageContract, evaluate_report, validate_contract},
+ fs::workspace_root,
+ generate, wasm,
+};
pub fn run(args: &[String]) -> Result<(), String> {
match args {
@@ -169,67 +39,6 @@ fn load_contract(root: &Path) -> Result<CoverageContract, String> {
toml::from_str(&raw).map_err(|error| format!("failed to parse {}: {error}", path.display()))
}
-fn validate_contract(contract: &CoverageContract) -> Result<(), String> {
- validate_non_empty(&contract.toolchain.rust, "toolchain.rust")?;
- validate_non_empty(&contract.toolchain.wasm_target, "toolchain.wasm_target")?;
- validate_non_empty(&contract.report.output, "report.output")?;
- validate_non_empty(
- &contract.report.ignore_filename_regex,
- "report.ignore_filename_regex",
- )?;
- validate_non_empty(&contract.generated.typescript, "generated.typescript")?;
- validate_non_empty(
- &contract.generated.binding_crates,
- "generated.binding_crates",
- )?;
- validate_non_empty(&contract.generated.wasm_glue, "generated.wasm_glue")?;
- if contract.scopes.is_empty() {
- return Err("contracts/coverage.toml scopes must not be empty".to_owned());
- }
- for (name, scope) in &contract.scopes {
- validate_non_empty(name, "scope name")?;
- validate_threshold(scope.threshold, &format!("scopes.{name}.threshold"))?;
- if scope.paths.is_empty() {
- return Err(format!("scopes.{name}.paths must not be empty"));
- }
- for path in &scope.paths {
- validate_non_empty(path, &format!("scopes.{name}.paths entry"))?;
- }
- }
- if contract.exclusions.is_empty() {
- return Err("contracts/coverage.toml exclusions must not be empty".to_owned());
- }
- for (name, exclusion) in &contract.exclusions {
- validate_non_empty(name, "exclusion name")?;
- validate_non_empty(&exclusion.reason, &format!("exclusions.{name}.reason"))?;
- if exclusion.paths.is_empty() {
- return Err(format!("exclusions.{name}.paths must not be empty"));
- }
- for path in &exclusion.paths {
- validate_non_empty(path, &format!("exclusions.{name}.paths entry"))?;
- }
- }
- Ok(())
-}
-
-fn validate_threshold(threshold: f64, field: &str) -> Result<(), String> {
- if (0.0..=100.0).contains(&threshold) {
- Ok(())
- } else {
- Err(format!(
- "contracts/coverage.toml {field} must be between 0 and 100"
- ))
- }
-}
-
-fn validate_non_empty(value: &str, field: &str) -> Result<(), String> {
- if value.trim().is_empty() {
- Err(format!("contracts/coverage.toml {field} must not be empty"))
- } else {
- Ok(())
- }
-}
-
fn preflight(contract: &CoverageContract) -> Result<(), String> {
require_command("rustup", &["--version"], "install rustup")?;
require_command(
@@ -335,330 +144,3 @@ fn run_llvm_cov(root: &Path, contract: &CoverageContract) -> Result<(), String>
}
Ok(())
}
-
-fn evaluate_report(
- root: &Path,
- report_path: &Path,
- contract: &CoverageContract,
-) -> Result<(), String> {
- let raw = fs::read_to_string(report_path)
- .map_err(|error| format!("failed to read {}: {error}", report_path.display()))?;
- let report = serde_json::from_str::<LlvmCovReport>(&raw)
- .map_err(|error| format!("failed to parse {}: {error}", report_path.display()))?;
- let data = report
- .data
- .first()
- .ok_or_else(|| format!("{} did not include coverage data", report_path.display()))?;
- validate_metric(
- "total lines",
- &data.totals.lines,
- contract.policy.require_lines,
- )?;
- validate_metric(
- "total functions",
- &data.totals.functions,
- contract.policy.require_functions,
- )?;
- validate_metric(
- "total regions",
- &data.totals.regions,
- contract.policy.require_regions,
- )?;
- let mut failures = Vec::new();
- for (scope_name, scope) in &contract.scopes {
- let scope_summary = match scope_summary(root, data, scope) {
- Ok(summary) => summary,
- Err(error) => {
- failures.push(format!("coverage scope {scope_name}: {error}"));
- continue;
- }
- };
- collect_scope_metric_failure(
- &mut failures,
- scope_name,
- "lines",
- &scope_summary.lines,
- scope.threshold,
- contract.policy.require_lines,
- );
- collect_scope_metric_failure(
- &mut failures,
- scope_name,
- "functions",
- &scope_summary.functions,
- scope.threshold,
- contract.policy.require_functions,
- );
- collect_scope_metric_failure(
- &mut failures,
- scope_name,
- "regions",
- &scope_summary.regions,
- scope.threshold,
- contract.policy.require_regions,
- );
- }
- if !contract.policy.enforce {
- println!(
- "coverage policy parsed and measured; enforcement disabled in {}",
- report_path.display()
- );
- return Ok(());
- }
- if !failures.is_empty() {
- return Err(failures.join("\n"));
- }
- println!("coverage policy passed using {}", report_path.display());
- Ok(())
-}
-
-fn scope_summary(
- root: &Path,
- data: &LlvmCovData,
- scope: &CoverageScope,
-) -> Result<LlvmCovSummary, String> {
- let mut accumulator = SummaryAccumulator::default();
- for file in &data.files {
- let filename = report_filename(root, &file.filename);
- if scope
- .paths
- .iter()
- .any(|pattern| path_matches(pattern, &filename))
- {
- accumulator.add(&file.summary);
- }
- }
- if accumulator.matched_files == 0 {
- return Err(format!(
- "matched no report files for {}",
- scope.paths.join(", ")
- ));
- }
- Ok(accumulator.summary())
-}
-
-fn report_filename(root: &Path, filename: &str) -> String {
- let path = Path::new(filename);
- let relative = path.strip_prefix(root).unwrap_or(path);
- relative.to_string_lossy().replace('\\', "/")
-}
-
-fn path_matches(pattern: &str, path: &str) -> bool {
- if let Some(prefix) = pattern.strip_suffix("/**") {
- path == prefix || path.starts_with(&format!("{prefix}/"))
- } else {
- path == pattern
- }
-}
-
-fn collect_scope_metric_failure(
- failures: &mut Vec<String>,
- scope_name: &str,
- metric_name: &str,
- metric: &LlvmCovMetric,
- threshold: f64,
- required: bool,
-) {
- if let Err(error) = validate_metric(metric_name, metric, required) {
- failures.push(format!("coverage scope {scope_name}: {error}"));
- }
- if let Err(error) = enforce_metric(metric_name, metric, threshold) {
- failures.push(format!("coverage scope {scope_name}: {error}"));
- }
-}
-
-fn validate_metric(name: &str, metric: &LlvmCovMetric, required: bool) -> Result<(), String> {
- if required && metric.count == 0 {
- return Err(format!(
- "coverage report did not include required {name} records"
- ));
- }
- if metric.covered > metric.count {
- return Err(format!("coverage report has invalid {name} counts"));
- }
- Ok(())
-}
-
-fn enforce_metric(name: &str, metric: &LlvmCovMetric, threshold: f64) -> Result<(), String> {
- if metric.percent < threshold {
- return Err(format!(
- "coverage {name} {:.3}% is below required {:.1}%",
- metric.percent, threshold
- ));
- }
- Ok(())
-}
-
-fn metric_percent(count: u64, covered: u64) -> f64 {
- if count == 0 {
- 0.0
- } else {
- covered as f64 * 100.0 / count as f64
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{
- CoverageContract, enforce_metric, evaluate_report, path_matches, validate_contract,
- validate_metric,
- };
-
- const CONTRACT: &str = r#"
-[policy]
-enforce = true
-require_regions = true
-require_functions = true
-require_lines = true
-
-[toolchain]
-rust = "1.92.0"
-wasm_target = "wasm32-unknown-unknown"
-
-[report]
-output = "target/sdk-coverage/summary.json"
-ignore_filename_regex = "generated"
-
-[generated]
-typescript = "excluded because generated TypeScript is owned by Rust source generators"
-binding_crates = "excluded because binding crates are generated source facades"
-wasm_glue = "excluded because wasm-bindgen glue is verified through generated package checks"
-
-[scopes.radroots_sdk]
-paths = ["crates/sdk/src/**"]
-threshold = 98.0
-
-[scopes.xtask]
-paths = ["tools/xtask/src/**"]
-threshold = 100.0
-
-[exclusions.generated]
-paths = ["packages/*/src/generated/**"]
-reason = "generated package output is checked through reproducibility"
-"#;
-
- #[test]
- fn validates_contract_shape() {
- let contract = toml::from_str::<CoverageContract>(CONTRACT).expect("contract parses");
- validate_contract(&contract).expect("contract validates");
- }
-
- #[test]
- fn rejects_invalid_scope_thresholds() {
- let raw = CONTRACT.replace("threshold = 98.0", "threshold = 101.0");
- let contract = toml::from_str::<CoverageContract>(&raw).expect("contract parses");
- assert!(validate_contract(&contract).is_err());
- }
-
- #[test]
- fn matches_recursive_scope_paths() {
- assert!(path_matches(
- "crates/sdk/src/**",
- "crates/sdk/src/adapters/radrootsd.rs"
- ));
- assert!(path_matches("crates/sdk/src/**", "crates/sdk/src"));
- assert!(!path_matches(
- "crates/sdk/src/**",
- "crates/sql_wasm_runtime/src/lib.rs"
- ));
- }
-
- #[test]
- fn accepts_required_metric_counts() {
- let metric = super::LlvmCovMetric {
- count: 10,
- covered: 10,
- percent: 100.0,
- };
- validate_metric("lines", &metric, true).expect("metric validates");
- enforce_metric("lines", &metric, 100.0).expect("metric passes");
- }
-
- #[test]
- fn rejects_missing_required_metric_counts() {
- let metric = super::LlvmCovMetric {
- count: 0,
- covered: 0,
- percent: 0.0,
- };
- assert!(validate_metric("lines", &metric, true).is_err());
- }
-
- #[test]
- fn rejects_under_threshold_metric() {
- let metric = super::LlvmCovMetric {
- count: 10,
- covered: 9,
- percent: 90.0,
- };
- assert!(enforce_metric("lines", &metric, 100.0).is_err());
- }
-
- #[test]
- fn enforcement_rejects_undercovered_scope() {
- let dir = std::env::temp_dir().join(format!(
- "radroots_sdk_xtask_coverage_{}",
- std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .expect("time")
- .as_nanos()
- ));
- std::fs::create_dir_all(&dir).expect("dir");
- let report_path = dir.join("summary.json");
- let filename = dir.join("crates/sdk/src/lib.rs");
- std::fs::write(
- &report_path,
- format!(
- r#"{{"data":[{{"files":[{{"filename":"{}","summary":{{"lines":{{"count":100,"covered":97,"percent":97.0}},"functions":{{"count":100,"covered":98,"percent":98.0}},"regions":{{"count":100,"covered":99,"percent":99.0}}}}}}],"totals":{{"lines":{{"count":100,"covered":97,"percent":97.0}},"functions":{{"count":100,"covered":98,"percent":98.0}},"regions":{{"count":100,"covered":99,"percent":99.0}}}}}}]}}"#,
- filename.display()
- ),
- )
- .expect("report");
- let contract = toml::from_str::<CoverageContract>(&CONTRACT.replace(
- r#"[scopes.xtask]
-paths = ["tools/xtask/src/**"]
-threshold = 100.0
-
-"#,
- "",
- ))
- .expect("contract parses");
- assert!(evaluate_report(&dir, &report_path, &contract).is_err());
- std::fs::remove_dir_all(dir).expect("cleanup");
- }
-
- #[test]
- fn disabled_enforcement_accepts_measured_scope() {
- let dir = std::env::temp_dir().join(format!(
- "radroots_sdk_xtask_coverage_disabled_{}",
- std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .expect("time")
- .as_nanos()
- ));
- std::fs::create_dir_all(&dir).expect("dir");
- let report_path = dir.join("summary.json");
- let filename = dir.join("crates/sdk/src/lib.rs");
- std::fs::write(
- &report_path,
- format!(
- r#"{{"data":[{{"files":[{{"filename":"{}","summary":{{"lines":{{"count":1,"covered":0,"percent":0.0}},"functions":{{"count":1,"covered":0,"percent":0.0}},"regions":{{"count":1,"covered":0,"percent":0.0}}}}}}],"totals":{{"lines":{{"count":1,"covered":0,"percent":0.0}},"functions":{{"count":1,"covered":0,"percent":0.0}},"regions":{{"count":1,"covered":0,"percent":0.0}}}}}}]}}"#,
- filename.display()
- ),
- )
- .expect("report");
- let raw = CONTRACT
- .replace("enforce = true", "enforce = false")
- .replace(
- r#"[scopes.xtask]
-paths = ["tools/xtask/src/**"]
-threshold = 100.0
-
-"#,
- "",
- );
- let contract = toml::from_str::<CoverageContract>(&raw).expect("contract parses");
- evaluate_report(&dir, &report_path, &contract).expect("disabled report passes");
- std::fs::remove_dir_all(dir).expect("cleanup");
- }
-}
diff --git a/tools/xtask/src/coverage_policy.rs b/tools/xtask/src/coverage_policy.rs
@@ -0,0 +1,362 @@
+use std::{collections::BTreeMap, fs, path::Path};
+
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct CoverageContract {
+ policy: CoveragePolicy,
+ pub(crate) toolchain: CoverageToolchain,
+ pub(crate) report: CoverageReport,
+ generated: GeneratedCoveragePolicy,
+ scopes: BTreeMap<String, CoverageScope>,
+ exclusions: BTreeMap<String, CoverageExclusion>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct CoveragePolicy {
+ enforce: bool,
+ require_regions: bool,
+ require_functions: bool,
+ require_lines: bool,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct CoverageToolchain {
+ pub(crate) rust: String,
+ pub(crate) wasm_target: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct CoverageReport {
+ pub(crate) output: String,
+ pub(crate) ignore_filename_regex: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct GeneratedCoveragePolicy {
+ typescript: String,
+ binding_crates: String,
+ wasm_glue: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct CoverageScope {
+ paths: Vec<String>,
+ threshold: f64,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct CoverageExclusion {
+ paths: Vec<String>,
+ reason: String,
+}
+
+#[derive(Debug, Deserialize)]
+struct LlvmCovReport {
+ data: Vec<LlvmCovData>,
+}
+
+#[derive(Debug, Deserialize)]
+struct LlvmCovData {
+ files: Vec<LlvmCovFile>,
+ totals: LlvmCovSummary,
+}
+
+#[derive(Debug, Deserialize)]
+struct LlvmCovFile {
+ filename: String,
+ summary: LlvmCovSummary,
+}
+
+#[derive(Debug, Deserialize)]
+struct LlvmCovSummary {
+ lines: LlvmCovMetric,
+ functions: LlvmCovMetric,
+ regions: LlvmCovMetric,
+}
+
+#[derive(Debug, Deserialize)]
+struct LlvmCovMetric {
+ count: u64,
+ covered: u64,
+ percent: f64,
+}
+
+#[derive(Debug, Default)]
+struct MetricAccumulator {
+ count: u64,
+ covered: u64,
+}
+
+impl MetricAccumulator {
+ fn add(&mut self, metric: &LlvmCovMetric) {
+ self.count += metric.count;
+ self.covered += metric.covered;
+ }
+
+ fn metric(&self) -> LlvmCovMetric {
+ LlvmCovMetric {
+ count: self.count,
+ covered: self.covered,
+ percent: metric_percent(self.count, self.covered),
+ }
+ }
+}
+
+#[derive(Debug, Default)]
+struct SummaryAccumulator {
+ lines: MetricAccumulator,
+ functions: MetricAccumulator,
+ regions: MetricAccumulator,
+ matched_files: usize,
+}
+
+impl SummaryAccumulator {
+ fn add(&mut self, summary: &LlvmCovSummary) {
+ self.lines.add(&summary.lines);
+ self.functions.add(&summary.functions);
+ self.regions.add(&summary.regions);
+ self.matched_files += 1;
+ }
+
+ fn summary(&self) -> LlvmCovSummary {
+ LlvmCovSummary {
+ lines: self.lines.metric(),
+ functions: self.functions.metric(),
+ regions: self.regions.metric(),
+ }
+ }
+}
+
+pub(crate) fn validate_contract(contract: &CoverageContract) -> Result<(), String> {
+ validate_non_empty(&contract.toolchain.rust, "toolchain.rust")?;
+ validate_non_empty(&contract.toolchain.wasm_target, "toolchain.wasm_target")?;
+ validate_non_empty(&contract.report.output, "report.output")?;
+ validate_non_empty(
+ &contract.report.ignore_filename_regex,
+ "report.ignore_filename_regex",
+ )?;
+ validate_non_empty(&contract.generated.typescript, "generated.typescript")?;
+ validate_non_empty(
+ &contract.generated.binding_crates,
+ "generated.binding_crates",
+ )?;
+ validate_non_empty(&contract.generated.wasm_glue, "generated.wasm_glue")?;
+ if contract.scopes.is_empty() {
+ return Err("contracts/coverage.toml scopes must not be empty".to_owned());
+ }
+ for (name, scope) in &contract.scopes {
+ validate_non_empty(name, "scope name")?;
+ validate_threshold(scope.threshold, &format!("scopes.{name}.threshold"))?;
+ if scope.paths.is_empty() {
+ return Err(format!("scopes.{name}.paths must not be empty"));
+ }
+ for path in &scope.paths {
+ validate_non_empty(path, &format!("scopes.{name}.paths entry"))?;
+ }
+ }
+ if contract.exclusions.is_empty() {
+ return Err("contracts/coverage.toml exclusions must not be empty".to_owned());
+ }
+ for (name, exclusion) in &contract.exclusions {
+ validate_non_empty(name, "exclusion name")?;
+ validate_non_empty(&exclusion.reason, &format!("exclusions.{name}.reason"))?;
+ if exclusion.paths.is_empty() {
+ return Err(format!("exclusions.{name}.paths must not be empty"));
+ }
+ for path in &exclusion.paths {
+ validate_non_empty(path, &format!("exclusions.{name}.paths entry"))?;
+ }
+ }
+ Ok(())
+}
+
+fn validate_threshold(threshold: f64, field: &str) -> Result<(), String> {
+ if (0.0..=100.0).contains(&threshold) {
+ Ok(())
+ } else {
+ Err(format!(
+ "contracts/coverage.toml {field} must be between 0 and 100"
+ ))
+ }
+}
+
+fn validate_non_empty(value: &str, field: &str) -> Result<(), String> {
+ if value.trim().is_empty() {
+ Err(format!("contracts/coverage.toml {field} must not be empty"))
+ } else {
+ Ok(())
+ }
+}
+
+pub(crate) fn evaluate_report(
+ root: &Path,
+ report_path: &Path,
+ contract: &CoverageContract,
+) -> Result<(), String> {
+ let raw = fs::read_to_string(report_path)
+ .map_err(|error| format!("failed to read {}: {error}", report_path.display()))?;
+ let report = serde_json::from_str::<LlvmCovReport>(&raw)
+ .map_err(|error| format!("failed to parse {}: {error}", report_path.display()))?;
+ let data = report
+ .data
+ .first()
+ .ok_or_else(|| format!("{} did not include coverage data", report_path.display()))?;
+ validate_metric(
+ "total lines",
+ &data.totals.lines,
+ contract.policy.require_lines,
+ )?;
+ validate_metric(
+ "total functions",
+ &data.totals.functions,
+ contract.policy.require_functions,
+ )?;
+ validate_metric(
+ "total regions",
+ &data.totals.regions,
+ contract.policy.require_regions,
+ )?;
+ let mut failures = Vec::new();
+ for (scope_name, scope) in &contract.scopes {
+ let scope_summary = match scope_summary(root, data, scope) {
+ Ok(summary) => summary,
+ Err(error) => {
+ failures.push(format!("coverage scope {scope_name}: {error}"));
+ continue;
+ }
+ };
+ collect_scope_metric_failure(
+ &mut failures,
+ scope_name,
+ "lines",
+ &scope_summary.lines,
+ scope.threshold,
+ contract.policy.require_lines,
+ );
+ collect_scope_metric_failure(
+ &mut failures,
+ scope_name,
+ "functions",
+ &scope_summary.functions,
+ scope.threshold,
+ contract.policy.require_functions,
+ );
+ collect_scope_metric_failure(
+ &mut failures,
+ scope_name,
+ "regions",
+ &scope_summary.regions,
+ scope.threshold,
+ contract.policy.require_regions,
+ );
+ }
+ if !contract.policy.enforce {
+ println!(
+ "coverage policy parsed and measured; enforcement disabled in {}",
+ report_path.display()
+ );
+ return Ok(());
+ }
+ if !failures.is_empty() {
+ return Err(failures.join("\n"));
+ }
+ println!("coverage policy passed using {}", report_path.display());
+ Ok(())
+}
+
+fn scope_summary(
+ root: &Path,
+ data: &LlvmCovData,
+ scope: &CoverageScope,
+) -> Result<LlvmCovSummary, String> {
+ let mut accumulator = SummaryAccumulator::default();
+ for file in &data.files {
+ let filename = report_filename(root, &file.filename);
+ if scope
+ .paths
+ .iter()
+ .any(|pattern| path_matches(pattern, &filename))
+ {
+ accumulator.add(&file.summary);
+ }
+ }
+ if accumulator.matched_files == 0 {
+ return Err(format!(
+ "matched no report files for {}",
+ scope.paths.join(", ")
+ ));
+ }
+ Ok(accumulator.summary())
+}
+
+fn report_filename(root: &Path, filename: &str) -> String {
+ let path = Path::new(filename);
+ let relative = path.strip_prefix(root).unwrap_or(path);
+ relative.to_string_lossy().replace('\\', "/")
+}
+
+fn path_matches(pattern: &str, path: &str) -> bool {
+ if let Some(prefix) = pattern.strip_suffix("/**") {
+ path == prefix || path.starts_with(&format!("{prefix}/"))
+ } else {
+ path == pattern
+ }
+}
+
+fn collect_scope_metric_failure(
+ failures: &mut Vec<String>,
+ scope_name: &str,
+ metric_name: &str,
+ metric: &LlvmCovMetric,
+ threshold: f64,
+ required: bool,
+) {
+ if let Err(error) = validate_metric(metric_name, metric, required) {
+ failures.push(format!("coverage scope {scope_name}: {error}"));
+ }
+ if let Err(error) = enforce_metric(metric_name, metric, threshold) {
+ failures.push(format!("coverage scope {scope_name}: {error}"));
+ }
+}
+
+fn validate_metric(name: &str, metric: &LlvmCovMetric, required: bool) -> Result<(), String> {
+ if required && metric.count == 0 {
+ return Err(format!(
+ "coverage report did not include required {name} records"
+ ));
+ }
+ if metric.covered > metric.count {
+ return Err(format!("coverage report has invalid {name} counts"));
+ }
+ Ok(())
+}
+
+fn enforce_metric(name: &str, metric: &LlvmCovMetric, threshold: f64) -> Result<(), String> {
+ if metric.percent < threshold {
+ return Err(format!(
+ "coverage {name} {:.3}% is below required {:.1}%",
+ metric.percent, threshold
+ ));
+ }
+ Ok(())
+}
+
+fn metric_percent(count: u64, covered: u64) -> f64 {
+ if count == 0 {
+ 0.0
+ } else {
+ covered as f64 * 100.0 / count as f64
+ }
+}
+
+#[cfg(test)]
+#[path = "coverage_policy_tests.rs"]
+mod tests;
diff --git a/tools/xtask/src/coverage_policy_tests.rs b/tools/xtask/src/coverage_policy_tests.rs
@@ -0,0 +1,382 @@
+use std::{
+ fs,
+ path::PathBuf,
+ time::{SystemTime, UNIX_EPOCH},
+};
+
+use super::{
+ CoverageContract, LlvmCovMetric, enforce_metric, evaluate_report, metric_percent, path_matches,
+ validate_contract, validate_metric,
+};
+
+const CONTRACT: &str = r#"
+[policy]
+enforce = true
+require_regions = true
+require_functions = true
+require_lines = true
+
+[toolchain]
+rust = "1.92.0"
+wasm_target = "wasm32-unknown-unknown"
+
+[report]
+output = "target/sdk-coverage/summary.json"
+ignore_filename_regex = "generated"
+
+[generated]
+typescript = "generated TypeScript is checked elsewhere"
+binding_crates = "generated binding crates are checked elsewhere"
+wasm_glue = "wasm glue is checked through package validation"
+
+[scopes.xtask_policy]
+paths = ["tools/xtask/src/coverage_policy.rs"]
+threshold = 100.0
+
+[exclusions.generated]
+paths = ["packages/*/src/generated/**"]
+reason = "generated output is checked through reproducibility"
+"#;
+
+#[derive(Clone, Copy)]
+struct Metrics {
+ lines: (u64, u64, f64),
+ functions: (u64, u64, f64),
+ regions: (u64, u64, f64),
+}
+
+fn covered() -> Metrics {
+ Metrics {
+ lines: (100, 100, 100.0),
+ functions: (50, 50, 100.0),
+ regions: (200, 200, 100.0),
+ }
+}
+
+fn contract(raw: &str) -> CoverageContract {
+ toml::from_str::<CoverageContract>(raw).expect("contract parses")
+}
+
+fn test_root(name: &str) -> PathBuf {
+ let stamp = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .expect("time")
+ .as_nanos();
+ let root = std::env::temp_dir().join(format!(
+ "radroots_sdk_coverage_policy_{name}_{}_{}",
+ std::process::id(),
+ stamp
+ ));
+ let _ = fs::remove_dir_all(&root);
+ fs::create_dir_all(&root).expect("create root");
+ root
+}
+
+fn metric_json(metric: (u64, u64, f64)) -> String {
+ format!(
+ r#"{{"count":{},"covered":{},"percent":{}}}"#,
+ metric.0, metric.1, metric.2
+ )
+}
+
+fn summary_json(metrics: Metrics) -> String {
+ format!(
+ r#"{{"lines":{},"functions":{},"regions":{}}}"#,
+ metric_json(metrics.lines),
+ metric_json(metrics.functions),
+ metric_json(metrics.regions)
+ )
+}
+
+fn report_json(filename: &str, file_metrics: Metrics, totals: Metrics) -> String {
+ format!(
+ r#"{{"data":[{{"files":[{{"filename":"{}","summary":{}}}],"totals":{}}}]}}"#,
+ filename,
+ summary_json(file_metrics),
+ summary_json(totals)
+ )
+}
+
+fn write_report(root: &PathBuf, raw: &str) -> PathBuf {
+ let report_path = root.join("summary.json");
+ fs::write(&report_path, raw).expect("write report");
+ report_path
+}
+
+fn scope_file(root: &PathBuf) -> String {
+ root.join("tools/xtask/src/coverage_policy.rs")
+ .display()
+ .to_string()
+}
+
+#[test]
+fn validates_contract_shape() {
+ validate_contract(&contract(CONTRACT)).expect("contract validates");
+}
+
+#[test]
+fn rejects_blank_contract_fields() {
+ let cases = [
+ ("rust = \"1.92.0\"", "rust = \" \"", "toolchain.rust"),
+ (
+ "wasm_target = \"wasm32-unknown-unknown\"",
+ "wasm_target = \" \"",
+ "toolchain.wasm_target",
+ ),
+ (
+ "output = \"target/sdk-coverage/summary.json\"",
+ "output = \" \"",
+ "report.output",
+ ),
+ (
+ "ignore_filename_regex = \"generated\"",
+ "ignore_filename_regex = \" \"",
+ "report.ignore_filename_regex",
+ ),
+ (
+ "typescript = \"generated TypeScript is checked elsewhere\"",
+ "typescript = \" \"",
+ "generated.typescript",
+ ),
+ (
+ "binding_crates = \"generated binding crates are checked elsewhere\"",
+ "binding_crates = \" \"",
+ "generated.binding_crates",
+ ),
+ (
+ "wasm_glue = \"wasm glue is checked through package validation\"",
+ "wasm_glue = \" \"",
+ "generated.wasm_glue",
+ ),
+ (
+ "paths = [\"tools/xtask/src/coverage_policy.rs\"]",
+ "paths = [\" \"]",
+ "scopes.xtask_policy.paths entry",
+ ),
+ (
+ "reason = \"generated output is checked through reproducibility\"",
+ "reason = \" \"",
+ "exclusions.generated.reason",
+ ),
+ (
+ "paths = [\"packages/*/src/generated/**\"]",
+ "paths = [\" \"]",
+ "exclusions.generated.paths entry",
+ ),
+ ];
+
+ for (from, to, expected) in cases {
+ let raw = CONTRACT.replace(from, to);
+ let error = validate_contract(&contract(&raw)).expect_err("invalid contract");
+ assert!(error.contains(expected), "{error}");
+ }
+}
+
+#[test]
+fn rejects_contract_collection_errors() {
+ let mut no_scopes = contract(CONTRACT);
+ no_scopes.scopes.clear();
+ assert_eq!(
+ validate_contract(&no_scopes).unwrap_err(),
+ "contracts/coverage.toml scopes must not be empty"
+ );
+
+ let mut no_exclusions = contract(CONTRACT);
+ no_exclusions.exclusions.clear();
+ assert_eq!(
+ validate_contract(&no_exclusions).unwrap_err(),
+ "contracts/coverage.toml exclusions must not be empty"
+ );
+
+ let cases = [
+ (
+ CONTRACT.replace("[scopes.xtask_policy]", "[scopes.\"\"]"),
+ "scope name",
+ ),
+ (
+ CONTRACT.replace("[exclusions.generated]", "[exclusions.\"\"]"),
+ "exclusion name",
+ ),
+ (
+ CONTRACT.replace("threshold = 100.0", "threshold = 101.0"),
+ "scopes.xtask_policy.threshold",
+ ),
+ (
+ CONTRACT.replace(
+ "paths = [\"tools/xtask/src/coverage_policy.rs\"]",
+ "paths = []",
+ ),
+ "scopes.xtask_policy.paths must not be empty",
+ ),
+ (
+ CONTRACT.replace("paths = [\"packages/*/src/generated/**\"]", "paths = []"),
+ "exclusions.generated.paths must not be empty",
+ ),
+ ];
+
+ for (raw, expected) in cases {
+ let error = validate_contract(&contract(&raw)).expect_err("invalid contract");
+ assert!(error.contains(expected), "{error}");
+ }
+}
+
+#[test]
+fn matches_recursive_scope_paths() {
+ assert!(path_matches(
+ "crates/sdk/src/**",
+ "crates/sdk/src/adapters/radrootsd.rs"
+ ));
+ assert!(path_matches("crates/sdk/src/**", "crates/sdk/src"));
+ assert!(path_matches(
+ "tools/xtask/src/coverage_policy.rs",
+ "tools/xtask/src/coverage_policy.rs"
+ ));
+ assert!(!path_matches(
+ "crates/sdk/src/**",
+ "crates/sql_wasm_runtime/src/lib.rs"
+ ));
+}
+
+#[test]
+fn accepts_passing_reports_and_rejects_undercovered_scopes() {
+ let root = test_root("passing_and_undercovered");
+ let filename = scope_file(&root);
+ let passing_report = report_json(&filename, covered(), covered());
+ let report_path = write_report(&root, &passing_report);
+ evaluate_report(&root, &report_path, &contract(CONTRACT)).expect("passing report");
+
+ let mut undercovered = covered();
+ undercovered.lines = (100, 99, 99.0);
+ let failing_report = report_json(&filename, undercovered, covered());
+ fs::write(&report_path, failing_report).expect("write failing report");
+ let error = evaluate_report(&root, &report_path, &contract(CONTRACT))
+ .expect_err("undercovered report rejected");
+ assert!(error.contains("coverage scope xtask_policy"), "{error}");
+ fs::remove_dir_all(root).expect("cleanup");
+}
+
+#[test]
+fn disabled_enforcement_accepts_measured_undercoverage() {
+ let root = test_root("disabled");
+ let filename = scope_file(&root);
+ let mut undercovered = covered();
+ undercovered.lines = (100, 0, 0.0);
+ undercovered.functions = (50, 0, 0.0);
+ undercovered.regions = (200, 0, 0.0);
+ let report_path = write_report(&root, &report_json(&filename, undercovered, undercovered));
+ let raw = CONTRACT.replace("enforce = true", "enforce = false");
+ evaluate_report(&root, &report_path, &contract(&raw)).expect("disabled policy passes");
+ fs::remove_dir_all(root).expect("cleanup");
+}
+
+#[test]
+fn rejects_unreadable_malformed_and_empty_reports() {
+ let root = test_root("bad_reports");
+ let missing = root.join("missing.json");
+ assert!(evaluate_report(&root, &missing, &contract(CONTRACT)).is_err());
+
+ let malformed = write_report(&root, "{");
+ assert!(evaluate_report(&root, &malformed, &contract(CONTRACT)).is_err());
+
+ fs::write(&malformed, r#"{"data":[]}"#).expect("write empty report");
+ assert!(evaluate_report(&root, &malformed, &contract(CONTRACT)).is_err());
+ fs::remove_dir_all(root).expect("cleanup");
+}
+
+#[test]
+fn rejects_required_total_metric_failures() {
+ let root = test_root("total_metrics");
+ let filename = scope_file(&root);
+ let mut totals = covered();
+ let cases = [
+ Metrics {
+ lines: (0, 0, 0.0),
+ ..totals
+ },
+ {
+ totals = covered();
+ totals.functions = (0, 0, 0.0);
+ totals
+ },
+ {
+ totals = covered();
+ totals.regions = (0, 0, 0.0);
+ totals
+ },
+ {
+ totals = covered();
+ totals.lines = (1, 2, 200.0);
+ totals
+ },
+ ];
+
+ let report_path = root.join("summary.json");
+ for total_metrics in cases {
+ fs::write(
+ &report_path,
+ report_json(&filename, covered(), total_metrics),
+ )
+ .expect("write report");
+ assert!(evaluate_report(&root, &report_path, &contract(CONTRACT)).is_err());
+ }
+ fs::remove_dir_all(root).expect("cleanup");
+}
+
+#[test]
+fn rejects_scope_metric_validation_and_missing_scope_files() {
+ let root = test_root("scope_metrics");
+ let filename = scope_file(&root);
+ let other_filename = root
+ .join("tools/xtask/src/coverage.rs")
+ .display()
+ .to_string();
+ let report_path = root.join("summary.json");
+
+ fs::write(
+ &report_path,
+ report_json(&other_filename, covered(), covered()),
+ )
+ .expect("write unmatched report");
+ let error = evaluate_report(&root, &report_path, &contract(CONTRACT))
+ .expect_err("unmatched scope rejected");
+ assert!(error.contains("matched no report files"), "{error}");
+
+ let mut invalid = covered();
+ invalid.lines = (0, 0, 0.0);
+ fs::write(&report_path, report_json(&filename, invalid, covered())).expect("write report");
+ assert!(evaluate_report(&root, &report_path, &contract(CONTRACT)).is_err());
+
+ invalid = covered();
+ invalid.functions = (1, 2, 200.0);
+ fs::write(&report_path, report_json(&filename, invalid, covered())).expect("write report");
+ assert!(evaluate_report(&root, &report_path, &contract(CONTRACT)).is_err());
+ fs::remove_dir_all(root).expect("cleanup");
+}
+
+#[test]
+fn metric_helpers_cover_edges() {
+ let valid = LlvmCovMetric {
+ count: 10,
+ covered: 10,
+ percent: 100.0,
+ };
+ validate_metric("lines", &valid, true).expect("metric validates");
+ enforce_metric("lines", &valid, 100.0).expect("metric passes");
+
+ let missing = LlvmCovMetric {
+ count: 0,
+ covered: 0,
+ percent: 0.0,
+ };
+ assert!(validate_metric("lines", &missing, true).is_err());
+ assert!(enforce_metric("lines", &missing, 100.0).is_err());
+
+ let invalid = LlvmCovMetric {
+ count: 1,
+ covered: 2,
+ percent: 200.0,
+ };
+ assert!(validate_metric("lines", &invalid, true).is_err());
+ assert_eq!(metric_percent(0, 0), 0.0);
+ assert_eq!(metric_percent(4, 2), 50.0);
+}
diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs
@@ -1,6 +1,7 @@
mod check;
mod contracts;
mod coverage;
+mod coverage_policy;
mod fs;
mod generate;
mod manifest;