use crate::{CatalogSourceKind, PhaseId, ProviderService, TransportKind};
use serde::{Deserialize, Serialize};
pub const CATALOG_PROOF_SCHEMA_VERSION: &str = "1.0.0";
pub const LIVE_CATALOG_DISCOVERY_CONFIRMATION: &str = "RUN_STEADYMUX_LIVE_CATALOG_DISCOVERY";
pub const LIVE_MODEL_QUALIFICATION_CONFIRMATION: &str = "RUN_STEADYMUX_LIVE_MODEL_QUALIFICATION";
pub const MAX_CATALOG_PROOF_PHASES: usize = 64;
pub const MAX_CATALOG_PROOF_MODELS: usize = 512;
pub const MAX_CATALOG_QUALIFICATION_TARGETS: usize = 64;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogDiscoveryPreviewRequest {
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogDiscoveryApplyRequest {
pub preview: CatalogDiscoveryPreview,
pub expected_preview_sha256: String,
pub confirmation: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogQualificationPreviewRequest {
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
pub discovery_receipt_sha256: String,
pub targets: Vec<CatalogQualificationTarget>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogQualificationApplyRequest {
pub preview: CatalogQualificationPreview,
pub expected_preview_sha256: String,
pub confirmation: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogDiscoveryPlanEntry {
pub phase_id: PhaseId,
pub provider: ProviderService,
pub transport: TransportKind,
pub source: CatalogSourceKind,
pub configured_model_ids: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogDiscoveryPreview {
pub schema_version: String,
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
pub phases: Vec<CatalogDiscoveryPlanEntry>,
pub maximum_provider_requests: u32,
pub network_effect: bool,
pub inference_effect: bool,
pub credential_read_effect: bool,
pub preview_sha256: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CatalogDiscoveryOutcome {
Accepted,
RetainedLastKnownGood,
RejectedNoUsableLastKnownGood,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogCapabilityClassification {
pub context_tokens: u64,
pub modalities: Vec<String>,
pub tool_support: bool,
pub reasoning_modes: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogDiscoveredModelReceipt {
pub provider_model_id: String,
pub model_sha256: String,
pub capabilities: CatalogCapabilityClassification,
pub qualification_status: CatalogQualificationStatus,
pub exclusion_reason: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogPhaseDiscoveryReceipt {
pub phase_id: PhaseId,
pub provider: ProviderService,
pub source: CatalogSourceKind,
pub observed_at_epoch_seconds: u64,
pub outcome: CatalogDiscoveryOutcome,
pub catalog_version: Option<String>,
pub catalog_sha256: Option<String>,
pub models: Vec<CatalogDiscoveredModelReceipt>,
pub exclusion_reason: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogDiscoveryReceipt {
pub schema_version: String,
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
pub completed_at_epoch_seconds: u64,
pub phases: Vec<CatalogPhaseDiscoveryReceipt>,
pub receipt_sha256: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CatalogProofRole {
Routine,
Standard,
Complex,
Vision,
LongContext,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogQualificationTarget {
pub phase_id: PhaseId,
pub provider: ProviderService,
pub profile_id: String,
pub provider_model_id: String,
pub roles: Vec<CatalogProofRole>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogQualificationPreview {
pub schema_version: String,
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
pub discovery_receipt_sha256: String,
pub targets: Vec<CatalogQualificationTarget>,
pub maximum_inference_requests: u32,
pub maximum_openrouter_micro_usd: u64,
pub network_effect: bool,
pub inference_effect: bool,
pub credential_read_effect: bool,
pub preview_sha256: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CatalogQualificationStatus {
DiscoveredUnqualified,
Qualifying,
Qualified,
Rejected,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogModelQualificationReceipt {
pub target: CatalogQualificationTarget,
pub status: CatalogQualificationStatus,
pub catalog_version: String,
pub catalog_sha256: String,
pub model_sha256: String,
pub policy_version: Option<String>,
pub policy_sha256: Option<String>,
pub conformance_sha256: Option<String>,
pub evidence_ref: Option<String>,
pub exclusion_reason: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogQualificationReceipt {
pub schema_version: String,
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
pub discovery_receipt_sha256: String,
pub completed_at_epoch_seconds: u64,
pub results: Vec<CatalogModelQualificationReceipt>,
pub artifacts: Vec<CatalogQualificationArtifact>,
pub receipt_sha256: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CatalogQualificationArtifactKind {
CatalogBundle,
PolicyPack,
ConformanceSuite,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogQualificationArtifact {
pub kind: CatalogQualificationArtifactKind,
pub file_name: String,
pub provider: Option<ProviderService>,
pub phase_id: Option<PhaseId>,
pub content_sha256: String,
pub content: serde_json::Value,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogProofArtifact {
pub kind: String,
pub provider: Option<ProviderService>,
pub content_sha256: String,
pub byte_length: u64,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogProofArtifactManifest {
pub schema_version: String,
pub configuration_authority_id: String,
pub pre_authority_configuration_sha256: String,
pub discovery_receipt_sha256: String,
pub qualification_receipt_sha256: Option<String>,
pub artifacts: Vec<CatalogProofArtifact>,
pub manifest_sha256: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn apply_contracts_deny_unknown_fields_and_keep_confirmation_out_of_receipts() {
let value = serde_json::json!({
"preview": {
"schema_version": CATALOG_PROOF_SCHEMA_VERSION,
"configuration_authority_id": "configuration.device.alpha",
"pre_authority_configuration_sha256": "a".repeat(64),
"phases": [],
"maximum_provider_requests": 0,
"network_effect": true,
"inference_effect": false,
"credential_read_effect": true,
"preview_sha256": "b".repeat(64)
},
"expected_preview_sha256": "a".repeat(64),
"confirmation": LIVE_CATALOG_DISCOVERY_CONFIRMATION,
"secret": "forbidden"
});
assert!(serde_json::from_value::<CatalogDiscoveryApplyRequest>(value).is_err());
let receipt = CatalogDiscoveryReceipt {
schema_version: CATALOG_PROOF_SCHEMA_VERSION.to_owned(),
configuration_authority_id: "configuration.device.alpha".to_owned(),
pre_authority_configuration_sha256: "a".repeat(64),
completed_at_epoch_seconds: 1,
phases: Vec::new(),
receipt_sha256: "b".repeat(64),
};
let encoded = serde_json::to_string(&receipt).expect("receipt JSON");
assert!(!encoded.contains("confirmation"));
assert!(!encoded.contains("secret"));
}
}