Skip to main content

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}