Skip to main content

caixa_core/
kind.rs

1use serde::{Deserialize, Serialize};
2
3/// What a caixa produces.
4///
5/// In `caixa.lisp`:
6///
7/// ```lisp
8/// :kind Biblioteca   ; library (lib/<nome>.lisp entry)
9/// :kind Binario      ; executable(s) under exe/
10/// :kind Servico      ; long-running service under servicos/
11/// :kind Supervisor   ; OTP-style typed supervisor tree (see supervisor.rs)
12/// ```
13///
14/// Authored as bare symbols (`Biblioteca` not `:biblioteca`) to match the
15/// tatara-lisp enum convention where symbols become enum discriminants via
16/// the serde `Deserialize` fallthrough.
17#[derive(
18    Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, gen_platform::IsVariant,
19)]
20pub enum CaixaKind {
21    /// Library — exports Lisp forms for other caixas to `(importar …)`.
22    Biblioteca,
23    /// Binary — one or more executables under `exe/`.
24    Binario,
25    /// Service — long-running daemon under `servicos/`.
26    Servico,
27    /// OTP-shaped supervisor — does not run any code itself; its
28    /// children are other caixas, restarted under a typed strategy.
29    /// See `supervisor.rs` for the full shape (`SupervisorSpec`).
30    Supervisor,
31    /// Typed application — composes multiple Servicos into a single
32    /// declarative mesh with WIT-typed `:contratos`, mesh-level
33    /// `:politicas`, and explicit `:placement`. See `aplicacao.rs`
34    /// (`AplicacaoSpec`) and `theory/MESH-COMPOSITION.md` for the
35    /// design frame.
36    Aplicacao,
37    /// Typed CI run — carries a `:ci` slot of
38    /// `canteiro_types::CiRun` (a repo's CI run as a set of typed
39    /// nodes + their dependency edges). Runs no code of its own and
40    /// owns no `lib`/`exe`/`servicos`/`children`/`membros` code
41    /// surface — its sole payload is the `ci` field on [`crate::Caixa`].
42    /// See CANTEIRO §7.1-C (`pleme-io/sui`'s `canteiro-types` crate)
43    /// for the DAG algebra (`decompose`/`affected_set`/`affected_waves`)
44    /// this slot feeds, and the `caixa-actions` renderer (currently
45    /// validate-only — see its crate docs) for the M0 consumer.
46    Acao,
47}
48
49impl CaixaKind {
50    /// Exhaustive iteration surface for every consumer that walks the
51    /// closed six-arm [`CaixaKind`] discriminator set (the future M4
52    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's admission-webhook
53    /// rejection body naming the accepted-`:kind` list, a future
54    /// `feira --kind …` CLI arg-parse's "did you mean" hint via a
55    /// [`Self::from_wire`]-scan over the slice, the future
56    /// `feira app graph` per-Aplicacao `:kind`-histogram column, any
57    /// future round-trip fuzz harness that sweeps every arm). A future
58    /// variant addition (an `Actor` virtual-actor arm the
59    /// [`ABSORPTION-ROADMAP`](https://github.com/pleme-io/theory/blob/main/ABSORPTION-ROADMAP.md)
60    /// M5 Orleans-inspired kind reaches through — a candidate future
61    /// arm named in the sibling [`Self::from_wire`] doc block —
62    /// extends this slice as a single edit and every consumer picks up
63    /// the new entry by construction; the compiler-checked
64    /// exhaustiveness on the sibling method `match` arms
65    /// ([`Self::as_str`] / [`Self::wire_name`] / [`Self::from_wire`] /
66    /// the `requires_*` predicates) is the build-time guarantee that
67    /// no arm forgets to grow.
68    ///
69    /// Peer of the sibling closed-set typed enums'
70    /// [`crate::aplicacao::PlacementStrategy::ALL`] (18c7342) /
71    /// [`crate::aplicacao::RateLimitUnit::ALL`] (6bce03d) /
72    /// [`crate::dep::DepList::ALL`] (45ee563) exhaustive-iteration
73    /// surfaces — the fourth (and structurally most fundamental —
74    /// every caixa carries a `:kind`) closed-set typed enum on the
75    /// caixa surface to converge onto the same
76    /// one-canonical-arm-list-per-enum discipline.
77    pub const ALL: &'static [Self] = &[
78        Self::Biblioteca,
79        Self::Binario,
80        Self::Servico,
81        Self::Supervisor,
82        Self::Aplicacao,
83        Self::Acao,
84    ];
85
86    /// A `Biblioteca` is expected to have at least one `lib/` entry.
87    #[must_use]
88    pub const fn requires_lib(self) -> bool {
89        matches!(self, Self::Biblioteca)
90    }
91
92    /// A `Binario` is expected to have at least one `exe/` entry.
93    #[must_use]
94    pub const fn requires_exe(self) -> bool {
95        matches!(self, Self::Binario)
96    }
97
98    /// A `Servico` is expected to have at least one `servicos/` entry.
99    #[must_use]
100    pub const fn requires_servicos(self) -> bool {
101        matches!(self, Self::Servico)
102    }
103
104    /// A `Supervisor` is expected to have at least one `:children` entry
105    /// (or a `SimpleOneForOne` strategy that spawns children dynamically).
106    #[must_use]
107    pub const fn requires_children(self) -> bool {
108        matches!(self, Self::Supervisor)
109    }
110
111    /// An `Aplicacao` is expected to have at least one `:membros` entry.
112    #[must_use]
113    pub const fn requires_membros(self) -> bool {
114        matches!(self, Self::Aplicacao)
115    }
116
117    /// An `Acao` is expected to carry a `:ci` slot (a typed
118    /// `canteiro_types::CiRun`). Mirror of the sibling
119    /// [`Self::requires_lib`]/[`Self::requires_exe`]/
120    /// [`Self::requires_servicos`]/[`Self::requires_membros`] required-
121    /// slot predicates on the fifth [`CaixaKind`] arm.
122    #[must_use]
123    pub const fn requires_ci(self) -> bool {
124        matches!(self, Self::Acao)
125    }
126
127    /// Substrate-canonical per-[`CaixaKind`] PascalCase wire byte-string
128    /// every consumer that emits the Caixa's `:kind` axis onto a wire
129    /// surface outside the caixa-core boundary keys off — returns the
130    /// per-arm byte-string the paired
131    /// [`crate::render::CAIXA_KIND_WIRE_BIBLIOTECA`] /
132    /// [`crate::render::CAIXA_KIND_WIRE_BINARIO`] /
133    /// [`crate::render::CAIXA_KIND_WIRE_SERVICO`] /
134    /// [`crate::render::CAIXA_KIND_WIRE_SUPERVISOR`] /
135    /// [`crate::render::CAIXA_KIND_WIRE_APLICACAO`] /
136    /// [`crate::render::CAIXA_KIND_WIRE_ACAO`] lifted consts pin, and
137    /// [`Self::from_wire`] parses back into the typed [`CaixaKind`]
138    /// discriminator.
139    ///
140    /// Byte-identical to the un-`rename`d `Serialize` derive's per-arm
141    /// wire scalar (`serde_json::to_string(&kind).unwrap()` unquoted),
142    /// with the pin test
143    /// [`tests::caixa_kind_wire_name_matches_serialize_wire_byte_string`]
144    /// making the two paths' byte-agreement load-bearing so a future
145    /// `#[serde(rename_all = "…")]` attribute drift at the derive
146    /// surface trips at caixa-core build time rather than silently
147    /// splitting the wire byte-shape from every consumer that reaches
148    /// for this typed dispatch. The paired [`Self::from_wire`] returns
149    /// `Some` on every string [`Self::wire_name`] emits and `None` on
150    /// every other input — the round-trip pin
151    /// [`tests::caixa_kind_wire_round_trips_through_from_wire`] locks
152    /// the two paths' accept-sets together by construction.
153    ///
154    /// Distinct axis from the sibling [`Self::as_str`] — which returns
155    /// the lowercase Portuguese diagnostic byte-string (`"biblioteca"`
156    /// / `"binario"` / …) every consumer that formats the caixa's
157    /// typed shape as user-facing text lands on — by design, not by
158    /// drift: the two-axis split the load-bearing pin
159    /// [`tests::caixa_kind_display_matches_as_str_and_not_serialize_wire`]
160    /// already encodes. This wire accessor closes the third axis on
161    /// the [`CaixaKind`] closed-set discriminator (wire byte-string),
162    /// peer of [`Self::as_str`] (human-readable byte-string) and the
163    /// [`std::fmt::Display`] impl (routed through [`Self::as_str`]).
164    ///
165    /// Prior to this lift, the six [`caixa-crd::conversion`] +
166    /// [`caixa-feira`] + future-M4-CR-materializer consumers that
167    /// needed the PascalCase wire byte-shape reached for one of two
168    /// fragile paths: `format!("{:?}", kind)` (couples the wire format
169    /// to `Debug`'s stability guarantee, which Rust's own conventions
170    /// give as *no guarantee at all* — a `#[derive(Debug)]` swap for
171    /// a hand-rolled `impl Debug` that pretty-prints the variant with
172    /// extra context is a permitted mechanical edit whose apply-time
173    /// symptom would be every downstream K8s CR carrying a stale wire
174    /// byte-string), or `serde_json::to_string(&kind)` + string-trim of
175    /// the outer quotes (introduces an allocation + error-handling
176    /// path for a byte-shape the compiler knows verbatim at build
177    /// time). Lifting the resolver to a typed method on the substrate
178    /// primitive means every downstream consumer of the Caixa's
179    /// `:kind` wire surface reaches for exactly one typed dispatch —
180    /// the resolver's accept-set migrates as a unit on any future arm
181    /// addition (a future virtual-actor `Actor` arm the
182    /// `theory/ABSORPTION-ROADMAP.md` M5 Orleans-inspired kind reaches
183    /// through, a per-cluster kind-alias table the M4 CR materializer
184    /// resolves per-CR).
185    #[must_use]
186    pub const fn wire_name(self) -> &'static str {
187        match self {
188            Self::Biblioteca => crate::render::CAIXA_KIND_WIRE_BIBLIOTECA,
189            Self::Binario => crate::render::CAIXA_KIND_WIRE_BINARIO,
190            Self::Servico => crate::render::CAIXA_KIND_WIRE_SERVICO,
191            Self::Supervisor => crate::render::CAIXA_KIND_WIRE_SUPERVISOR,
192            Self::Aplicacao => crate::render::CAIXA_KIND_WIRE_APLICACAO,
193            Self::Acao => crate::render::CAIXA_KIND_WIRE_ACAO,
194        }
195    }
196
197    /// Substrate-canonical inverse of [`Self::wire_name`] — parses a
198    /// PascalCase wire byte-string into the typed [`CaixaKind`]
199    /// discriminator, returning `None` on any string not in the six-arm
200    /// accept-set the sibling [`Self::wire_name`] emits.
201    ///
202    /// The pair `(wire_name, from_wire)` forms a total round-trip
203    /// discipline on the six [`CaixaKind`] arms — every
204    /// [`Self::wire_name`] output parses back through this accessor
205    /// (pinned load-bearing by the sibling
206    /// [`tests::caixa_kind_wire_round_trips_through_from_wire`] test),
207    /// so consumers that emit a wire byte-string through
208    /// [`Self::wire_name`] and later re-parse it here (the K8s
209    /// [`caixa_crd`] `CaixaSpec.kind` `String`-carry round-trip through
210    /// `caixa_into_cr` + `caixa_from_cr`, the future M4
211    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's admission-time
212    /// wire re-parse, the future `feira` CLI verb that accepts a
213    /// `--kind <Biblioteca|Servico|…>` arg and binds it into the typed
214    /// enum) reach for one typed dispatch on the substrate primitive
215    /// instead of the hand-rolled per-arm `match` cascade every
216    /// pre-lift consumer previously carried verbatim. A future arm
217    /// addition (a virtual-actor `Actor` arm the M5 Orleans-inspired
218    /// kind reaches through) lands one caixa-core edit — the parser's
219    /// arm-set migrates as a unit — rather than a coordinated rewrite
220    /// across every hand-rolled `match cr.spec.kind.as_str()` at every
221    /// downstream consumer site.
222    ///
223    /// Prior to this lift, the sole in-tree consumer of the reverse
224    /// parse — [`caixa_crd::conversion::caixa_from_cr`] — carried a
225    /// six-arm `match cr.spec.kind.as_str() { "Biblioteca" => …,
226    /// "Binario" => …, "Servico" => …, "Supervisor" => …, "Aplicacao"
227    /// => …, "Acao" => …, _ => CaixaKind::Biblioteca }` cascade that
228    /// hard-coded every wire byte-string as a per-arm string literal
229    /// with no compile-time link back to the typed
230    /// [`crate::CaixaKind`] enum. A future variant rename or a serde
231    /// attribute drift on the derive would silently split the wire
232    /// format the forward `caixa_into_cr` emits from the reverse
233    /// parser's arm-set — the CR would round-trip through JSON cleanly
234    /// but land on the `_ => CaixaKind::Biblioteca` silent fallback
235    /// on every non-Biblioteca variant, far from the derive-attribute
236    /// commit that caused the drift. Lifting the resolver to a typed
237    /// method on the substrate primitive closes the drift footgun by
238    /// construction: the parser's accept-set is the same set the
239    /// [`Self::wire_name`] emitter walks, so both halves of the
240    /// round-trip migrate through one caixa-core edit on any future
241    /// arm addition.
242    ///
243    /// Returns `Option<CaixaKind>` rather than `Result<CaixaKind, _>`
244    /// because the existing in-tree consumer [`caixa_from_cr`] carries
245    /// a hard-coded silent fallback (`_ => CaixaKind::Biblioteca`) —
246    /// the fallback's shape is preserved verbatim by the caller's
247    /// `.unwrap_or(CaixaKind::Biblioteca)` on the return value, so
248    /// this lift is a byte-equal behavioral swap on today's call site
249    /// (the CR round-trip is invariant), and future callers that want
250    /// a typed error (a future `feira --kind …` arg-parse that
251    /// surfaces `unknown kind: <arg>` at the CLI) can build one on top
252    /// without disturbing the existing consumer's contract.
253    #[must_use]
254    pub fn from_wire(s: &str) -> Option<Self> {
255        match s {
256            crate::render::CAIXA_KIND_WIRE_BIBLIOTECA => Some(Self::Biblioteca),
257            crate::render::CAIXA_KIND_WIRE_BINARIO => Some(Self::Binario),
258            crate::render::CAIXA_KIND_WIRE_SERVICO => Some(Self::Servico),
259            crate::render::CAIXA_KIND_WIRE_SUPERVISOR => Some(Self::Supervisor),
260            crate::render::CAIXA_KIND_WIRE_APLICACAO => Some(Self::Aplicacao),
261            crate::render::CAIXA_KIND_WIRE_ACAO => Some(Self::Acao),
262            _ => None,
263        }
264    }
265
266    /// The canonical human-readable name.
267    ///
268    /// The five arms route through the paired
269    /// [`crate::render::CAIXA_KIND_LABEL_BIBLIOTECA`] /
270    /// [`crate::render::CAIXA_KIND_LABEL_BINARIO`] /
271    /// [`crate::render::CAIXA_KIND_LABEL_SERVICO`] /
272    /// [`crate::render::CAIXA_KIND_LABEL_SUPERVISOR`] /
273    /// [`crate::render::CAIXA_KIND_LABEL_APLICACAO`] lifted constants so
274    /// every substrate consumer that formats a caixa's typed shape as
275    /// user-facing text (the future wasm-operator's per-caixa startup
276    /// log line, the future `feira app graph` per-member kind column,
277    /// the future M4 CR materializer's admission-webhook rejection
278    /// body) reads the same byte-string the [`std::fmt::Display`] impl
279    /// (routed through this helper) emits — the pin test
280    /// [`tests::caixa_kind_as_str_returns_lifted_peer_const`] asserts
281    /// the five paths agree. Peer of the sibling
282    /// [`crate::supervisor::RestartStrategy::as_str`] (09ffb2d),
283    /// [`crate::supervisor::RestartPolicy::as_str`] (ccdf955), and M3
284    /// [`crate::aplicacao::PlacementStrategy::as_str`] (cc8f749) on the
285    /// sibling closed-set typed-enum discriminator axes — the fourth
286    /// closed-set typed enum on the caixa surface to converge onto the
287    /// same drift-detection posture.
288    ///
289    /// The two axes ([`Self::as_str`] returning lowercase Portuguese
290    /// vs. the un-`rename`d `Serialize` derive emitting PascalCase
291    /// `"Biblioteca"` / `"Binario"` / `"Servico"` / `"Supervisor"` /
292    /// `"Aplicacao"`) are intentionally distinct: the wire format is
293    /// the tatara-lisp author surface (`:kind Biblioteca`), while
294    /// [`Self::as_str`] / [`std::fmt::Display`] emit the substrate's
295    /// canonical human-readable form for diagnostics + graph output +
296    /// audit views. Two paths on this enum surface (rather than three
297    /// as on the sibling OTP-shape and M3 enums where wire ==
298    /// human-readable), but the same "one canonical byte-string per
299    /// axis, routed through a lifted const" discipline.
300    #[must_use]
301    pub const fn as_str(self) -> &'static str {
302        match self {
303            Self::Biblioteca => crate::render::CAIXA_KIND_LABEL_BIBLIOTECA,
304            Self::Binario => crate::render::CAIXA_KIND_LABEL_BINARIO,
305            Self::Servico => crate::render::CAIXA_KIND_LABEL_SERVICO,
306            Self::Supervisor => crate::render::CAIXA_KIND_LABEL_SUPERVISOR,
307            Self::Aplicacao => crate::render::CAIXA_KIND_LABEL_APLICACAO,
308            Self::Acao => crate::render::CAIXA_KIND_LABEL_ACAO,
309        }
310    }
311}
312
313/// [`std::fmt::Display`] routed through [`CaixaKind::as_str`], so the
314/// pretty-printed byte-string every consumer that formats the caixa's
315/// typed shape as user-facing text lands on (the future wasm-operator's
316/// per-caixa startup log line, the future `feira app graph` per-member
317/// kind column, the future M4 `wasm.pleme.io/v1alpha1/ComputeUnit` /
318/// `mesh.pleme.io/v1alpha1/*` CR materializer's admission-webhook
319/// rejection body) reaches for the same lifted
320/// [`crate::render::CAIXA_KIND_LABEL_BIBLIOTECA`] /
321/// [`crate::render::CAIXA_KIND_LABEL_BINARIO`] /
322/// [`crate::render::CAIXA_KIND_LABEL_SERVICO`] /
323/// [`crate::render::CAIXA_KIND_LABEL_SUPERVISOR`] /
324/// [`crate::render::CAIXA_KIND_LABEL_APLICACAO`] const the
325/// [`CaixaKind::as_str`] helper already returns.
326///
327/// Pre-convergence [`CaixaKind`] carried no [`std::fmt::Display`]
328/// surface at all — every consumer past the wire format
329/// (`Serialize` → PascalCase) had to pick between two paths
330/// ([`CaixaKind::as_str`] returning the lowercase Portuguese label, or
331/// `format!("{v:?}")` on the `Debug` derive returning the PascalCase
332/// variant name), each with different bytes on every arm and no
333/// compile-time link between the two — with the failure surfacing as a
334/// downstream consumer's log / graph / diagnostic reading one spelling
335/// while a peer consumer emitted another, far from any single-site
336/// commit. Wiring [`std::fmt::Display`] through [`CaixaKind::as_str`]
337/// closes the drift footgun structurally: every `format!("{v}")` call
338/// reaches the same lifted [`crate::render::CAIXA_KIND_LABEL_*`] const
339/// [`CaixaKind::as_str`] returns, and a future rebrand (a per-consumer
340/// disambiguation of the `:kind` vocabulary, an English-canonical
341/// rebrand of `"biblioteca"` → `"library"` under an M4 substrate-wide-
342/// vocabulary shift) reaches every consumer through exactly one
343/// const-edit.
344///
345/// The wire format axis (`Serialize` derive, PascalCase, tatara-lisp
346/// author surface `:kind Biblioteca`) stays deliberately distinct from
347/// the human-readable axis (`Display` / `as_str`, lowercase Portuguese
348/// diagnostic form): the two-path split is by design, not drift. The
349/// pin test
350/// [`tests::caixa_kind_display_matches_as_str_and_not_serialize_wire`]
351/// makes the split load-bearing so a future accidental collapse of
352/// either axis onto the other (routing `Display` through the wire
353/// format via `serde_json::to_string`, or routing `Serialize` through
354/// [`CaixaKind::as_str`] via `#[serde(rename_all = "…")]`) trips at
355/// build time rather than silently merging the two axes into one at
356/// some future consumer.
357///
358/// Pin tests
359/// [`tests::caixa_kind_display_routes_through_as_str_helper`] and
360/// [`tests::caixa_kind_as_str_returns_lifted_peer_const`] assert the
361/// two paths agree byte-for-byte on every variant, so a future variant
362/// rename or per-arm serde attribute drift is a build error visible at
363/// caixa-core test time.
364///
365/// Mirrors the M3 [`crate::aplicacao::PlacementStrategy`] `Display`
366/// impl (aplicacao.rs:2306), the M2
367/// [`crate::supervisor::RestartStrategy`] `Display` impl
368/// (supervisor.rs:164), and the M2 [`crate::supervisor::RestartPolicy`]
369/// `Display` impl (supervisor.rs:306) on the sibling closed-set typed-
370/// enum discriminator axes — same as_str-through-Display convergence
371/// discipline, extended to close the fourth (and structurally most
372/// fundamental — every caixa carries a `:kind`) closed-set typed-enum
373/// discriminator axis on the caixa typed surface.
374impl std::fmt::Display for CaixaKind {
375    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
376        f.write_str(self.as_str())
377    }
378}
379
380#[cfg(test)]
381mod tests {
382    use super::*;
383
384    #[test]
385    fn kind_requirements() {
386        assert!(CaixaKind::Biblioteca.requires_lib());
387        assert!(!CaixaKind::Biblioteca.requires_exe());
388        assert!(CaixaKind::Binario.requires_exe());
389        assert!(CaixaKind::Servico.requires_servicos());
390        assert!(CaixaKind::Supervisor.requires_children());
391        assert!(!CaixaKind::Servico.requires_children());
392        assert!(CaixaKind::Acao.requires_ci());
393        assert!(!CaixaKind::Servico.requires_ci());
394    }
395
396    #[test]
397    fn kind_deserializes_from_pascal_symbol() {
398        let v: CaixaKind = serde_json::from_str("\"Biblioteca\"").unwrap();
399        assert_eq!(v, CaixaKind::Biblioteca);
400        let v: CaixaKind = serde_json::from_str("\"Supervisor\"").unwrap();
401        assert_eq!(v, CaixaKind::Supervisor);
402    }
403
404    #[test]
405    fn supervisor_kind_has_canonical_name() {
406        assert_eq!(CaixaKind::Supervisor.as_str(), "supervisor");
407    }
408
409    #[test]
410    fn caixa_kind_as_str_returns_lifted_peer_const() {
411        // The fail-before-pass-after pin: pre-lift the five
412        // [`CaixaKind::as_str`] match arms each returned a hand-authored
413        // byte-string literal (`"biblioteca"` / `"binario"` /
414        // `"servico"` / `"supervisor"` / `"aplicacao"`) with no
415        // compile-time link to any lifted peer const on the sibling
416        // layout-diagnostic axis (whose bytes coincide on `Biblioteca` /
417        // `Servico` by design — see the existing alignment pin in
418        // `crate::layout::tests`). A future rebrand touching either
419        // endpoint (a per-consumer disambiguation of the `:kind`
420        // vocabulary, an English-canonical rename lands on one arm's
421        // byte-string without touching the peer axis) would silently
422        // desynchronize until a downstream consumer surfaced the drift
423        // at diagnostic / graph time. Pinning the five arms to the five
424        // lifted [`crate::render::CAIXA_KIND_LABEL_*`] consts makes any
425        // future drift a caixa-core-build-time failure. Peer of the
426        // sibling
427        // [`crate::supervisor::tests::restart_strategy_variants_serialize_to_lifted_scalar_values`]
428        // (09ffb2d) /
429        // [`crate::supervisor::tests::restart_policy_variants_serialize_to_lifted_scalar_values`]
430        // (ccdf955) /
431        // `placement_strategy_variants_serialize_to_lifted_scalar_values`
432        // (3f0e21c) pins on the sibling closed-set typed-enum
433        // discriminator axes.
434        for (variant, expected) in [
435            (
436                CaixaKind::Biblioteca,
437                crate::render::CAIXA_KIND_LABEL_BIBLIOTECA,
438            ),
439            (CaixaKind::Binario, crate::render::CAIXA_KIND_LABEL_BINARIO),
440            (CaixaKind::Servico, crate::render::CAIXA_KIND_LABEL_SERVICO),
441            (
442                CaixaKind::Supervisor,
443                crate::render::CAIXA_KIND_LABEL_SUPERVISOR,
444            ),
445            (
446                CaixaKind::Aplicacao,
447                crate::render::CAIXA_KIND_LABEL_APLICACAO,
448            ),
449            (CaixaKind::Acao, crate::render::CAIXA_KIND_LABEL_ACAO),
450        ] {
451            assert_eq!(
452                variant.as_str(),
453                expected,
454                "CaixaKind::{variant:?}.as_str() must return the lifted \
455                 CAIXA_KIND_LABEL_* const"
456            );
457        }
458    }
459
460    #[test]
461    fn caixa_kind_display_routes_through_as_str_helper() {
462        // The fail-before-pass-after pin on the two-path convergence:
463        // pre-lift [`CaixaKind`] carried no [`std::fmt::Display`]
464        // surface at all — every consumer past the wire format had to
465        // pick between [`CaixaKind::as_str`] returning the lowercase
466        // Portuguese label or `format!("{v:?}")` on the `Debug` derive
467        // returning the PascalCase variant name. Wiring
468        // [`std::fmt::Display`] through [`CaixaKind::as_str`] closes
469        // the drift footgun: every `format!("{v}")` call reaches the
470        // same lifted [`crate::render::CAIXA_KIND_LABEL_*`] const the
471        // [`CaixaKind::as_str`] helper already returns, so a future
472        // variant rename lands at exactly one place. Pin the routing
473        // here so a future `impl std::fmt::Display for CaixaKind`
474        // reimplementation that hand-rolls the arms instead of
475        // delegating to [`CaixaKind::as_str`] fails at caixa-core
476        // build time. Peer of the sibling
477        // [`crate::supervisor::tests::restart_strategy_display_routes_through_as_str_helper`]
478        // /
479        // [`crate::supervisor::tests::restart_policy_display_routes_through_as_str_helper`]
480        // (15a1305) on the sibling M2 closed-set typed-enum
481        // discriminator axes.
482        for &variant in CaixaKind::ALL {
483            assert_eq!(
484                variant.to_string(),
485                variant.as_str(),
486                "CaixaKind::{variant:?} Display must route through \
487                 CaixaKind::as_str (single source of truth: the lifted \
488                 CAIXA_KIND_LABEL_* const)"
489            );
490        }
491    }
492
493    #[test]
494    fn caixa_kind_display_matches_as_str_and_not_serialize_wire() {
495        // The fail-before-pass-after pin on the two-axis split
496        // discipline: unlike the sibling OTP-shape / M3 typed enums
497        // ([`crate::supervisor::RestartStrategy`],
498        // [`crate::supervisor::RestartPolicy`],
499        // [`crate::aplicacao::PlacementStrategy`]) where the wire
500        // format and the human-readable format share bytes (both
501        // PascalCase / camelCase), [`CaixaKind`] carries two axes with
502        // *distinct* byte-shapes by design: the wire format is
503        // PascalCase (`"Biblioteca"` / `"Binario"` / `"Servico"` /
504        // `"Supervisor"` / `"Aplicacao"` — the tatara-lisp author
505        // surface `:kind Biblioteca`), while [`CaixaKind::as_str`] /
506        // [`std::fmt::Display`] emit the lowercase Portuguese
507        // diagnostic form (`"biblioteca"` etc.). The pin here makes
508        // the split load-bearing: a future accidental collapse of
509        // either axis onto the other (routing `Serialize` through
510        // [`CaixaKind::as_str`] via `#[serde(rename_all = "lowercase")]`,
511        // routing [`std::fmt::Display`] through the wire format
512        // directly) would trip here at caixa-core build time rather
513        // than silently merging the two axes at some future consumer's
514        // dispatch step.
515        for &variant in CaixaKind::ALL {
516            let wire = serde_json::to_string(&variant).unwrap();
517            let unquoted = wire
518                .strip_prefix('"')
519                .and_then(|s| s.strip_suffix('"'))
520                .expect("serialized CaixaKind is a JSON string");
521            let display = variant.to_string();
522            assert_eq!(
523                display,
524                variant.as_str(),
525                "CaixaKind::{variant:?} Display must byte-equal as_str"
526            );
527            assert_ne!(
528                display, unquoted,
529                "CaixaKind::{variant:?} Display / as_str (lowercase Portuguese \
530                 diagnostic form) must stay structurally distinct from the \
531                 Serialize wire format (PascalCase tatara-lisp author surface)"
532            );
533            assert!(
534                unquoted.chars().next().is_some_and(char::is_uppercase),
535                "CaixaKind::{variant:?} wire format must open with an \
536                 uppercase byte (PascalCase tatara-lisp author surface)"
537            );
538            assert!(
539                display.chars().next().is_some_and(char::is_lowercase),
540                "CaixaKind::{variant:?} Display / as_str must open with a \
541                 lowercase byte (Portuguese diagnostic form)"
542            );
543        }
544    }
545
546    #[test]
547    fn caixa_kind_label_consts_pin_canonical_bytes() {
548        // Drift-detection pin: the five
549        // [`crate::render::CAIXA_KIND_LABEL_*`] lifted consts must
550        // continue to carry their canonical byte-shapes. A rebrand
551        // touching one const's declaration would silently desynchronize
552        // every consumer this const routes through (the
553        // [`CaixaKind::as_str`] arm, the [`std::fmt::Display`] route,
554        // the byte-shape coincidence pins against
555        // [`crate::render::LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] /
556        // [`crate::render::LAYOUT_MISSING_ENTRY_KIND_SERVICO`] /
557        // [`crate::render::FLEET_PROGRAMS_KEY_APLICACAO`]) — pinning
558        // the five byte-shapes here makes any rebrand attempt a build
559        // error at this call, forcing the author to reason about every
560        // downstream consumer explicitly. Mirror of the peer
561        // drift-detection pins the sibling OTP-shape / M3 closed-set
562        // const families carry (`SUPERVISOR_ESTRATEGIA_*`,
563        // `SUPERVISOR_CHILD_RESTART_*`, `M3_PLACEMENT_ESTRATEGIA_*`).
564        assert_eq!(crate::render::CAIXA_KIND_LABEL_BIBLIOTECA, "biblioteca");
565        assert_eq!(crate::render::CAIXA_KIND_LABEL_BINARIO, "binario");
566        assert_eq!(crate::render::CAIXA_KIND_LABEL_SERVICO, "servico");
567        assert_eq!(crate::render::CAIXA_KIND_LABEL_SUPERVISOR, "supervisor");
568        assert_eq!(crate::render::CAIXA_KIND_LABEL_APLICACAO, "aplicacao");
569        assert_eq!(crate::render::CAIXA_KIND_LABEL_ACAO, "acao");
570    }
571
572    #[test]
573    fn caixa_kind_is_variant_predicates_partition_the_arm_set() {
574        // Fail-before-pass-after pin on the [`gen_platform::IsVariant`]
575        // derive: for each of the five variants, exactly one of the
576        // generated `is_biblioteca` / `is_binario` / `is_servico` /
577        // `is_supervisor` / `is_aplicacao` predicates returns `true` and
578        // the other four return `false`. Prior to this derive the ten
579        // production `caixa.kind() == CaixaKind::X` / `!=` sites in
580        // `layout.rs` (`SupervisorOwnsCode` / `AplicacaoOwnsCode` /
581        // `MeshSlotsOnNonAplicacao` / `SupervisorSlotsOnNonSupervisor` /
582        // `ServicoSlotsOnNonServico` / `MissingLib` biblioteca-fallback
583        // / Supervisor invariants / Aplicacao invariants) plus
584        // `manifest.rs` (`aplicacao_view` / `supervisor_view` kind
585        // gates) each open-coded a per-arm PartialEq compare against
586        // the enum variant — ten sites that expressed no compile-time
587        // link back to the closed-set typed dispatch a future sixth
588        // `:kind` (e.g. an `Actor` virtual-actor arm for the
589        // absorption-roadmap M5 Orleans-inspired kind) would have to
590        // thread through in lockstep or one gate would silently
591        // disagree with the others on which arms it treats as "runs
592        // no code" / "declares mesh slots" / etc. Peer of the sibling
593        // [`crate::supervisor::RestartStrategy`] / [`crate::supervisor::RestartPolicy`] /
594        // [`crate::upgrade::UpgradeInstruction`] `IsVariant` derives on
595        // the sibling closed-set typed-enum discriminator axes — extends
596        // the same one-typed-dispatch-per-variant discipline onto the
597        // fourth (and structurally most fundamental — every caixa
598        // carries a `:kind`) closed-set typed-enum discriminator axis.
599        let rows: [(CaixaKind, [bool; 6]); 6] = [
600            (
601                CaixaKind::Biblioteca,
602                [true, false, false, false, false, false],
603            ),
604            (
605                CaixaKind::Binario,
606                [false, true, false, false, false, false],
607            ),
608            (
609                CaixaKind::Servico,
610                [false, false, true, false, false, false],
611            ),
612            (
613                CaixaKind::Supervisor,
614                [false, false, false, true, false, false],
615            ),
616            (
617                CaixaKind::Aplicacao,
618                [false, false, false, false, true, false],
619            ),
620            (CaixaKind::Acao, [false, false, false, false, false, true]),
621        ];
622        for (variant, expected) in rows {
623            let observed = [
624                variant.is_biblioteca(),
625                variant.is_binario(),
626                variant.is_servico(),
627                variant.is_supervisor(),
628                variant.is_aplicacao(),
629                variant.is_acao(),
630            ];
631            assert_eq!(
632                observed, expected,
633                "CaixaKind::{variant:?} is_* predicates must partition \
634                 the arm set (biblioteca, binario, servico, supervisor, \
635                 aplicacao, acao); got {observed:?}"
636            );
637        }
638    }
639
640    #[test]
641    fn caixa_kind_is_variant_predicates_are_const_fn() {
642        // The [`gen_platform::IsVariant`] derive emits `const fn`
643        // predicates on the peer [`crate::upgrade::UpgradeInstruction`] +
644        // [`crate::supervisor::RestartStrategy`] +
645        // [`crate::supervisor::RestartPolicy`] closed-set typed enums —
646        // pin the same posture on [`CaixaKind`] so a future accidental
647        // downgrade to non-`const` (an added runtime helper reachable
648        // only from a non-`const` context, a manual hand-rolled `impl`
649        // that shadows the derive-generated method) trips at
650        // caixa-core build time rather than surfacing as a
651        // downstream `const`-context regression far from the derive
652        // declaration.
653        const IS_APLICACAO: bool = CaixaKind::Aplicacao.is_aplicacao();
654        const IS_BIBLIOTECA: bool = CaixaKind::Biblioteca.is_biblioteca();
655        const IS_SERVICO: bool = CaixaKind::Servico.is_servico();
656        const IS_SUPERVISOR: bool = CaixaKind::Supervisor.is_supervisor();
657        const IS_BINARIO: bool = CaixaKind::Binario.is_binario();
658        const IS_ACAO: bool = CaixaKind::Acao.is_acao();
659        assert!(IS_APLICACAO);
660        assert!(IS_BIBLIOTECA);
661        assert!(IS_SERVICO);
662        assert!(IS_SUPERVISOR);
663        assert!(IS_BINARIO);
664        assert!(IS_ACAO);
665    }
666
667    #[test]
668    fn caixa_kind_wire_name_returns_lifted_peer_const() {
669        // Fail-before-pass-after pin: the six [`CaixaKind::wire_name`]
670        // match arms each return one of the paired
671        // [`crate::render::CAIXA_KIND_WIRE_*`] lifted consts, and a
672        // future rebrand touching either endpoint (a per-consumer
673        // disambiguation of the `:kind` vocabulary, a rename lands on
674        // one arm's byte-string without touching the peer axis) would
675        // silently desynchronize the emitter from the paired
676        // [`CaixaKind::from_wire`] parser's accept-set. Pinning the six
677        // arms to the six lifted consts makes any future drift a
678        // caixa-core-build-time failure — peer of the sibling
679        // [`caixa_kind_as_str_returns_lifted_peer_const`] pin on the
680        // human-readable-label axis.
681        for (variant, expected) in [
682            (
683                CaixaKind::Biblioteca,
684                crate::render::CAIXA_KIND_WIRE_BIBLIOTECA,
685            ),
686            (CaixaKind::Binario, crate::render::CAIXA_KIND_WIRE_BINARIO),
687            (CaixaKind::Servico, crate::render::CAIXA_KIND_WIRE_SERVICO),
688            (
689                CaixaKind::Supervisor,
690                crate::render::CAIXA_KIND_WIRE_SUPERVISOR,
691            ),
692            (
693                CaixaKind::Aplicacao,
694                crate::render::CAIXA_KIND_WIRE_APLICACAO,
695            ),
696            (CaixaKind::Acao, crate::render::CAIXA_KIND_WIRE_ACAO),
697        ] {
698            assert_eq!(
699                variant.wire_name(),
700                expected,
701                "CaixaKind::{variant:?}.wire_name() must return the \
702                 lifted CAIXA_KIND_WIRE_* const"
703            );
704        }
705    }
706
707    #[test]
708    fn caixa_kind_wire_name_matches_serialize_wire_byte_string() {
709        // Load-bearing pin on the derive-to-const identity: the six
710        // [`CaixaKind::wire_name`] outputs must byte-equal the
711        // un-`rename`d `Serialize` derive's per-arm wire scalar (the
712        // JSON quoted-string with its outer quotes stripped). A future
713        // accidental `#[serde(rename_all = "…")]` attribute drift at
714        // the derive surface would silently split the wire byte-shape
715        // every K8s-CR / tatara-lisp author-surface / future-M4-CR
716        // materializer consumer emits through this typed dispatch from
717        // the shape the un-`rename`d derive projects — the drift's
718        // apply-time symptom (a K8s Caixa CR whose `spec.kind` no
719        // longer round-trips through `caixa_from_cr` because the
720        // reverse [`CaixaKind::from_wire`] parser rejects the new
721        // rename-transformed byte-string) would surface far from the
722        // derive attribute's commit. Pinning the identity here makes
723        // any such drift a caixa-core-build-time failure. Peer of the
724        // sibling
725        // [`caixa_kind_display_matches_as_str_and_not_serialize_wire`]
726        // pin — that one keeps `Display` structurally *distinct* from
727        // the wire byte-shape (by design); this one keeps
728        // [`CaixaKind::wire_name`] structurally *aligned* with the
729        // wire byte-shape (by design).
730        for &variant in CaixaKind::ALL {
731            let json = serde_json::to_string(&variant).unwrap();
732            let unquoted = json
733                .strip_prefix('"')
734                .and_then(|s| s.strip_suffix('"'))
735                .expect("serialized CaixaKind is a JSON string");
736            assert_eq!(
737                variant.wire_name(),
738                unquoted,
739                "CaixaKind::{variant:?}.wire_name() must byte-equal the \
740                 un-renamed Serialize derive's wire scalar — a mismatch \
741                 means either the derive attributes drifted or the \
742                 CAIXA_KIND_WIRE_* const family drifted; either way \
743                 downstream K8s-CR round-trip through caixa_from_cr \
744                 silently splits from the accessor-routed source of \
745                 truth"
746            );
747        }
748    }
749
750    #[test]
751    fn caixa_kind_wire_round_trips_through_from_wire() {
752        // Total-round-trip pin on the (wire_name, from_wire) pair:
753        // every arm's [`CaixaKind::wire_name`] output must parse back
754        // through [`CaixaKind::from_wire`] to the same variant. Any
755        // future accessor extension that adds a new arm to one side of
756        // the pair without extending the other — a new `CaixaKind`
757        // variant whose `wire_name` arm lands but whose `from_wire`
758        // arm is forgotten, or a rename that touches `wire_name`'s
759        // per-arm const without threading through `from_wire`'s peer
760        // arm — trips here at caixa-core build time rather than
761        // surfacing as a downstream K8s-CR round-trip miss (a
762        // `caixa_into_cr` emit that lands a `spec.kind` byte-string
763        // the paired `caixa_from_cr`'s `CaixaKind::from_wire` cannot
764        // parse, silently falling through to the caller's
765        // `.unwrap_or(CaixaKind::Biblioteca)` fallback).
766        for &variant in CaixaKind::ALL {
767            let wire = variant.wire_name();
768            let parsed = CaixaKind::from_wire(wire).unwrap_or_else(|| {
769                panic!(
770                    "CaixaKind::from_wire({wire:?}) must accept every \
771                     CaixaKind::wire_name output — got None for the \
772                     wire byte-string of {variant:?}"
773                )
774            });
775            assert_eq!(
776                parsed, variant,
777                "CaixaKind::from_wire(CaixaKind::{variant:?}.wire_name()) \
778                 must return CaixaKind::{variant:?} — the (wire_name, \
779                 from_wire) pair must form a total round-trip on the \
780                 closed six-arm CaixaKind arm-set"
781            );
782        }
783    }
784
785    #[test]
786    fn caixa_kind_from_wire_rejects_unknown_byte_strings() {
787        // Rejection pin on the parser's accept-set: any string outside
788        // the six-arm [`CaixaKind::wire_name`] output set must return
789        // `None`. A future accidental widening of the accept-set (a
790        // case-insensitive match that accepts `"biblioteca"` on the
791        // wire axis, a hand-rolled Levenshtein-forgiving arm-lookup
792        // that admits `"Biblioteka"` typos) would silently drift the
793        // parser's accept-set from the emitter's — a K8s CR carrying
794        // a malformed `spec.kind` byte-string that today's parser
795        // rejects (letting the caller's `.unwrap_or(Biblioteca)`
796        // fallback fire on the operator-visible-drift path) would then
797        // land on a plausibly-wrong typed arm the caller does not
798        // route through the fallback, silently binding the CR to the
799        // wrong runtime contract. Also rejects the sibling
800        // lowercase-Portuguese diagnostic-form strings (`"biblioteca"`
801        // / `"servico"`), which are the *human-readable* form the
802        // [`CaixaKind::as_str`] axis emits — the two-axis split
803        // documented on the sibling
804        // [`caixa_kind_display_matches_as_str_and_not_serialize_wire`]
805        // pin explicitly forbids accepting one axis's byte-shapes as
806        // parseable on the other axis.
807        for bad in [
808            "",
809            "biblioteca",
810            "servico",
811            "aplicacao",
812            "ACao",
813            "unknown",
814            "actor",
815            "Biblioteka",
816        ] {
817            assert!(
818                CaixaKind::from_wire(bad).is_none(),
819                "CaixaKind::from_wire({bad:?}) must return None — the \
820                 parser's accept-set is exactly the six CaixaKind::wire_name \
821                 outputs; a widening would silently split the parser's \
822                 accept-set from the emitter's"
823            );
824        }
825    }
826
827    #[test]
828    fn caixa_kind_wire_name_is_const_fn() {
829        // Const-context pin: [`CaixaKind::wire_name`] must remain
830        // `const fn` (its match arms return `pub const` byte-strings,
831        // so no non-const operation exists on the resolution path).
832        // Downstream consumers reaching for the accessor from a
833        // `const` context (a future substrate-wide const-fold-driven
834        // audit table that materializes every kind's wire byte-string
835        // at build time, a `const` gate on a per-arm CR-schema
836        // registration) rely on the const-ness. A future accidental
837        // downgrade to non-`const` (an added runtime helper reachable
838        // only from a non-`const` context, a manual hand-rolled `impl`
839        // that shadows this method) trips at caixa-core build time
840        // rather than surfacing as a downstream `const`-context
841        // regression far from the accessor declaration. Peer of the
842        // sibling [`caixa_kind_is_variant_predicates_are_const_fn`]
843        // pin on the [`gen_platform::IsVariant`] derive's per-arm
844        // predicates.
845        const BIBLIOTECA_WIRE: &str = CaixaKind::Biblioteca.wire_name();
846        const BINARIO_WIRE: &str = CaixaKind::Binario.wire_name();
847        const SERVICO_WIRE: &str = CaixaKind::Servico.wire_name();
848        const SUPERVISOR_WIRE: &str = CaixaKind::Supervisor.wire_name();
849        const APLICACAO_WIRE: &str = CaixaKind::Aplicacao.wire_name();
850        const ACAO_WIRE: &str = CaixaKind::Acao.wire_name();
851        assert_eq!(BIBLIOTECA_WIRE, "Biblioteca");
852        assert_eq!(BINARIO_WIRE, "Binario");
853        assert_eq!(SERVICO_WIRE, "Servico");
854        assert_eq!(SUPERVISOR_WIRE, "Supervisor");
855        assert_eq!(APLICACAO_WIRE, "Aplicacao");
856        assert_eq!(ACAO_WIRE, "Acao");
857    }
858
859    #[test]
860    fn caixa_kind_wire_consts_are_pairwise_distinct() {
861        // Distinctness pin: the six [`crate::render::CAIXA_KIND_WIRE_*`]
862        // consts must be pairwise distinct — an accidental copy-paste
863        // flip that reroutes one arm's byte-string to also match
864        // another silently collapses two per-kind wire arms onto one,
865        // so a downstream K8s CR carrying the collapsed byte-string
866        // round-trips through [`CaixaKind::from_wire`] to whichever
867        // arm the parser's match cascade lands on first (the collapse
868        // makes the outcome match-arm-ordering-dependent). Peer of the
869        // sibling [`caixa_kind_label_consts_are_pairwise_distinct`]
870        // pin on the human-readable-label axis.
871        let all = [
872            crate::render::CAIXA_KIND_WIRE_BIBLIOTECA,
873            crate::render::CAIXA_KIND_WIRE_BINARIO,
874            crate::render::CAIXA_KIND_WIRE_SERVICO,
875            crate::render::CAIXA_KIND_WIRE_SUPERVISOR,
876            crate::render::CAIXA_KIND_WIRE_APLICACAO,
877            crate::render::CAIXA_KIND_WIRE_ACAO,
878        ];
879        for (i, a) in all.iter().enumerate() {
880            for (j, b) in all.iter().enumerate() {
881                if i != j {
882                    assert_ne!(
883                        a, b,
884                        "CAIXA_KIND_WIRE_* consts must be pairwise \
885                         distinct — found duplicate byte-string {a:?} \
886                         at indices {i} and {j}"
887                    );
888                }
889            }
890        }
891    }
892
893    #[test]
894    fn caixa_kind_label_consts_are_pairwise_distinct() {
895        // Distinctness pin: the five
896        // [`crate::render::CAIXA_KIND_LABEL_*`] consts must be pairwise
897        // distinct — an accidental copy-paste flip that reroutes one
898        // label's byte-string to also match another silently collapses
899        // two per-kind labels onto one, so an operator reads
900        // `biblioteca` for what should have surfaced as `servico` (or
901        // vice versa). This pin catches any such flip at build time.
902        // Mirror of the peer distinctness pins on other closed-set
903        // typed axes (e.g.
904        // `layout_missing_entry_kind_consts_are_pairwise_distinct`).
905        let all = [
906            crate::render::CAIXA_KIND_LABEL_BIBLIOTECA,
907            crate::render::CAIXA_KIND_LABEL_BINARIO,
908            crate::render::CAIXA_KIND_LABEL_SERVICO,
909            crate::render::CAIXA_KIND_LABEL_SUPERVISOR,
910            crate::render::CAIXA_KIND_LABEL_APLICACAO,
911            crate::render::CAIXA_KIND_LABEL_ACAO,
912        ];
913        for (i, a) in all.iter().enumerate() {
914            for (j, b) in all.iter().enumerate() {
915                if i != j {
916                    assert_ne!(
917                        a, b,
918                        "CAIXA_KIND_LABEL_* consts must be pairwise distinct \
919                         — found duplicate byte-string {a:?} at indices {i} \
920                         and {j}"
921                    );
922                }
923            }
924        }
925    }
926
927    #[test]
928    fn caixa_kind_all_enumerates_every_variant_exactly_once() {
929        // Fail-before-pass-after pin on the [`CaixaKind::ALL`]
930        // exhaustive-iteration surface: the slice length matches the
931        // arm count of the closed six-arm set, every variant appears
932        // at least once, and no variant appears twice. A future arm
933        // addition (an `Actor` virtual-actor arm the M5 Orleans-
934        // inspired kind reaches through, per the sibling
935        // [`CaixaKind::from_wire`] doc block) that grows the enum but
936        // forgets to grow [`Self::ALL`] silently truncates every
937        // downstream consumer's accept-set at the pre-addition
938        // boundary — a future `feira --kind …` CLI-side "did you
939        // mean" scan that iterates the slice, the future M4
940        // admission-webhook's rejection body naming the accepted-
941        // `:kind` list, any future round-trip fuzz harness — all read
942        // through this slice, so a truncation there silently splits
943        // every accept-set from the arm-set the paired
944        // [`gen_platform::IsVariant`] predicates + [`Self::wire_name`]
945        // / [`Self::as_str`] / [`Self::from_wire`] siblings walk.
946        // Pinning the exhaustive-enumeration invariant here catches
947        // the drift at caixa-core build time.
948        //
949        // Peer of the sibling
950        // [`crate::aplicacao::tests::placement_strategy_all_enumerates_every_variant_once`]
951        // (18c7342) / `rate_limit_unit_all_enumerates_every_variant_once`
952        // (6bce03d) / `dep_list_all_enumerates_every_variant_once`
953        // (45ee563) pins on the peer closed-set typed-enum axes.
954        let all: &[CaixaKind] = CaixaKind::ALL;
955        assert_eq!(
956            all.len(),
957            6,
958            "CaixaKind::ALL must enumerate every variant of the \
959             six-arm closed set (Biblioteca, Binario, Servico, \
960             Supervisor, Aplicacao, Acao); got {all:?}"
961        );
962        for (i, a) in all.iter().enumerate() {
963            for (j, b) in all.iter().enumerate() {
964                if i != j {
965                    assert_ne!(
966                        a, b,
967                        "CaixaKind::ALL must carry every variant \
968                         exactly once — got duplicate {a:?} at \
969                         indices {i} and {j}"
970                    );
971                }
972            }
973        }
974        for variant in [
975            CaixaKind::Biblioteca,
976            CaixaKind::Binario,
977            CaixaKind::Servico,
978            CaixaKind::Supervisor,
979            CaixaKind::Aplicacao,
980            CaixaKind::Acao,
981        ] {
982            assert!(
983                all.contains(&variant),
984                "CaixaKind::ALL must contain {variant:?} — a future \
985                 variant addition that grows the enum but forgets to \
986                 grow the ALL slice silently truncates every \
987                 downstream consumer's accept-set at the pre-addition \
988                 boundary"
989            );
990        }
991    }
992
993    #[test]
994    fn caixa_kind_all_is_the_from_wire_accept_set() {
995        // Load-bearing pin on the two-axis identity: [`CaixaKind::ALL`]
996        // is exactly the variant image of the [`CaixaKind::from_wire`]
997        // accept-set — every arm in the slice parses back through
998        // `from_wire ∘ wire_name` to itself, and the paired
999        // [`caixa_kind_from_wire_rejects_unknown_byte_strings`] pin
1000        // guarantees `from_wire` rejects everything outside the six-
1001        // arm wire-string image. Together these two pins make the
1002        // slice the authoritative arm-set every consumer of the
1003        // closed six-arm [`CaixaKind`] discriminator reads through:
1004        // the future M4 admission-webhook can enumerate accepted
1005        // `:kind` values by walking [`Self::ALL`] and rendering each
1006        // arm's `wire_name`, the future `feira --kind …` "did you
1007        // mean" hint can score against the same slice, and no
1008        // consumer needs to re-inline a six-arm literal list. Any
1009        // future arm addition that grows one axis and forgets the
1010        // other trips here at caixa-core build time.
1011        for &variant in CaixaKind::ALL {
1012            let wire = variant.wire_name();
1013            assert_eq!(
1014                CaixaKind::from_wire(wire),
1015                Some(variant),
1016                "CaixaKind::from_wire(CaixaKind::{variant:?}.wire_name() = \
1017                 {wire:?}) must return Some({variant:?}) — CaixaKind::ALL \
1018                 must be a subset of the from_wire accept-set"
1019            );
1020        }
1021    }
1022
1023    #[test]
1024    fn caixa_kind_all_is_const_and_matches_iteration_count() {
1025        // Const-context pin: [`CaixaKind::ALL`] is a `pub const`
1026        // slice, so it materializes at build time. Downstream
1027        // consumers reaching for the slice from a `const` context (a
1028        // future substrate-wide const-fold-driven audit table that
1029        // materializes every kind's wire byte-string at build time, a
1030        // per-arm CR-schema registration in a `const` gate) rely on
1031        // the const-ness. A future accidental downgrade to a runtime
1032        // `fn ALL() -> Vec<Self>` reachable only from a non-`const`
1033        // context trips at caixa-core build time. Peer of the sibling
1034        // [`caixa_kind_wire_name_is_const_fn`] +
1035        // [`caixa_kind_is_variant_predicates_are_const_fn`] pins on
1036        // the peer accessor axes.
1037        const ALL: &[CaixaKind] = CaixaKind::ALL;
1038        const LEN: usize = ALL.len();
1039        assert_eq!(
1040            LEN, 6,
1041            "CaixaKind::ALL length must byte-equal the six-arm closed-set \
1042             cardinality at const-fold time"
1043        );
1044    }
1045}