pub const AC_CRUX_001_REQUIRED_STORY_COUNT: usize = 250;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux001Verdict { Pass, Fail }
#[must_use]
pub const fn verdict_from_story_count(observed: usize) -> Crux001Verdict {
if observed == AC_CRUX_001_REQUIRED_STORY_COUNT { Crux001Verdict::Pass } else { Crux001Verdict::Fail }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux002Verdict { Pass, Fail }
#[must_use]
pub fn verdict_from_contract_paths_exist(
referenced: &[String],
existing: &[String],
) -> Crux002Verdict {
if referenced.is_empty() { return Crux002Verdict::Fail; }
for c in referenced {
if !existing.iter().any(|e| e == c) { return Crux002Verdict::Fail; }
}
Crux002Verdict::Pass
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux003Verdict { Pass, Fail }
#[must_use]
pub fn verdict_from_supported_have_golden(stories: &[(bool, bool)]) -> Crux003Verdict {
if stories.is_empty() { return Crux003Verdict::Fail; }
for &(supported, has_golden) in stories {
if supported && !has_golden { return Crux003Verdict::Fail; }
}
Crux003Verdict::Pass
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux004Verdict { Pass, Fail }
#[must_use]
pub fn verdict_from_category_j_pending(category_j_interpretations: &[&str]) -> Crux004Verdict {
if category_j_interpretations.is_empty() { return Crux004Verdict::Fail; }
for s in category_j_interpretations {
if *s != "pending" { return Crux004Verdict::Fail; }
}
Crux004Verdict::Pass
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CruxStatus { Supported, InProgress, Missing, Pending }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux005Verdict { Pass, Fail }
#[must_use]
pub const fn verdict_from_coverage_monotone(
prev: CruxStatus,
next: CruxStatus,
has_defect_ticket: bool,
) -> Crux005Verdict {
let is_regression = matches!(prev, CruxStatus::Supported) && !matches!(next, CruxStatus::Supported);
if is_regression && !has_defect_ticket { Crux005Verdict::Fail } else { Crux005Verdict::Pass }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux006Verdict { Pass, Fail }
#[must_use]
pub const fn verdict_from_sdk_compatibility(
supported_claim: bool,
sdk_tests_pass: bool,
) -> Crux006Verdict {
if supported_claim && !sdk_tests_pass { Crux006Verdict::Fail } else { Crux006Verdict::Pass }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux007Verdict { Pass, Fail }
#[must_use]
pub fn verdict_from_missing_has_ticket(stories: &[(CruxStatus, bool)]) -> Crux007Verdict {
if stories.is_empty() { return Crux007Verdict::Fail; }
for &(status, has_ticket) in stories {
if matches!(status, CruxStatus::Missing) && !has_ticket {
return Crux007Verdict::Fail;
}
}
Crux007Verdict::Pass
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux008Verdict { Pass, Fail }
#[must_use]
pub fn expected_priority(demand_score: u8) -> Option<&'static str> {
match demand_score {
5 => Some("critical"),
4 => Some("high"),
3 => Some("medium"),
2 => Some("low"),
1 => Some("minor"),
_ => None,
}
}
#[must_use]
pub fn verdict_from_priority_alignment(demand_score: u8, priority: &str) -> Crux008Verdict {
match expected_priority(demand_score) {
Some(expected) if expected == priority => Crux008Verdict::Pass,
_ => Crux008Verdict::Fail,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux009Verdict { Pass, Fail }
#[must_use]
pub const fn verdict_from_demand_score_range(demand_score: u8) -> Crux009Verdict {
if matches!(demand_score, 1..=5) { Crux009Verdict::Pass } else { Crux009Verdict::Fail }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Crux010Verdict { Pass, Fail }
#[must_use]
pub fn verdict_from_coverage_table_match(
yaml_counts: (u64, u64, u64, u64),
md_counts: (u64, u64, u64, u64),
) -> Crux010Verdict {
if yaml_counts == md_counts { Crux010Verdict::Pass } else { Crux010Verdict::Fail }
}
#[cfg(test)]
mod tests {
use super::*;
#[test] fn crux001_pass_250() { assert_eq!(verdict_from_story_count(250), Crux001Verdict::Pass); }
#[test] fn crux001_fail_249() { assert_eq!(verdict_from_story_count(249), Crux001Verdict::Fail); }
#[test] fn crux001_fail_251() { assert_eq!(verdict_from_story_count(251), Crux001Verdict::Fail); }
#[test] fn crux001_fail_zero() { assert_eq!(verdict_from_story_count(0), Crux001Verdict::Fail); }
fn s(items: &[&str]) -> Vec<String> { items.iter().map(|i| i.to_string()).collect() }
#[test] fn crux002_pass_match() {
let refd = s(&["a-v1.yaml", "b-v1.yaml"]);
let exists = s(&["a-v1.yaml", "b-v1.yaml", "c-v1.yaml"]);
assert_eq!(verdict_from_contract_paths_exist(&refd, &exists), Crux002Verdict::Pass);
}
#[test] fn crux002_fail_missing() {
let refd = s(&["a-v1.yaml", "missing-v1.yaml"]);
let exists = s(&["a-v1.yaml"]);
assert_eq!(verdict_from_contract_paths_exist(&refd, &exists), Crux002Verdict::Fail);
}
#[test] fn crux002_fail_empty_refs() {
let exists = s(&["a-v1.yaml"]);
assert_eq!(verdict_from_contract_paths_exist(&[], &exists), Crux002Verdict::Fail);
}
#[test] fn crux003_pass_supported_with_golden() {
let stories = vec![(true, true), (false, false), (true, true)];
assert_eq!(verdict_from_supported_have_golden(&stories), Crux003Verdict::Pass);
}
#[test] fn crux003_fail_supported_no_golden() {
let stories = vec![(true, true), (true, false)];
assert_eq!(verdict_from_supported_have_golden(&stories), Crux003Verdict::Fail);
}
#[test] fn crux003_pass_unsupported_no_golden() {
let stories = vec![(false, false), (false, false)];
assert_eq!(verdict_from_supported_have_golden(&stories), Crux003Verdict::Pass);
}
#[test] fn crux003_fail_empty() {
assert_eq!(verdict_from_supported_have_golden(&[]), Crux003Verdict::Fail);
}
#[test] fn crux004_pass_all_pending() {
let interps = ["pending", "pending", "pending"];
assert_eq!(verdict_from_category_j_pending(&interps), Crux004Verdict::Pass);
}
#[test] fn crux004_fail_resolved_too_early() {
let interps = ["pending", "openclaw_resolved", "pending"];
assert_eq!(verdict_from_category_j_pending(&interps), Crux004Verdict::Fail);
}
#[test] fn crux004_fail_empty() {
assert_eq!(verdict_from_category_j_pending(&[]), Crux004Verdict::Fail);
}
#[test] fn crux005_pass_no_regression() {
assert_eq!(
verdict_from_coverage_monotone(CruxStatus::Missing, CruxStatus::Supported, false),
Crux005Verdict::Pass
);
}
#[test] fn crux005_pass_regression_with_ticket() {
assert_eq!(
verdict_from_coverage_monotone(CruxStatus::Supported, CruxStatus::Missing, true),
Crux005Verdict::Pass
);
}
#[test] fn crux005_fail_regression_no_ticket() {
assert_eq!(
verdict_from_coverage_monotone(CruxStatus::Supported, CruxStatus::Missing, false),
Crux005Verdict::Fail
);
}
#[test] fn crux005_fail_regression_in_progress_no_ticket() {
assert_eq!(
verdict_from_coverage_monotone(CruxStatus::Supported, CruxStatus::InProgress, false),
Crux005Verdict::Fail
);
}
#[test] fn crux006_pass_supported_and_passing() {
assert_eq!(verdict_from_sdk_compatibility(true, true), Crux006Verdict::Pass);
}
#[test] fn crux006_pass_not_claimed() {
assert_eq!(verdict_from_sdk_compatibility(false, false), Crux006Verdict::Pass);
}
#[test] fn crux006_fail_supported_but_failing() {
assert_eq!(verdict_from_sdk_compatibility(true, false), Crux006Verdict::Fail);
}
#[test] fn crux007_pass_missing_has_ticket() {
let stories = vec![
(CruxStatus::Missing, true),
(CruxStatus::Supported, false),
(CruxStatus::Missing, true),
];
assert_eq!(verdict_from_missing_has_ticket(&stories), Crux007Verdict::Pass);
}
#[test] fn crux007_fail_missing_no_ticket() {
let stories = vec![(CruxStatus::Missing, false)];
assert_eq!(verdict_from_missing_has_ticket(&stories), Crux007Verdict::Fail);
}
#[test] fn crux007_fail_empty() {
assert_eq!(verdict_from_missing_has_ticket(&[]), Crux007Verdict::Fail);
}
#[test] fn crux008_pass_critical() { assert_eq!(verdict_from_priority_alignment(5, "critical"), Crux008Verdict::Pass); }
#[test] fn crux008_pass_high() { assert_eq!(verdict_from_priority_alignment(4, "high"), Crux008Verdict::Pass); }
#[test] fn crux008_pass_medium() { assert_eq!(verdict_from_priority_alignment(3, "medium"), Crux008Verdict::Pass); }
#[test] fn crux008_pass_low() { assert_eq!(verdict_from_priority_alignment(2, "low"), Crux008Verdict::Pass); }
#[test] fn crux008_pass_minor() { assert_eq!(verdict_from_priority_alignment(1, "minor"), Crux008Verdict::Pass); }
#[test] fn crux008_fail_score_5_high() { assert_eq!(verdict_from_priority_alignment(5, "high"), Crux008Verdict::Fail); }
#[test] fn crux008_fail_invalid_score() { assert_eq!(verdict_from_priority_alignment(6, "critical"), Crux008Verdict::Fail); }
#[test] fn crux009_pass_in_range() {
for score in 1..=5_u8 {
assert_eq!(verdict_from_demand_score_range(score), Crux009Verdict::Pass);
}
}
#[test] fn crux009_fail_zero() { assert_eq!(verdict_from_demand_score_range(0), Crux009Verdict::Fail); }
#[test] fn crux009_fail_six() { assert_eq!(verdict_from_demand_score_range(6), Crux009Verdict::Fail); }
#[test] fn crux009_fail_max() { assert_eq!(verdict_from_demand_score_range(255), Crux009Verdict::Fail); }
#[test] fn crux010_pass_match() {
let yaml = (50, 30, 20, 150);
let md = (50, 30, 20, 150);
assert_eq!(verdict_from_coverage_table_match(yaml, md), Crux010Verdict::Pass);
}
#[test] fn crux010_fail_drift_supported() {
let yaml = (50, 30, 20, 150);
let md = (51, 30, 20, 150);
assert_eq!(verdict_from_coverage_table_match(yaml, md), Crux010Verdict::Fail);
}
#[test] fn provenance_story_count() {
assert_eq!(AC_CRUX_001_REQUIRED_STORY_COUNT, 250);
}
}