made_core/value_objects/deliberation_outcome.rs
1//! [`DeliberationOutcome`] — the terminal result of a deliberation run.
2
3/// The terminal result of a deliberation that ran to completion.
4///
5/// A deliberation that reaches its end lands in exactly one of these:
6/// either a winning proposal was selected, or — under an output
7/// contract — every proposal was generated but none satisfied it.
8///
9/// Adapter-shaped aborts (an agent or validator returning `Err`) are
10/// deliberately **not** outcomes: they surface as [`DomainError`]s and as
11/// dedicated error counters (the judge/provider `*_errors_total` families).
12/// Keeping this enum to the two genuine end-states keeps the `outcome`
13/// metric label low-cardinality and meaningful.
14///
15/// [`DomainError`]: crate::error::DomainError
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum DeliberationOutcome {
18 /// A winning proposal was selected and returned to the caller.
19 Success,
20 /// An output contract was in force but no proposal satisfied it.
21 NoValidProposal,
22}
23
24impl DeliberationOutcome {
25 /// Stable, low-cardinality label value for metrics exposition.
26 ///
27 /// The strings are part of the metric contract; downstream
28 /// dashboards and alerts match on them, so they must not change.
29 #[must_use]
30 pub const fn as_label(self) -> &'static str {
31 match self {
32 Self::Success => "success",
33 Self::NoValidProposal => "no_valid_proposal",
34 }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn labels_are_stable_and_distinct() {
44 assert_eq!(DeliberationOutcome::Success.as_label(), "success");
45 assert_eq!(
46 DeliberationOutcome::NoValidProposal.as_label(),
47 "no_valid_proposal"
48 );
49 assert_ne!(
50 DeliberationOutcome::Success.as_label(),
51 DeliberationOutcome::NoValidProposal.as_label()
52 );
53 }
54}