pub const AC_GPUTRAIN_004_CPU_DISPATCH_VARIANTS: &[&str] = &["Cpu"];
pub const AC_GPUTRAIN_004_CUDA_DISPATCH_VARIANTS: &[&str] = &["Cuda"];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Gputrain004Verdict {
Pass,
Fail,
}
#[must_use]
pub fn verdict_from_dispatch_label(requested: &str, dispatched: &str) -> Gputrain004Verdict {
let req_cpu = AC_GPUTRAIN_004_CPU_DISPATCH_VARIANTS.contains(&requested);
let req_cuda = AC_GPUTRAIN_004_CUDA_DISPATCH_VARIANTS.contains(&requested);
let dis_cpu = AC_GPUTRAIN_004_CPU_DISPATCH_VARIANTS.contains(&dispatched);
let dis_cuda = AC_GPUTRAIN_004_CUDA_DISPATCH_VARIANTS.contains(&dispatched);
match (req_cpu, req_cuda, dis_cpu, dis_cuda) {
(true, false, true, false) => Gputrain004Verdict::Pass, (false, true, false, true) => Gputrain004Verdict::Pass, _ => Gputrain004Verdict::Fail,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn falsify_gputrain_004_cpu_fallback_preserved_logic() {
assert_eq!(
verdict_from_dispatch_label("Cpu", "Cpu"),
Gputrain004Verdict::Pass,
"cpu → cpu must Pass (primary INV-GPUTRAIN-004 case)",
);
assert_eq!(
verdict_from_dispatch_label("Cuda", "Cuda"),
Gputrain004Verdict::Pass,
"cuda → cuda must Pass (symmetric CUDA path preservation)",
);
assert_eq!(
verdict_from_dispatch_label("Cpu", "Cuda"),
Gputrain004Verdict::Fail,
"cpu → cuda must Fail (silent GPU promotion bug)",
);
assert_eq!(
verdict_from_dispatch_label("Cuda", "Cpu"),
Gputrain004Verdict::Fail,
"cuda → cpu must Fail (this is the task #126 silent-CPU-fallback bug)",
);
assert_eq!(
verdict_from_dispatch_label("xpu", "Cpu"),
Gputrain004Verdict::Fail,
"unknown requested label must Fail (no implicit default)",
);
assert_eq!(
verdict_from_dispatch_label("Cpu", "metal"),
Gputrain004Verdict::Fail,
"unknown dispatched label must Fail (no implicit default)",
);
assert_eq!(
verdict_from_dispatch_label("rocm", "rocm"),
Gputrain004Verdict::Fail,
"unknown label on both sides must Fail even if matched \
(only the two recorded sets are allowed)",
);
assert_eq!(
verdict_from_dispatch_label("", "Cpu"),
Gputrain004Verdict::Fail,
"empty requested label must Fail",
);
assert_eq!(
verdict_from_dispatch_label("Cpu", ""),
Gputrain004Verdict::Fail,
"empty dispatched label must Fail",
);
assert_eq!(
verdict_from_dispatch_label("", ""),
Gputrain004Verdict::Fail,
"both-empty must Fail (degenerate input, no implicit default)",
);
assert_eq!(
verdict_from_dispatch_label("CPU", "Cpu"),
Gputrain004Verdict::Fail,
"uppercase `CPU` is not in the pinned slice — must Fail",
);
assert_eq!(
verdict_from_dispatch_label("cpu", "Cpu"),
Gputrain004Verdict::Fail,
"lowercase `cpu` is not in the pinned slice — must Fail \
(slice contents are the authoritative grammar)",
);
assert_eq!(
verdict_from_dispatch_label("Cpu ", "Cpu"),
Gputrain004Verdict::Fail,
"trailing whitespace must Fail (no implicit trim)",
);
assert_eq!(
AC_GPUTRAIN_004_CPU_DISPATCH_VARIANTS,
&["Cpu"],
"CPU dispatch set must be exactly [\"Cpu\"] \
(spec §14.4 / gpu-training-backend-v1 INV-GPUTRAIN-004)",
);
assert_eq!(
AC_GPUTRAIN_004_CUDA_DISPATCH_VARIANTS,
&["Cuda"],
"CUDA dispatch set must be exactly [\"Cuda\"] \
(spec §14.4 / gpu-training-backend-v1 INV-GPUTRAIN-004)",
);
for cpu in AC_GPUTRAIN_004_CPU_DISPATCH_VARIANTS {
assert!(
!AC_GPUTRAIN_004_CUDA_DISPATCH_VARIANTS.contains(cpu),
"CPU/CUDA dispatch sets must be disjoint",
);
}
}
}