Skip to main content

jev_harness/
types.rs

1//! Strongly typed data contracts for TypeSafe Jev System One.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Choice question: selects one key from a map of criteria.
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8pub struct ChoiceQuestion {
9    pub instructions: String,
10    pub criteria: HashMap<String, String>,
11}
12
13/// Score question: rates state against an ordered rubric array.
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub struct ScoreQuestion {
16    pub instructions: String,
17    pub criteria: Vec<String>,
18}
19
20/// Noul question: asks for probability (0.0 to 1.0) that answer is affirmative.
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
22pub struct NoulQuestion {
23    pub instructions: String,
24}
25
26/// Question enum tagged by "type".
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28#[serde(tag = "type")]
29pub enum Question {
30    #[serde(rename = "choice")]
31    Choice(ChoiceQuestion),
32    #[serde(rename = "score")]
33    Score(ScoreQuestion),
34    #[serde(rename = "noul")]
35    Noul(NoulQuestion),
36}
37
38/// Choice answer with chosen key and calibrated confidence.
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
40pub struct ChoiceAnswer {
41    pub choice: String,
42    pub confidence: f64,
43    #[serde(default)]
44    pub probabilities: Option<HashMap<String, f64>>,
45}
46
47/// Score answer with integer rating (1-indexed) and confidence.
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
49pub struct ScoreAnswer {
50    /// Live payloads return a float score (e.g. 1.76); the offline mock uses whole numbers.
51    pub score: f64,
52    pub confidence: f64,
53    /// Live payloads return a level -> description map; some clients send a list.
54    #[serde(default)]
55    pub legend: Option<serde_json::Value>,
56    #[serde(default)]
57    pub probabilities: Option<HashMap<String, f64>>,
58}
59
60/// Noul answer with calibrated probability between 0.0 and 1.0.
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
62pub struct NoulAnswer {
63    pub noul: f64,
64}
65
66/// Answer enum tagged by "type".
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
68#[serde(tag = "type")]
69pub enum Answer {
70    #[serde(rename = "choice")]
71    Choice(ChoiceAnswer),
72    #[serde(rename = "score")]
73    Score(ScoreAnswer),
74    #[serde(rename = "noul")]
75    Noul(NoulAnswer),
76}
77
78impl Answer {
79    pub fn as_choice(&self) -> Option<&ChoiceAnswer> {
80        match self {
81            Answer::Choice(a) => Some(a),
82            _ => None,
83        }
84    }
85
86    pub fn as_score(&self) -> Option<&ScoreAnswer> {
87        match self {
88            Answer::Score(a) => Some(a),
89            _ => None,
90        }
91    }
92
93    pub fn as_noul(&self) -> Option<&NoulAnswer> {
94        match self {
95            Answer::Noul(a) => Some(a),
96            _ => None,
97        }
98    }
99}
100
101/// Token usage reported by API.
102#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
103pub struct JevUsage {
104    #[serde(default)]
105    pub input_tokens: u32,
106    #[serde(default)]
107    pub output_tokens: u32,
108}
109
110/// Complete response from Jev System One.
111#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
112pub struct JevResponse {
113    pub model: String,
114    pub answers: HashMap<String, Answer>,
115    #[serde(default)]
116    pub usage: JevUsage,
117    #[serde(default)]
118    pub is_mock: bool,
119    /// Set when the answer came from a fallback (auth_401, http_500, timeout, connection).
120    #[serde(default)]
121    pub degraded_reason: String,
122}
123
124/// Triage result for test or execution failure.
125#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
126pub struct TestTriageResult {
127    pub category: String,
128    pub confidence: f64,
129    pub skip_llm: bool,
130    pub skip_llm_prob: f64,
131    pub severity_score: f64,
132    pub action_recommendation: String,
133    pub recommendation: String,
134    pub is_mock: bool,
135    /// Set when a provider failure caused the offline fallback (E0.2).
136    #[serde(default)]
137    pub degraded_reason: String,
138}
139
140/// Result of loop abort and dead-end check.
141#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
142pub struct AbortGateResult {
143    pub should_abort: bool,
144    pub abort_probability: f64,
145    pub action: String,
146    pub viability_score: f64,
147    pub reasoning_summary: String,
148    pub summary: String,
149    pub is_mock: bool,
150    /// Set when a provider failure caused the offline fallback (E0.2).
151    #[serde(default)]
152    pub degraded_reason: String,
153}
154
155/// Model tier routing decision.
156#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
157pub struct ModelRouteResult {
158    pub selected_tier: String,
159    pub confidence: f64,
160    pub complexity_score: f64,
161    pub recommended_model: String,
162    pub rationale: String,
163    pub is_mock: bool,
164    /// Set when a provider failure caused the offline fallback (E0.2).
165    #[serde(default)]
166    pub degraded_reason: String,
167}
168
169/// Step completion verification result.
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
171pub struct VerificationResult {
172    pub is_verified: bool,
173    pub satisfaction_probability: f64,
174    pub rigor_score: f64,
175    pub confidence: f64,
176    pub needs_rework: bool,
177    pub is_mock: bool,
178    /// Set when a provider failure caused the offline fallback (E0.2).
179    #[serde(default)]
180    pub degraded_reason: String,
181}
182
183/// Dynamic reasoning effort modulation result (Astra-Jev).
184#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
185pub struct ReasoningEffortResult {
186    pub effort: String,
187    pub confidence: f64,
188    pub complexity_score: f64,
189    pub rationale: String,
190    pub provider: String,
191    pub provider_params: serde_json::Value,
192    pub is_reasoning_supported: bool,
193    pub cache_safe_recommendation: String,
194    pub lease_steps: u32,
195    pub is_mock: bool,
196    /// Set when a provider failure caused the offline fallback (E0.2).
197    #[serde(default)]
198    pub degraded_reason: String,
199}
200
201/// Continuation nudge decision result (CommandCode Jev Nudge).
202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
203pub struct NudgeGateResult {
204    pub should_nudge: bool,
205    pub nudge_probability: f64,
206    pub waiting_probability: f64,
207    pub progress_probability: f64,
208    pub workflow_phase: String,
209    pub suggested_nudge_prompt: String,
210    pub rationale: String,
211    pub is_mock: bool,
212    /// Set when a provider failure caused the offline fallback (E0.2).
213    #[serde(default)]
214    pub degraded_reason: String,
215}
216
217/// Error type for Jev operations.
218#[derive(Debug)]
219pub enum JevError {
220    Http(reqwest::Error),
221    Json(serde_json::Error),
222    Config(String),
223    Api { status: u16, message: String },
224}
225
226impl std::fmt::Display for JevError {
227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228        match self {
229            JevError::Http(e) => write!(f, "HTTP error: {}", e),
230            JevError::Json(e) => write!(f, "JSON serialization error: {}", e),
231            JevError::Config(m) => write!(f, "Configuration error: {}", m),
232            JevError::Api { status, message } => {
233                write!(f, "API error (HTTP {}): {}", status, message)
234            }
235        }
236    }
237}
238
239impl std::error::Error for JevError {}
240
241impl From<reqwest::Error> for JevError {
242    fn from(e: reqwest::Error) -> Self {
243        JevError::Http(e)
244    }
245}
246
247impl From<serde_json::Error> for JevError {
248    fn from(e: serde_json::Error) -> Self {
249        JevError::Json(e)
250    }
251}