///|
/// Machine-readable contract checks for production analytics inputs.
pub struct ContractCheck {
name : String
passed : Bool
observed : Double
expected : Double
message : String
}
///|
pub struct ContractSummary {
checks : Array[ContractCheck]
passed : Int
failed : Int
score : Double
}
///|
pub fn contract_check(
name : String,
passed : Bool,
observed : Double,
expected : Double,
message : String,
) -> ContractCheck {
{ name, passed, observed, expected, message }
}
///|
pub fn contract_summary(checks : Array[ContractCheck]) -> ContractSummary {
let mut passed = 0
for check in checks {
if check.passed {
passed += 1
}
}
{
checks,
passed,
failed: checks.length() - passed,
score: if checks.length() == 0 {
1.0
} else {
passed.to_double() / checks.length().to_double()
},
}
}
///|
pub fn contract_numeric(data : Array[Double]) -> ContractSummary {
let checks = [
contract_check(
"non-empty",
data.length() > 0,
data.length().to_double(),
1.0,
"input must contain observations",
),
contract_check(
"finite",
validation_finite(data, "numeric").failed == 0,
data.length().to_double(),
data.length().to_double(),
"values must be finite",
),
contract_check(
"variance",
sample_variance(data) >= 0.0,
sample_variance(data),
0.0,
"variance cannot be negative",
),
]
contract_summary(checks)
}
///|
pub fn contract_pair(
left : Array[Double],
right : Array[Double],
) -> ContractSummary {
let checks = [
contract_check(
"same-length",
left.length() == right.length(),
left.length().to_double(),
right.length().to_double(),
"paired inputs must align",
),
contract_check(
"left-finite",
validation_finite(left, "left").failed == 0,
left.length().to_double(),
left.length().to_double(),
"left values must be finite",
),
contract_check(
"right-finite",
validation_finite(right, "right").failed == 0,
right.length().to_double(),
right.length().to_double(),
"right values must be finite",
),
]
contract_summary(checks)
}
///|
pub fn contract_probability(data : Array[Double]) -> ContractSummary {
let checks = [
contract_check(
"probability-range",
validation_probability(data, "probability").failed == 0,
min_value(data),
0.0,
"probabilities must be bounded",
),
contract_check(
"probability-upper",
max_value(data) <= 1.0,
max_value(data),
1.0,
"probabilities must not exceed one",
),
]
contract_summary(checks)
}
///|
pub fn contract_matrix(matrix : Array[Array[Double]]) -> ContractSummary {
let report = validation_matrix(matrix, "matrix")
contract_summary([
contract_check(
"matrix-valid",
report.failed == 0,
report.score,
1.0,
"matrix must be rectangular and finite",
),
])
}
///|
pub fn contract_passed(summary : ContractSummary) -> Bool {
summary.failed == 0
}
///|
pub fn contract_score(summary : ContractSummary) -> Double {
summary.score
}
///|
pub fn contract_names(summary : ContractSummary) -> Array[String] {
let result = []
for check in summary.checks {
result.push(check.name)
}
result
}
///|
pub fn contract_failures(summary : ContractSummary) -> Array[ContractCheck] {
let result = []
for check in summary.checks {
if !check.passed {
result.push(check)
}
}
result
}
///|
pub fn contract_lines(summary : ContractSummary) -> Array[String] {
let lines = [
"passed=" + summary.passed.to_string(),
"failed=" + summary.failed.to_string(),
"score=" + summary.score.to_string(),
]
for check in summary.checks {
lines.push(
check.name +
"|" +
check.passed.to_string() +
"|" +
check.observed.to_string() +
"|" +
check.expected.to_string() +
"|" +
check.message,
)
}
lines
}
///|
pub fn contract_string(summary : ContractSummary) -> String {
contract_lines(summary).join("\n")
}
///|
pub fn contract_merge(
left : ContractSummary,
right : ContractSummary,
) -> ContractSummary {
let checks = left.checks.copy()
for check in right.checks {
checks.push(check)
}
contract_summary(checks)
}
///|
pub fn contract_batch(data_sets : Array[Array[Double]]) -> Array[Double] {
let result = []
for data in data_sets {
result.push(contract_score(contract_numeric(data)))
}
result
}
///|
pub fn contract_quality_gate(data : Array[Double], threshold : Double) -> Bool {
contract_score(contract_numeric(data)) >= threshold
}
///|
pub fn contract_summary_vector(summary : ContractSummary) -> Array[Double] {
[
summary.passed.to_double(),
summary.failed.to_double(),
summary.score,
if contract_passed(summary) {
1.0
} else {
0.0
},
]
}