1use crate::engine::Paradigm;
8use crate::symbol::ParadigmSet;
9
10#[derive(Debug, Clone)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize))]
16pub struct Verdict {
17 pub valid: bool,
19
20 pub confidence: Confidence,
27
28 pub paradigms_evaluated: ParadigmSet,
30
31 pub trace: LogicTrace,
33
34 pub cross_validation: CrossValidation,
36
37 #[cfg(feature = "alloc")]
39 pub formal_notation: alloc::string::String,
40
41 #[cfg(feature = "alloc")]
43 pub citations: alloc::vec::Vec<Citation>,
44}
45
46impl Verdict {
47 pub fn deny_immediate(reason: &'static str) -> Self {
50 let mut trace = LogicTrace::new();
51 trace.push(TraceEntry {
52 stage: Stage::CrossValidation,
53 paradigm: Some(Paradigm::Deontic),
54 description: reason,
55 outcome: EntryOutcome::Denied,
56 });
57 Verdict {
58 valid: false,
59 confidence: Confidence::CERTAIN,
60 paradigms_evaluated: {
61 let mut s = ParadigmSet::empty();
62 s.insert(Paradigm::Deontic);
63 s
64 },
65 trace,
66 cross_validation: CrossValidation {
67 consistent: false,
68 conflicts_detected: 1,
69 conflict_detail: Some(reason),
70 },
71 #[cfg(feature = "alloc")]
72 formal_notation: alloc::format!("¬permitted({reason})"),
73 #[cfg(feature = "alloc")]
74 citations: alloc::vec![],
75 }
76 }
77
78 pub fn permit_immediate(reason: &'static str) -> Self {
80 let mut trace = LogicTrace::new();
81 trace.push(TraceEntry {
82 stage: Stage::CrossValidation,
83 paradigm: Some(Paradigm::Deontic),
84 description: reason,
85 outcome: EntryOutcome::Permitted,
86 });
87 Verdict {
88 valid: true,
89 confidence: Confidence::CERTAIN,
90 paradigms_evaluated: {
91 let mut s = ParadigmSet::empty();
92 s.insert(Paradigm::Deontic);
93 s
94 },
95 trace,
96 cross_validation: CrossValidation {
97 consistent: true,
98 conflicts_detected: 0,
99 conflict_detail: None,
100 },
101 #[cfg(feature = "alloc")]
102 formal_notation: alloc::format!("permitted({reason})"),
103 #[cfg(feature = "alloc")]
104 citations: alloc::vec![],
105 }
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
114#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
115pub struct Confidence(pub u8);
116
117impl Confidence {
118 pub const CERTAIN: Confidence = Confidence(255);
119 pub const HIGH: Confidence = Confidence(204); pub const MEDIUM: Confidence = Confidence(153); pub const LOW: Confidence = Confidence(102); pub const UNCERTAIN: Confidence = Confidence(51); pub const NONE: Confidence = Confidence(0);
124
125 pub fn from_agreement(agreed: u8, total: u8) -> Self {
127 if total == 0 {
128 return Confidence::NONE;
129 }
130 Confidence(((agreed as u16 * 255) / total as u16) as u8)
131 }
132
133 pub fn as_f32(self) -> f32 {
134 self.0 as f32 / 255.0
135 }
136}
137
138#[derive(Debug, Clone)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize))]
148pub struct CrossValidation {
149 pub consistent: bool,
151 pub conflicts_detected: u8,
153 pub conflict_detail: Option<&'static str>,
155}
156
157impl CrossValidation {
158 pub fn ok() -> Self {
159 CrossValidation {
160 consistent: true,
161 conflicts_detected: 0,
162 conflict_detail: None,
163 }
164 }
165}
166
167#[derive(Debug, Clone)]
173#[cfg_attr(feature = "serde", derive(serde::Serialize))]
175pub struct LogicTrace {
176 #[cfg(feature = "alloc")]
177 pub entries: alloc::vec::Vec<TraceEntry>,
178 #[cfg(not(feature = "alloc"))]
179 pub entries: heapless::Vec<TraceEntry, 64>,
180}
181
182impl LogicTrace {
183 pub fn new() -> Self {
184 LogicTrace {
185 #[cfg(feature = "alloc")]
186 entries: alloc::vec::Vec::new(),
187 #[cfg(not(feature = "alloc"))]
188 entries: heapless::Vec::new(),
189 }
190 }
191
192 pub fn push(&mut self, entry: TraceEntry) {
193 #[cfg(feature = "alloc")]
194 self.entries.push(entry);
195 #[cfg(not(feature = "alloc"))]
196 let _ = self.entries.push(entry);
197 }
198
199 pub fn len(&self) -> usize {
200 self.entries.len()
201 }
202
203 pub fn is_empty(&self) -> bool {
204 self.entries.is_empty()
205 }
206}
207
208impl Default for LogicTrace {
209 fn default() -> Self {
210 Self::new()
211 }
212}
213
214#[derive(Debug, Clone)]
216#[cfg_attr(feature = "serde", derive(serde::Serialize))]
218pub struct TraceEntry {
219 pub stage: Stage,
221 pub paradigm: Option<Paradigm>,
223 pub description: &'static str,
225 pub outcome: EntryOutcome,
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
232pub enum Stage {
233 Tokenization,
234 ParadigmDetection,
235 AstConstruction,
236 EngineRouting,
237 EngineEvaluation,
238 CrossValidation,
239 VerdictSynthesis,
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
245pub enum EntryOutcome {
246 Permitted,
247 Denied,
248 Evaluated,
249 Routed,
250 Conflict,
251 Skipped,
252}
253
254#[cfg(feature = "alloc")]
256#[derive(Debug, Clone)]
257#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
258pub struct Citation {
259 pub id: alloc::string::String,
261 pub description: alloc::string::String,
263}