pub fn require_single_servico(caixa: &Caixa) -> Result<(), ServicoCountMismatch>Expand description
Predicate: assert that caixa.servicos.len() == 1, returning a typed
ServicoCountMismatch view (carrying Caixa::nome + the actual
count) on rejection. The canonical entry-point every per-Servico
renderer wraps in its own thiserror Error variant via
#[from] — the call site becomes a single
caixa_core::require_single_servico(caixa)?; in place of the prior
inline if caixa.servicos.len() != 1 { return Err(Error::UnsupportedServicoCount(caixa.servicos.len())); }
block.
Lifted to a single helper so the V0 :servicos-singularity invariant
— the same shape the crate::Caixa::validate_code_paths doc
comment already names as load-bearing on caixa-helm + caixa-flux
(caixa-core/src/manifest.rs:4108) — lives in exactly one place across
every per-Servico renderer. A future per-Servico renderer
(caixa-otel, the future per-Servico OCI packager, the future M4
wasm.pleme.io/v1alpha1/ComputeUnit CR materializer) gets the same
naming-the-offending-caixa diagnostic for free, and a future change
to the V0 invariant (e.g. allowing multi-servico Servicos when the
component-model multi-world boundary lands in M5) is one edit here,
not a coordinated rewrite of every renderer’s per-arm
UnsupportedServicoCount check.
Same trajectory as require_kind / KindMismatch on the peer
V0 Servico-shape axis: every per-Servico renderer reaches for one
caixa_core::require_* helper per V0 invariant, so the diagnostic
shape (named caixa, named field) is uniform across the substrate.
§Errors
Returns ServicoCountMismatch when caixa.servicos.len() != 1
(both empty and ≥ 2 land on this arm — the V0 contract requires
exactly one entry, not at-least one). The error carries the
caixa’s :nome + the offending count so the diagnostic names the
offending caixa.lisp — same shape every renderer’s
Error::From<ServicoCountMismatch> converts into the renderer’s
local error type.