1use crate::{CatalogSourceKind, PhaseId, ProviderService, TransportKind};
6use serde::{Deserialize, Serialize};
7
8pub const CATALOG_PROOF_SCHEMA_VERSION: &str = "1.0.0";
9pub const LIVE_CATALOG_DISCOVERY_CONFIRMATION: &str = "RUN_STEADYMUX_LIVE_CATALOG_DISCOVERY";
10pub const LIVE_MODEL_QUALIFICATION_CONFIRMATION: &str = "RUN_STEADYMUX_LIVE_MODEL_QUALIFICATION";
11pub const MAX_CATALOG_PROOF_PHASES: usize = 64;
12pub const MAX_CATALOG_PROOF_MODELS: usize = 512;
13pub const MAX_CATALOG_QUALIFICATION_TARGETS: usize = 64;
14
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(deny_unknown_fields)]
17pub struct CatalogDiscoveryPreviewRequest {
18 pub configuration_authority_id: String,
22 pub pre_authority_configuration_sha256: String,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(deny_unknown_fields)]
28pub struct CatalogDiscoveryApplyRequest {
29 pub preview: CatalogDiscoveryPreview,
30 pub expected_preview_sha256: String,
31 pub confirmation: String,
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(deny_unknown_fields)]
36pub struct CatalogQualificationPreviewRequest {
37 pub configuration_authority_id: String,
38 pub pre_authority_configuration_sha256: String,
39 pub discovery_receipt_sha256: String,
40 pub targets: Vec<CatalogQualificationTarget>,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(deny_unknown_fields)]
45pub struct CatalogQualificationApplyRequest {
46 pub preview: CatalogQualificationPreview,
47 pub expected_preview_sha256: String,
48 pub confirmation: String,
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
52#[serde(deny_unknown_fields)]
53pub struct CatalogDiscoveryPlanEntry {
54 pub phase_id: PhaseId,
55 pub provider: ProviderService,
56 pub transport: TransportKind,
57 pub source: CatalogSourceKind,
58 pub configured_model_ids: Vec<String>,
59}
60
61#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
62#[serde(deny_unknown_fields)]
63pub struct CatalogDiscoveryPreview {
64 pub schema_version: String,
65 pub configuration_authority_id: String,
66 pub pre_authority_configuration_sha256: String,
67 pub phases: Vec<CatalogDiscoveryPlanEntry>,
68 pub maximum_provider_requests: u32,
69 pub network_effect: bool,
70 pub inference_effect: bool,
71 pub credential_read_effect: bool,
72 pub preview_sha256: String,
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
76#[serde(rename_all = "snake_case")]
77pub enum CatalogDiscoveryOutcome {
78 Accepted,
79 RetainedLastKnownGood,
80 RejectedNoUsableLastKnownGood,
81}
82
83#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
84#[serde(deny_unknown_fields)]
85pub struct CatalogCapabilityClassification {
86 pub context_tokens: u64,
87 pub modalities: Vec<String>,
88 pub tool_support: bool,
89 pub reasoning_modes: Vec<String>,
90}
91
92#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
93#[serde(deny_unknown_fields)]
94pub struct CatalogDiscoveredModelReceipt {
95 pub provider_model_id: String,
96 pub model_sha256: String,
97 pub capabilities: CatalogCapabilityClassification,
98 pub qualification_status: CatalogQualificationStatus,
99 pub exclusion_reason: Option<String>,
100}
101
102#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
103#[serde(deny_unknown_fields)]
104pub struct CatalogPhaseDiscoveryReceipt {
105 pub phase_id: PhaseId,
106 pub provider: ProviderService,
107 pub source: CatalogSourceKind,
108 pub observed_at_epoch_seconds: u64,
109 pub outcome: CatalogDiscoveryOutcome,
110 pub catalog_version: Option<String>,
111 pub catalog_sha256: Option<String>,
112 pub models: Vec<CatalogDiscoveredModelReceipt>,
113 pub exclusion_reason: Option<String>,
114}
115
116#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
117#[serde(deny_unknown_fields)]
118pub struct CatalogDiscoveryReceipt {
119 pub schema_version: String,
120 pub configuration_authority_id: String,
121 pub pre_authority_configuration_sha256: String,
122 pub completed_at_epoch_seconds: u64,
123 pub phases: Vec<CatalogPhaseDiscoveryReceipt>,
124 pub receipt_sha256: String,
125}
126
127#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
128#[serde(rename_all = "snake_case")]
129pub enum CatalogProofRole {
130 Routine,
131 Standard,
132 Complex,
133 Vision,
134 LongContext,
135}
136
137#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(deny_unknown_fields)]
139pub struct CatalogQualificationTarget {
140 pub phase_id: PhaseId,
141 pub provider: ProviderService,
142 pub profile_id: String,
146 pub provider_model_id: String,
147 pub roles: Vec<CatalogProofRole>,
148}
149
150#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
151#[serde(deny_unknown_fields)]
152pub struct CatalogQualificationPreview {
153 pub schema_version: String,
154 pub configuration_authority_id: String,
155 pub pre_authority_configuration_sha256: String,
156 pub discovery_receipt_sha256: String,
157 pub targets: Vec<CatalogQualificationTarget>,
158 pub maximum_inference_requests: u32,
159 pub maximum_openrouter_micro_usd: u64,
160 pub network_effect: bool,
161 pub inference_effect: bool,
162 pub credential_read_effect: bool,
163 pub preview_sha256: String,
164}
165
166#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
167#[serde(rename_all = "snake_case")]
168pub enum CatalogQualificationStatus {
169 DiscoveredUnqualified,
170 Qualifying,
171 Qualified,
172 Rejected,
173}
174
175#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
176#[serde(deny_unknown_fields)]
177pub struct CatalogModelQualificationReceipt {
178 pub target: CatalogQualificationTarget,
179 pub status: CatalogQualificationStatus,
180 pub catalog_version: String,
181 pub catalog_sha256: String,
182 pub model_sha256: String,
183 pub policy_version: Option<String>,
184 pub policy_sha256: Option<String>,
185 pub conformance_sha256: Option<String>,
186 pub evidence_ref: Option<String>,
187 pub exclusion_reason: Option<String>,
188}
189
190#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
191#[serde(deny_unknown_fields)]
192pub struct CatalogQualificationReceipt {
193 pub schema_version: String,
194 pub configuration_authority_id: String,
195 pub pre_authority_configuration_sha256: String,
196 pub discovery_receipt_sha256: String,
197 pub completed_at_epoch_seconds: u64,
198 pub results: Vec<CatalogModelQualificationReceipt>,
199 pub artifacts: Vec<CatalogQualificationArtifact>,
204 pub receipt_sha256: String,
205}
206
207#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
208#[serde(rename_all = "snake_case")]
209pub enum CatalogQualificationArtifactKind {
210 CatalogBundle,
211 PolicyPack,
212 ConformanceSuite,
213}
214
215#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
216#[serde(deny_unknown_fields)]
217pub struct CatalogQualificationArtifact {
218 pub kind: CatalogQualificationArtifactKind,
219 pub file_name: String,
220 pub provider: Option<ProviderService>,
221 pub phase_id: Option<PhaseId>,
222 pub content_sha256: String,
223 pub content: serde_json::Value,
224}
225
226#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
227#[serde(deny_unknown_fields)]
228pub struct CatalogProofArtifact {
229 pub kind: String,
230 pub provider: Option<ProviderService>,
231 pub content_sha256: String,
232 pub byte_length: u64,
233}
234
235#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
236#[serde(deny_unknown_fields)]
237pub struct CatalogProofArtifactManifest {
238 pub schema_version: String,
239 pub configuration_authority_id: String,
240 pub pre_authority_configuration_sha256: String,
241 pub discovery_receipt_sha256: String,
242 pub qualification_receipt_sha256: Option<String>,
243 pub artifacts: Vec<CatalogProofArtifact>,
244 pub manifest_sha256: String,
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn apply_contracts_deny_unknown_fields_and_keep_confirmation_out_of_receipts() {
253 let value = serde_json::json!({
254 "preview": {
255 "schema_version": CATALOG_PROOF_SCHEMA_VERSION,
256 "configuration_authority_id": "configuration.device.alpha",
257 "pre_authority_configuration_sha256": "a".repeat(64),
258 "phases": [],
259 "maximum_provider_requests": 0,
260 "network_effect": true,
261 "inference_effect": false,
262 "credential_read_effect": true,
263 "preview_sha256": "b".repeat(64)
264 },
265 "expected_preview_sha256": "a".repeat(64),
266 "confirmation": LIVE_CATALOG_DISCOVERY_CONFIRMATION,
267 "secret": "forbidden"
268 });
269 assert!(serde_json::from_value::<CatalogDiscoveryApplyRequest>(value).is_err());
270 let receipt = CatalogDiscoveryReceipt {
271 schema_version: CATALOG_PROOF_SCHEMA_VERSION.to_owned(),
272 configuration_authority_id: "configuration.device.alpha".to_owned(),
273 pre_authority_configuration_sha256: "a".repeat(64),
274 completed_at_epoch_seconds: 1,
275 phases: Vec::new(),
276 receipt_sha256: "b".repeat(64),
277 };
278 let encoded = serde_json::to_string(&receipt).expect("receipt JSON");
279 assert!(!encoded.contains("confirmation"));
280 assert!(!encoded.contains("secret"));
281 }
282}