dsfb_gpu_debug_core/verdict.rs
1//! Final verdict enum and its lexical name table.
2//!
3//! Every value here corresponds to a specific exit path through the
4//! pipeline. The verdict is the only end-state of a comparison or a
5//! single-run case file, and the spec's breach-detection tests check
6//! that the right one fires under each manipulation.
7
8/// Final verdict attached to every case-file. Names are spec-defined.
9#[derive(Copy, Clone, Eq, PartialEq, Debug)]
10#[repr(u8)]
11pub enum FinalVerdict {
12 /// CPU and GPU paths produced byte-identical artifacts: the
13 /// strongest possible outcome.
14 ReplayAdmissible = 0,
15 /// CPU-only path executed; no GPU comparison was attempted (host
16 /// without CUDA, or `run-gpu` not invoked).
17 CpuOnlyAdmissible = 1,
18 /// GPU path executed and matches what a CPU run would have produced;
19 /// the CPU side wasn't available for the comparison at this run.
20 GpuReplayAdmissible = 2,
21 /// Contract bytes themselves were rejected (numeric mode wrong,
22 /// kernel sequence reordered, etc.).
23 ContractBreach = 3,
24 /// `bank_hash` in the contract does not match the bank actually
25 /// loaded.
26 BankMismatch = 4,
27 /// `detector_registry_hash` in the contract does not match the
28 /// detector registry.
29 DetectorRegistryMismatch = 5,
30 /// A per-stage hash diverged between the CPU and GPU artifacts.
31 NumericMismatch = 6,
32 /// The kernel-sequence list in the contract does not match what
33 /// the run actually executed.
34 KernelSequenceMismatch = 7,
35 /// An episode was found in the case file that did not carry a bank
36 /// admission token — the Semantic Non-Bypass guard tripped.
37 SemanticBypassRejected = 8,
38}
39
40impl FinalVerdict {
41 /// Stable lowercase-camel name used in the canonical case-file
42 /// bytes. Renaming any of these breaks every prior case file.
43 #[must_use]
44 pub const fn name(self) -> &'static str {
45 match self {
46 Self::ReplayAdmissible => "ReplayAdmissible",
47 Self::CpuOnlyAdmissible => "CpuOnlyAdmissible",
48 Self::GpuReplayAdmissible => "GpuReplayAdmissible",
49 Self::ContractBreach => "ContractBreach",
50 Self::BankMismatch => "BankMismatch",
51 Self::DetectorRegistryMismatch => "DetectorRegistryMismatch",
52 Self::NumericMismatch => "NumericMismatch",
53 Self::KernelSequenceMismatch => "KernelSequenceMismatch",
54 Self::SemanticBypassRejected => "SemanticBypassRejected",
55 }
56 }
57
58 /// Exit code the CLI uses for this verdict. Mirrors the matrix in
59 /// the README.
60 #[must_use]
61 pub const fn exit_code(self) -> u8 {
62 match self {
63 Self::ReplayAdmissible | Self::CpuOnlyAdmissible | Self::GpuReplayAdmissible => 0,
64 Self::ContractBreach
65 | Self::BankMismatch
66 | Self::DetectorRegistryMismatch
67 | Self::NumericMismatch
68 | Self::KernelSequenceMismatch => 3,
69 Self::SemanticBypassRejected => 4,
70 }
71 }
72}