use router_protocol::CatalogSourceKind;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::{BTreeSet, HashSet};
use thiserror::Error;
pub const CATALOG_SCHEMA_VERSION: &str = "1.0.0";
pub const PROMOTION_AUTHORITY_SCHEMA_VERSION: &str = "1.0.0";
pub const REFRESH_BUCKET_SECONDS: u64 = 6 * 60 * 60;
pub const STALE_WARNING_SECONDS: u64 = 18 * 60 * 60;
pub const SNAPSHOT_EXPIRY_SECONDS: u64 = 24 * 60 * 60;
const MAX_CATALOG_MODELS: usize = 512;
const MAX_MODEL_MODALITIES: usize = 8;
const MAX_REASONING_MODES: usize = 8;
const MAX_ROLE_ALIASES: usize = 8;
pub trait ProviderCatalogDiscovery {
type NativeResponse;
fn source(&self) -> CatalogSourceKind;
fn normalize(
&self,
response: &Self::NativeResponse,
observed_at_epoch_seconds: u64,
) -> Result<Vec<NormalizedModelSpec>, CatalogError>;
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NormalizedModelSpec {
pub provider_model_id: String,
pub context_tokens: u64,
pub modalities: Vec<String>,
pub tool_support: bool,
pub reasoning_modes: Vec<String>,
pub pricing_provenance: String,
pub availability: String,
pub observed_at_epoch_seconds: u64,
}
impl NormalizedModelSpec {
pub fn fingerprint(&self) -> Result<String, CatalogError> {
validate_spec(self)?;
serde_json::to_vec(self)
.map(|bytes| sha256_hex(&bytes))
.map_err(|_| CatalogError::Malformed)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CatalogSnapshot {
schema_version: String,
snapshot_id: String,
provider_id: String,
catalog_version: String,
source: CatalogSourceKind,
source_receipt: String,
created_at_epoch_seconds: u64,
expires_at_epoch_seconds: u64,
content_sha256: String,
models: Vec<NormalizedModelSpec>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CatalogFreshness {
Fresh,
Warning,
Expired,
InvalidClock,
}
impl CatalogSnapshot {
#[allow(clippy::too_many_arguments)]
pub fn accept(
snapshot_id: impl Into<String>,
provider_id: impl Into<String>,
catalog_version: impl Into<String>,
source: CatalogSourceKind,
source_receipt: impl Into<String>,
created_at_epoch_seconds: u64,
mut models: Vec<NormalizedModelSpec>,
) -> Result<Self, CatalogError> {
let snapshot_id = snapshot_id.into();
let provider_id = provider_id.into();
let catalog_version = catalog_version.into();
let source_receipt = source_receipt.into();
if !valid_id(&snapshot_id)
|| !valid_id(&provider_id)
|| !valid_id(&catalog_version)
|| !valid_typed_digest_ref(&source_receipt, &["receipt", "manifest"])
|| models.is_empty()
|| models.len() > MAX_CATALOG_MODELS
{
return Err(CatalogError::Malformed);
}
let mut ids = HashSet::new();
for model in &models {
validate_spec(model)?;
if model.observed_at_epoch_seconds > created_at_epoch_seconds
|| !ids.insert(model.provider_model_id.as_str())
{
return Err(CatalogError::Contradictory);
}
}
models.sort_by(|left, right| left.provider_model_id.cmp(&right.provider_model_id));
let canonical = serde_json::to_vec(&models).map_err(|_| CatalogError::Malformed)?;
Ok(Self {
schema_version: CATALOG_SCHEMA_VERSION.to_owned(),
snapshot_id,
provider_id,
catalog_version,
source,
source_receipt,
created_at_epoch_seconds,
expires_at_epoch_seconds: created_at_epoch_seconds
.saturating_add(SNAPSHOT_EXPIRY_SECONDS),
content_sha256: sha256_hex(&canonical),
models,
})
}
pub fn freshness(&self, now_epoch_seconds: u64) -> CatalogFreshness {
if self.validate_integrity().is_err() {
return CatalogFreshness::Expired;
}
if now_epoch_seconds < self.created_at_epoch_seconds {
return CatalogFreshness::InvalidClock;
}
let age = now_epoch_seconds - self.created_at_epoch_seconds;
if age >= SNAPSHOT_EXPIRY_SECONDS {
CatalogFreshness::Expired
} else if age >= STALE_WARNING_SECONDS {
CatalogFreshness::Warning
} else {
CatalogFreshness::Fresh
}
}
pub fn content_sha256(&self) -> &str {
&self.content_sha256
}
pub fn catalog_version(&self) -> &str {
&self.catalog_version
}
pub fn provider_id(&self) -> &str {
&self.provider_id
}
pub fn model(&self, provider_model_id: &str) -> Option<&NormalizedModelSpec> {
self.models
.iter()
.find(|model| model.provider_model_id == provider_model_id)
}
pub fn models(&self) -> &[NormalizedModelSpec] {
&self.models
}
pub fn promotion_subset(&self, provider_model_ids: &[String]) -> Result<Self, CatalogError> {
self.validate_integrity()?;
if provider_model_ids.is_empty() || provider_model_ids.len() > MAX_CATALOG_MODELS {
return Err(CatalogError::Malformed);
}
let wanted = provider_model_ids.iter().collect::<HashSet<_>>();
if wanted.len() != provider_model_ids.len() {
return Err(CatalogError::Contradictory);
}
let models = self
.models
.iter()
.filter(|model| wanted.contains(&model.provider_model_id))
.cloned()
.collect::<Vec<_>>();
if models.len() != wanted.len() {
return Err(CatalogError::Contradictory);
}
Self::accept(
format!("{}.qualified", self.snapshot_id),
self.provider_id.clone(),
self.catalog_version.clone(),
self.source,
self.source_receipt.clone(),
self.created_at_epoch_seconds,
models,
)
}
pub fn validate_integrity(&self) -> Result<(), CatalogError> {
if self.schema_version != CATALOG_SCHEMA_VERSION
|| !valid_id(&self.snapshot_id)
|| !valid_id(&self.provider_id)
|| !valid_id(&self.catalog_version)
|| !valid_typed_digest_ref(&self.source_receipt, &["receipt", "manifest"])
|| self.models.is_empty()
|| self.models.len() > MAX_CATALOG_MODELS
|| self.expires_at_epoch_seconds
!= self
.created_at_epoch_seconds
.saturating_add(SNAPSHOT_EXPIRY_SECONDS)
{
return Err(CatalogError::Malformed);
}
let mut ids = HashSet::with_capacity(self.models.len());
for model in &self.models {
validate_spec(model)?;
if model.observed_at_epoch_seconds > self.created_at_epoch_seconds
|| !ids.insert(model.provider_model_id.as_str())
{
return Err(CatalogError::Contradictory);
}
}
let mut canonical = self.models.clone();
canonical.sort_by(|left, right| left.provider_model_id.cmp(&right.provider_model_id));
let encoded = serde_json::to_vec(&canonical).map_err(|_| CatalogError::Malformed)?;
if self.content_sha256 != sha256_hex(&encoded) {
return Err(CatalogError::Contradictory);
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum QualificationState {
Discovered,
Quarantined,
Qualifying,
Qualified,
Rejected,
Retired,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct QualificationEvidence {
pub evidence_ref: String,
pub model_sha256: String,
pub catalog_version: String,
pub catalog_sha256: String,
pub policy_version: String,
pub policy_sha256: String,
pub conformance_sha256: String,
pub operator_promotion_receipt: String,
pub role_aliases: Vec<String>,
pub fixture_only: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ModelQualification {
pub provider_model_id: String,
pub model_fingerprint: String,
pub catalog_version: String,
pub state: QualificationState,
pub evidence: Option<QualificationEvidence>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EligibilityBinding<'a> {
pub policy_version: &'a str,
pub policy_sha256: &'a str,
pub conformance_sha256: &'a str,
pub operator_promotion_receipt: &'a str,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PromotionMutationBinding {
pub schema_version: String,
pub promotion_id: String,
pub provider_id: String,
pub phase_id: String,
pub account_ref: String,
pub catalog_ref: String,
pub provider_model_id: String,
pub model_sha256: String,
pub catalog_version: String,
pub catalog_sha256: String,
pub policy_version: String,
pub policy_sha256: String,
pub conformance_sha256: String,
pub configuration_authority_id: String,
pub configuration_authority_sha256: String,
pub expected_state_generation: u64,
pub state_preimage_sha256: String,
pub state_postimage_sha256: String,
pub rollback_snapshot_sha256: String,
pub authorization_nonce: String,
pub authorized_at_epoch_seconds: u64,
pub rollback_not_after_epoch_seconds: u64,
}
impl PromotionMutationBinding {
pub fn binding_sha256(&self) -> Result<String, PromotionAuthorityError> {
self.validate()?;
serde_json::to_vec(self)
.map(|canonical| sha256_hex(&canonical))
.map_err(|_| PromotionAuthorityError::MalformedBinding)
}
fn validate(&self) -> Result<(), PromotionAuthorityError> {
if self.schema_version != PROMOTION_AUTHORITY_SCHEMA_VERSION
|| !valid_id(&self.promotion_id)
|| !valid_id(&self.provider_id)
|| !valid_id(&self.phase_id)
|| !valid_id(&self.account_ref)
|| !valid_id(&self.catalog_ref)
|| !valid_model_id(&self.provider_model_id)
|| !valid_sha256(&self.model_sha256)
|| !valid_id(&self.catalog_version)
|| !valid_sha256(&self.catalog_sha256)
|| !valid_id(&self.policy_version)
|| !valid_sha256(&self.policy_sha256)
|| !valid_sha256(&self.conformance_sha256)
|| !valid_id(&self.configuration_authority_id)
|| !valid_sha256(&self.configuration_authority_sha256)
|| !valid_sha256(&self.state_preimage_sha256)
|| !valid_sha256(&self.state_postimage_sha256)
|| !valid_sha256(&self.rollback_snapshot_sha256)
|| self.state_preimage_sha256 == self.state_postimage_sha256
|| self.rollback_snapshot_sha256 != self.state_preimage_sha256
|| !valid_id(&self.authorization_nonce)
|| self.rollback_not_after_epoch_seconds <= self.authorized_at_epoch_seconds
{
return Err(PromotionAuthorityError::MalformedBinding);
}
Ok(())
}
}
pub struct PromotionAuthorityRequest {
pub binding: PromotionMutationBinding,
pub operator_authority_id: String,
pub conformance_authority_id: String,
pub operator_evidence: Vec<u8>,
pub conformance_evidence: Vec<u8>,
pub fixture_only: bool,
}
impl PromotionAuthorityRequest {
fn validate(&self) -> Result<(), PromotionAuthorityError> {
const MAX_AUTHORITY_EVIDENCE_BYTES: usize = 64 * 1024;
self.binding.validate()?;
if !valid_id(&self.operator_authority_id)
|| !valid_id(&self.conformance_authority_id)
|| self.operator_evidence.is_empty()
|| self.operator_evidence.len() > MAX_AUTHORITY_EVIDENCE_BYTES
|| self.conformance_evidence.is_empty()
|| self.conformance_evidence.len() > MAX_AUTHORITY_EVIDENCE_BYTES
{
return Err(PromotionAuthorityError::MalformedEvidence);
}
Ok(())
}
}
mod promotion_verifier_sealed {
pub trait Sealed {}
}
pub trait PromotionAuthorityVerifier: promotion_verifier_sealed::Sealed {
fn verify(
&self,
request: &PromotionAuthorityRequest,
) -> Result<AuthenticatedPromotionAuthority, PromotionAuthorityError>;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct UnconfiguredPromotionAuthorityVerifier;
impl promotion_verifier_sealed::Sealed for UnconfiguredPromotionAuthorityVerifier {}
impl PromotionAuthorityVerifier for UnconfiguredPromotionAuthorityVerifier {
fn verify(
&self,
_request: &PromotionAuthorityRequest,
) -> Result<AuthenticatedPromotionAuthority, PromotionAuthorityError> {
Err(PromotionAuthorityError::TrustRootDecisionUnavailable)
}
}
#[derive(Debug, PartialEq, Eq)]
#[must_use]
pub struct AuthenticatedPromotionAuthority {
binding_sha256: String,
operator_authority_id: String,
conformance_authority_id: String,
}
impl AuthenticatedPromotionAuthority {
pub fn binding_sha256(&self) -> &str {
&self.binding_sha256
}
pub fn operator_authority_id(&self) -> &str {
&self.operator_authority_id
}
pub fn conformance_authority_id(&self) -> &str {
&self.conformance_authority_id
}
#[cfg(test)]
fn from_verified(request: &PromotionAuthorityRequest) -> Result<Self, PromotionAuthorityError> {
Ok(Self {
binding_sha256: request.binding.binding_sha256()?,
operator_authority_id: request.operator_authority_id.clone(),
conformance_authority_id: request.conformance_authority_id.clone(),
})
}
}
pub fn authenticate_promotion(
verifier: &impl PromotionAuthorityVerifier,
request: &PromotionAuthorityRequest,
) -> Result<AuthenticatedPromotionAuthority, PromotionAuthorityError> {
request.validate()?;
if request.fixture_only {
return Err(PromotionAuthorityError::FixtureEvidenceForbidden);
}
let expected_binding = request.binding.binding_sha256()?;
let authenticated = verifier.verify(request)?;
if authenticated.binding_sha256 != expected_binding
|| authenticated.operator_authority_id != request.operator_authority_id
|| authenticated.conformance_authority_id != request.conformance_authority_id
{
return Err(PromotionAuthorityError::BindingMismatch);
}
Ok(authenticated)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)]
pub enum PromotionAuthorityError {
#[error("promotion authority binding is malformed")]
MalformedBinding,
#[error("promotion authority evidence is malformed")]
MalformedEvidence,
#[error("fixture evidence cannot authorize promotion")]
FixtureEvidenceForbidden,
#[error("promotion trust-root decision is unavailable")]
TrustRootDecisionUnavailable,
#[error("promotion authority authentication failed")]
AuthenticationFailed,
#[error("authenticated promotion binding changed")]
BindingMismatch,
}
impl ModelQualification {
pub fn discovered(
provider_model_id: impl Into<String>,
model_fingerprint: impl Into<String>,
catalog_version: impl Into<String>,
) -> Result<Self, CatalogError> {
let value = Self {
provider_model_id: provider_model_id.into(),
model_fingerprint: model_fingerprint.into(),
catalog_version: catalog_version.into(),
state: QualificationState::Discovered,
evidence: None,
};
if !valid_model_id(&value.provider_model_id)
|| !valid_sha256(&value.model_fingerprint)
|| !valid_id(&value.catalog_version)
{
return Err(CatalogError::Malformed);
}
Ok(value)
}
pub fn quarantine(mut self) -> Result<Self, CatalogError> {
self.transition(
QualificationState::Discovered,
QualificationState::Quarantined,
)?;
Ok(self)
}
pub fn begin_qualification(mut self) -> Result<Self, CatalogError> {
self.transition(
QualificationState::Quarantined,
QualificationState::Qualifying,
)?;
Ok(self)
}
pub fn qualify(mut self, evidence: QualificationEvidence) -> Result<Self, CatalogError> {
if self.state != QualificationState::Qualifying
|| evidence.model_sha256 != self.model_fingerprint
|| evidence.catalog_version != self.catalog_version
|| !valid_qualification_evidence(&evidence)
{
return Err(CatalogError::InvalidTransition);
}
self.state = QualificationState::Qualified;
self.evidence = Some(evidence);
Ok(self)
}
pub fn reject(mut self) -> Result<Self, CatalogError> {
if !matches!(
self.state,
QualificationState::Quarantined | QualificationState::Qualifying
) {
return Err(CatalogError::InvalidTransition);
}
self.state = QualificationState::Rejected;
Ok(self)
}
pub fn retire(mut self) -> Result<Self, CatalogError> {
if self.state != QualificationState::Qualified {
return Err(CatalogError::InvalidTransition);
}
self.state = QualificationState::Retired;
Ok(self)
}
pub fn automatic_eligible(
&self,
snapshot: &CatalogSnapshot,
now_epoch_seconds: u64,
binding: &EligibilityBinding<'_>,
operator_approved: bool,
) -> bool {
snapshot.validate_integrity().is_ok()
&& valid_typed_digest_ref(binding.operator_promotion_receipt, &["approval", "receipt"])
&& valid_model_id(&self.provider_model_id)
&& valid_sha256(&self.model_fingerprint)
&& valid_id(&self.catalog_version)
&& self.state == QualificationState::Qualified
&& operator_approved
&& matches!(
snapshot.freshness(now_epoch_seconds),
CatalogFreshness::Fresh | CatalogFreshness::Warning
)
&& snapshot.catalog_version() == self.catalog_version
&& self.evidence.as_ref().is_some_and(|evidence| {
valid_qualification_evidence(evidence)
&& !evidence.fixture_only
&& evidence.model_sha256 == self.model_fingerprint
&& evidence.catalog_version == self.catalog_version
&& evidence.catalog_sha256 == snapshot.content_sha256()
&& evidence.policy_version == binding.policy_version
&& evidence.policy_sha256 == binding.policy_sha256
&& evidence.conformance_sha256 == binding.conformance_sha256
&& evidence.operator_promotion_receipt == binding.operator_promotion_receipt
})
&& snapshot
.model(&self.provider_model_id)
.is_some_and(|model| {
model.fingerprint().ok().as_deref() == Some(self.model_fingerprint.as_str())
})
}
fn transition(
&mut self,
expected: QualificationState,
next: QualificationState,
) -> Result<(), CatalogError> {
if self.state != expected {
return Err(CatalogError::InvalidTransition);
}
self.state = next;
Ok(())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RefreshReason {
StartupCatchUp,
UtcBucket,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RefreshDirective {
Due { bucket: u64, reason: RefreshReason },
Wait { until_epoch_seconds: u64 },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RefreshScheduler {
jitter_seconds: u64,
}
impl RefreshScheduler {
pub fn new(jitter_seconds: u64) -> Result<Self, CatalogError> {
if jitter_seconds >= REFRESH_BUCKET_SECONDS {
return Err(CatalogError::InvalidSchedule);
}
Ok(Self { jitter_seconds })
}
pub fn directive(
self,
now_epoch_seconds: u64,
last_success_epoch_seconds: Option<u64>,
) -> RefreshDirective {
let bucket = now_epoch_seconds / REFRESH_BUCKET_SECONDS;
let scheduled = bucket
.saturating_mul(REFRESH_BUCKET_SECONDS)
.saturating_add(self.jitter_seconds);
let Some(last_success) = last_success_epoch_seconds else {
return RefreshDirective::Due {
bucket,
reason: RefreshReason::StartupCatchUp,
};
};
if last_success / REFRESH_BUCKET_SECONDS < bucket && now_epoch_seconds >= scheduled {
RefreshDirective::Due {
bucket,
reason: RefreshReason::UtcBucket,
}
} else {
RefreshDirective::Wait {
until_epoch_seconds: if now_epoch_seconds < scheduled {
scheduled
} else {
bucket
.saturating_add(1)
.saturating_mul(REFRESH_BUCKET_SECONDS)
.saturating_add(self.jitter_seconds)
},
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)]
pub enum CatalogError {
#[error("catalog record is malformed")]
Malformed,
#[error("catalog contains contradictory records")]
Contradictory,
#[error("qualification transition is invalid")]
InvalidTransition,
#[error("refresh schedule is invalid")]
InvalidSchedule,
}
fn validate_spec(spec: &NormalizedModelSpec) -> Result<(), CatalogError> {
if !valid_model_id(&spec.provider_model_id)
|| spec.context_tokens == 0
|| spec.modalities.is_empty()
|| spec.modalities.len() > MAX_MODEL_MODALITIES
|| spec.modalities.iter().any(|item| !valid_id(item))
|| spec.modalities.iter().collect::<BTreeSet<_>>().len() != spec.modalities.len()
|| spec.reasoning_modes.len() > MAX_REASONING_MODES
|| spec.reasoning_modes.iter().any(|item| !valid_id(item))
|| spec.reasoning_modes.iter().collect::<BTreeSet<_>>().len() != spec.reasoning_modes.len()
|| !valid_id(&spec.pricing_provenance)
|| !valid_id(&spec.availability)
{
return Err(CatalogError::Malformed);
}
Ok(())
}
fn valid_qualification_evidence(evidence: &QualificationEvidence) -> bool {
valid_sha256(&evidence.model_sha256)
&& valid_id(&evidence.catalog_version)
&& valid_sha256(&evidence.catalog_sha256)
&& valid_id(&evidence.policy_version)
&& valid_sha256(&evidence.policy_sha256)
&& valid_sha256(&evidence.conformance_sha256)
&& valid_typed_digest_ref(
&evidence.operator_promotion_receipt,
&["approval", "receipt"],
)
&& valid_typed_digest_ref(
&evidence.evidence_ref,
&["evaluation", "manifest", "receipt"],
)
&& !evidence.role_aliases.is_empty()
&& evidence.role_aliases.len() <= MAX_ROLE_ALIASES
&& evidence.role_aliases.iter().all(|role| valid_id(role))
&& evidence.role_aliases.iter().collect::<BTreeSet<_>>().len()
== evidence.role_aliases.len()
}
fn valid_id(value: &str) -> bool {
!value.is_empty()
&& value.len() <= 128
&& value
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':'))
}
fn valid_model_id(value: &str) -> bool {
!value.is_empty()
&& value.len() <= 256
&& !value.starts_with('/')
&& !value.ends_with('/')
&& !value.contains("..")
&& !value.contains("//")
&& value.bytes().all(|byte| {
byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':' | b'/')
})
}
fn valid_sha256(value: &str) -> bool {
value.len() == 64
&& value
.bytes()
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
}
fn valid_typed_digest_ref(value: &str, allowed_kinds: &[&str]) -> bool {
let mut parts = value.split(':');
let kind = parts.next();
let algorithm = parts.next();
let digest = parts.next();
parts.next().is_none()
&& kind.is_some_and(|kind| allowed_kinds.contains(&kind))
&& algorithm == Some("sha256")
&& digest.is_some_and(valid_sha256)
}
fn sha256_hex(bytes: &[u8]) -> String {
let digest = Sha256::digest(bytes);
digest.iter().map(|byte| format!("{byte:02x}")).collect()
}
#[cfg(test)]
mod tests {
use super::*;
struct DeterministicTestVerifier;
impl promotion_verifier_sealed::Sealed for DeterministicTestVerifier {}
impl DeterministicTestVerifier {
fn evidence(label: &[u8], binding_sha256: &str) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(label);
hasher.update(binding_sha256.as_bytes());
hasher.finalize().to_vec()
}
fn request(&self, binding: PromotionMutationBinding) -> PromotionAuthorityRequest {
let binding_sha256 = binding.binding_sha256().expect("fixture binding");
PromotionAuthorityRequest {
binding,
operator_authority_id: "operator.test-anchor".to_owned(),
conformance_authority_id: "conformance.test-anchor".to_owned(),
operator_evidence: Self::evidence(b"operator-test-anchor", &binding_sha256),
conformance_evidence: Self::evidence(b"conformance-test-anchor", &binding_sha256),
fixture_only: false,
}
}
}
impl PromotionAuthorityVerifier for DeterministicTestVerifier {
fn verify(
&self,
request: &PromotionAuthorityRequest,
) -> Result<AuthenticatedPromotionAuthority, PromotionAuthorityError> {
let binding_sha256 = request.binding.binding_sha256()?;
let operator = Self::evidence(b"operator-test-anchor", &binding_sha256);
let conformance = Self::evidence(b"conformance-test-anchor", &binding_sha256);
if request.operator_evidence != operator
|| request.conformance_evidence != conformance
|| request.operator_authority_id != "operator.test-anchor"
|| request.conformance_authority_id != "conformance.test-anchor"
{
return Err(PromotionAuthorityError::AuthenticationFailed);
}
AuthenticatedPromotionAuthority::from_verified(request)
}
}
fn digest_ref(kind: &str, digit: char) -> String {
format!("{kind}:sha256:{}", digit.to_string().repeat(64))
}
fn model(id: &str, observed: u64) -> NormalizedModelSpec {
NormalizedModelSpec {
provider_model_id: id.to_owned(),
context_tokens: 32_768,
modalities: vec!["text".to_owned()],
tool_support: true,
reasoning_modes: vec!["medium".to_owned()],
pricing_provenance: "fixture".to_owned(),
availability: "available".to_owned(),
observed_at_epoch_seconds: observed,
}
}
#[test]
fn snapshot_is_versioned_hashed_and_expires_at_exact_boundaries() {
let snapshot = CatalogSnapshot::accept(
"snapshot.fixture.1",
"openai",
"catalog.1",
CatalogSourceKind::OpenaiHarnessCatalog,
digest_ref("receipt", '1'),
100,
vec![model("gpt-5.6-terra", 100)],
)
.expect("valid snapshot");
assert!(valid_sha256(snapshot.content_sha256()));
assert_eq!(
snapshot.freshness(100 + STALE_WARNING_SECONDS - 1),
CatalogFreshness::Fresh
);
assert_eq!(
snapshot.freshness(100 + STALE_WARNING_SECONDS),
CatalogFreshness::Warning
);
assert_eq!(
snapshot.freshness(100 + SNAPSHOT_EXPIRY_SECONDS),
CatalogFreshness::Expired
);
assert_eq!(snapshot.freshness(99), CatalogFreshness::InvalidClock);
}
#[test]
fn new_models_are_ineligible_until_exact_qualification_and_approval() {
let spec = model("gpt-5.6-luna", 10);
let fingerprint = spec.fingerprint().expect("fingerprint");
let snapshot = CatalogSnapshot::accept(
"snapshot.fixture.2",
"openai",
"catalog.2",
CatalogSourceKind::OpenaiHarnessCatalog,
digest_ref("receipt", '2'),
10,
vec![spec],
)
.expect("snapshot");
let discovered =
ModelQualification::discovered("gpt-5.6-luna", fingerprint.clone(), "catalog.2")
.expect("discovered");
let policy_sha256 = "1".repeat(64);
let conformance_sha256 = "2".repeat(64);
let operator_receipt = digest_ref("approval", '3');
let binding = EligibilityBinding {
policy_version: "policy.1",
policy_sha256: &policy_sha256,
conformance_sha256: &conformance_sha256,
operator_promotion_receipt: &operator_receipt,
};
assert!(!discovered.automatic_eligible(&snapshot, 10, &binding, true));
let qualified = discovered
.quarantine()
.expect("quarantine")
.begin_qualification()
.expect("qualification")
.qualify(QualificationEvidence {
evidence_ref: digest_ref("evaluation", '4'),
model_sha256: fingerprint,
catalog_version: "catalog.2".to_owned(),
catalog_sha256: snapshot.content_sha256().to_owned(),
policy_version: "policy.1".to_owned(),
policy_sha256: "1".repeat(64),
conformance_sha256: "2".repeat(64),
operator_promotion_receipt: digest_ref("approval", '3'),
role_aliases: vec!["routine".to_owned()],
fixture_only: false,
})
.expect("qualified");
assert!(!qualified.automatic_eligible(&snapshot, 10, &binding, false));
assert!(qualified.automatic_eligible(&snapshot, 10, &binding, true));
let mut fixture_qualification = qualified.clone();
fixture_qualification
.evidence
.as_mut()
.expect("evidence")
.fixture_only = true;
assert!(!fixture_qualification.automatic_eligible(&snapshot, 10, &binding, true));
assert!(!qualified.automatic_eligible(
&snapshot,
10 + SNAPSHOT_EXPIRY_SECONDS,
&binding,
true
));
}
#[test]
fn namespaced_model_ids_remain_eligible_after_exact_qualification() {
let spec = model("vendor/gpt-role", 10);
let fingerprint = spec.fingerprint().expect("fingerprint");
let snapshot = CatalogSnapshot::accept(
"snapshot.fixture.namespaced",
"openrouter",
"catalog.namespaced",
CatalogSourceKind::OpenrouterCatalog,
digest_ref("receipt", '5'),
10,
vec![spec],
)
.expect("namespaced snapshot");
let policy_sha256 = "6".repeat(64);
let conformance_sha256 = "7".repeat(64);
let operator_receipt = digest_ref("approval", '8');
let qualification = ModelQualification::discovered(
"vendor/gpt-role",
fingerprint.clone(),
"catalog.namespaced",
)
.expect("discovered namespaced model")
.quarantine()
.expect("quarantined")
.begin_qualification()
.expect("qualifying")
.qualify(QualificationEvidence {
evidence_ref: digest_ref("evaluation", '9'),
model_sha256: fingerprint,
catalog_version: "catalog.namespaced".to_owned(),
catalog_sha256: snapshot.content_sha256().to_owned(),
policy_version: "policy.namespaced".to_owned(),
policy_sha256: policy_sha256.clone(),
conformance_sha256: conformance_sha256.clone(),
operator_promotion_receipt: operator_receipt.clone(),
role_aliases: vec!["standard".to_owned()],
fixture_only: false,
})
.expect("qualified namespaced model");
let binding = EligibilityBinding {
policy_version: "policy.namespaced",
policy_sha256: &policy_sha256,
conformance_sha256: &conformance_sha256,
operator_promotion_receipt: &operator_receipt,
};
assert!(qualification.automatic_eligible(&snapshot, 10, &binding, true));
}
#[test]
fn contradictory_and_invalid_transitions_fail_closed() {
assert_eq!(
CatalogSnapshot::accept(
"snapshot.fixture.3",
"openai",
"catalog.3",
CatalogSourceKind::OpenaiHarnessCatalog,
digest_ref("receipt", '3'),
10,
vec![model("duplicate", 10), model("duplicate", 10)],
),
Err(CatalogError::Contradictory)
);
let discovered = ModelQualification::discovered("gpt-5.6-sol", "0".repeat(64), "catalog.3")
.expect("discovered");
assert_eq!(
discovered.clone().begin_qualification(),
Err(CatalogError::InvalidTransition)
);
assert_eq!(discovered.retire(), Err(CatalogError::InvalidTransition));
}
#[test]
fn deserialized_catalog_tampering_and_unhashed_receipts_fail_closed() {
assert_eq!(
CatalogSnapshot::accept(
"snapshot.fixture.4",
"openai",
"catalog.4",
CatalogSourceKind::OpenaiHarnessCatalog,
"receipt:raw-path/unsafe",
10,
vec![model("gpt-5.6-terra", 10)],
),
Err(CatalogError::Malformed)
);
let mut snapshot = CatalogSnapshot::accept(
"snapshot.fixture.4",
"openai",
"catalog.4",
CatalogSourceKind::OpenaiHarnessCatalog,
digest_ref("receipt", '4'),
10,
vec![model("gpt-5.6-terra", 10)],
)
.expect("snapshot");
snapshot.models[0].context_tokens = 1;
assert_eq!(
snapshot.validate_integrity(),
Err(CatalogError::Contradictory)
);
assert_eq!(snapshot.freshness(10), CatalogFreshness::Expired);
}
#[test]
fn scheduler_uses_six_hour_utc_buckets_jitter_and_startup_catchup() {
let scheduler = RefreshScheduler::new(300).expect("schedule");
assert_eq!(
scheduler.directive(25, None),
RefreshDirective::Due {
bucket: 0,
reason: RefreshReason::StartupCatchUp
}
);
assert_eq!(
scheduler.directive(REFRESH_BUCKET_SECONDS, Some(100)),
RefreshDirective::Wait {
until_epoch_seconds: REFRESH_BUCKET_SECONDS + 300
}
);
assert_eq!(
scheduler.directive(REFRESH_BUCKET_SECONDS + 300, Some(100)),
RefreshDirective::Due {
bucket: 1,
reason: RefreshReason::UtcBucket
}
);
}
fn promotion_binding() -> PromotionMutationBinding {
PromotionMutationBinding {
schema_version: PROMOTION_AUTHORITY_SCHEMA_VERSION.to_owned(),
promotion_id: "promotion.catalog.1".to_owned(),
provider_id: "openai".to_owned(),
phase_id: "openai_subscription".to_owned(),
account_ref: "account:openai".to_owned(),
catalog_ref: "catalog:v2:openai-subscription".to_owned(),
provider_model_id: "gpt-5.6-terra".to_owned(),
model_sha256: "1".repeat(64),
catalog_version: "catalog.1".to_owned(),
catalog_sha256: "2".repeat(64),
policy_version: "policy.1".to_owned(),
policy_sha256: "3".repeat(64),
conformance_sha256: "4".repeat(64),
configuration_authority_id: "config-authority.local".to_owned(),
configuration_authority_sha256: "5".repeat(64),
expected_state_generation: 9,
state_preimage_sha256: "6".repeat(64),
state_postimage_sha256: "7".repeat(64),
rollback_snapshot_sha256: "6".repeat(64),
authorization_nonce: "nonce.catalog.1".to_owned(),
authorized_at_epoch_seconds: 100,
rollback_not_after_epoch_seconds: 200,
}
}
#[test]
fn promotion_authority_binding_is_canonical_and_tamper_evident() {
let binding = promotion_binding();
let digest = binding.binding_sha256().expect("valid exact binding");
assert!(valid_sha256(&digest));
assert_eq!(
digest,
binding.binding_sha256().expect("deterministic digest")
);
let mut changed_generation = binding.clone();
changed_generation.expected_state_generation += 1;
assert_ne!(
digest,
changed_generation
.binding_sha256()
.expect("changed generation remains structurally valid")
);
let mut changed_postimage = binding.clone();
changed_postimage.state_postimage_sha256 = "8".repeat(64);
assert_ne!(
digest,
changed_postimage
.binding_sha256()
.expect("changed postimage remains structurally valid")
);
}
#[test]
fn promotion_authority_is_fail_closed_without_a_decided_trust_root() {
let request = PromotionAuthorityRequest {
binding: promotion_binding(),
operator_authority_id: "operator.local".to_owned(),
conformance_authority_id: "conformance.local".to_owned(),
operator_evidence: b"opaque-operator-evidence".to_vec(),
conformance_evidence: b"opaque-conformance-evidence".to_vec(),
fixture_only: false,
};
assert_eq!(
authenticate_promotion(&UnconfiguredPromotionAuthorityVerifier, &request),
Err(PromotionAuthorityError::TrustRootDecisionUnavailable)
);
}
#[test]
fn deterministic_test_verifier_rejects_fixture_replay_and_binding_substitution() {
let verifier = DeterministicTestVerifier;
let mut request = verifier.request(promotion_binding());
request.fixture_only = true;
assert_eq!(
authenticate_promotion(&verifier, &request),
Err(PromotionAuthorityError::FixtureEvidenceForbidden)
);
request.fixture_only = false;
let authenticated = authenticate_promotion(&verifier, &request)
.expect("unit-only configured-anchor fixture authenticates exact binding");
assert_eq!(
authenticated.binding_sha256(),
request.binding.binding_sha256().expect("binding digest")
);
let mut substituted = request;
substituted.binding.state_preimage_sha256 = "9".repeat(64);
substituted.binding.rollback_snapshot_sha256 = "9".repeat(64);
assert_eq!(
authenticate_promotion(&verifier, &substituted),
Err(PromotionAuthorityError::AuthenticationFailed)
);
}
}