use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum VerdictStatus {
Pass,
Fail,
Abstain,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum RerunStrategy {
Single,
#[default]
SequentialSprt,
AlwaysThree,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum TieBreakPolicy {
#[default]
FailClosed,
Quarantine,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ReliabilityConfig {
pub borderline_min: f64,
pub borderline_max: f64,
pub rerun_strategy: RerunStrategy,
pub max_extra_calls_per_test: u32,
pub max_extra_calls_per_run: u32,
pub tie_break: TieBreakPolicy,
pub blind_labeling: bool,
pub order_randomized: bool,
pub hijack_defense: bool,
}
impl Default for ReliabilityConfig {
fn default() -> Self {
Self {
borderline_min: 0.4,
borderline_max: 0.6,
rerun_strategy: RerunStrategy::SequentialSprt,
max_extra_calls_per_test: 2,
max_extra_calls_per_run: 20,
tie_break: TieBreakPolicy::FailClosed,
blind_labeling: true,
order_randomized: true,
hijack_defense: true,
}
}
}
impl ReliabilityConfig {
pub fn assess(&self, score: f64) -> VerdictStatus {
if score >= self.borderline_min && score <= self.borderline_max {
VerdictStatus::Abstain
} else if score > self.borderline_max {
VerdictStatus::Pass
} else {
VerdictStatus::Fail
}
}
pub fn triggers_rerun(&self, score: f64, iteration: u32) -> bool {
match self.rerun_strategy {
RerunStrategy::Single => false,
RerunStrategy::AlwaysThree => iteration < 3,
RerunStrategy::SequentialSprt => {
iteration < 2 || (score >= self.borderline_min && score <= self.borderline_max)
}
}
}
}