vex_adversarial/
debate.rs

1//! Debate protocol between Blue and Red agents
2
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// A single round in a debate
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct DebateRound {
9    /// Round number
10    pub round: u32,
11    /// Blue agent's claim/response
12    pub blue_claim: String,
13    /// Red agent's challenge
14    pub red_challenge: String,
15    /// Blue agent's rebuttal (if any)
16    pub blue_rebuttal: Option<String>,
17}
18
19/// A complete debate between Blue and Red agents
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct Debate {
22    /// Unique ID
23    pub id: Uuid,
24    /// Blue agent ID
25    pub blue_agent_id: Uuid,
26    /// Red agent ID
27    pub red_agent_id: Uuid,
28    /// The initial claim being debated
29    pub initial_claim: String,
30    /// Rounds of debate
31    pub rounds: Vec<DebateRound>,
32    /// Final verdict (true = claim upheld, false = claim rejected)
33    pub verdict: Option<bool>,
34    /// Confidence in the verdict (0.0 - 1.0)
35    pub confidence: f64,
36}
37
38impl Debate {
39    /// Create a new debate
40    pub fn new(blue_id: Uuid, red_id: Uuid, claim: &str) -> Self {
41        Self {
42            id: Uuid::new_v4(),
43            blue_agent_id: blue_id,
44            red_agent_id: red_id,
45            initial_claim: claim.to_string(),
46            rounds: Vec::new(),
47            verdict: None,
48            confidence: 0.0,
49        }
50    }
51
52    /// Add a round to the debate
53    pub fn add_round(&mut self, round: DebateRound) {
54        self.rounds.push(round);
55    }
56
57    /// Conclude the debate with a verdict
58    pub fn conclude(&mut self, upheld: bool, confidence: f64) {
59        self.verdict = Some(upheld);
60        self.confidence = confidence.clamp(0.0, 1.0);
61    }
62
63    /// Check if debate is concluded
64    pub fn is_concluded(&self) -> bool {
65        self.verdict.is_some()
66    }
67
68    /// Get number of rounds
69    pub fn round_count(&self) -> usize {
70        self.rounds.len()
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_debate_lifecycle() {
80        let mut debate = Debate::new(Uuid::new_v4(), Uuid::new_v4(), "The sky is blue");
81
82        assert!(!debate.is_concluded());
83
84        debate.add_round(DebateRound {
85            round: 1,
86            blue_claim: "The sky is blue due to Rayleigh scattering".to_string(),
87            red_challenge: "But the sky is red at sunset".to_string(),
88            blue_rebuttal: Some("Rayleigh scattering still applies...".to_string()),
89        });
90
91        assert_eq!(debate.round_count(), 1);
92
93        debate.conclude(true, 0.85);
94        assert!(debate.is_concluded());
95        assert_eq!(debate.verdict, Some(true));
96    }
97}