koala-core 1.0.4

Shared types, invariant evaluator, and primitives for the koala framework.
Documentation
//! Performance baseline check: pass/fail decision for a measured p99
//! against a stored baseline. The actual measurement comes from
//! criterion (or any timing harness) — this module owns the policy.
//!
//! v1.0 spec: a measurement that exceeds `baseline + tolerance` is a
//! Fail; under-or-equal is Pass; missing baseline is Skip (informational
//! first run).

use std::time::Duration;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Baseline {
    pub p99: Duration,
    /// Allowed slack above baseline. 5–10 % is typical to avoid flakes.
    pub tolerance: Duration,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PerfDecision {
    Pass {
        measured: Duration,
        ceiling: Duration,
    },
    Fail {
        measured: Duration,
        ceiling: Duration,
        excess: Duration,
    },
    Skip {
        reason: &'static str,
    },
}

pub fn evaluate_against_baseline(measured: Duration, baseline: Option<Baseline>) -> PerfDecision {
    let Some(baseline) = baseline else {
        return PerfDecision::Skip {
            reason: "no baseline yet — record this run as the first sample",
        };
    };
    let ceiling = baseline.p99 + baseline.tolerance;
    if measured <= ceiling {
        PerfDecision::Pass { measured, ceiling }
    } else {
        PerfDecision::Fail {
            measured,
            ceiling,
            excess: measured - ceiling,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn perf_baseline_regression_blocks() {
        // Baseline 5 ms ± 1 ms tolerance → ceiling 6 ms.
        let baseline = Baseline {
            p99: Duration::from_millis(5),
            tolerance: Duration::from_millis(1),
        };
        // 7 ms measurement is 1 ms above ceiling → must Fail.
        let decision = evaluate_against_baseline(Duration::from_millis(7), Some(baseline));
        match decision {
            PerfDecision::Fail {
                measured,
                ceiling,
                excess,
            } => {
                assert_eq!(measured, Duration::from_millis(7));
                assert_eq!(ceiling, Duration::from_millis(6));
                assert_eq!(excess, Duration::from_millis(1));
            }
            other => panic!("expected Fail, got {other:?}"),
        }
    }

    #[test]
    fn within_tolerance_passes() {
        let baseline = Baseline {
            p99: Duration::from_millis(5),
            tolerance: Duration::from_millis(1),
        };
        assert!(matches!(
            evaluate_against_baseline(Duration::from_millis(6), Some(baseline)),
            PerfDecision::Pass { .. }
        ));
        assert!(matches!(
            evaluate_against_baseline(Duration::from_millis(3), Some(baseline)),
            PerfDecision::Pass { .. }
        ));
    }

    #[test]
    fn no_baseline_is_skip() {
        let decision = evaluate_against_baseline(Duration::from_millis(42), None);
        assert!(matches!(decision, PerfDecision::Skip { .. }));
    }

    #[test]
    fn at_ceiling_passes() {
        let baseline = Baseline {
            p99: Duration::from_millis(10),
            tolerance: Duration::from_millis(2),
        };
        // Exactly at ceiling — Pass (≤).
        assert!(matches!(
            evaluate_against_baseline(Duration::from_millis(12), Some(baseline)),
            PerfDecision::Pass { .. }
        ));
    }
}