use converge_kernel::ContextKey;
use converge_kernel::formation::{
FormationCatalog, FormationKind, FormationTemplateQuery, SuggestorCapability, SuggestorRole,
};
use converge_provider::{BackendRequirements, ComplianceLevel, DataSovereignty};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use organism_catalog::{CatalogSuggestorDescriptor, DiscoveryCatalog};
pub use organism_catalog::{
DataContract, GovernanceClass, ProviderDescriptor, ProviderDescriptorCatalog, ProviderId,
ReplayMode, SuggestorDescriptor, SuggestorDescriptorCatalog, SuggestorDescriptorId,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct FormationTemplateId(String);
impl FormationTemplateId {
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn into_inner(self) -> String {
self.0
}
}
impl std::fmt::Display for FormationTemplateId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl AsRef<str> for FormationTemplateId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::borrow::Borrow<str> for FormationTemplateId {
fn borrow(&self) -> &str {
&self.0
}
}
impl std::ops::Deref for FormationTemplateId {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl From<&str> for FormationTemplateId {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
impl From<String> for FormationTemplateId {
fn from(s: String) -> Self {
Self(s)
}
}
impl From<&String> for FormationTemplateId {
fn from(s: &String) -> Self {
Self(s.clone())
}
}
impl From<FormationTemplateId> for String {
fn from(id: FormationTemplateId) -> Self {
id.0
}
}
impl PartialEq<str> for FormationTemplateId {
fn eq(&self, other: &str) -> bool {
self.0 == other
}
}
impl PartialEq<&str> for FormationTemplateId {
fn eq(&self, other: &&str) -> bool {
self.0.as_str() == *other
}
}
impl PartialEq<String> for FormationTemplateId {
fn eq(&self, other: &String) -> bool {
&self.0 == other
}
}
impl PartialEq<FormationTemplateId> for &str {
fn eq(&self, other: &FormationTemplateId) -> bool {
*self == other.0.as_str()
}
}
impl PartialEq<FormationTemplateId> for String {
fn eq(&self, other: &FormationTemplateId) -> bool {
self == &other.0
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormationCompilerCatalogs {
pub formation_templates: FormationCatalog,
pub suggestors: SuggestorDescriptorCatalog,
pub providers: ProviderDescriptorCatalog,
}
impl FormationCompilerCatalogs {
pub fn new(formation_templates: FormationCatalog) -> Self {
Self {
formation_templates,
suggestors: SuggestorDescriptorCatalog::new(),
providers: ProviderDescriptorCatalog::new(),
}
}
pub fn with_suggestor(mut self, descriptor: SuggestorDescriptor) -> Self {
self.suggestors.register(descriptor);
self
}
pub fn with_provider(mut self, descriptor: ProviderDescriptor) -> Self {
self.providers.register(descriptor);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormationCompileRequest {
pub plan_id: Uuid,
pub correlation_id: Uuid,
pub tenant_id: Option<String>,
pub query: FormationTemplateQuery,
pub domain_tags: Vec<String>,
}
impl FormationCompileRequest {
pub fn new(plan_id: Uuid, correlation_id: Uuid, query: FormationTemplateQuery) -> Self {
Self {
plan_id,
correlation_id,
tenant_id: None,
query,
domain_tags: Vec::new(),
}
}
pub fn with_tenant_id(mut self, tenant_id: impl Into<String>) -> Self {
self.tenant_id = Some(tenant_id.into());
self
}
pub fn with_domain_tag(mut self, tag: impl Into<String>) -> Self {
self.domain_tags.push(tag.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompiledSuggestorRole {
pub suggestor_id: SuggestorDescriptorId,
pub role: SuggestorRole,
pub capabilities: Vec<SuggestorCapability>,
pub reads: Vec<ContextKey>,
pub writes: Vec<ContextKey>,
pub input_contracts: Vec<DataContract>,
pub output_contracts: Vec<DataContract>,
pub replay_mode: ReplayMode,
pub governance_class: GovernanceClass,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoleProviderAssignment {
pub suggestor_id: SuggestorDescriptorId,
pub role: SuggestorRole,
pub provider_id: ProviderId,
pub requirements: BackendRequirements,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompiledFormationPlan {
pub plan_id: Uuid,
pub correlation_id: Uuid,
pub tenant_id: Option<String>,
pub template_id: FormationTemplateId,
pub template_kind: FormationKind,
pub roster: Vec<CompiledSuggestorRole>,
pub provider_assignments: Vec<RoleProviderAssignment>,
pub trace: Vec<String>,
pub decisions: Vec<RoleDecision>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoleDecision {
pub unmatched_roles_at_start: Vec<SuggestorRole>,
pub unmatched_capabilities_at_start: Vec<SuggestorCapability>,
pub considered: Vec<CandidateConsideration>,
pub chosen: Option<SuggestorDescriptorId>,
pub chosen_role: Option<SuggestorRole>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CandidateConsideration {
pub descriptor_id: SuggestorDescriptorId,
pub disposition: CandidateDisposition,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CandidateDisposition {
Selected { reason: SelectionReason },
Rejected { reason: RejectionReason },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SelectionReason {
pub coverage: usize,
pub domain_hits: usize,
pub advisory_hit: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RejectionReason {
AlreadySelected,
NoCoverage,
Outranked {
chosen_id: SuggestorDescriptorId,
own_coverage: usize,
own_domain_hits: usize,
},
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum FormationCompileError {
#[error("no formation template matched the compile request")]
NoTemplate,
#[error("formation requirements were not covered")]
UncoveredRequirements {
unmatched_roles: Vec<SuggestorRole>,
unmatched_capabilities: Vec<SuggestorCapability>,
},
#[error("no provider matched backend requirements for suggestor '{suggestor_id}'")]
MissingProvider {
suggestor_id: SuggestorDescriptorId,
role: SuggestorRole,
},
#[error("draft references unknown descriptor '{descriptor_id}'")]
DraftDescriptorMissing {
descriptor_id: SuggestorDescriptorId,
},
#[error("draft references descriptor '{descriptor_id}' more than once")]
DuplicateDraftDescriptor {
descriptor_id: SuggestorDescriptorId,
},
}
#[derive(Debug, Clone, thiserror::Error)]
#[error("{error}")]
pub struct CatalogCompileFailure {
#[source]
pub error: FormationCompileError,
pub decisions: Vec<RoleDecision>,
}
#[derive(Debug, Default)]
pub struct FormationCompiler;
impl FormationCompiler {
pub fn new() -> Self {
Self
}
pub fn compile(
&self,
request: &FormationCompileRequest,
catalogs: &FormationCompilerCatalogs,
) -> Result<CompiledFormationPlan, FormationCompileError> {
let template = catalogs
.formation_templates
.top_match(&request.query)
.ok_or(FormationCompileError::NoTemplate)?;
let metadata = template.metadata();
let mut unmatched_roles = metadata.required_roles.clone();
let mut unmatched_capabilities = unique_capabilities(
metadata
.required_capabilities
.iter()
.chain(request.query.required_capabilities.iter())
.copied(),
);
let mut selected: Vec<&SuggestorDescriptor> = Vec::new();
let mut trace = vec![format!("selected template '{}'", metadata.id)];
while !unmatched_roles.is_empty() || !unmatched_capabilities.is_empty() {
let Some(next) = best_suggestor(
(&catalogs.suggestors).into_iter(),
&selected,
&unmatched_roles,
&unmatched_capabilities,
&request.domain_tags,
) else {
return Err(FormationCompileError::UncoveredRequirements {
unmatched_roles,
unmatched_capabilities,
});
};
trace.push(format!(
"selected suggestor '{}' for role {:?}",
next.id, next.profile.role
));
remove_role(&mut unmatched_roles, next.profile.role);
remove_capabilities(&mut unmatched_capabilities, &next.profile.capabilities);
selected.push(next);
}
let mut provider_assignments = Vec::new();
for descriptor in &selected {
let Some(requirements) = &descriptor.backend_requirements else {
continue;
};
let Some(provider) =
best_provider((&catalogs.providers).into_iter(), descriptor, requirements)
else {
return Err(FormationCompileError::MissingProvider {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
});
};
trace.push(format!(
"assigned provider '{}' to suggestor '{}'",
provider.id, descriptor.id
));
provider_assignments.push(RoleProviderAssignment {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
provider_id: provider.id.clone(),
requirements: requirements.clone(),
});
}
let roster = selected
.into_iter()
.map(|descriptor| CompiledSuggestorRole {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
capabilities: descriptor.profile.capabilities.clone(),
reads: descriptor.reads.clone(),
writes: descriptor.profile.output_keys.clone(),
input_contracts: descriptor.input_contracts.clone(),
output_contracts: descriptor.output_contracts.clone(),
replay_mode: descriptor.replay_mode,
governance_class: descriptor.governance_class,
})
.collect();
Ok(CompiledFormationPlan {
plan_id: request.plan_id,
correlation_id: request.correlation_id,
tenant_id: request.tenant_id.clone(),
template_id: metadata.id.clone().into(),
template_kind: template.kind(),
roster,
provider_assignments,
trace,
decisions: Vec::new(),
})
}
#[allow(clippy::too_many_lines)]
pub fn compile_from_catalog(
&self,
request: &FormationCompileRequest,
formation_templates: &FormationCatalog,
catalog: &DiscoveryCatalog,
providers: &ProviderDescriptorCatalog,
advisory_order: Option<&[String]>,
) -> Result<CompiledFormationPlan, CatalogCompileFailure> {
let mut decisions: Vec<RoleDecision> = Vec::new();
let template = formation_templates
.top_match(&request.query)
.ok_or_else(|| CatalogCompileFailure {
error: FormationCompileError::NoTemplate,
decisions: decisions.clone(),
})?;
let metadata = template.metadata();
let mut unmatched_roles = metadata.required_roles.clone();
let mut unmatched_capabilities = unique_capabilities(
metadata
.required_capabilities
.iter()
.chain(request.query.required_capabilities.iter())
.copied(),
);
let mut selected: Vec<&CatalogSuggestorDescriptor> = Vec::new();
let mut trace = vec![format!("selected template '{}'", metadata.id)];
while !unmatched_roles.is_empty() || !unmatched_capabilities.is_empty() {
let unmatched_roles_at_start = unmatched_roles.clone();
let unmatched_capabilities_at_start = unmatched_capabilities.clone();
let (chosen, considered) = best_from_catalog(
catalog,
&selected,
&unmatched_roles,
&unmatched_capabilities,
&request.domain_tags,
advisory_order,
);
let Some(next) = chosen else {
decisions.push(RoleDecision {
unmatched_roles_at_start,
unmatched_capabilities_at_start,
considered,
chosen: None,
chosen_role: None,
});
return Err(CatalogCompileFailure {
error: FormationCompileError::UncoveredRequirements {
unmatched_roles,
unmatched_capabilities,
},
decisions,
});
};
trace.push(format!(
"selected suggestor '{}' for role {:?}",
next.descriptor.id, next.descriptor.profile.role
));
let chosen_id = next.descriptor.id.clone();
let chosen_role = next.descriptor.profile.role;
decisions.push(RoleDecision {
unmatched_roles_at_start,
unmatched_capabilities_at_start,
considered,
chosen: Some(chosen_id),
chosen_role: Some(chosen_role),
});
remove_role(&mut unmatched_roles, next.descriptor.profile.role);
remove_capabilities(
&mut unmatched_capabilities,
&next.descriptor.profile.capabilities,
);
selected.push(next);
}
let mut provider_assignments = Vec::new();
for entry in &selected {
let descriptor = &entry.descriptor;
let Some(requirements) = &descriptor.backend_requirements else {
continue;
};
let Some(provider) = best_provider(providers.into_iter(), descriptor, requirements)
else {
return Err(CatalogCompileFailure {
error: FormationCompileError::MissingProvider {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
},
decisions,
});
};
trace.push(format!(
"assigned provider '{}' to suggestor '{}'",
provider.id, descriptor.id
));
provider_assignments.push(RoleProviderAssignment {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
provider_id: provider.id.clone(),
requirements: requirements.clone(),
});
}
let roster = selected
.into_iter()
.map(|entry| {
let descriptor = &entry.descriptor;
CompiledSuggestorRole {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
capabilities: descriptor.profile.capabilities.clone(),
reads: descriptor.reads.clone(),
writes: descriptor.profile.output_keys.clone(),
input_contracts: descriptor.input_contracts.clone(),
output_contracts: descriptor.output_contracts.clone(),
replay_mode: descriptor.replay_mode,
governance_class: descriptor.governance_class,
}
})
.collect();
Ok(CompiledFormationPlan {
plan_id: request.plan_id,
correlation_id: request.correlation_id,
tenant_id: request.tenant_id.clone(),
template_id: metadata.id.clone().into(),
template_kind: template.kind(),
roster,
provider_assignments,
trace,
decisions,
})
}
#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
pub fn compile_draft_from_catalog(
&self,
request: &FormationCompileRequest,
formation_templates: &FormationCatalog,
catalog: &DiscoveryCatalog,
providers: &ProviderDescriptorCatalog,
descriptor_ids: &[SuggestorDescriptorId],
) -> Result<CompiledFormationPlan, CatalogCompileFailure> {
let mut decisions: Vec<RoleDecision> = Vec::new();
let template = formation_templates
.top_match(&request.query)
.ok_or_else(|| CatalogCompileFailure {
error: FormationCompileError::NoTemplate,
decisions: decisions.clone(),
})?;
let metadata = template.metadata();
let mut seen_descriptor_ids = std::collections::BTreeSet::new();
for id in descriptor_ids {
if !seen_descriptor_ids.insert(id.as_str()) {
return Err(CatalogCompileFailure {
error: FormationCompileError::DuplicateDraftDescriptor {
descriptor_id: id.clone(),
},
decisions,
});
}
}
let mut selected: Vec<&CatalogSuggestorDescriptor> =
Vec::with_capacity(descriptor_ids.len());
for id in descriptor_ids {
let entry = catalog
.get(id.as_str())
.ok_or_else(|| CatalogCompileFailure {
error: FormationCompileError::DraftDescriptorMissing {
descriptor_id: id.clone(),
},
decisions: decisions.clone(),
})?;
selected.push(entry);
}
let mut unmatched_roles = metadata.required_roles.clone();
let mut unmatched_capabilities = unique_capabilities(
metadata
.required_capabilities
.iter()
.chain(request.query.required_capabilities.iter())
.copied(),
);
for entry in &selected {
remove_role(&mut unmatched_roles, entry.descriptor.profile.role);
remove_capabilities(
&mut unmatched_capabilities,
&entry.descriptor.profile.capabilities,
);
}
if !unmatched_roles.is_empty() || !unmatched_capabilities.is_empty() {
return Err(CatalogCompileFailure {
error: FormationCompileError::UncoveredRequirements {
unmatched_roles,
unmatched_capabilities,
},
decisions,
});
}
let mut trace = vec![format!(
"validated draft against template '{}'",
metadata.id
)];
for entry in &selected {
trace.push(format!(
"draft chose suggestor '{}' for role {:?}",
entry.descriptor.id, entry.descriptor.profile.role
));
decisions.push(RoleDecision {
unmatched_roles_at_start: Vec::new(),
unmatched_capabilities_at_start: Vec::new(),
considered: Vec::new(),
chosen: Some(entry.descriptor.id.clone()),
chosen_role: Some(entry.descriptor.profile.role),
});
}
let mut provider_assignments = Vec::new();
for entry in &selected {
let descriptor = &entry.descriptor;
let Some(requirements) = &descriptor.backend_requirements else {
continue;
};
let Some(provider) = best_provider(providers.into_iter(), descriptor, requirements)
else {
return Err(CatalogCompileFailure {
error: FormationCompileError::MissingProvider {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
},
decisions,
});
};
trace.push(format!(
"assigned provider '{}' to suggestor '{}'",
provider.id, descriptor.id
));
provider_assignments.push(RoleProviderAssignment {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
provider_id: provider.id.clone(),
requirements: requirements.clone(),
});
}
let roster = selected
.into_iter()
.map(|entry| {
let descriptor = &entry.descriptor;
CompiledSuggestorRole {
suggestor_id: descriptor.id.clone(),
role: descriptor.profile.role,
capabilities: descriptor.profile.capabilities.clone(),
reads: descriptor.reads.clone(),
writes: descriptor.profile.output_keys.clone(),
input_contracts: descriptor.input_contracts.clone(),
output_contracts: descriptor.output_contracts.clone(),
replay_mode: descriptor.replay_mode,
governance_class: descriptor.governance_class,
}
})
.collect();
Ok(CompiledFormationPlan {
plan_id: request.plan_id,
correlation_id: request.correlation_id,
tenant_id: request.tenant_id.clone(),
template_id: metadata.id.clone().into(),
template_kind: template.kind(),
roster,
provider_assignments,
trace,
decisions,
})
}
}
fn best_suggestor<'a>(
candidates: impl Iterator<Item = &'a SuggestorDescriptor>,
selected: &[&SuggestorDescriptor],
unmatched_roles: &[SuggestorRole],
unmatched_capabilities: &[SuggestorCapability],
domain_tags: &[String],
) -> Option<&'a SuggestorDescriptor> {
candidates
.filter(|candidate| !selected.iter().any(|chosen| chosen.id == candidate.id))
.map(|candidate| {
let coverage = suggestor_coverage(candidate, unmatched_roles, unmatched_capabilities);
let domain_hits = domain_overlap(&candidate.domain_tags, domain_tags);
(candidate, coverage, domain_hits)
})
.filter(|(_, coverage, _)| *coverage > 0)
.max_by(
|(left, left_coverage, left_domain), (right, right_coverage, right_domain)| {
left_coverage
.cmp(right_coverage)
.then_with(|| left_domain.cmp(right_domain))
.then_with(|| right.profile.cost_hint.cmp(&left.profile.cost_hint))
.then_with(|| right.profile.latency_hint.cmp(&left.profile.latency_hint))
.then_with(|| right.id.cmp(&left.id))
},
)
.map(|(candidate, _, _)| candidate)
}
fn suggestor_coverage(
candidate: &SuggestorDescriptor,
unmatched_roles: &[SuggestorRole],
unmatched_capabilities: &[SuggestorCapability],
) -> usize {
let role_score = usize::from(unmatched_roles.contains(&candidate.profile.role));
let capability_score = unmatched_capabilities
.iter()
.filter(|capability| candidate.profile.capabilities.contains(capability))
.count();
role_score + capability_score
}
impl FormationCompiler {
pub fn compile_k_candidates(
&self,
request: &FormationCompileRequest,
formation_templates: &FormationCatalog,
catalog: &DiscoveryCatalog,
providers: &ProviderDescriptorCatalog,
k: usize,
) -> Result<Vec<CompiledFormationPlan>, CatalogCompileFailure> {
let mut candidates: Vec<CompiledFormationPlan> = Vec::new();
let mut excluded: Vec<String> = Vec::new();
for _ in 0..k {
let filtered = filter_out_ids(catalog, &excluded);
match self.compile_from_catalog(
request,
formation_templates,
&filtered,
providers,
None,
) {
Ok(plan) => {
let excluded_before = excluded.len();
for role in &plan.roster {
let mut trial_exclude = excluded.clone();
trial_exclude.push(role.suggestor_id.to_string());
let trial_catalog = filter_out_ids(catalog, &trial_exclude);
if self
.compile_from_catalog(
request,
formation_templates,
&trial_catalog,
providers,
None,
)
.is_ok()
{
excluded.push(role.suggestor_id.to_string());
}
}
let candidate_added_no_exclusions = excluded.len() == excluded_before;
candidates.push(plan);
if candidate_added_no_exclusions {
break;
}
}
Err(failure) => {
if candidates.is_empty() {
return Err(failure);
}
break;
}
}
}
Ok(candidates)
}
}
fn filter_out_ids(source: &DiscoveryCatalog, exclude_ids: &[String]) -> DiscoveryCatalog {
let mut filtered = DiscoveryCatalog::new();
for entry in source {
if !exclude_ids.iter().any(|id| id == entry.id().as_str()) {
filtered.register(entry.clone());
}
}
filtered
}
#[allow(clippy::too_many_lines)]
fn best_from_catalog<'a>(
catalog: &'a DiscoveryCatalog,
selected: &[&'a CatalogSuggestorDescriptor],
unmatched_roles: &[SuggestorRole],
unmatched_capabilities: &[SuggestorCapability],
domain_tags: &[String],
advisory_order: Option<&[String]>,
) -> (
Option<&'a CatalogSuggestorDescriptor>,
Vec<CandidateConsideration>,
) {
let mut candidate_ids: Vec<String> = Vec::new();
let mut candidate_refs: Vec<&CatalogSuggestorDescriptor> = Vec::new();
let mut push = |entry: &'a CatalogSuggestorDescriptor| {
if !candidate_ids.iter().any(|id| id == entry.id().as_str()) {
candidate_ids.push(entry.id().to_string());
candidate_refs.push(entry);
}
};
for role in unmatched_roles {
for entry in catalog.find_by_role(*role) {
push(entry);
}
}
for capability in unmatched_capabilities {
for entry in catalog.find_by_capability(*capability) {
push(entry);
}
}
let mut considered: Vec<CandidateConsideration> = Vec::new();
let mut ranked: Vec<(&CatalogSuggestorDescriptor, usize, usize, bool)> = Vec::new();
for entry in candidate_refs {
if selected.iter().any(|chosen| chosen.id() == entry.id()) {
considered.push(CandidateConsideration {
descriptor_id: entry.id().clone(),
disposition: CandidateDisposition::Rejected {
reason: RejectionReason::AlreadySelected,
},
});
continue;
}
let coverage =
suggestor_coverage(&entry.descriptor, unmatched_roles, unmatched_capabilities);
if coverage == 0 {
considered.push(CandidateConsideration {
descriptor_id: entry.id().clone(),
disposition: CandidateDisposition::Rejected {
reason: RejectionReason::NoCoverage,
},
});
continue;
}
let domain_hits = domain_overlap(&entry.descriptor.domain_tags, domain_tags);
let advisory_hit =
advisory_order.is_some_and(|order| order.iter().any(|id| id == entry.id().as_str()));
ranked.push((entry, coverage, domain_hits, advisory_hit));
}
let advisory_rank = |id: &str| -> usize {
advisory_order
.and_then(|order| order.iter().position(|x| x == id))
.unwrap_or(usize::MAX)
};
let chosen = ranked
.iter()
.max_by(|(left, l_cov, l_dom, _), (right, r_cov, r_dom, _)| {
l_cov
.cmp(r_cov)
.then_with(|| l_dom.cmp(r_dom))
.then_with(|| {
right
.descriptor
.profile
.cost_hint
.cmp(&left.descriptor.profile.cost_hint)
})
.then_with(|| {
right
.descriptor
.profile
.latency_hint
.cmp(&left.descriptor.profile.latency_hint)
})
.then_with(|| {
advisory_rank(right.id().as_str()).cmp(&advisory_rank(left.id().as_str()))
})
.then_with(|| right.id().cmp(left.id()))
})
.map(|(entry, _, _, _)| *entry);
for (entry, coverage, domain_hits, advisory_hit) in &ranked {
let is_chosen = chosen.is_some_and(|c| c.id() == entry.id());
let disposition = if is_chosen {
CandidateDisposition::Selected {
reason: SelectionReason {
coverage: *coverage,
domain_hits: *domain_hits,
advisory_hit: *advisory_hit,
},
}
} else {
let chosen_id =
chosen.map_or_else(|| SuggestorDescriptorId::new(""), |c| c.id().clone());
CandidateDisposition::Rejected {
reason: RejectionReason::Outranked {
chosen_id,
own_coverage: *coverage,
own_domain_hits: *domain_hits,
},
}
};
considered.push(CandidateConsideration {
descriptor_id: entry.id().clone(),
disposition,
});
}
(chosen, considered)
}
fn best_provider<'a>(
candidates: impl Iterator<Item = &'a ProviderDescriptor>,
descriptor: &SuggestorDescriptor,
requirements: &BackendRequirements,
) -> Option<&'a ProviderDescriptor> {
candidates
.filter(|candidate| provider_satisfies(candidate, requirements))
.map(|candidate| {
let role_hit = usize::from(candidate.role_affinity.contains(&descriptor.profile.role));
let domain_hits = domain_overlap(&candidate.domain_tags, &descriptor.domain_tags);
(candidate, role_hit, domain_hits)
})
.max_by(
|(left, left_role, left_domain), (right, right_role, right_domain)| {
left_role
.cmp(right_role)
.then_with(|| left_domain.cmp(right_domain))
.then_with(|| {
right
.requirements
.max_cost_class
.cmp(&left.requirements.max_cost_class)
})
.then_with(|| {
right
.requirements
.max_latency_ms
.cmp(&left.requirements.max_latency_ms)
})
.then_with(|| right.id.cmp(&left.id))
},
)
.map(|(candidate, _, _)| candidate)
}
fn provider_satisfies(provider: &ProviderDescriptor, requirements: &BackendRequirements) -> bool {
provider.requirements.kind == requirements.kind
&& requirements.required_capabilities.iter().all(|capability| {
provider
.requirements
.required_capabilities
.contains(capability)
})
&& provider.requirements.max_cost_class <= requirements.max_cost_class
&& latency_satisfies(
provider.requirements.max_latency_ms,
requirements.max_latency_ms,
)
&& sovereignty_satisfies(
provider.requirements.data_sovereignty,
requirements.data_sovereignty,
)
&& compliance_satisfies(provider.requirements.compliance, requirements.compliance)
&& (!requirements.requires_replay || provider.requirements.requires_replay)
&& (!requirements.requires_offline || provider.requirements.requires_offline)
}
fn latency_satisfies(provider_ms: u32, required_ms: u32) -> bool {
required_ms == 0 || provider_ms <= required_ms
}
fn sovereignty_satisfies(provider: DataSovereignty, required: DataSovereignty) -> bool {
match required {
DataSovereignty::Any => true,
_ => provider == required || provider == DataSovereignty::OnPremises,
}
}
fn compliance_satisfies(provider: ComplianceLevel, required: ComplianceLevel) -> bool {
required == ComplianceLevel::None || provider == required
}
fn domain_overlap(left: &[String], right: &[String]) -> usize {
left.iter().filter(|tag| right.contains(tag)).count()
}
fn unique_capabilities(
capabilities: impl IntoIterator<Item = SuggestorCapability>,
) -> Vec<SuggestorCapability> {
let mut unique = Vec::new();
for capability in capabilities {
if !unique.contains(&capability) {
unique.push(capability);
}
}
unique
}
fn remove_role(roles: &mut Vec<SuggestorRole>, role: SuggestorRole) {
if let Some(index) = roles.iter().position(|candidate| *candidate == role) {
roles.remove(index);
}
}
fn remove_capabilities(
capabilities: &mut Vec<SuggestorCapability>,
covered: &[SuggestorCapability],
) {
capabilities.retain(|capability| !covered.contains(capability));
}
#[cfg(test)]
mod tests {
use super::*;
use crate::vendor_selection::vendor_selection_formation_catalog;
use converge_kernel::formation::ProfileSnapshot;
use converge_provider::{BackendKind, Capability, CostClass, LatencyClass};
fn id(n: u128) -> Uuid {
Uuid::from_u128(n)
}
fn profile(
name: &str,
role: SuggestorRole,
output_keys: Vec<ContextKey>,
capabilities: Vec<SuggestorCapability>,
) -> ProfileSnapshot {
ProfileSnapshot {
name: name.to_string(),
role,
output_keys,
cost_hint: CostClass::Low,
latency_hint: LatencyClass::Interactive,
capabilities,
confidence_min: 0.7,
confidence_max: 0.95,
}
}
fn market_scan_descriptor() -> SuggestorDescriptor {
SuggestorDescriptor::new(
"market-scan",
profile(
"market-scan",
SuggestorRole::Signal,
vec![ContextKey::Signals],
vec![SuggestorCapability::KnowledgeRetrieval],
),
)
.with_read(ContextKey::Seeds)
.with_domain_tag("vendor-selection")
.with_output_contract(DataContract::new("MarketEvidence", "1.0"))
}
fn weighted_evaluator_descriptor() -> SuggestorDescriptor {
SuggestorDescriptor::new(
"weighted-evaluator",
profile(
"weighted-evaluator",
SuggestorRole::Evaluation,
vec![ContextKey::Evaluations],
vec![SuggestorCapability::Analytics],
),
)
.with_read(ContextKey::Signals)
.with_domain_tag("vendor-selection")
.with_input_contract(DataContract::new("NormalizedVendorResponse", "1.0"))
}
fn policy_gate_descriptor(policy_requirements: BackendRequirements) -> SuggestorDescriptor {
SuggestorDescriptor::new(
"policy-gate",
profile(
"policy-gate",
SuggestorRole::Constraint,
vec![ContextKey::Constraints],
vec![SuggestorCapability::PolicyEnforcement],
),
)
.with_read(ContextKey::Evaluations)
.with_domain_tag("vendor-selection")
.with_replay_mode(ReplayMode::Required)
.with_governance_class(GovernanceClass::HumanApprovalRequired)
.with_backend_requirements(policy_requirements)
}
fn decision_synthesis_descriptor() -> SuggestorDescriptor {
SuggestorDescriptor::new(
"decision-synthesis",
profile(
"decision-synthesis",
SuggestorRole::Synthesis,
vec![ContextKey::Proposals],
vec![SuggestorCapability::LlmReasoning],
),
)
.with_read(ContextKey::Evaluations)
.with_read(ContextKey::Constraints)
.with_domain_tag("vendor-selection")
.with_output_contract(DataContract::new("VendorSelectionDecisionRecord", "1.0"))
}
fn cedar_provider(policy_requirements: BackendRequirements) -> ProviderDescriptor {
ProviderDescriptor::new(
"cedar-local",
"Cedar local policy engine",
policy_requirements,
)
.with_role_affinity(SuggestorRole::Constraint)
.with_domain_tag("vendor-selection")
}
fn complete_vendor_selection_catalogs(
policy_requirements: BackendRequirements,
) -> FormationCompilerCatalogs {
FormationCompilerCatalogs::new(vendor_selection_formation_catalog())
.with_suggestor(market_scan_descriptor())
.with_suggestor(weighted_evaluator_descriptor())
.with_suggestor(policy_gate_descriptor(policy_requirements.clone()))
.with_suggestor(decision_synthesis_descriptor())
.with_provider(cedar_provider(policy_requirements))
}
#[test]
fn compiles_complementary_vendor_selection_team() {
let request = FormationCompileRequest::new(
id(1),
id(2),
FormationTemplateQuery::new()
.with_keyword("vendor")
.with_keyword("diligence-evaluate-decide")
.with_entity("VendorSelectionDecisionRecord"),
)
.with_tenant_id("tenant-a")
.with_domain_tag("vendor-selection");
let policy_requirements = BackendRequirements::access_policy().with_replay();
let catalogs = complete_vendor_selection_catalogs(policy_requirements);
let plan = FormationCompiler::new()
.compile(&request, &catalogs)
.expect("vendor selection should compile");
assert_eq!(plan.template_id, "vendor-selection-decide");
assert_eq!(plan.correlation_id, id(2));
assert_eq!(plan.tenant_id.as_deref(), Some("tenant-a"));
assert_eq!(plan.roster.len(), 4);
assert_eq!(plan.provider_assignments.len(), 1);
assert_eq!(plan.provider_assignments[0].provider_id, "cedar-local");
assert!(
plan.roster
.iter()
.any(|role| role.suggestor_id == "market-scan")
);
assert!(
plan.roster
.iter()
.any(|role| role.suggestor_id == "weighted-evaluator")
);
assert!(
plan.roster
.iter()
.any(|role| role.suggestor_id == "policy-gate")
);
assert!(
plan.roster
.iter()
.any(|role| role.suggestor_id == "decision-synthesis")
);
}
#[test]
fn reports_uncovered_requirements_instead_of_over_filtering() {
let request = FormationCompileRequest::new(
id(3),
id(4),
FormationTemplateQuery::new()
.with_keyword("vendor")
.with_keyword("diligence-evaluate-decide"),
);
let catalogs = FormationCompilerCatalogs::new(vendor_selection_formation_catalog())
.with_suggestor(SuggestorDescriptor::new(
"analytics-only",
profile(
"analytics-only",
SuggestorRole::Evaluation,
vec![ContextKey::Evaluations],
vec![SuggestorCapability::Analytics],
),
));
let error = FormationCompiler::new()
.compile(&request, &catalogs)
.expect_err("missing roles and capabilities should be explicit");
match error {
FormationCompileError::UncoveredRequirements {
unmatched_roles,
unmatched_capabilities,
} => {
assert!(unmatched_roles.contains(&SuggestorRole::Signal));
assert!(unmatched_roles.contains(&SuggestorRole::Constraint));
assert!(unmatched_roles.contains(&SuggestorRole::Synthesis));
assert!(unmatched_capabilities.contains(&SuggestorCapability::KnowledgeRetrieval));
assert!(unmatched_capabilities.contains(&SuggestorCapability::PolicyEnforcement));
assert!(unmatched_capabilities.contains(&SuggestorCapability::LlmReasoning));
}
other => panic!("unexpected compile error: {other:?}"),
}
}
#[test]
fn requires_role_level_provider_match_when_backend_is_declared() {
let request = FormationCompileRequest::new(
id(5),
id(6),
FormationTemplateQuery::new()
.with_keyword("vendor")
.with_keyword("diligence-evaluate-decide"),
);
let policy_requirements = BackendRequirements::access_policy().with_replay();
let catalogs = FormationCompilerCatalogs::new(vendor_selection_formation_catalog())
.with_suggestor(market_scan_descriptor())
.with_suggestor(weighted_evaluator_descriptor())
.with_suggestor(policy_gate_descriptor(policy_requirements))
.with_suggestor(decision_synthesis_descriptor())
.with_provider(ProviderDescriptor::new(
"generic-llm",
"Generic LLM",
BackendRequirements::reasoning_llm(),
));
let error = FormationCompiler::new()
.compile(&request, &catalogs)
.expect_err("policy role should not route to an LLM provider");
assert_eq!(
error,
FormationCompileError::MissingProvider {
suggestor_id: "policy-gate".into(),
role: SuggestorRole::Constraint,
}
);
}
#[test]
fn carries_rich_provider_requirements_per_role() {
let requirements = BackendRequirements::new(BackendKind::Llm)
.with_capability(Capability::TextGeneration)
.with_capability(Capability::Reasoning)
.with_data_sovereignty(DataSovereignty::EU)
.with_compliance(ComplianceLevel::HighExplainability)
.with_capability(Capability::StructuredOutput);
let descriptor = SuggestorDescriptor::new(
"decision-synthesis",
profile(
"decision-synthesis",
SuggestorRole::Synthesis,
vec![ContextKey::Proposals],
vec![SuggestorCapability::LlmReasoning],
),
)
.with_backend_requirements(requirements.clone());
assert_eq!(
descriptor
.backend_requirements
.as_ref()
.expect("requirements should be present")
.data_sovereignty,
DataSovereignty::EU
);
assert!(
descriptor
.backend_requirements
.as_ref()
.expect("requirements should be present")
.required_capabilities
.contains(&Capability::StructuredOutput)
);
}
use converge_kernel::formation::{FormationTemplate, StaticFormationTemplate};
use organism_catalog::{
CatalogSuggestorDescriptor, DiscoveryCatalog, DiscoveryMetadata, LoopContribution,
};
fn loop_demo_template_catalog() -> FormationCatalog {
let metadata = converge_kernel::formation::FormationTemplateMetadata::new(
"loop-demo",
"Demonstrate Retrieve / Score / Optimize / Authorize loop coverage.",
vec![
SuggestorRole::Signal,
SuggestorRole::Evaluation,
SuggestorRole::Planning,
SuggestorRole::Constraint,
],
)
.with_keyword("loop-demo")
.with_required_capability(SuggestorCapability::KnowledgeRetrieval)
.with_required_capability(SuggestorCapability::Analytics)
.with_required_capability(SuggestorCapability::Optimization)
.with_required_capability(SuggestorCapability::PolicyEnforcement);
FormationCatalog::new().with_template(FormationTemplate::static_template(
StaticFormationTemplate::new(metadata),
))
}
fn loop_demo_query() -> FormationCompileRequest {
FormationCompileRequest::new(
id(100),
id(200),
FormationTemplateQuery::new().with_keyword("loop-demo"),
)
}
fn catalog_entry(
id: &str,
role: SuggestorRole,
capability: SuggestorCapability,
contribution: LoopContribution,
summary: &str,
) -> CatalogSuggestorDescriptor {
let descriptor =
SuggestorDescriptor::new(id, profile(id, role, Vec::new(), vec![capability]));
let discovery = DiscoveryMetadata::new(summary, "Synthetic test fixture.")
.with_loop_contribution(contribution);
CatalogSuggestorDescriptor::new(descriptor, discovery)
}
fn loop_demo_catalog_full() -> DiscoveryCatalog {
DiscoveryCatalog::new()
.with_entry(catalog_entry(
"retrieve-suggestor",
SuggestorRole::Signal,
SuggestorCapability::KnowledgeRetrieval,
LoopContribution::Retrieve,
"Pull external evidence into context.",
))
.with_entry(catalog_entry(
"score-suggestor",
SuggestorRole::Evaluation,
SuggestorCapability::Analytics,
LoopContribution::Score,
"Score candidates against weighted criteria.",
))
.with_entry(catalog_entry(
"optimize-suggestor",
SuggestorRole::Planning,
SuggestorCapability::Optimization,
LoopContribution::Optimize,
"Optimize selection under declared constraints.",
))
.with_entry(catalog_entry(
"authorize-suggestor",
SuggestorRole::Constraint,
SuggestorCapability::PolicyEnforcement,
LoopContribution::Authorize,
"Authorize the proposal via a policy gate.",
))
}
#[test]
fn catalog_compile_satisfies_four_contribution_formation() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full();
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let outcome = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect("4-entry catalog should satisfy the loop-demo template");
assert_eq!(outcome.template_id, "loop-demo");
assert_eq!(outcome.roster.len(), 4);
assert_eq!(outcome.decisions.len(), 4);
let chosen: Vec<&str> = outcome
.decisions
.iter()
.filter_map(|d| d.chosen.as_deref())
.collect();
for expected in [
"retrieve-suggestor",
"score-suggestor",
"optimize-suggestor",
"authorize-suggestor",
] {
assert!(
chosen.contains(&expected),
"expected {expected} in decisions, got {chosen:?}"
);
}
}
#[test]
fn catalog_compile_records_selected_disposition_with_structured_reason() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full();
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let outcome = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect("compile should succeed");
for decision in &outcome.decisions {
let chosen_id = decision.chosen.as_deref().expect("each iteration chose");
let chosen_consideration = decision
.considered
.iter()
.find(|c| c.descriptor_id == chosen_id)
.expect("chosen descriptor must appear in considered list");
match &chosen_consideration.disposition {
CandidateDisposition::Selected { reason } => {
assert!(reason.coverage >= 1, "chosen must cover at least one need");
assert!(!reason.advisory_hit);
}
CandidateDisposition::Rejected { reason } => {
panic!("chosen descriptor must be Selected, got Rejected({reason:?})")
}
}
}
}
#[test]
fn catalog_compile_fails_with_partial_trace_when_capability_missing() {
let templates = loop_demo_template_catalog();
let catalog = DiscoveryCatalog::new()
.with_entry(catalog_entry(
"retrieve-suggestor",
SuggestorRole::Signal,
SuggestorCapability::KnowledgeRetrieval,
LoopContribution::Retrieve,
"Pull external evidence into context.",
))
.with_entry(catalog_entry(
"score-suggestor",
SuggestorRole::Evaluation,
SuggestorCapability::Analytics,
LoopContribution::Score,
"Score candidates.",
))
.with_entry(catalog_entry(
"authorize-suggestor",
SuggestorRole::Constraint,
SuggestorCapability::PolicyEnforcement,
LoopContribution::Authorize,
"Authorize via policy gate.",
));
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let failure = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect_err("missing optimize should fail to compile");
match &failure.error {
FormationCompileError::UncoveredRequirements {
unmatched_roles,
unmatched_capabilities,
} => {
assert!(unmatched_roles.contains(&SuggestorRole::Planning));
assert!(unmatched_capabilities.contains(&SuggestorCapability::Optimization));
}
other => panic!("expected UncoveredRequirements, got {other:?}"),
}
let final_decision = failure
.decisions
.last()
.expect("partial trace must exist even on failure");
assert!(final_decision.chosen.is_none());
assert!(
final_decision
.unmatched_roles_at_start
.contains(&SuggestorRole::Planning)
);
}
#[test]
fn catalog_compile_is_deterministic_across_repeated_runs() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full();
let providers = ProviderDescriptorCatalog::new();
let a = FormationCompiler::new()
.compile_from_catalog(&loop_demo_query(), &templates, &catalog, &providers, None)
.expect("compile a");
let b = FormationCompiler::new()
.compile_from_catalog(&loop_demo_query(), &templates, &catalog, &providers, None)
.expect("compile b");
let ids_a: Vec<_> = a.roster.iter().map(|r| r.suggestor_id.clone()).collect();
let ids_b: Vec<_> = b.roster.iter().map(|r| r.suggestor_id.clone()).collect();
assert_eq!(ids_a, ids_b);
}
#[test]
fn catalog_compile_records_outranked_disposition_for_competing_candidates() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full().with_entry(catalog_entry(
"retrieve-suggestor-alt",
SuggestorRole::Signal,
SuggestorCapability::KnowledgeRetrieval,
LoopContribution::Retrieve,
"Alternative retrieve specialist.",
));
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let outcome = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect("compile should succeed");
let retrieve_decision = outcome
.decisions
.iter()
.find(|d| d.chosen_role == Some(SuggestorRole::Signal))
.expect("Signal-role decision should exist");
let retrieve_alt = retrieve_decision
.considered
.iter()
.find(|c| {
c.descriptor_id == "retrieve-suggestor-alt"
|| c.descriptor_id == "retrieve-suggestor"
})
.expect("at least one retrieve candidate should be considered");
let chosen_id = retrieve_decision.chosen.as_deref().unwrap();
let other_id = if chosen_id == "retrieve-suggestor" {
"retrieve-suggestor-alt"
} else {
"retrieve-suggestor"
};
let other = retrieve_decision
.considered
.iter()
.find(|c| c.descriptor_id == other_id)
.expect("other retrieve candidate should appear");
match &other.disposition {
CandidateDisposition::Rejected {
reason: RejectionReason::Outranked { chosen_id: cid, .. },
} => assert_eq!(cid, chosen_id),
other => panic!("expected Outranked, got {other:?}"),
}
let _ = retrieve_alt; }
#[test]
fn catalog_compile_trace_reports_actual_chosen_role_when_later_role_wins() {
let templates = loop_demo_template_catalog();
let catalog = DiscoveryCatalog::new()
.with_entry(CatalogSuggestorDescriptor::new(
SuggestorDescriptor::new(
"narrow-signal",
profile(
"narrow-signal",
SuggestorRole::Signal,
Vec::new(),
vec![SuggestorCapability::KnowledgeRetrieval],
),
),
DiscoveryMetadata::new("Narrow signal.", "Test fixture."),
))
.with_entry(CatalogSuggestorDescriptor::new(
SuggestorDescriptor::new(
"broad-evaluation",
profile(
"broad-evaluation",
SuggestorRole::Evaluation,
Vec::new(),
vec![
SuggestorCapability::Analytics,
SuggestorCapability::Optimization,
SuggestorCapability::PolicyEnforcement,
],
),
),
DiscoveryMetadata::new("Broad evaluation.", "Test fixture."),
))
.with_entry(catalog_entry(
"narrow-planning",
SuggestorRole::Planning,
SuggestorCapability::Optimization,
LoopContribution::Optimize,
"Narrow planning.",
))
.with_entry(catalog_entry(
"narrow-constraint",
SuggestorRole::Constraint,
SuggestorCapability::PolicyEnforcement,
LoopContribution::Authorize,
"Narrow constraint.",
));
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let outcome = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect("compile should succeed");
let first = &outcome.decisions[0];
assert_eq!(
first.unmatched_roles_at_start,
vec![
SuggestorRole::Signal,
SuggestorRole::Evaluation,
SuggestorRole::Planning,
SuggestorRole::Constraint,
],
);
assert_eq!(first.chosen.as_deref(), Some("broad-evaluation"));
assert_eq!(first.chosen_role, Some(SuggestorRole::Evaluation));
assert_ne!(
first.chosen_role,
first.unmatched_roles_at_start.first().copied(),
"chosen_role must reflect actual fill, not the first remaining role"
);
}
#[test]
fn catalog_compile_advisory_order_breaks_ties_but_not_coverage() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full().with_entry(catalog_entry(
"retrieve-suggestor-alt",
SuggestorRole::Signal,
SuggestorCapability::KnowledgeRetrieval,
LoopContribution::Retrieve,
"Alternative retrieve specialist.",
));
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let baseline = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect("baseline compile");
let baseline_signal_pick = baseline
.decisions
.iter()
.find(|d| d.chosen_role == Some(SuggestorRole::Signal))
.and_then(|d| d.chosen.clone())
.unwrap();
let other = if baseline_signal_pick == "retrieve-suggestor" {
"retrieve-suggestor-alt"
} else {
"retrieve-suggestor"
};
let advisory = vec![other.to_string()];
let advised = FormationCompiler::new()
.compile_from_catalog(&request, &templates, &catalog, &providers, Some(&advisory))
.expect("advised compile");
let advised_signal_pick = advised
.decisions
.iter()
.find(|d| d.chosen_role == Some(SuggestorRole::Signal))
.and_then(|d| d.chosen.clone())
.unwrap();
assert_eq!(advised_signal_pick, other);
let bogus_advisory = vec!["does-not-exist".to_string()];
let unaffected = FormationCompiler::new()
.compile_from_catalog(
&request,
&templates,
&catalog,
&providers,
Some(&bogus_advisory),
)
.expect("bogus advisor compile");
assert_eq!(
unaffected
.decisions
.iter()
.find(|d| d.chosen_role == Some(SuggestorRole::Signal))
.and_then(|d| d.chosen.clone())
.unwrap(),
baseline_signal_pick
);
}
#[test]
fn compile_draft_rejects_unknown_descriptor() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full();
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let descriptor_ids = vec![
"retrieve-suggestor".into(),
"does-not-exist".into(),
"optimize-suggestor".into(),
"authorize-suggestor".into(),
];
let failure = FormationCompiler::new()
.compile_draft_from_catalog(&request, &templates, &catalog, &providers, &descriptor_ids)
.expect_err("unknown descriptor must be rejected");
assert!(matches!(
failure.error,
FormationCompileError::DraftDescriptorMissing { ref descriptor_id }
if descriptor_id == "does-not-exist"
));
}
#[test]
fn compile_draft_rejects_duplicate_descriptor() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full();
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let descriptor_ids = vec![
"retrieve-suggestor".into(),
"retrieve-suggestor".into(),
"optimize-suggestor".into(),
"authorize-suggestor".into(),
];
let failure = FormationCompiler::new()
.compile_draft_from_catalog(&request, &templates, &catalog, &providers, &descriptor_ids)
.expect_err("duplicate descriptor must be rejected");
assert!(matches!(
failure.error,
FormationCompileError::DuplicateDraftDescriptor { ref descriptor_id }
if descriptor_id == "retrieve-suggestor"
));
}
#[test]
fn compile_draft_rejects_undercovering_roster() {
let templates = loop_demo_template_catalog();
let catalog = loop_demo_catalog_full();
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let descriptor_ids = vec![
"retrieve-suggestor".into(),
"score-suggestor".into(),
"authorize-suggestor".into(),
];
let failure = FormationCompiler::new()
.compile_draft_from_catalog(&request, &templates, &catalog, &providers, &descriptor_ids)
.expect_err("undercovering draft must be rejected");
match failure.error {
FormationCompileError::UncoveredRequirements {
unmatched_roles,
unmatched_capabilities,
} => {
assert!(unmatched_roles.contains(&SuggestorRole::Planning));
assert!(unmatched_capabilities.contains(&SuggestorCapability::Optimization));
}
other => panic!("expected UncoveredRequirements, got {other:?}"),
}
}
#[test]
fn compile_draft_preserves_exact_roster_no_greedy_reselect() {
let templates = loop_demo_template_catalog();
let providers = ProviderDescriptorCatalog::new();
let request = loop_demo_query();
let mut catalog = loop_demo_catalog_full();
catalog.register(catalog_entry(
"retrieve-alt",
SuggestorRole::Signal,
SuggestorCapability::KnowledgeRetrieval,
LoopContribution::Retrieve,
"Alternative retrieve.",
));
catalog.register(catalog_entry(
"score-alt",
SuggestorRole::Evaluation,
SuggestorCapability::Analytics,
LoopContribution::Score,
"Alternative score.",
));
let compiler = FormationCompiler::new();
let greedy = compiler
.compile_from_catalog(&request, &templates, &catalog, &providers, None)
.expect("greedy compile");
let greedy_ids: Vec<_> = greedy
.roster
.iter()
.map(|r| r.suggestor_id.clone())
.collect();
let draft_ids = vec![
"retrieve-alt".into(),
"score-alt".into(),
"optimize-suggestor".into(),
"authorize-suggestor".into(),
];
assert_ne!(
greedy_ids, draft_ids,
"test fixture is wrong: greedy already matches the draft"
);
let validated = compiler
.compile_draft_from_catalog(&request, &templates, &catalog, &providers, &draft_ids)
.expect("valid draft must compile");
let validated_ids: Vec<_> = validated
.roster
.iter()
.map(|r| r.suggestor_id.clone())
.collect();
assert_eq!(
validated_ids, draft_ids,
"compile_draft_from_catalog must preserve the draft's exact roster — no greedy reselect"
);
}
}