use std::fmt;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tatara_core::domain::classification as core;
use tatara_core::domain::compliance_binding as core_compl;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct Classification {
pub point_type: ConvergencePointType,
pub substrate: SubstrateType,
#[serde(default)]
pub horizon: Horizon,
#[serde(default)]
pub calm: CalmClassification,
#[serde(default)]
pub data_classification: DataClassification,
}
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
JsonSchema,
tatara_lisp::DeriveClosedSet,
)]
#[serde(rename_all = "PascalCase")]
#[closed_set(via = "as_str", generate_unknown, display)]
pub enum ConvergencePointType {
Transform,
Fork,
Join,
Gate,
Select,
Broadcast,
Reduce,
Observe,
}
impl ConvergencePointType {
pub const ALL: [Self; 8] = [
Self::Transform,
Self::Fork,
Self::Join,
Self::Gate,
Self::Select,
Self::Broadcast,
Self::Reduce,
Self::Observe,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::Transform => "Transform",
Self::Fork => "Fork",
Self::Join => "Join",
Self::Gate => "Gate",
Self::Select => "Select",
Self::Broadcast => "Broadcast",
Self::Reduce => "Reduce",
Self::Observe => "Observe",
}
}
pub const fn input_arity(self) -> Arity {
match self {
Self::Transform | Self::Fork | Self::Broadcast | Self::Observe => Arity::One,
Self::Join | Self::Gate | Self::Select | Self::Reduce => Arity::Many,
}
}
pub const fn output_arity(self) -> Arity {
match self {
Self::Fork | Self::Broadcast => Arity::Many,
Self::Transform
| Self::Join
| Self::Gate
| Self::Select
| Self::Reduce
| Self::Observe => Arity::One,
}
}
pub const fn is_endomorphic(self) -> bool {
match self {
Self::Transform | Self::Observe => true,
Self::Fork
| Self::Join
| Self::Gate
| Self::Select
| Self::Broadcast
| Self::Reduce => false,
}
}
pub const fn is_diffusive(self) -> bool {
match self {
Self::Fork | Self::Broadcast => true,
Self::Transform
| Self::Join
| Self::Gate
| Self::Select
| Self::Reduce
| Self::Observe => false,
}
}
pub const fn is_convergent(self) -> bool {
match self {
Self::Join | Self::Gate | Self::Select | Self::Reduce => true,
Self::Transform | Self::Fork | Self::Broadcast | Self::Observe => false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Arity {
One,
Many,
}
impl Arity {
pub const ALL: [Self; 2] = [Self::One, Self::Many];
pub const fn as_str(self) -> &'static str {
match self {
Self::One => "One",
Self::Many => "Many",
}
}
pub const fn is_one(self) -> bool {
match self {
Self::One => true,
Self::Many => false,
}
}
}
impl fmt::Display for Arity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Serialize,
Deserialize,
JsonSchema,
tatara_lisp::DeriveClosedSet,
)]
#[serde(rename_all = "PascalCase")]
#[closed_set(via = "as_str", generate_unknown, display)]
pub enum SubstrateType {
Financial,
Compute,
Network,
Storage,
Security,
Identity,
Observability,
Regulatory,
}
impl SubstrateType {
pub const ALL: [Self; 8] = [
Self::Financial,
Self::Compute,
Self::Network,
Self::Storage,
Self::Security,
Self::Identity,
Self::Observability,
Self::Regulatory,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::Financial => "Financial",
Self::Compute => "Compute",
Self::Network => "Network",
Self::Storage => "Storage",
Self::Security => "Security",
Self::Identity => "Identity",
Self::Observability => "Observability",
Self::Regulatory => "Regulatory",
}
}
pub const fn is_resource(self) -> bool {
match self {
Self::Financial | Self::Compute | Self::Network | Self::Storage => true,
Self::Security | Self::Identity | Self::Observability | Self::Regulatory => false,
}
}
pub const fn is_policy(self) -> bool {
match self {
Self::Security | Self::Identity | Self::Regulatory => true,
Self::Financial
| Self::Compute
| Self::Network
| Self::Storage
| Self::Observability => false,
}
}
pub const fn is_telemetry(self) -> bool {
match self {
Self::Observability => true,
Self::Financial
| Self::Compute
| Self::Network
| Self::Storage
| Self::Security
| Self::Identity
| Self::Regulatory => false,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct Horizon {
#[serde(default)]
pub kind: HorizonKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metric: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub direction: Option<OptimizationDirection>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub healthy_rate_threshold: Option<f64>,
}
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
JsonSchema,
Default,
tatara_lisp::DeriveClosedSet,
)]
#[serde(rename_all = "PascalCase")]
#[closed_set(via = "as_str", generate_unknown, display)]
pub enum HorizonKind {
#[default]
Bounded,
Asymptotic,
}
impl HorizonKind {
pub const ALL: [Self; 2] = [Self::Bounded, Self::Asymptotic];
pub const fn as_str(self) -> &'static str {
match self {
Self::Bounded => "Bounded",
Self::Asymptotic => "Asymptotic",
}
}
pub const fn terminates(self) -> bool {
match self {
Self::Bounded => true,
Self::Asymptotic => false,
}
}
pub const fn requires_metric_axes(self) -> bool {
match self {
Self::Bounded => false,
Self::Asymptotic => true,
}
}
}
impl Horizon {
pub fn bounded() -> Self {
Self::default()
}
pub fn asymptotic(
metric: impl Into<String>,
direction: OptimizationDirection,
threshold: f64,
) -> Self {
Self {
kind: HorizonKind::Asymptotic,
metric: Some(metric.into()),
direction: Some(direction),
healthy_rate_threshold: Some(threshold),
}
}
}
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
JsonSchema,
Default,
tatara_lisp::DeriveClosedSet,
)]
#[serde(rename_all = "PascalCase")]
#[closed_set(via = "as_str", generate_unknown, display)]
pub enum OptimizationDirection {
#[default]
Minimize,
Maximize,
}
impl OptimizationDirection {
pub const ALL: [Self; 2] = [Self::Minimize, Self::Maximize];
pub const fn as_str(self) -> &'static str {
match self {
Self::Minimize => "Minimize",
Self::Maximize => "Maximize",
}
}
pub const fn prefers_lower(self) -> bool {
match self {
Self::Minimize => true,
Self::Maximize => false,
}
}
pub fn is_improvement(self, before: f64, after: f64) -> bool {
match self {
Self::Minimize => after < before,
Self::Maximize => after > before,
}
}
}
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
JsonSchema,
Default,
tatara_lisp::DeriveClosedSet,
)]
#[serde(rename_all = "PascalCase")]
#[closed_set(via = "as_str", generate_unknown, display)]
pub enum CalmClassification {
#[default]
Monotone,
NonMonotone,
}
impl CalmClassification {
pub const ALL: [Self; 2] = [Self::Monotone, Self::NonMonotone];
pub const fn as_str(self) -> &'static str {
match self {
Self::Monotone => "Monotone",
Self::NonMonotone => "NonMonotone",
}
}
pub const fn requires_coordination(self) -> bool {
match self {
Self::Monotone => false,
Self::NonMonotone => true,
}
}
}
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
JsonSchema,
Default,
tatara_lisp::DeriveClosedSet,
)]
#[serde(rename_all = "PascalCase")]
#[closed_set(via = "as_str", generate_unknown, display)]
pub enum DataClassification {
Public,
#[default]
Internal,
Confidential,
Pii,
Phi,
Pci,
}
impl DataClassification {
pub const ALL: [Self; 6] = [
Self::Public,
Self::Internal,
Self::Confidential,
Self::Pii,
Self::Phi,
Self::Pci,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::Public => "Public",
Self::Internal => "Internal",
Self::Confidential => "Confidential",
Self::Pii => "Pii",
Self::Phi => "Phi",
Self::Pci => "Pci",
}
}
pub const fn sensitivity_rank(self) -> u8 {
match self {
Self::Public => 0,
Self::Internal => 1,
Self::Confidential => 2,
Self::Pii => 3,
Self::Phi => 4,
Self::Pci => 5,
}
}
pub const fn is_regulated(self) -> bool {
match self {
Self::Pii | Self::Phi | Self::Pci => true,
Self::Public | Self::Internal | Self::Confidential => false,
}
}
pub const fn is_restricted(self) -> bool {
match self {
Self::Public => false,
Self::Internal | Self::Confidential | Self::Pii | Self::Phi | Self::Pci => true,
}
}
}
impl From<ConvergencePointType> for core::ConvergencePointType {
fn from(v: ConvergencePointType) -> Self {
use ConvergencePointType::*;
match v {
Transform => Self::Transform,
Fork => Self::Fork,
Join => Self::Join,
Gate => Self::Gate,
Select => Self::Select,
Broadcast => Self::Broadcast,
Reduce => Self::Reduce,
Observe => Self::Observe,
}
}
}
impl From<core::ConvergencePointType> for ConvergencePointType {
fn from(v: core::ConvergencePointType) -> Self {
use core::ConvergencePointType as C;
match v {
C::Transform => Self::Transform,
C::Fork => Self::Fork,
C::Join => Self::Join,
C::Gate => Self::Gate,
C::Select => Self::Select,
C::Broadcast => Self::Broadcast,
C::Reduce => Self::Reduce,
C::Observe => Self::Observe,
}
}
}
impl From<SubstrateType> for core::SubstrateType {
fn from(v: SubstrateType) -> Self {
use SubstrateType::*;
match v {
Financial => Self::Financial,
Compute => Self::Compute,
Network => Self::Network,
Storage => Self::Storage,
Security => Self::Security,
Identity => Self::Identity,
Observability => Self::Observability,
Regulatory => Self::Regulatory,
}
}
}
impl From<core::SubstrateType> for SubstrateType {
fn from(v: core::SubstrateType) -> Self {
use core::SubstrateType as C;
match v {
C::Financial => Self::Financial,
C::Compute => Self::Compute,
C::Network => Self::Network,
C::Storage => Self::Storage,
C::Security => Self::Security,
C::Identity => Self::Identity,
C::Observability => Self::Observability,
C::Regulatory => Self::Regulatory,
}
}
}
impl From<OptimizationDirection> for core::OptimizationDirection {
fn from(v: OptimizationDirection) -> Self {
match v {
OptimizationDirection::Minimize => Self::Minimize,
OptimizationDirection::Maximize => Self::Maximize,
}
}
}
impl From<core::OptimizationDirection> for OptimizationDirection {
fn from(v: core::OptimizationDirection) -> Self {
use core::OptimizationDirection as C;
match v {
C::Minimize => Self::Minimize,
C::Maximize => Self::Maximize,
}
}
}
impl From<Horizon> for core::ConvergenceHorizon {
fn from(v: Horizon) -> Self {
match v.kind {
HorizonKind::Bounded => Self::Bounded,
HorizonKind::Asymptotic => Self::Asymptotic {
metric: v.metric.unwrap_or_default(),
direction: v.direction.unwrap_or_default().into(),
healthy_rate_threshold: v.healthy_rate_threshold.unwrap_or_default(),
},
}
}
}
impl From<CalmClassification> for core::CalmClassification {
fn from(v: CalmClassification) -> Self {
match v {
CalmClassification::Monotone => Self::Monotone,
CalmClassification::NonMonotone => Self::NonMonotone,
}
}
}
impl From<core::CalmClassification> for CalmClassification {
fn from(v: core::CalmClassification) -> Self {
use core::CalmClassification as C;
match v {
C::Monotone => Self::Monotone,
C::NonMonotone => Self::NonMonotone,
}
}
}
impl From<DataClassification> for core_compl::DataClassification {
fn from(v: DataClassification) -> Self {
use DataClassification::*;
match v {
Public => Self::Public,
Internal => Self::Internal,
Confidential => Self::Confidential,
Pii => Self::Pii,
Phi => Self::Phi,
Pci => Self::Pci,
}
}
}
impl From<core_compl::DataClassification> for DataClassification {
fn from(v: core_compl::DataClassification) -> Self {
use core_compl::DataClassification as C;
match v {
C::Public => Self::Public,
C::Internal => Self::Internal,
C::Confidential => Self::Confidential,
C::Pii => Self::Pii,
C::Phi => Self::Phi,
C::Pci => Self::Pci,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn bridges_roundtrip() {
let pt: core::ConvergencePointType = ConvergencePointType::Gate.into();
let back: ConvergencePointType = pt.into();
assert_eq!(back, ConvergencePointType::Gate);
let sub: core::SubstrateType = SubstrateType::Observability.into();
let back: SubstrateType = sub.into();
assert_eq!(back, SubstrateType::Observability);
}
#[test]
fn data_classification_ordering() {
assert!(DataClassification::Public < DataClassification::Pii);
assert!(DataClassification::Internal < DataClassification::Confidential);
}
#[test]
fn horizon_default_is_bounded() {
assert_eq!(Horizon::default().kind, HorizonKind::Bounded);
}
#[test]
fn data_classification_is_well_formed_closed_set() {
tatara_lisp::assert_closed_set_well_formed::<DataClassification>();
}
#[test]
fn data_classification_as_str_matches_serde() {
for class in DataClassification::ALL {
let serialized = serde_json::to_string(&class).expect("serialize");
let unquoted = serialized
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
assert_eq!(
unquoted,
class.as_str(),
"as_str drift for {class:?}: as_str={} serde={unquoted}",
class.as_str()
);
}
}
#[test]
fn data_classification_display_matches_as_str() {
for class in DataClassification::ALL {
assert_eq!(class.to_string(), class.as_str());
}
}
#[test]
fn unknown_data_classification_errors() {
for bad in [
"pii", "PII", "PersonalData", "internal_data",
"Steady", "Replace", "Attested", "Compute", "Gate", "Monotone", ] {
let err = DataClassification::from_str(bad).unwrap_err();
assert_eq!(err.0, bad, "error payload should echo input verbatim");
}
}
#[test]
fn data_classification_predicate_truth_tables() {
assert!(!DataClassification::Public.is_restricted());
assert!(!DataClassification::Public.is_regulated());
assert!(DataClassification::Internal.is_restricted());
assert!(!DataClassification::Internal.is_regulated());
assert!(DataClassification::Confidential.is_restricted());
assert!(!DataClassification::Confidential.is_regulated());
assert!(DataClassification::Pii.is_restricted());
assert!(DataClassification::Pii.is_regulated());
assert!(DataClassification::Phi.is_restricted());
assert!(DataClassification::Phi.is_regulated());
assert!(DataClassification::Pci.is_restricted());
assert!(DataClassification::Pci.is_regulated());
}
#[test]
fn data_classification_regulated_implies_restricted() {
for class in DataClassification::ALL {
assert!(
!class.is_regulated() || class.is_restricted(),
"{class:?} is regulated but not restricted — \
regulated data is by definition not freely distributable",
);
}
}
#[test]
fn data_classification_buckets_cover_every_variant() {
let mut free = 0u32;
let mut restricted_only = 0u32;
let mut regulated = 0u32;
for class in DataClassification::ALL {
match (class.is_restricted(), class.is_regulated()) {
(false, false) => free += 1,
(true, false) => restricted_only += 1,
(true, true) => regulated += 1,
(false, true) => {
panic!("regulated_implies_restricted already pins this empty for {class:?}")
}
}
}
assert_eq!(free, 1, "free bucket: Public");
assert_eq!(
restricted_only, 2,
"restricted-only bucket: Internal + Confidential"
);
assert_eq!(regulated, 3, "regulated bucket: Pii + Phi + Pci");
assert_eq!(
free + restricted_only + regulated,
DataClassification::ALL.len() as u32
);
}
#[test]
fn data_classification_rank_is_strictly_monotone_over_all() {
let ranks: Vec<u8> = DataClassification::ALL
.into_iter()
.map(DataClassification::sensitivity_rank)
.collect();
for win in ranks.windows(2) {
assert!(win[0] < win[1], "ranks not strictly monotone: {ranks:?}");
}
assert_eq!(*ranks.first().unwrap(), 0, "bottom rank must be 0");
assert_eq!(
*ranks.last().unwrap(),
(DataClassification::ALL.len() as u8) - 1,
"top rank must be ALL.len() - 1"
);
}
#[test]
fn data_classification_rank_agrees_with_partial_ord() {
for a in DataClassification::ALL {
for b in DataClassification::ALL {
assert_eq!(
a.sensitivity_rank() <= b.sensitivity_rank(),
a <= b,
"rank vs. PartialOrd drift on ({a:?}, {b:?})"
);
}
}
}
#[test]
fn data_classification_default_is_internal_in_restricted_only_bucket() {
let d = DataClassification::default();
assert_eq!(d, DataClassification::Internal);
assert!(d.is_restricted());
assert!(!d.is_regulated());
assert_eq!(d.sensitivity_rank(), 1);
}
#[test]
fn data_classification_bridge_roundtrip_over_all() {
for class in DataClassification::ALL {
let core: core_compl::DataClassification = class.into();
let back: DataClassification = core.into();
assert_eq!(back, class, "bridge round-trip failed for {class:?}");
}
}
#[test]
fn convergence_point_type_is_well_formed_closed_set() {
tatara_lisp::assert_closed_set_well_formed::<ConvergencePointType>();
}
#[test]
fn convergence_point_type_as_str_matches_serde() {
for t in ConvergencePointType::ALL {
let serialized = serde_json::to_string(&t).expect("serialize");
let unquoted = serialized
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
assert_eq!(
unquoted,
t.as_str(),
"as_str drift for {t:?}: as_str={} serde={unquoted}",
t.as_str()
);
}
}
#[test]
fn convergence_point_type_display_matches_as_str() {
for t in ConvergencePointType::ALL {
assert_eq!(t.to_string(), t.as_str());
}
}
#[test]
fn unknown_convergence_point_type_errors() {
for bad in [
"gate", "GATE", "Transformr", "Filter",
"Steady", "Pii", "Attested", "Compute", "Monotone", "PromQL", ] {
let err = ConvergencePointType::from_str(bad).unwrap_err();
assert_eq!(err.0, bad, "error payload should echo input verbatim");
}
}
#[test]
fn convergence_point_type_predicate_truth_tables() {
assert!(ConvergencePointType::Transform.is_endomorphic());
assert!(!ConvergencePointType::Transform.is_diffusive());
assert!(!ConvergencePointType::Transform.is_convergent());
assert!(ConvergencePointType::Observe.is_endomorphic());
assert!(!ConvergencePointType::Observe.is_diffusive());
assert!(!ConvergencePointType::Observe.is_convergent());
assert!(!ConvergencePointType::Fork.is_endomorphic());
assert!(ConvergencePointType::Fork.is_diffusive());
assert!(!ConvergencePointType::Fork.is_convergent());
assert!(!ConvergencePointType::Broadcast.is_endomorphic());
assert!(ConvergencePointType::Broadcast.is_diffusive());
assert!(!ConvergencePointType::Broadcast.is_convergent());
for t in [
ConvergencePointType::Join,
ConvergencePointType::Gate,
ConvergencePointType::Select,
ConvergencePointType::Reduce,
] {
assert!(!t.is_endomorphic(), "{t:?} should not be endomorphic");
assert!(!t.is_diffusive(), "{t:?} should not be diffusive");
assert!(t.is_convergent(), "{t:?} should be convergent");
}
}
#[test]
fn convergence_point_type_buckets_cover_every_variant() {
let mut endomorphic = 0u32;
let mut diffusive = 0u32;
let mut convergent = 0u32;
for t in ConvergencePointType::ALL {
let buckets = [t.is_endomorphic(), t.is_diffusive(), t.is_convergent()];
let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
assert_eq!(
hits, 1,
"{t:?} landed in {hits} buckets: {buckets:?} (must be exactly one)"
);
if t.is_endomorphic() {
endomorphic += 1;
}
if t.is_diffusive() {
diffusive += 1;
}
if t.is_convergent() {
convergent += 1;
}
}
assert_eq!(endomorphic, 2, "endomorphic bucket: Transform + Observe");
assert_eq!(diffusive, 2, "diffusive bucket: Fork + Broadcast");
assert_eq!(
convergent, 4,
"convergent bucket: Join + Gate + Select + Reduce"
);
assert_eq!(
endomorphic + diffusive + convergent,
ConvergencePointType::ALL.len() as u32
);
}
#[test]
fn convergence_point_type_arity_pair_agrees_with_bucket() {
for t in ConvergencePointType::ALL {
match (t.input_arity(), t.output_arity()) {
(Arity::One, Arity::One) => assert!(
t.is_endomorphic(),
"{t:?} has (One, One) arity but is not endomorphic"
),
(Arity::One, Arity::Many) => assert!(
t.is_diffusive(),
"{t:?} has (One, Many) arity but is not diffusive"
),
(Arity::Many, Arity::One) => assert!(
t.is_convergent(),
"{t:?} has (Many, One) arity but is not convergent"
),
(Arity::Many, Arity::Many) => panic!(
"{t:?} has (Many, Many) arity — pinned empty; \
extend the topology carving before adding a variant here"
),
}
}
}
#[test]
fn convergence_point_type_bridge_roundtrip_over_all() {
for t in ConvergencePointType::ALL {
let core_t: core::ConvergencePointType = t.into();
let back: ConvergencePointType = core_t.into();
assert_eq!(back, t, "bridge round-trip failed for {t:?}");
}
}
#[test]
fn arity_all_is_unique_and_complete() {
let mut seen = std::collections::HashSet::new();
for a in Arity::ALL {
assert!(seen.insert(a), "duplicate variant in ALL: {a:?}");
}
assert_eq!(seen.len(), Arity::ALL.len());
}
#[test]
fn arity_display_matches_as_str() {
for a in Arity::ALL {
assert_eq!(a.to_string(), a.as_str());
}
}
#[test]
fn arity_is_one_predicate_truth_table() {
assert!(Arity::One.is_one());
assert!(!Arity::Many.is_one());
}
#[test]
fn substrate_type_is_well_formed_closed_set() {
tatara_lisp::assert_closed_set_well_formed::<SubstrateType>();
}
#[test]
fn substrate_type_as_str_matches_serde() {
for t in SubstrateType::ALL {
let serialized = serde_json::to_string(&t).expect("serialize");
let unquoted = serialized
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
assert_eq!(
unquoted,
t.as_str(),
"as_str drift for {t:?}: as_str={} serde={unquoted}",
t.as_str()
);
}
}
#[test]
fn substrate_type_display_matches_as_str() {
for t in SubstrateType::ALL {
assert_eq!(t.to_string(), t.as_str());
}
}
#[test]
fn unknown_substrate_type_errors() {
for bad in [
"compute", "COMPUTE", "Computte", "Database", "Steady", "Pii", "Attested", "Gate", "Monotone", "PromQL", ] {
let err = SubstrateType::from_str(bad).unwrap_err();
assert_eq!(err.0, bad, "error payload should echo input verbatim");
}
}
#[test]
fn substrate_type_predicate_truth_tables() {
for t in [
SubstrateType::Financial,
SubstrateType::Compute,
SubstrateType::Network,
SubstrateType::Storage,
] {
assert!(t.is_resource(), "{t:?} should be a resource substrate");
assert!(!t.is_policy(), "{t:?} should not be a policy substrate");
assert!(
!t.is_telemetry(),
"{t:?} should not be a telemetry substrate"
);
}
for t in [
SubstrateType::Security,
SubstrateType::Identity,
SubstrateType::Regulatory,
] {
assert!(!t.is_resource(), "{t:?} should not be a resource substrate");
assert!(t.is_policy(), "{t:?} should be a policy substrate");
assert!(
!t.is_telemetry(),
"{t:?} should not be a telemetry substrate"
);
}
assert!(!SubstrateType::Observability.is_resource());
assert!(!SubstrateType::Observability.is_policy());
assert!(SubstrateType::Observability.is_telemetry());
}
#[test]
fn substrate_type_buckets_cover_every_variant() {
let mut resource = 0u32;
let mut policy = 0u32;
let mut telemetry = 0u32;
for t in SubstrateType::ALL {
let buckets = [t.is_resource(), t.is_policy(), t.is_telemetry()];
let hits: u32 = buckets.iter().map(|b| u32::from(*b)).sum();
assert_eq!(
hits, 1,
"{t:?} landed in {hits} buckets: {buckets:?} (must be exactly one)"
);
if t.is_resource() {
resource += 1;
}
if t.is_policy() {
policy += 1;
}
if t.is_telemetry() {
telemetry += 1;
}
}
assert_eq!(
resource, 4,
"resource bucket: Financial + Compute + Network + Storage"
);
assert_eq!(policy, 3, "policy bucket: Security + Identity + Regulatory");
assert_eq!(telemetry, 1, "telemetry bucket: Observability");
assert_eq!(
resource + policy + telemetry,
SubstrateType::ALL.len() as u32
);
}
#[test]
fn substrate_type_bridge_roundtrip_over_all() {
for t in SubstrateType::ALL {
let core_t: core::SubstrateType = t.into();
let back: SubstrateType = core_t.into();
assert_eq!(back, t, "bridge round-trip failed for {t:?}");
}
}
#[test]
fn calm_classification_is_well_formed_closed_set() {
tatara_lisp::assert_closed_set_well_formed::<CalmClassification>();
}
#[test]
fn calm_classification_as_str_matches_serde() {
for c in CalmClassification::ALL {
let serialized = serde_json::to_string(&c).expect("serialize");
let unquoted = serialized
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
assert_eq!(
unquoted,
c.as_str(),
"as_str drift for {c:?}: as_str={} serde={unquoted}",
c.as_str()
);
}
}
#[test]
fn calm_classification_display_matches_as_str() {
for c in CalmClassification::ALL {
assert_eq!(c.to_string(), c.as_str());
}
}
#[test]
fn unknown_calm_classification_errors() {
for bad in [
"monotone", "MONOTONE", "Mono", "non_monotone", "non-monotone", "Monotonic", "Steady", "Pii", "Attested", "Compute", "Gate", "PromQL", ] {
let err = CalmClassification::from_str(bad).unwrap_err();
assert_eq!(err.0, bad, "error payload should echo input verbatim");
}
}
#[test]
fn calm_classification_requires_coordination_truth_table() {
assert!(!CalmClassification::Monotone.requires_coordination());
assert!(CalmClassification::NonMonotone.requires_coordination());
}
#[test]
fn calm_classification_buckets_cover_every_variant() {
let mut no_coord = 0u32;
let mut coord = 0u32;
for c in CalmClassification::ALL {
if c.requires_coordination() {
coord += 1;
} else {
no_coord += 1;
}
}
assert_eq!(no_coord, 1, "no-coordination bucket: Monotone");
assert_eq!(coord, 1, "requires-coordination bucket: NonMonotone");
assert_eq!(no_coord + coord, CalmClassification::ALL.len() as u32);
}
#[test]
fn calm_classification_default_is_monotone_no_coordination() {
let c = CalmClassification::default();
assert_eq!(c, CalmClassification::Monotone);
assert!(!c.requires_coordination());
}
#[test]
fn calm_classification_bridge_roundtrip_over_all() {
for c in CalmClassification::ALL {
let core_c: core::CalmClassification = c.into();
let back: CalmClassification = core_c.into();
assert_eq!(back, c, "bridge round-trip failed for {c:?}");
}
}
#[test]
fn optimization_direction_is_well_formed_closed_set() {
tatara_lisp::assert_closed_set_well_formed::<OptimizationDirection>();
}
#[test]
fn optimization_direction_as_str_matches_serde() {
for d in OptimizationDirection::ALL {
let serialized = serde_json::to_string(&d).expect("serialize");
let unquoted = serialized
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
assert_eq!(
unquoted,
d.as_str(),
"as_str drift for {d:?}: as_str={} serde={unquoted}",
d.as_str()
);
}
}
#[test]
fn optimization_direction_display_matches_as_str() {
for d in OptimizationDirection::ALL {
assert_eq!(d.to_string(), d.as_str());
}
}
#[test]
fn unknown_optimization_direction_errors() {
for bad in [
"minimize", "MINIMIZE", "Minimze", "Lower", "Higher", "Asc", "Desc", "Bounded", "Monotone", "Steady", "Pii", "Attested", "Compute", "Gate", "PromQL", ] {
let err = OptimizationDirection::from_str(bad).unwrap_err();
assert_eq!(err.0, bad, "error payload should echo input verbatim");
}
}
#[test]
fn optimization_direction_prefers_lower_truth_table() {
assert!(OptimizationDirection::Minimize.prefers_lower());
assert!(!OptimizationDirection::Maximize.prefers_lower());
}
#[test]
fn optimization_direction_buckets_cover_every_variant() {
let mut lower = 0u32;
let mut higher = 0u32;
for d in OptimizationDirection::ALL {
if d.prefers_lower() {
lower += 1;
} else {
higher += 1;
}
}
assert_eq!(lower, 1, "prefers-lower bucket: Minimize");
assert_eq!(higher, 1, "prefers-higher bucket: Maximize");
assert_eq!(lower + higher, OptimizationDirection::ALL.len() as u32);
}
#[test]
fn optimization_direction_is_improvement_truth_table() {
assert!(OptimizationDirection::Minimize.is_improvement(10.0, 5.0));
assert!(!OptimizationDirection::Minimize.is_improvement(5.0, 10.0));
assert!(OptimizationDirection::Maximize.is_improvement(5.0, 10.0));
assert!(!OptimizationDirection::Maximize.is_improvement(10.0, 5.0));
}
#[test]
fn optimization_direction_no_op_is_not_improvement() {
for d in OptimizationDirection::ALL {
assert!(
!d.is_improvement(7.0, 7.0),
"{d:?}: equal samples must not count as improvement",
);
assert!(
!d.is_improvement(0.0, 0.0),
"{d:?}: zero/zero must not count as improvement",
);
}
}
#[test]
fn optimization_direction_nan_is_not_improvement() {
let nan = f64::NAN;
for d in OptimizationDirection::ALL {
assert!(
!d.is_improvement(nan, 1.0),
"{d:?}: NaN before must not count as improvement",
);
assert!(
!d.is_improvement(1.0, nan),
"{d:?}: NaN after must not count as improvement",
);
assert!(
!d.is_improvement(nan, nan),
"{d:?}: NaN/NaN must not count as improvement",
);
}
}
#[test]
fn optimization_direction_is_improvement_is_antisymmetric() {
let pairs = [(1.0_f64, 2.0_f64), (0.0, 100.0), (-3.5, 3.5), (1e9, 1e-9)];
for d in OptimizationDirection::ALL {
for (a, b) in pairs {
assert!(a != b, "test fixture requires distinct samples");
assert!(
d.is_improvement(a, b) ^ d.is_improvement(b, a),
"{d:?}: antisymmetry violated on ({a}, {b})",
);
}
}
}
#[test]
fn optimization_direction_default_is_minimize_prefers_lower() {
let d = OptimizationDirection::default();
assert_eq!(d, OptimizationDirection::Minimize);
assert!(d.prefers_lower());
}
#[test]
fn optimization_direction_bridge_roundtrip_over_all() {
for d in OptimizationDirection::ALL {
let core_d: core::OptimizationDirection = d.into();
let back: OptimizationDirection = core_d.into();
assert_eq!(back, d, "bridge round-trip failed for {d:?}");
}
}
#[test]
fn horizon_kind_is_well_formed_closed_set() {
tatara_lisp::assert_closed_set_well_formed::<HorizonKind>();
}
#[test]
fn horizon_kind_as_str_matches_serde() {
for k in HorizonKind::ALL {
let serialized = serde_json::to_string(&k).expect("serialize");
let unquoted = serialized
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
assert_eq!(
unquoted,
k.as_str(),
"as_str drift for {k:?}: as_str={} serde={unquoted}",
k.as_str()
);
}
}
#[test]
fn horizon_kind_display_matches_as_str() {
for k in HorizonKind::ALL {
assert_eq!(k.to_string(), k.as_str());
}
}
#[test]
fn unknown_horizon_kind_errors() {
for bad in [
"bounded", "BOUNDED", "Boundd", "Finite", "Perpetual", "Infinite", "Minimize", "Monotone", "Pii", "Steady", "Attested", "Compute", "Gate", "PromQL", ] {
let err = HorizonKind::from_str(bad).unwrap_err();
assert_eq!(err.0, bad, "error payload should echo input verbatim");
}
}
#[test]
fn horizon_kind_terminates_truth_table() {
assert!(HorizonKind::Bounded.terminates());
assert!(!HorizonKind::Asymptotic.terminates());
}
#[test]
fn horizon_kind_requires_metric_axes_truth_table() {
assert!(!HorizonKind::Bounded.requires_metric_axes());
assert!(HorizonKind::Asymptotic.requires_metric_axes());
}
#[test]
fn horizon_kind_buckets_cover_every_variant() {
let mut terminating = 0u32;
let mut perpetual = 0u32;
for k in HorizonKind::ALL {
if k.terminates() {
terminating += 1;
} else {
perpetual += 1;
}
}
assert_eq!(terminating, 1, "terminating bucket: Bounded");
assert_eq!(perpetual, 1, "perpetual bucket: Asymptotic");
assert_eq!(terminating + perpetual, HorizonKind::ALL.len() as u32);
}
#[test]
fn horizon_kind_terminate_xor_requires_metric_axes() {
for k in HorizonKind::ALL {
assert!(
k.terminates() ^ k.requires_metric_axes(),
"{k:?}: terminates() XOR requires_metric_axes() must hold",
);
}
}
#[test]
fn horizon_kind_default_is_bounded_terminates() {
let k = HorizonKind::default();
assert_eq!(k, HorizonKind::Bounded);
assert!(k.terminates());
assert!(!k.requires_metric_axes());
}
#[test]
fn horizon_kind_agrees_with_struct_optionality() {
let bounded = Horizon::bounded();
assert_eq!(bounded.kind, HorizonKind::Bounded);
assert!(!bounded.kind.requires_metric_axes());
assert!(bounded.metric.is_none());
assert!(bounded.direction.is_none());
assert!(bounded.healthy_rate_threshold.is_none());
let asymp = Horizon::asymptotic("p99_latency", OptimizationDirection::Minimize, 0.1);
assert_eq!(asymp.kind, HorizonKind::Asymptotic);
assert!(asymp.kind.requires_metric_axes());
assert!(asymp.metric.is_some());
assert!(asymp.direction.is_some());
assert!(asymp.healthy_rate_threshold.is_some());
}
}