///|
/// Compact evidence records for local acceptance runs.
pub struct EvidenceRecord {
name : String
metric : String
value : Int
expected : Int
passed : Bool
}
///|
/// Create an evidence record.
pub fn evidence_record(
name : String,
metric : String,
value : Int,
expected : Int,
passed : Bool,
) -> EvidenceRecord {
{ name, metric, value, expected, passed }
}
///|
pub fn EvidenceRecord::passed(self : EvidenceRecord) -> Bool {
self.passed
}
///|
pub fn EvidenceRecord::value(self : EvidenceRecord) -> Int {
self.value
}
///|
pub fn EvidenceRecord::expected(self : EvidenceRecord) -> Int {
self.expected
}
///|
pub fn EvidenceRecord::describe(self : EvidenceRecord) -> String {
"\{self.name}:\{self.metric}=\{self.value}/\{self.expected} (\{self.passed})"
}
///|
/// A collection of evidence records.
pub struct EvidenceBundle {
records : Array[EvidenceRecord]
}
///|
/// Create a bundle.
pub fn evidence_bundle() -> EvidenceBundle {
{ records: [] }
}
///|
pub fn EvidenceBundle::add(
self : EvidenceBundle,
record : EvidenceRecord,
) -> Bool {
self.records.push(record)
true
}
///|
pub fn EvidenceBundle::length(self : EvidenceBundle) -> Int {
self.records.length()
}
///|
pub fn EvidenceBundle::passed(self : EvidenceBundle) -> Bool {
for record in self.records {
if !record.passed {
return false
}
}
true
}
///|
pub fn EvidenceBundle::failure_count(self : EvidenceBundle) -> Int {
let mut result = 0
for record in self.records {
if !record.passed {
result += 1
}
}
result
}
///|
pub fn EvidenceBundle::values(self : EvidenceBundle) -> Array[Int] {
self.records.map(record => record.value)
}
///|
pub fn EvidenceBundle::describe(self : EvidenceBundle) -> String {
let builder = StringBuilder()
for index, record in self.records {
if index > 0 {
builder.write_char('\n')
}
builder.write_string(record.describe())
}
builder.to_string()
}
///|
pub fn EvidenceBundle::signature(self : EvidenceBundle) -> Int {
let mut result = 31
for record in self.records {
result = result * 37 + record.value + record.expected
}
result
}
///|
/// Add a minimum evidence gate.
pub fn EvidenceBundle::minimum(
self : EvidenceBundle,
name : String,
metric : String,
value : Int,
expected : Int,
) -> Unit {
ignore(
self.add(evidence_record(name, metric, value, expected, value >= expected)),
)
}
///|
/// Add a maximum evidence gate.
pub fn EvidenceBundle::maximum(
self : EvidenceBundle,
name : String,
metric : String,
value : Int,
expected : Int,
) -> Unit {
ignore(
self.add(evidence_record(name, metric, value, expected, value <= expected)),
)
}
///|
/// Add an exact evidence gate.
pub fn EvidenceBundle::exact(
self : EvidenceBundle,
name : String,
metric : String,
value : Int,
expected : Int,
) -> Unit {
ignore(
self.add(evidence_record(name, metric, value, expected, value == expected)),
)
}
///|
/// Build source-scale evidence.
pub fn source_scale_evidence(lines : Int, target : Int) -> EvidenceBundle {
let bundle = evidence_bundle()
bundle.minimum(
"production-source", "noncomment-nonblank-lines", lines, target,
)
bundle
}
///|
/// Build benchmark evidence.
pub fn benchmark_evidence(
suite : BenchmarkArtifactSuite,
minimum_cases : Int,
) -> EvidenceBundle {
let bundle = evidence_bundle()
bundle.minimum("benchmark-suite", "cases", suite.length(), minimum_cases)
bundle.exact(
"benchmark-suite",
"all-solved",
if suite.all_solved() {
1
} else {
0
},
1,
)
bundle.minimum("benchmark-suite", "total-work", suite.total_work(), 0)
bundle
}
///|
/// Build model evidence.
pub fn model_evidence(report : ModelReport) -> EvidenceBundle {
let bundle = evidence_bundle()
bundle.minimum(report.name, "variables", report.variables, 1)
bundle.minimum(report.name, "constraints", report.constraints, 1)
bundle.exact(report.name, "solved", if report.solved { 1 } else { 0 }, 1)
bundle
}
///|
/// Compare two evidence bundles.
pub fn compare_evidence(left : EvidenceBundle, right : EvidenceBundle) -> Int {
right.failure_count() - left.failure_count()
}
///|
/// Return the number of passing records.
pub fn evidence_pass_count(bundle : EvidenceBundle) -> Int {
bundle.length() - bundle.failure_count()
}
///|
/// Return a stable evidence summary.
pub fn evidence_summary(bundle : EvidenceBundle) -> String {
"records=\{bundle.length()}, passed=\{evidence_pass_count(bundle)}, failed=\{bundle.failure_count()}, status=\{bundle.passed()}"
}