commit 6014c14bba0548a018bd3a2205064a3bd2c9ac7c
parent 50d83b8b6ba8c96ad01908ff87fe5f31f169a823
Author: triesap <tyson@radroots.org>
Date: Sat, 21 Feb 2026 16:58:57 +0000
xtask: add coverage gate evaluator and branch enforcement
- add threshold and gate result models for deterministic coverage evaluation
- enforce required branch data handling in gate evaluation logic
- emit exact fail reason strings for executable lines functions and branches
- run cargo check -q -p xtask and cargo test -q -p xtask
Diffstat:
1 file changed, 63 insertions(+), 0 deletions(-)
diff --git a/crates/xtask/src/coverage.rs b/crates/xtask/src/coverage.rs
@@ -30,6 +30,20 @@ pub struct LcovCoverage {
pub branch_percent: Option<f64>,
}
+#[derive(Debug, Clone, Copy)]
+pub struct CoverageThresholds {
+ pub fail_under_exec_lines: f64,
+ pub fail_under_functions: f64,
+ pub fail_under_branches: f64,
+ pub require_branches: bool,
+}
+
+#[derive(Debug, Clone)]
+pub struct CoverageGateResult {
+ pub pass: bool,
+ pub fail_reasons: Vec<String>,
+}
+
#[derive(Debug, Deserialize)]
struct LlvmCovSummaryRoot {
data: Vec<LlvmCovSummaryData>,
@@ -155,6 +169,55 @@ pub fn read_lcov(path: &Path) -> Result<LcovCoverage, String> {
})
}
+pub fn evaluate_gate(
+ summary: &CoverageSummary,
+ lcov: &LcovCoverage,
+ thresholds: CoverageThresholds,
+) -> CoverageGateResult {
+ let exec_ok = lcov.executable_percent >= thresholds.fail_under_exec_lines;
+ let functions_ok = summary.functions_percent >= thresholds.fail_under_functions;
+ let branch_presence_ok = !thresholds.require_branches || lcov.branches_available;
+
+ let mut branch_ok = true;
+ if lcov.branches_available {
+ if let Some(branch_percent) = lcov.branch_percent {
+ branch_ok = branch_percent >= thresholds.fail_under_branches;
+ }
+ }
+
+ let pass = exec_ok && functions_ok && branch_presence_ok && branch_ok;
+ let mut fail_reasons: Vec<String> = Vec::new();
+
+ if !exec_ok {
+ fail_reasons.push(format!(
+ "executable_lines={:.6} < {:.6}",
+ lcov.executable_percent, thresholds.fail_under_exec_lines
+ ));
+ }
+
+ if !functions_ok {
+ fail_reasons.push(format!(
+ "functions={:.6} < {:.6}",
+ summary.functions_percent, thresholds.fail_under_functions
+ ));
+ }
+
+ if thresholds.require_branches && !lcov.branches_available {
+ fail_reasons.push("branches=unavailable".to_string());
+ }
+
+ if lcov.branches_available && !branch_ok {
+ if let Some(branch_percent) = lcov.branch_percent {
+ fail_reasons.push(format!(
+ "branches={:.6} < {:.6}",
+ branch_percent, thresholds.fail_under_branches
+ ));
+ }
+ }
+
+ CoverageGateResult { pass, fail_reasons }
+}
+
pub fn run(args: &[String]) -> Result<(), String> {
match args.first().map(String::as_str) {
Some("help") => Ok(()),