pub mod catalog;
mod composition;
pub mod identity;
mod machine;
pub mod types;
pub use identity::{
NamedTypeBinding, RustTypeAtom, TypePathEnumPayloadAtom, TypePathEnumPayloadField,
TypePathEnumStructuralVariant, TypePathStructField, TypePathStructFieldAtom,
};
pub use types::{CommsRuntimeId, McpServerId, MobId, PeerCorrelationId};
pub use catalog::{
CodeAnchor, CompositionCoverageManifest, MachineCoverageManifest,
MachineProductionOwnerRelation, ScenarioCoverage, SemanticCoverageEntry,
canonical_composition_coverage_manifests, canonical_composition_schemas,
canonical_machine_coverage_manifests, canonical_machine_production_owner_relations,
canonical_machine_schemas, compat_composition_schemas, meerkat_mob_seam_composition,
};
pub use composition::{
ActorKind, ActorPriority, ActorSchema, ClosurePolicy, CompositionDriver,
CompositionDriverRustBinding, CompositionInvariant, CompositionInvariantKind,
CompositionSchema, CompositionSchemaError, CompositionStateLimits, CompositionTransactionPlan,
CompositionWitness, CompositionWitnessField, CompositionWitnessInput, CompositionWitnessState,
CompositionWitnessTransition, CompositionWitnessTransitionOrder, DriverDispatchRoute,
EffectHandoffProtocol, EntryInput, FeedbackFieldBinding, FeedbackFieldSource, FeedbackInputRef,
HandleBridgeFeedbackBinding, MachineInstance, ProtocolGenerationMode,
ProtocolHelperReturnShape, ProtocolRustBinding, Route, RouteBindingSource, RouteDelivery,
RouteFieldBinding, RouteTarget, RouteTargetKind, RouteTargetSelector, RouteVariantId,
SchedulerRule, WatchedEffect,
};
pub use machine::{
EffectDisposition, EffectDispositionRule, EffectEmit, EnumSchema, Expr, FieldInit, FieldSchema,
FieldType, Guard, HelperSchema, InitSchema, InputMatch, InvariantSchema, MachineSchema,
MachineSchemaError, Quantifier, RustBinding, StateSchema, TransitionSchema, TriggerKind,
TriggerMatch, TypeRef, Update, VariantSchema,
};
#[cfg(test)]
mod tests {
use super::{Update, canonical_machine_coverage_manifests, canonical_machine_schemas};
use crate::catalog::dsl::dsl_schedule_lifecycle_machine as schedule_lifecycle_machine;
#[test]
fn schedule_and_occurrence_machines_are_registered_in_canonical_catalog() {
let machine_names: Vec<_> = canonical_machine_schemas()
.into_iter()
.map(|schema| schema.machine)
.collect();
let coverage_names: Vec<_> = canonical_machine_coverage_manifests()
.into_iter()
.map(|manifest| manifest.machine)
.collect();
assert!(
machine_names
.iter()
.any(|name| name.as_str() == "ScheduleLifecycleMachine"),
"schedule lifecycle machine must be a canonical schema"
);
assert!(
machine_names
.iter()
.any(|name| name.as_str() == "OccurrenceLifecycleMachine"),
"occurrence lifecycle machine must be a canonical schema"
);
assert!(
coverage_names
.iter()
.any(|name| name.as_str() == "ScheduleLifecycleMachine"),
"schedule lifecycle machine must have coverage metadata"
);
assert!(
coverage_names
.iter()
.any(|name| name.as_str() == "OccurrenceLifecycleMachine"),
"occurrence lifecycle machine must have coverage metadata"
);
}
#[test]
fn schedule_delete_transitions_bump_revision_and_supersede_pending_occurrences() {
let machine = schedule_lifecycle_machine();
for transition_name in ["DeleteActive", "DeletePaused"] {
let transition = machine
.transitions
.iter()
.find(|transition| transition.name.as_str() == transition_name);
assert!(transition.is_some(), "missing {transition_name} transition");
let Some(transition) = transition else {
return;
};
assert!(
transition.updates.iter().any(|update| matches!(
update,
Update::Increment { field, amount } if field.as_str() == "revision" && *amount == 1
)),
"{transition_name} should advance the revision"
);
assert!(
transition
.emit
.iter()
.any(|effect| effect.variant.as_str() == "SupersedePendingOccurrences"),
"{transition_name} should supersede older pending occurrences"
);
}
}
#[test]
fn canonical_registry_excludes_absorbed_flow_machine_schemas() {
let machine_names: Vec<_> = canonical_machine_schemas()
.into_iter()
.map(|schema| schema.machine)
.collect();
for compat_name in ["FlowRunMachine", "FlowFrameMachine", "LoopIterationMachine"] {
assert!(
!machine_names
.iter()
.any(|name| name.as_str() == compat_name),
"{compat_name} should be absorbed into MobMachine, not canonical"
);
}
}
}