Skip to main content

switchyard_libsy/algorithms/vgr/
mode.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! What a deployment actually serves, given what the rules decided.
5//!
6//! Deciding and serving are separate steps, and this is the second one. Keeping
7//! them apart is what lets a deployment record complete decisions — including
8//! the local commits it is not yet willing to make — while serving something
9//! more conservative.
10
11use super::config::ServingMode;
12use super::decide::{Decision, Route};
13
14/// The route a deployment serves for a decision.
15///
16/// Only [`ServingMode::Active`] can serve a local commit in production, and it
17/// serves the readiness-gated route rather than the raw decision.
18/// [`ServingMode::Evaluate`] serves the *ungated* decision, which is why it is
19/// restricted to isolated measurement: it will serve routes the gates exist to
20/// refuse.
21pub(super) fn serve_route(mode: &ServingMode, decision: &Decision) -> Route {
22    match mode {
23        // No decision authority at all, so nothing local is served.
24        ServingMode::Off | ServingMode::Shadow => Route::Cloud,
25        ServingMode::Evaluate => decision.route,
26        ServingMode::Active { .. } => decision.effective_route,
27    }
28}
29
30/// The attestation an operator must record to serve live local commits.
31pub const ACTIVE_APPROVAL: &str = "prospective-validation-and-canary-approved";
32
33/// Whether a mode is configured coherently.
34///
35/// Only [`ServingMode::Active`] can be misconfigured: it is the one mode that
36/// lets a decision commit locally, so it must carry the operator's recorded
37/// approval verbatim. A typo yields an error at construction rather than a
38/// route that silently serves cloud forever.
39pub(super) fn validate(mode: &ServingMode) -> Result<(), String> {
40    match mode {
41        ServingMode::Active { approval } if approval != ACTIVE_APPROVAL => Err(format!(
42            "vgr active mode requires the approval attestation {ACTIVE_APPROVAL:?}"
43        )),
44        _ => Ok(()),
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::super::Branch;
51    use super::super::decide::ReadinessGate;
52    use super::super::rules::Signals;
53    use super::*;
54
55    /// A decision with the given decided and readiness-gated routes.
56    fn decision(route: Route, effective_route: Route) -> Decision {
57        Decision {
58            route,
59            effective_route,
60            readiness_gate: (effective_route != route)
61                .then_some(ReadinessGate::SecureCheckerMissing),
62            branch: Branch::CodingNoChecks,
63            signals: Signals::default(),
64            policy_version: "test",
65        }
66    }
67
68    #[test]
69    fn only_active_mode_can_serve_a_local_commit_in_production() {
70        // A route configured but never consciously enabled must not commit.
71        assert_eq!(ServingMode::default(), ServingMode::Off);
72        let committed = decision(Route::Local, Route::Local);
73        assert_eq!(serve_route(&ServingMode::Off, &committed), Route::Cloud);
74        assert_eq!(serve_route(&ServingMode::Shadow, &committed), Route::Cloud);
75        assert_eq!(
76            serve_route(
77                &ServingMode::Active {
78                    approval: ACTIVE_APPROVAL.into()
79                },
80                &committed
81            ),
82            Route::Local
83        );
84    }
85
86    #[test]
87    fn active_mode_serves_the_gated_route_and_evaluate_serves_the_ungated_one() {
88        // A local decision the readiness gates refuse: active must not serve it,
89        // and evaluate deliberately does, which is why it is measurement-only.
90        let gated = decision(Route::Local, Route::Cloud);
91        assert_eq!(
92            serve_route(
93                &ServingMode::Active {
94                    approval: ACTIVE_APPROVAL.into()
95                },
96                &gated
97            ),
98            Route::Cloud
99        );
100        assert_eq!(serve_route(&ServingMode::Evaluate, &gated), Route::Local);
101    }
102
103    #[test]
104    fn active_mode_requires_the_approval_attestation_verbatim() {
105        assert!(validate(&ServingMode::Off).is_ok());
106        assert!(validate(&ServingMode::Shadow).is_ok());
107        assert!(
108            validate(&ServingMode::Active {
109                approval: ACTIVE_APPROVAL.into()
110            })
111            .is_ok()
112        );
113        // A near miss is a misconfiguration, not an approval.
114        assert!(
115            validate(&ServingMode::Active {
116                approval: "approved".into()
117            })
118            .is_err()
119        );
120        assert!(
121            validate(&ServingMode::Active {
122                approval: "vgr-active-serving-approved".into()
123            })
124            .is_err(),
125            "the retired approval token must fail closed"
126        );
127        assert!(
128            validate(&ServingMode::Active {
129                approval: String::new()
130            })
131            .is_err()
132        );
133    }
134}