use std::collections::BTreeMap;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub(crate) struct Contract {
pub(crate) snapshot: Snapshot,
#[serde(default)]
pub(crate) components: BTreeMap<String, Component>,
#[serde(default)]
pub(crate) services: BTreeMap<String, Service>,
#[serde(default)]
pub(crate) incompatible: Incompatible,
}
#[derive(Debug, Deserialize)]
pub(crate) struct Snapshot {
pub(crate) date: String,
pub(crate) arcature_version: String,
pub(crate) arcature_build_version: String,
pub(crate) arcature_client_version: String,
#[allow(dead_code)]
pub(crate) rust_toolchain: String,
}
#[derive(Debug, Deserialize)]
pub(crate) struct Component {
pub(crate) version: String,
#[allow(dead_code)]
pub(crate) status: String,
#[allow(dead_code)]
pub(crate) role: String,
}
#[derive(Debug, Deserialize)]
pub(crate) struct Service {
pub(crate) certified_versions: Vec<String>,
#[allow(dead_code)]
pub(crate) status: String,
pub(crate) role: String,
}
#[derive(Debug, Default, Deserialize)]
pub(crate) struct Incompatible {
#[serde(default)]
pub(crate) entries: Vec<IncompatibleEntry>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct IncompatibleEntry {
pub(crate) component: String,
pub(crate) version: String,
pub(crate) reason: String,
}
pub(crate) fn load() -> Contract {
toml::from_str(include_str!("contract.toml"))
.expect("embedded certified-stack contract is valid TOML")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn contract_parses_and_lists_all_components() {
let contract = load();
assert_eq!(contract.snapshot.arcature_version, "2026.2.1");
assert_eq!(
contract.snapshot.arcature_build_version, "2026.1.0",
"contract snapshot must declare an arcature-build version (its own release unit)"
);
assert!(
!contract.snapshot.arcature_client_version.is_empty(),
"contract snapshot must declare an @arcature/client version"
);
for name in [
"rust",
"tokio",
"axum",
"tower",
"tower_http",
"hyper",
"rustls",
"aws_lc_rs",
"serde",
"serde_json",
"sqlx",
"sea_orm",
"sea_orm_migration",
"redis",
"opendal",
"reqwest",
"lettre",
"argon2",
"tower_sessions",
"tracing",
"inertia",
"node",
"pnpm",
"vite",
"typescript",
"react",
"react_dom",
"vue",
"inertia_react",
"inertia_vue",
] {
assert!(
contract.components.contains_key(name),
"contract missing component `{name}`"
);
}
assert!(contract.services.contains_key("postgresql"));
assert!(contract.services.contains_key("valkey"));
assert_eq!(
contract.services["postgresql"].certified_versions,
vec!["15.13", "16.9", "17.5", "18.4"]
);
}
#[test]
fn no_component_claims_latest() {
let contract = load();
for (name, component) in &contract.components {
assert!(
!component.version.eq_ignore_ascii_case("latest"),
"component `{name}` claims `latest` — certified versions must be exact"
);
}
}
}