Skip to main content

caixa_core/
manifest.rs

1use std::path::{Path, PathBuf};
2
3use serde::{Deserialize, Serialize};
4use tatara_lisp::DeriveTataraDomain;
5
6use thiserror::Error;
7
8use crate::{
9    CaixaKind, Dep,
10    behavior::BehaviorSpec,
11    dep::DepError,
12    limits::LimitsSpec,
13    render::{
14        PathShapeViolation, is_computeunit_yaml_extension, is_git_repo_url, is_lisp_extension,
15        is_sandboxed_relative_path,
16    },
17    supervisor::SupervisorSpec,
18    upgrade::UpgradeFromEntry,
19};
20
21/// Top-level manifest for a caixa (a tatara-lisp package).
22///
23/// Authored as `caixa.lisp`:
24///
25/// ```lisp
26/// (defcaixa
27///   :nome        "pangea-tatara-aws"
28///   :versao      "0.1.0"
29///   :kind        Biblioteca
30///   :edicao      "2026"
31///   :descricao   "AWS provider caixa for tatara-lisp"
32///   :repositorio "github:pleme-io/pangea-tatara-aws"
33///   :licenca     "MIT"
34///   :autores     ("pleme-io")
35///   :etiquetas   ("iac" "aws" "pangea")
36///   :deps        ((:nome "caixa-teia"    :versao "^0.1")
37///                 (:nome "iac-forge-ir"  :versao "^0.5"))
38///   :deps-dev    ((:nome "tatara-check"  :versao "*"))
39///   :bibliotecas ("lib/pangea-tatara-aws.lisp"))
40/// ```
41///
42/// Because `Caixa` derives [`tatara_lisp::domain::TataraDomain`], the manifest
43/// is parsed directly by the tatara-lisp compiler — an ill-formed manifest is
44/// a compile error, not a runtime error.
45#[derive(DeriveTataraDomain, Serialize, Deserialize, Debug, Clone, PartialEq)]
46#[serde(rename_all = "camelCase")]
47#[tatara(keyword = "defcaixa")]
48pub struct Caixa {
49    /// Package name — the canonical string used in `:deps`, the registry, and
50    /// the default lib/exe entry names.
51    pub nome: String,
52
53    /// Package version — a semver literal like `"0.1.0"`. Parsed lazily via
54    /// [`crate::CaixaVersion::parse`].
55    pub versao: String,
56
57    /// What this caixa produces. See [`CaixaKind`].
58    pub kind: CaixaKind,
59
60    /// Language edition — determines macro surface + compatibility flags.
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub edicao: Option<String>,
63
64    /// Free-form description shown in the registry listing.
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub descricao: Option<String>,
67
68    /// Homepage or repo URL.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub repositorio: Option<String>,
71
72    /// SPDX license expression — `"MIT"`, `"Apache-2.0 OR MIT"`, etc.
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub licenca: Option<String>,
75
76    /// Authors — free-form strings.
77    #[serde(default)]
78    pub autores: Vec<String>,
79
80    /// Topical tags used for registry search.
81    #[serde(default)]
82    pub etiquetas: Vec<String>,
83
84    /// Runtime dependencies.
85    #[serde(default)]
86    pub deps: Vec<Dep>,
87
88    /// Development-only dependencies (tests, lint, bench).
89    #[serde(default)]
90    pub deps_dev: Vec<Dep>,
91
92    /// Paths to executable entry points (relative to the package root).
93    /// Required when `:kind Binario`.
94    #[serde(default)]
95    pub exe: Vec<String>,
96
97    /// Paths to library entry points (relative to the package root).
98    /// First entry is the canonical `lib/<nome>.lisp`; when omitted under
99    /// `:kind Biblioteca`, the layout check expects `lib/<nome>.lisp`.
100    #[serde(default)]
101    pub bibliotecas: Vec<String>,
102
103    /// Paths to service manifests (relative to the package root).
104    /// Required when `:kind Servico`.
105    #[serde(default)]
106    pub servicos: Vec<String>,
107
108    // ── M2 typed-substrate extensions per theory/ABSORPTION-ROADMAP.md ──
109    //
110    // All four are optional + default to "absent"; existing caixas
111    // round-trip unchanged. Each maps onto a prior-art primitive named
112    // in theory/INSPIRATIONS.md:
113    //
114    //   :limits        — Lunatic per-process limits (§III.1)
115    //   :behavior      — OTP gen_server callbacks  (§II.3)
116    //   :upgrade-from  — OTP appup migration       (§II.4)
117    //   :estrategia    — OTP supervisor strategy   (§II.2 + §III.2)
118    //   :children      — OTP supervisor children    (§II.2 + §III.2)
119    //
120    // The supervisor slots are flat on Caixa (vs nested under a
121    // SupervisorSpec sub-form) to keep tatara-lisp authoring at one
122    // level of nesting; SupervisorSpec exists for validation +
123    // composition convenience (`Caixa::supervisor_view()`).
124    /// Lunatic-style per-process resource limits. None = unbounded.
125    #[serde(default, skip_serializing_if = "Option::is_none")]
126    pub limits: Option<LimitsSpec>,
127
128    /// OTP-shaped behavior callbacks for Servico-kind caixas.
129    /// Authored as `(:on-init "..." :on-call "..." …)`.
130    #[serde(default, skip_serializing_if = "Option::is_none")]
131    pub behavior: Option<BehaviorSpec>,
132
133    /// OTP appup — declarative upgrade instructions per prior version.
134    /// Empty list = no hot-upgrade path declared (caller falls back to
135    /// `:Restart` strategy).
136    #[serde(default)]
137    pub upgrade_from: Vec<UpgradeFromEntry>,
138
139    /// OTP supervisor strategy. Required when `:kind Supervisor`;
140    /// ignored otherwise.
141    #[serde(default, skip_serializing_if = "Option::is_none")]
142    pub estrategia: Option<crate::supervisor::RestartStrategy>,
143
144    /// Max restarts before the supervisor itself fails. Defaults via
145    /// SupervisorSpec at validation time.
146    #[serde(default, skip_serializing_if = "Option::is_none")]
147    pub max_restarts: Option<u32>,
148
149    /// Sliding window for `max_restarts`. Authored as a duration
150    /// string (`"60s"`, `"5m"`).
151    #[serde(default, skip_serializing_if = "Option::is_none")]
152    pub restart_window: Option<String>,
153
154    /// Static children of a supervisor. Required for OneForOne /
155    /// OneForAll / RestForOne; must be empty for SimpleOneForOne.
156    #[serde(default)]
157    pub children: Vec<crate::supervisor::ChildSpec>,
158
159    // ── M3 Aplicacao slots (theory/MESH-COMPOSITION.md) ─────────────────
160    //
161    // Required when :kind Aplicacao; ignored otherwise.
162    // Composed into a typed AplicacaoSpec via Caixa::aplicacao_view().
163    /// Member Servicos that make up this Aplicacao. Each is a
164    /// caixa-name + version-constraint pair. Required for Aplicacao.
165    #[serde(default)]
166    pub membros: Vec<crate::aplicacao::Membro>,
167
168    /// WIT-typed inter-Servico contracts. Each `:de` and `:para`
169    /// must reference a name in `:membros`.
170    #[serde(default)]
171    pub contratos: Vec<crate::aplicacao::WitContract>,
172
173    /// Mesh-level policies (timeout, retries, circuit-breaker, mTLS,
174    /// rate-limit). Apply to every contrato unless overridden per-edge
175    /// in M4.
176    #[serde(default, skip_serializing_if = "Option::is_none")]
177    pub politicas: Option<crate::aplicacao::MeshPolicy>,
178
179    /// Placement strategy across the cluster fleet
180    /// (single-node | replicated | sharded).
181    #[serde(default, skip_serializing_if = "Option::is_none")]
182    pub placement: Option<crate::aplicacao::Placement>,
183
184    /// External entry point — gateway / ingress shape. Optional;
185    /// only for public Aplicacaos.
186    #[serde(default, skip_serializing_if = "Option::is_none")]
187    pub entrada: Option<crate::aplicacao::Entrada>,
188
189    // ── Acao slot (CANTEIRO §7.1-C) ──────────────────────────────────────
190    //
191    // Required when :kind Acao; ignored otherwise (mirrors the M2/
192    // supervisor-tree/M3 slot triads above — a declared-but-foreign `:ci`
193    // is a `LayoutError::CiOnNonAcao` build error, not a silent drop).
194    /// Typed CI run — a repo's CI run as a set of typed nodes + their
195    /// dependency edges. Required for `:kind Acao`; validated (not
196    /// rendered) by the `caixa-actions` renderer via
197    /// `canteiro_types::decompose`. See `caixa-actions`' crate docs for
198    /// the M0 validate-only contract.
199    #[serde(default, skip_serializing_if = "Option::is_none")]
200    pub ci: Option<canteiro_types::CiRun>,
201}
202
203/// Why reading a manifest into a [`Caixa`] failed.
204///
205/// Split from [`ManifestError`] (which reports a *parsed* manifest that is
206/// semantically wrong) because the two answer different questions, and the
207/// distinction is the whole point of this type: `ManifestError` means "your
208/// caixa is wrong", `LeituraError::DialetoEstrangeiro` means "this file is not
209/// a caixa".
210#[derive(Debug, thiserror::Error)]
211pub enum LeituraError {
212    /// The source is not readable as a `(defcaixa …)` package manifest — bad
213    /// syntax, a wrong head symbol, an unknown or mistyped slot.
214    ///
215    /// `#[source]`, not `#[error(transparent)]`. Transparent delegates
216    /// `source()` past the inner error to ITS source, which drops the
217    /// `LispError` off the cause chain — and `feira`'s
218    /// `load_caixa_parse_error_preserves_underlying_lisp_error_on_chain`
219    /// pins that a caller can `downcast_ref::<tatara_lisp::LispError>()`
220    /// through an anyhow context to read the typed payload. That pin caught
221    /// this exact regression when the variant first landed transparent.
222    #[error("{0}")]
223    Leitura(
224        #[source]
225        #[from]
226        tatara_lisp::LispError,
227    ),
228
229    /// The source IS a well-formed `(defcaixa …)` form, but of a different
230    /// declaration than this crate's.
231    ///
232    /// The variant that did not exist before, and whose absence is the defect.
233    /// A `(defcaixa :name "x" :ecosystem :go …)` used to reach the derive's
234    /// `parse_kwargs_strict` and come back as an unknown-keyword rejection —
235    /// byte-identical in shape to a typo in a real manifest. Measured over the
236    /// org checkout on 2026-07-31, that shape is the MAJORITY of the corpus, so
237    /// the confusing error was also the common one.
238    ///
239    /// Carrying the dialect means a consumer can branch on "not mine" without
240    /// re-parsing, and a census can count it. Every user-facing byte-string
241    /// (canonical keyword, one-line description, consuming crate) is a
242    /// projection of [`crate::dialeto::CaixaDialeto`] — the variant stores the
243    /// typed dialect and the `#[error]` template calls
244    /// [`CaixaDialeto::palavra_canonica`] /
245    /// [`CaixaDialeto::descricao`] / [`CaixaDialeto::consumidor`] on it, so
246    /// the three axes cannot silently diverge from the classification. Prior
247    /// to this closure the variant carried each accessor's return value as a
248    /// stored `&'static str` snapshot alongside `dialeto`, and the sole
249    /// constructor at [`Caixa::from_lisp`] filled all four fields — a caller
250    /// could construct `DialetoEstrangeiro { dialeto: Molde,
251    /// palavra_canonica: "defcaixa", … }` and every downstream consumer
252    /// (Display, ad-hoc audit, future JSON serialization) would silently
253    /// disagree with `dialeto.palavra_canonica() == "defmolde"`. The typed
254    /// enum owns the projections; the variant only carries the axis.
255    #[error(
256        "this is a `{palavra}` declaration ({desc}), read by \
257         {cons} — not a caixa-core package manifest. `defcaixa` is the \
258         tatara-lisp package manifest (`:nome :versao :kind :deps …`); the two \
259         are different declarations that shared one keyword until 2026-07-31",
260        palavra = dialeto.palavra_canonica(),
261        desc = dialeto.descricao(),
262        cons = dialeto.consumidor()
263    )]
264    DialetoEstrangeiro {
265        /// Which declaration this actually is. Sole authoritative axis;
266        /// every user-facing projection routes through
267        /// [`crate::dialeto::CaixaDialeto`]'s typed accessors so the four
268        /// axes cannot silently disagree.
269        dialeto: crate::dialeto::CaixaDialeto,
270    },
271
272    /// Not a manifest declaration at all.
273    #[error(transparent)]
274    Dialeto(#[from] crate::dialeto::DialetoError),
275}
276
277impl LeituraError {
278    /// Construct a [`LeituraError::DialetoEstrangeiro`] naming the
279    /// foreign-dialect classification the [`Caixa::from_lisp`] gate
280    /// refused a `(defcaixa …)` source as.
281    ///
282    /// Substrate primitive every foreign-dialect emission on the
283    /// [`Caixa::from_lisp`] classification-gate surface routes through,
284    /// folding the pre-lift uniform three-line
285    /// `Self::DialetoEstrangeiro { dialeto }` one-field struct-literal
286    /// onto one substrate primitive matching the peer
287    /// [`crate::dialeto::DialetoError::cabeca_errada`] (38d5159)
288    /// single-slot inherent-ctor discipline on the sibling
289    /// [`crate::dialeto::DialetoError`] envelope's `{ encontrado: String }`
290    /// axis, and matching the peer `LimitsError::unknown_byte_unit` /
291    /// `LimitsError::unknown_duration_unit` (`limits_codec_unit_only_ctors!`
292    /// — 29fac09) / `ManifestError::code_path_empty` (94dabc8) /
293    /// `BehaviorError::empty_path` (0e33b37) /
294    /// `UpgradeError::duplicate_from` (7e52aec) /
295    /// `AplicacaoError::placement_cluster_duplicate` (92b1c92) single-slot
296    /// inherent-ctor discipline every sibling `{ <field>: <T> }`
297    /// error-envelope variant on caixa-core's error surface now carries.
298    ///
299    /// The one open-coded wire-up site — [`Caixa::from_lisp`]'s
300    /// [`crate::dialeto::CaixaDialeto::is_molde_family`] branch after the
301    /// [`crate::dialeto::classify_form`] classification — opened the
302    /// uniform two-line `Self::DialetoEstrangeiro { dialeto }` block
303    /// against the codec-scoped `dialeto: CaixaDialeto` binding. Routes
304    /// through `LeituraError::dialeto_estrangeiro(dialeto)`, byte-equal
305    /// to the pre-lift struct-literal on the same [`Copy`]-bound
306    /// [`crate::dialeto::CaixaDialeto`] fixture, so any future widening
307    /// of the diagnostic shape (a stored source-file path alongside the
308    /// classified dialect, an authoring-surface caret offset into the
309    /// top-level form, a promotion of the plain `dialeto:` field into a
310    /// richer projection carrying both the typed dialect and a
311    /// `Vec<Suggestion>` neighborhood) lands at exactly one dispatch on
312    /// the substrate primitive rather than re-inlining the struct-literal
313    /// at every foreign-dialect emission on the classification gate.
314    #[must_use]
315    pub fn dialeto_estrangeiro(dialeto: crate::dialeto::CaixaDialeto) -> Self {
316        Self::DialetoEstrangeiro { dialeto }
317    }
318}
319
320/// Substrate-canonical universal-axis per-[`Caixa`] `:licenca` SPDX-shaped
321/// license-expression fallback for the `Option<String>` `:licenca` slot —
322/// the `"MIT"` SPDX identifier every [`caixa-helm`]-rendered
323/// `lareira-<nome>` Helm chart's `README.md` `## License` section folds an
324/// author-omitted (`None`) `:licenca` slot through, extracted as a typed
325/// `pub const` so every substrate-side consumer that resolves "what license
326/// scalar does an author-omitted `:licenca` degrade onto?" reaches for
327/// exactly one substrate-primitive `&'static str`.
328///
329/// The `:licenca` fallback axis has one production consumer today — the
330/// [`caixa-helm`] `build_readme` fold at `caixa-helm/src/lib.rs`'s
331/// `caixa.licenca().unwrap_or(CAIXA_LICENCA_DEFAULT)` `README.md`
332/// `## License` section body — with three sibling caixa-core sites that
333/// cite the `"MIT"` fallback in prose (this crate's [`Caixa::licenca`]
334/// accessor's docstring, [`Self::validate_licenca`]'s docstring, and the
335/// [`ManifestError::LicencaEmpty`] `#[error]` template's user-facing text)
336/// all quoting the exact byte-string a future substrate-side rebrand of the
337/// fallback (a tightening to `"Apache-2.0"` as the substrate absorbs the
338/// wasm-component-model conventions the `wasi:*` WIT worlds already carry,
339/// a per-cluster license-default overlay the M4 CR materializer resolves
340/// per-CR, a promotion to the plain `Option<String>` byte-string into a
341/// richer `SpdxExpression` enum once the SPDX-expression parser lands per
342/// [`Self::validate_licenca`]'s docstring roadmap) would silently split
343/// against — the caixa-helm renderer would emit the new byte, the
344/// docstrings would still cite the prior byte, and every author who reads
345/// the accessor docstring before authoring would file a fresh
346/// `:licenca "MIT"` verbatim rather than defer to the substrate default,
347/// with the drift surfacing at chart-README-audit time far from the
348/// substrate rebrand commit.
349///
350/// Prior to this lift the sole production emitter (`build_readme`) carried
351/// an inline `"MIT"` byte literal at
352/// `caixa-helm/src/lib.rs:1018`'s `.unwrap_or("MIT")` fallback arm — one
353/// occurrence of the same load-bearing per-`Caixa` universal-axis
354/// SPDX-shaped license-expression convention as the four sibling caixa-core
355/// docstring citations, drift-prone by construction ahead of the second
356/// occurrence the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
357/// materializer's per-Aplicacao registry-annotation synthesis (the
358/// [`Self::validate_licenca`] roadmap already names the `Chart.yaml
359/// annotations["artifacthub.io/license"]` axis every registry-facing chart
360/// carries as the second consumer) will surface.
361///
362/// The `"MIT"` value pins the canonical CAIXA-SDLC §I license scaffold
363/// every `feira init`-emitted [`Self::template`] carries verbatim
364/// (`:licenca "MIT"`) and every substrate-side renderer fixture
365/// ([`caixa-helm`]'s `sample_caixa`, [`caixa-flux`]'s renderer fixtures,
366/// [`caixa-mesh`]'s renderer fixtures) seeds by construction, matching the
367/// pleme-io repo `LICENSE` header this workspace itself ships under. The
368/// alternatives an author declares explicitly (compound SPDX expressions
369/// like `"Apache-2.0 OR MIT"`, permissive-family peers like
370/// `"Apache-2.0"` / `"BSD-3-Clause"`, license-with-exception forms like
371/// `"Apache-2.0 WITH LLVM-exception"`) express deliberate license postures
372/// an author declares explicitly, never a posture an author-omitted slot
373/// should silently assume by default.
374///
375/// Lifted as a typed `pub const` so the substrate's chosen license
376/// fallback has exactly one source of truth on the `:licenca` fallback
377/// axis, on the same substrate-primitive lift discipline the peer
378/// per-`Caixa` load-bearing-scalar constants
379/// ([`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`],
380/// [`crate::version::DEFAULT_GIT_REMOTE`],
381/// [`crate::version::DEFAULT_PLEME_GIT_ORG`]) already carry on the sibling
382/// per-`Caixa` universal-axis publish-side convention surface, and the
383/// same discipline the sibling M2 per-supervisor default set carries
384/// end-to-end ([`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`],
385/// [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`],
386/// [`crate::supervisor::SUPERVISOR_RESTART_WINDOW_DEFAULT`],
387/// [`crate::supervisor::SUPERVISOR_CHILD_RESTART_DEFAULT`]) and the M3
388/// per-`:placement` default set already carries
389/// ([`crate::aplicacao::PLACEMENT_ESTRATEGIA_DEFAULT`]) on the paired
390/// M2 / M3 typed-slot-default axes. First typed default on the outer
391/// top-level [`Caixa`] universal-axis surface to converge onto the
392/// substrate-primitive-lift discipline the M2 / M3 typed-slot families
393/// already carry.
394pub const CAIXA_LICENCA_DEFAULT: &str = "MIT";
395
396impl Caixa {
397    /// Parse a `caixa.lisp` source string to a typed `Caixa`.
398    ///
399    /// Classifies the dialect **before** parsing. A `(defcaixa …)` of another
400    /// declaration is [`LeituraError::DialetoEstrangeiro`], naming what it is
401    /// and who reads it, instead of an unknown-keyword rejection that reads as
402    /// "your manifest is broken".
403    ///
404    /// The ordering is load-bearing. Handing a foreign dialect to the derive
405    /// first and interpreting the failure afterwards would mean guessing from
406    /// an error message, and the guess would be wrong for every file whose
407    /// first unknown slot happens to be one both schemas could plausibly carry.
408    pub fn from_lisp(src: &str) -> Result<Self, LeituraError> {
409        use tatara_lisp::domain::TataraDomain;
410        let forms = tatara_lisp::read(src).map_err(LeituraError::Leitura)?;
411        let first = forms.first().ok_or(crate::dialeto::DialetoError::Vazio)?;
412
413        // Route the foreign-dialect rejection gate through the lifted
414        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
415        // typed predicate rather than the pre-lift hand-rolled three-arm
416        // `match { Pacote => {}, Desconhecido => {}, foreign => Err(…) }`
417        // literal — the `defmolde` declaration-family partition (the two-
418        // arity closure of [`crate::dialeto::CaixaDialeto::Molde`] and
419        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two arms
420        // whose sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
421        // projection already collapses onto `"defmolde"` and whose sibling
422        // [`crate::dialeto::CaixaDialeto::consumidor`] projection already
423        // collapses onto `"pleme-doc-gen"`) resolves through one dispatch
424        // on the substrate primitive. `Pacote` (the tatara-lisp package
425        // manifest this derive can parse) and `Desconhecido` (deliberately
426        // falls through to the derive rather than short-circuiting: a
427        // `(defcaixa …)` matching neither schema is most likely a genuine
428        // package manifest with a typo in `:nome`, and the derive's
429        // diagnostic — which names the offending keyword and suggests the
430        // nearest slot — is far better than anything this classifier
431        // could say) both return `false` from `is_molde_family()` and fall
432        // through to the derive. Only the typed dialect flows into the
433        // error — the three user-facing projections (canonical keyword,
434        // description, consumer) are read at Display time through
435        // [`crate::dialeto::CaixaDialeto`]'s own accessors, so the
436        // variant cannot carry a snapshot that drifts from
437        // [`crate::dialeto::CaixaDialeto::palavra_canonica`] /
438        // `descricao` / `consumidor`. A future fifth dialect the
439        // [`crate::dialeto`] module doc's "third dialect" hazard
440        // actualises that belongs to the `defmolde` family lands one
441        // match arm at [`crate::dialeto::CaixaDialeto::is_molde_family`]
442        // and this gate picks up the new arm by construction — the pre-
443        // lift wildcard `foreign =>` was compile-time-anonymous and would
444        // silently absorb any hypothetical fifth `defcaixa`-family arm as
445        // foreign; routing the partition through the typed predicate
446        // closes both drift surfaces.
447        let dialeto = crate::dialeto::classify_form(first)?;
448        if dialeto.is_molde_family() {
449            return Err(LeituraError::dialeto_estrangeiro(dialeto));
450        }
451
452        Self::compile_from_sexp(first).map_err(LeituraError::Leitura)
453    }
454
455    /// Register `Caixa` with the global tatara-lisp domain registry so
456    /// `defcaixa` is dispatchable from any tatara-lisp binary that seeds
457    /// the registry (e.g. `tatara-check`).
458    ///
459    /// Returns the typed [`tatara_lisp::KeywordCollision`] on the second
460    /// (and every subsequent) call in the same process — one keyword,
461    /// one type, per process is a hard invariant of the upstream
462    /// registry, and a caller that hits it must fix its crate graph
463    /// rather than swallowing the error. Peer of the sibling per-crate
464    /// `register()` entry points at `caixa-flake/src/flake.rs`,
465    /// `caixa-fmt/src/lisp_config.rs`, `caixa-lacre/src/lock.rs`,
466    /// `caixa-lint/src/lisp_config.rs`, `caixa-resolver/src/lisp_config.rs`
467    /// — every substrate crate that owns a tatara-lisp keyword now
468    /// propagates the same typed error verbatim, so a downstream binary
469    /// that seeds the registry (`tatara-check`, the future LSP) reaches
470    /// for one shape at every call site.
471    ///
472    /// # Errors
473    ///
474    /// [`tatara_lisp::KeywordCollision`] when a peer type has already
475    /// claimed the `defcaixa` keyword in this process.
476    pub fn register() -> Result<(), tatara_lisp::KeywordCollision> {
477        tatara_lisp::domain::register::<Self>()
478    }
479
480    /// Substrate-canonical per-`Caixa` `:licenca` SPDX-expression scalar
481    /// accessor every consumer of the top-level manifest's license axis
482    /// keys off — returns the author-declared `:licenca` byte-string
483    /// verbatim as an `Option<&str>`, borrowed from the typed slot's own
484    /// `Option<String>` storage. `None` when the slot is absent (the
485    /// canonical "omit to defer to the caixa-helm renderer's `MIT`
486    /// fallback" shape [`Self::validate_licenca`] documents at
487    /// caixa-core/src/manifest.rs:1560; the peer [`caixa-helm`]
488    /// `build_readme` fold at caixa-helm/src/lib.rs:962 reads this
489    /// predicate too, so an authored-but-unset `:licenca` round-trips to
490    /// a rendered `lareira-<nome>` chart's `README.md` `## License`
491    /// section structurally identical to one that omits the slot).
492    ///
493    /// The `:licenca` slot carries the universal-axis SPDX-expression
494    /// license identifier every kind of caixa emits under (CAIXA-SDLC
495    /// §I — the author-facing surface every `defcaixa` form supplies) —
496    /// the typed slot's `Option<String>` accept-set (empty-string
497    /// rejected through [`ManifestError::LicencaEmpty`], SPDX-alphabet-
498    /// invalid rejected through [`ManifestError::LicencaInvalid`]) maps
499    /// onto the `lareira-<nome>` Helm chart's `README.md` `## License`
500    /// section (caixa-helm/src/lib.rs:962) and (through future
501    /// tightening documented at [`Self::validate_licenca`]) the
502    /// Chart.yaml `annotations["artifacthub.io/license"]` axis every
503    /// registry-facing chart carries. Every downstream consumer that
504    /// reads the license byte-string keys off this scalar (the
505    /// [`Self::validate_licenca`] empty-arm + SPDX-shape gate that
506    /// routes through `self.licenca.as_deref()`, the caixa-helm
507    /// `build_readme` `unwrap_or_else(|| "MIT".into())` fold that keys
508    /// the fallback off the `Option::is_none()` arm, every future
509    /// per-`Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
510    /// acknowledges).
511    ///
512    /// Prior to this lift the `.licenca` field was accessed inline at
513    /// two production sites — [`Self::validate_licenca`]'s
514    /// `self.licenca.as_deref()` empty-and-shape gate binding and the
515    /// caixa-helm `build_readme` `caixa.licenca.clone().unwrap_or_else(||
516    /// "MIT".into())` `README.md` `## License` fold — two open-coded
517    /// field-accesses that expressed no compile-time link back to the
518    /// typed slot. A future extension of the `:licenca` axis to a
519    /// richer author surface — a per-`:licenca` structured SPDX
520    /// expression parser + license-id allowlist (the future tightening
521    /// [`Self::validate_licenca`]'s docstring acknowledges), a
522    /// per-cluster license-default overlay the M4 CR materializer
523    /// resolves per-CR (the "cluster policy pins `Apache-2.0` for every
524    /// unlisted caixa" arm), a promotion of the plain
525    /// `Option<String>` byte-string to a richer `SpdxExpression` enum
526    /// once the SPDX-expression parser lands — would have had to be
527    /// threaded through both open-coded copies in lockstep or the
528    /// validate gate and the caixa-helm emit path would silently
529    /// disagree on which license a given [`Caixa`] resolves to (an
530    /// author's `:licenca "MIT OR Apache-2.0"` would satisfy validate
531    /// while the emit path silently rendered a stale `MIT` fallback,
532    /// or vice versa). Lifting the resolution to a typed method on the
533    /// substrate primitive means every downstream consumer of the
534    /// caixa's per-`Caixa` license surface reaches for exactly one
535    /// typed dispatch — the resolver's accept-set migrates as a unit
536    /// on any future axis addition.
537    ///
538    /// First `Option<&str>`-return top-level [`Caixa`] scalar accessor —
539    /// opens the "outer [`Caixa`] `Option<&str>` scalar" projection
540    /// pattern the sibling per-`Caixa` `:descricao` / `:repositorio` /
541    /// `:edicao` future lifts fold on. Same "one typed dispatch on the
542    /// substrate primitive, thin projections at each consumer"
543    /// discipline the peer per-`:placement` [`crate::aplicacao::Placement::shard_key`]
544    /// (7cd2a28) / [`crate::aplicacao::Placement::affinity`] (74ec2d3)
545    /// / per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
546    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
547    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
548    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
549    /// typed-slot atom axes, extended here to the outer top-level
550    /// `Caixa` universal-axis surface. Named `licenca()` to match the
551    /// storage field's name; the accessor's identity maps onto the
552    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
553    /// carries.
554    #[must_use]
555    pub const fn licenca(&self) -> Option<&str> {
556        match &self.licenca {
557            Some(s) => Some(s.as_str()),
558            None => None,
559        }
560    }
561
562    /// Substrate-canonical per-`Caixa` `:repositorio` git-repo-URL scalar
563    /// accessor every consumer of the top-level manifest's homepage /
564    /// source-of-truth axis keys off — returns the author-declared
565    /// `:repositorio` byte-string verbatim as an `Option<&str>`, borrowed
566    /// from the typed slot's own `Option<String>` storage. `None` when
567    /// the slot is absent (the canonical "omit to defer to the renderer's
568    /// per-target placeholder" shape — [`caixa-helm`]'s `ChartYaml.home`
569    /// carries the `Option<String>` through verbatim so an author-omitted
570    /// `:repositorio` renders a `Chart.yaml` without a `home:` field
571    /// (`skip_serializing_if = "Option::is_none"`), while [`caixa-flux`]'s
572    /// `ClusterBundleOpts::for_caixa` folds the omitted slot through a
573    /// `format!("https://github.com/{DEFAULT_PLEME_GIT_ORG}/{nome}")`
574    /// fallback derived from `caixa.nome`).
575    ///
576    /// The `:repositorio` slot carries the universal-axis git-repo-URL
577    /// homepage identifier every kind of caixa emits under (CAIXA-SDLC
578    /// §I — the author-facing surface every `defcaixa` form supplies) —
579    /// the typed slot's `Option<String>` accept-set (empty-string
580    /// rejected through [`ManifestError::RepositorioEmpty`], git-repo-URL-
581    /// shape-invalid rejected through [`ManifestError::RepositorioInvalid`]
582    /// past the shared [`crate::render::is_git_repo_url`] predicate the
583    /// peer per-`:deps :fonte :repo` axis also routes through) maps onto
584    /// four load-bearing downstream consumers:
585    ///
586    ///   - [`Self::validate_repositorio`]'s empty-arm + shape-predicate
587    ///     gate binding at caixa-core/src/manifest.rs:1456 — the
588    ///     universal-axis identity gate wired at caixa-build time.
589    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.home` fold at
590    ///     caixa-helm/src/lib.rs:840 — the rendered `lareira-<nome>`
591    ///     Helm chart's `Chart.yaml` `home:` field, which every registry
592    ///     that ingests the chart (ArtifactHub, chartmuseum,
593    ///     `helm search repo`) surfaces as the chart's canonical source-
594    ///     of-truth link.
595    ///   - [`caixa-helm`]'s `build_readme` `## Source` fold at
596    ///     caixa-helm/src/lib.rs:957 — the rendered `lareira-<nome>`
597    ///     chart's `README.md` header link back to the source repo,
598    ///     which every author who inspects the rendered chart bundle
599    ///     lands at.
600    ///   - [`caixa-flux`]'s `ClusterBundleOpts::for_caixa`
601    ///     `GitRepository.spec.url` fold at caixa-flux/src/lib.rs:2006 —
602    ///     the rendered `GitRepository` CR's `spec.url` field, which
603    ///     FluxCD's `source-controller` polls to reconcile the caixa's
604    ///     manifest bundle from git.
605    ///
606    /// Prior to this lift the `.repositorio` field was accessed inline
607    /// at four production sites — [`Self::validate_repositorio`]'s
608    /// `self.repositorio.as_deref()` empty-and-shape gate binding, the
609    /// caixa-helm `build_chart_yaml` `caixa.repositorio.clone()`
610    /// `Chart.yaml` `home:` field fold, the caixa-helm `build_readme`
611    /// `caixa.repositorio.clone().unwrap_or_else(|| caixa.nome.clone())`
612    /// `README.md` `## Source` fold, and the caixa-flux
613    /// `ClusterBundleOpts::for_caixa`
614    /// `caixa.repositorio.clone().unwrap_or_else(|| format!(...))`
615    /// `GitRepository.spec.url` fold — four open-coded field-accesses
616    /// that expressed no compile-time link back to the typed slot. A
617    /// future extension of the `:repositorio` axis to a richer author
618    /// surface — a per-`:repositorio` structured
619    /// [`crate::render::GitRepoUrl`]-shaped scheme+host+path parse
620    /// (the future tightening [`Self::validate_repositorio`]'s
621    /// docstring anticipates alongside the peer per-`:deps :fonte
622    /// :repo` axis), a per-cluster repo-mirror overlay the M4 CR
623    /// materializer resolves per-CR (the "cluster policy rewrites
624    /// `github:pleme-io/...` to `git.internal/mirror/pleme-io/...`"
625    /// arm the private-registry story acknowledges), a promotion of
626    /// the plain `Option<String>` byte-string to a richer
627    /// `RepoUrl` enum discriminated on scheme — would have had to be
628    /// threaded through all four open-coded copies in lockstep or the
629    /// validate gate and the three emit paths would silently disagree
630    /// on which URL a given [`Caixa`] resolves to (an author's
631    /// `:repositorio "github:pleme-io/checkout"` would satisfy validate
632    /// while one of the emit paths silently rendered a stale URL, or
633    /// vice versa). Lifting the resolution to a typed method on the
634    /// substrate primitive means every downstream consumer of the
635    /// caixa's per-`Caixa` repo-URL surface reaches for exactly one
636    /// typed dispatch — the resolver's accept-set migrates as a unit on
637    /// any future axis addition.
638    ///
639    /// Second outer top-level [`Caixa`] `Option<&str>`-return scalar
640    /// accessor — sibling of [`Self::licenca`] (6d5bc28), the accessor
641    /// that opened the "outer [`Caixa`] `Option<&str>` scalar"
642    /// projection pattern this lift folds on. Same "one typed dispatch
643    /// on the substrate primitive, thin projections at each consumer"
644    /// discipline the peer per-`:placement`
645    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
646    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
647    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
648    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
649    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
650    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
651    /// typed-slot atom axes, extended here to the second outer top-level
652    /// `Caixa` universal-axis surface. Named `repositorio()` to match
653    /// the storage field's name; the accessor's identity maps onto the
654    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
655    /// carries.
656    #[must_use]
657    pub const fn repositorio(&self) -> Option<&str> {
658        match &self.repositorio {
659            Some(s) => Some(s.as_str()),
660            None => None,
661        }
662    }
663
664    /// Substrate-canonical per-`Caixa` **resolved-git-repo-URL** composer —
665    /// returns the caixa's canonical git-source-of-truth URL as an owned
666    /// [`String`], author-declared `:repositorio` byte-string verbatim on
667    /// the `Some` arm and the substrate's canonical pleme-org github URL
668    /// fallback ([`crate::DEFAULT_PLEME_GIT_ORG`] and [`Self::nome`]
669    /// interpolated into `https://github.com/<org>/<nome>`) on the
670    /// `None` arm. Every substrate-side consumer that resolves
671    /// "which git URL does this caixa's source live at?" reaches for
672    /// exactly one typed dispatch on the substrate primitive — the raw
673    /// `caixa.repositorio().map(str::to_owned).unwrap_or_else(|| format!(
674    /// "https://github.com/{org}/{nome}", org = DEFAULT_PLEME_GIT_ORG,
675    /// nome = caixa.nome()))` open-coded composition every prior caller
676    /// re-derived collapses onto one canonical arm.
677    ///
678    /// Distinct from [`Self::repositorio`] (`Option<&str>`, exposes the
679    /// author-omitted / author-declared partition to the caller) — this
680    /// accessor is the **resolved** URL surface, folding the fallback in
681    /// at the substrate-primitive boundary. Every consumer that keys off
682    /// the `Option::is_none()` discriminator (a [`Chart.yaml`] `home:`
683    /// field emit that must omit the field entirely on an author-omitted
684    /// `:repositorio`, per the [`Self::repositorio`] docstring's
685    /// documented four-consumer list) reaches through the raw
686    /// [`Self::repositorio`] `Option<&str>` accessor by construction — the
687    /// resolved-URL composer sits alongside it as the second projection
688    /// on the same underlying `:repositorio` slot rather than replacing
689    /// the raw accessor.
690    ///
691    /// The fallback branch is the exact byte-image of the prior inline
692    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url` composer at
693    /// caixa-flux/src/lib.rs:2080 — pinned by the sibling caixa-flux
694    /// byte-parity test
695    /// `cluster_bundle_opts_for_caixa_git_url_routes_through_canonical_git_url_accessor`
696    /// against a future implementation of this method that reordered the
697    /// `format!` template arguments, migrated the `<org>` segment to a
698    /// different constant (the [`crate::DEFAULT_PLEME_GIT_ORG`] axis a
699    /// future substrate-side git-org migration may split off), or
700    /// silently absorbed the empty-string arm (a hypothetical
701    /// `Some("") → fallback` collapse the raw [`Self::repositorio`]
702    /// accessor's docstring explicitly rejects on the sibling raw
703    /// accessor).
704    ///
705    /// Peer of the sibling per-`&Caixa`-axis composed helpers
706    /// [`caixa-flux::cluster_bundle_for_caixa`] (06d52d7) on the sibling
707    /// substrate-side renderer surface — same "close the composed
708    /// substrate-primitive at one canonical arm on the single-`&Caixa`
709    /// dispatch, converge every prior open-coded caller onto the arm"
710    /// discipline extended onto the resolved-git-URL projection of the
711    /// per-`Caixa` `:repositorio` axis. Owns per-call [`String`]
712    /// allocation on both arms (the `Some` arm's `str::to_owned` and the
713    /// `None` arm's `format!`) — the by-value return matches every
714    /// downstream consumer's field-fill shape (the caixa-flux
715    /// `ClusterBundleOpts::git_url: String` field, every future
716    /// `Chart.yaml` `home:` fold's `Option<String>` field-fill on the
717    /// `Some` arm).
718    #[must_use]
719    pub fn canonical_git_url(&self) -> String {
720        self.repositorio().map_or_else(
721            || {
722                format!(
723                    "https://github.com/{org}/{nome}",
724                    org = crate::DEFAULT_PLEME_GIT_ORG,
725                    nome = self.nome(),
726                )
727            },
728            str::to_owned,
729        )
730    }
731
732    /// Substrate-canonical per-`Caixa` **resolved-publish-tag** composer —
733    /// returns the caixa's canonical Zig-style git-publish-tag as an owned
734    /// [`String`], derived by concatenating
735    /// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] with the typed
736    /// [`Self::versao`] byte-string on a single `format!` template.
737    /// Every substrate-side consumer that resolves "which git tag does this
738    /// caixa publish under?" reaches for exactly one typed dispatch on the
739    /// substrate primitive — the raw `format!("{prefix}{versao}", prefix =
740    /// caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao = caixa.versao())`
741    /// open-coded composition every prior caller re-derived collapses onto
742    /// one canonical arm.
743    ///
744    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
745    /// git-URL composer on the paired per-`Caixa` git-remote axis — same
746    /// "close the composed substrate-primitive at one canonical arm on the
747    /// single-`&Caixa` dispatch, converge every prior open-coded caller
748    /// onto the arm" discipline extended from the resolved-URL projection
749    /// of the per-`Caixa` `:repositorio` axis onto the resolved-tag
750    /// projection of the per-`Caixa` `:versao` axis. The two accessors
751    /// jointly close the pair of scalars every `FluxCD` `GitRepository` CR
752    /// keys off (`spec.url` via [`Self::canonical_git_url`],
753    /// `spec.ref.tag` via [`Self::publish_tag`]) at the substrate primitive
754    /// — a downstream consumer that reaches through both accessors reads
755    /// the complete published-git-identity of a caixa through two typed
756    /// dispatches, not four open-coded field accesses.
757    ///
758    /// The reader-side (`caixa-flux::cluster_bundle` /
759    /// `ClusterBundleOpts::for_caixa`'s `git_ref` field, every future
760    /// per-cluster snapshot bundle emitter, the future M4
761    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's tag-carrier
762    /// slot on the tatara `Process` intent) always resolves the tag under
763    /// the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] prefix — this
764    /// method encodes that reader-side convention. The writer-side
765    /// (`caixa-feira`'s `feira publish` `--prefix` clap flag) allows the
766    /// operator to override the prefix at publish time; the two surfaces
767    /// intentionally sit on the "canonical default + operator override"
768    /// pair the sibling [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] constant's
769    /// own docstring documents — a `feira publish --prefix release/`
770    /// override is the operator's explicit opt-out from the substrate
771    /// default, not a supported drift axis.
772    ///
773    /// The composition body is the exact byte-image of the prior inline
774    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_ref` composer at
775    /// caixa-flux/src/lib.rs:2105 — pinned by the sibling caixa-flux
776    /// byte-parity test
777    /// `cluster_bundle_opts_for_caixa_git_ref_routes_through_publish_tag_accessor`
778    /// against a future implementation of this method that reordered the
779    /// `format!` template arguments, migrated the `<prefix>` segment to a
780    /// different constant (the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] axis
781    /// a future Zig-style-tag rebrand may split off — the constant's own
782    /// docstring anticipates a substrate-side move to `release/<versao>`
783    /// or bare `<versao>` shapes once a sibling forge convention adopts a
784    /// slash-namespaced or bare-scalar form), interposed a canonicalization
785    /// pass on the `:versao` axis (a SemVer-2 build-metadata strip an OCI-
786    /// tag normalizer might apply once the M4 registry-alignment slot
787    /// lands), or silently absorbed an empty `:versao` arm (which cannot
788    /// occur past the [`Self::validate_versao`] gate but which a
789    /// hypothetical bypass on the accessor path must not silently paper
790    /// over).
791    ///
792    /// Owns per-call [`String`] allocation via the single `format!`
793    /// invocation — the by-value return matches every downstream
794    /// consumer's field-fill shape (the caixa-flux `GitRefSpec::Tag(String)`
795    /// variant's owned payload, every future `intent.aplicacao.tag: String`
796    /// field-fill on the M4 CR materializer's tag-carrier slot).
797    #[must_use]
798    pub fn publish_tag(&self) -> String {
799        format!(
800            "{prefix}{versao}",
801            prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
802            versao = self.versao(),
803        )
804    }
805
806    /// Substrate-canonical per-`Caixa` **resolved-Helm-chart-name** composer
807    /// — returns the caixa's canonical `lareira-<nome>` per-Servico Helm
808    /// chart identity as an owned [`String`], derived by dispatching through
809    /// the substrate-canonical [`crate::lareira_chart_name`] helper against
810    /// the typed [`Self::nome`] byte-string. Every substrate-side consumer
811    /// that resolves "which Helm chart identity does this caixa render
812    /// under?" reaches for exactly one typed dispatch on the substrate
813    /// primitive — the raw `caixa_core::lareira_chart_name(caixa.nome())`
814    /// two-step compose every prior caller re-derived collapses onto one
815    /// canonical arm on the single-`&Caixa` dispatch.
816    ///
817    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
818    /// git-URL composer + [`Self::publish_tag`] (07e05b8) resolved-publish-
819    /// tag composer on the paired per-`Caixa` published-artifact-identity
820    /// axis — same "close the composed substrate-primitive at one canonical
821    /// arm on the single-`&Caixa` dispatch, converge every prior open-coded
822    /// caller onto the arm" discipline extended from the resolved-URL /
823    /// resolved-tag projections of the `:repositorio` / `:versao` axes onto
824    /// the resolved-chart-name projection of the `:nome` axis. The three
825    /// accessors jointly close the triple of scalars every per-Servico
826    /// deploy artifact keys off (git source URL via
827    /// [`Self::canonical_git_url`], git source tag via
828    /// [`Self::publish_tag`], per-Servico Helm chart identity via
829    /// [`Self::lareira_chart_name`]) at the substrate primitive — a
830    /// downstream consumer that reaches through all three reads the
831    /// complete deploy-artifact identity of a caixa through three typed
832    /// dispatches, not six open-coded compositions across three renderer
833    /// crates.
834    ///
835    /// The reader-side (three production sites at the time of the lift —
836    /// [`caixa-helm::render_chart_for_servico_with`]'s `ChartDir.name`
837    /// composer at caixa-helm/src/lib.rs:778, the peer
838    /// [`caixa-flux::cluster_bundle`]'s per-CR `chart_name` binding at
839    /// caixa-flux/src/lib.rs:2219, and
840    /// [`caixa-tatara::process_for_aplicacao`]'s `release_name`
841    /// composer at caixa-tatara/src/lib.rs:227, plus every future
842    /// per-Servico OCI publish emitter the CAIXA-SDLC §II
843    /// `caixa-publish.yml` reusable workflow's `skopeo push` step keys
844    /// off, the future per-cluster snapshot bundle emitter, the future
845    /// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
846    /// per-member chart-carrier slot on the tatara `Process` intent) —
847    /// always resolves the chart name under the canonical
848    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] prefix; this method encodes
849    /// that reader-side convention. The joint-length invariant the peer
850    /// [`Self::validate_nome_chart_name_budget`] gate enforces at
851    /// caixa-build time (author-declared `:nome` + fixed prefix ≤
852    /// [`crate::DNS_1123_LABEL_MAX_LEN`]) is verified on the input to
853    /// this composer by construction, so the produced `lareira-<nome>`
854    /// string is a valid Helm chart-name segment on every accept-set
855    /// input.
856    ///
857    /// The composition body is the exact byte-image of the prior inline
858    /// `caixa_core::lareira_chart_name(caixa.nome())` two-step form every
859    /// prior caller re-derived — pinned by the sibling caixa-helm /
860    /// caixa-flux / caixa-tatara byte-parity tests
861    /// `<crate>_lareira_chart_name_routes_through_caixa_accessor` against
862    /// a future implementation of this method that reordered the
863    /// composition arguments, migrated the `<prefix>` segment to a
864    /// different constant (the [`crate::LAREIRA_CHART_NAME_PREFIX`] axis a
865    /// future substrate-side chart-family rebrand may split off — the
866    /// constant's own docstring anticipates a substrate-side move once
867    /// the `lareira-` scoping intent outlives the family it names),
868    /// interposed a canonicalization pass on the `:nome` axis (a per-
869    /// registry namespace-qualification an M4 CR materializer might apply
870    /// per-CR — the "`pleme-io/checkout` vs `partner-org/checkout`
871    /// collision" arm the multi-tenant-registry story acknowledges), or
872    /// silently absorbed an empty `:nome` arm (which cannot occur past
873    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
874    /// on the accessor path must not silently paper over).
875    ///
876    /// Owns per-call [`String`] allocation via the single
877    /// [`crate::lareira_chart_name`] `format!` invocation — the by-value
878    /// return matches every downstream consumer's field-fill shape (the
879    /// caixa-helm `ChartDir.name: String` field, the caixa-flux per-CR
880    /// `chart_name: String` binding, the caixa-tatara
881    /// `AplicacaoIntent.release_name: Option<String>` field-fill on the
882    /// `Some` arm).
883    #[must_use]
884    pub fn lareira_chart_name(&self) -> String {
885        crate::lareira_chart_name(self.nome())
886    }
887
888    /// Substrate-canonical per-`Caixa` **resolved-OCI-chart-ref** composer
889    /// — returns the caixa's canonical `oci://<registry>/lareira-<nome>`
890    /// per-Servico Helm chart OCI artifact reference as an owned
891    /// [`String`], derived by dispatching through the substrate-canonical
892    /// [`crate::oci_chart_ref`] helper (which itself composes
893    /// [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied `registry` +
894    /// [`crate::lareira_chart_name`]-of-[`Self::nome`]) against the
895    /// caller-supplied `registry` and the typed [`Self::nome`] byte-string.
896    /// Every substrate-side consumer that resolves "which OCI chart
897    /// artifact does this caixa publish under, in this registry?" reaches
898    /// for exactly one typed dispatch on the substrate primitive — the raw
899    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step compose
900    /// every prior caller re-derived collapses onto one canonical arm on
901    /// the single-`(&Caixa, &str)` dispatch.
902    ///
903    /// Fourth member of the paired per-`Caixa` published-artifact-identity
904    /// axis alongside [`Self::canonical_git_url`] (124f864) /
905    /// [`Self::publish_tag`] (07e05b8) / [`Self::lareira_chart_name`]
906    /// (a8f0bee) — same "close the composed substrate-primitive at one
907    /// canonical arm on the single-`&Caixa` dispatch, converge every
908    /// prior open-coded caller onto the arm" discipline extended from the
909    /// resolved-URL / resolved-tag / resolved-chart-name projections of
910    /// the `:repositorio` / `:versao` / `:nome` axes onto the resolved-
911    /// OCI-ref projection over the paired `(registry, :nome)` inputs. The
912    /// four accessors jointly close the per-`Caixa` published-artifact-
913    /// identity surface every downstream consumer of a caixa's published
914    /// deploy artifacts keys off (git source URL via
915    /// [`Self::canonical_git_url`], git source tag via
916    /// [`Self::publish_tag`], per-Servico Helm chart identity via
917    /// [`Self::lareira_chart_name`], per-registry OCI chart artifact
918    /// reference via [`Self::oci_chart_ref`]) at the substrate primitive
919    /// — a downstream consumer that reaches through all four reads the
920    /// complete deploy-artifact identity of a caixa through four typed
921    /// dispatches, not eight open-coded compositions across four renderer
922    /// crates. The unique-signature dispatch (`(&Caixa, &str)` on this
923    /// method vs. `&Caixa` on the sibling three) reflects the extra input
924    /// axis this composer folds in: unlike the git-URL / git-tag / chart-
925    /// name axes (each derived purely from a `&Caixa`), the OCI-ref axis
926    /// pairs the caixa's per-`:nome` chart identity with the caller-
927    /// supplied per-registry authority segment, so the accessor threads
928    /// the registry byte-string through as a positional `&str`.
929    ///
930    /// The reader-side (one production site at the time of the lift —
931    /// [`caixa-tatara::process_for_aplicacao`]'s `derive_chart_ref` helper
932    /// at caixa-tatara/src/lib.rs:333 that composes the emitted
933    /// `AplicacaoIntent.chart_ref` scalar the tatara-reconciler feeds into
934    /// `helm install`, plus every future per-Servico OCI publish emitter
935    /// the CAIXA-SDLC §II `caixa-publish.yml` reusable workflow's
936    /// `skopeo push` step keys off, the future per-cluster snapshot bundle
937    /// emitter's per-CR `oci://…` field-fill on the M4 registry-alignment
938    /// slot, the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
939    /// materializer's per-member `chart_ref` slot on the tatara `Process`
940    /// intent, the `FluxCD` `HelmRelease` `spec.chart.spec.chart` field-fill
941    /// on the OCI-source path an M4 per-cluster registry-rewrite overlay
942    /// applies per-CR) — always resolves the OCI ref under the canonical
943    /// [`crate::OCI_SCHEME_PREFIX`] scheme prefix + the canonical
944    /// [`Self::lareira_chart_name`] chart-name segment; this method
945    /// encodes that reader-side convention.
946    ///
947    /// The composition body is the exact byte-image of the prior inline
948    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step form
949    /// every prior caller re-derived — pinned by the sibling caixa-tatara
950    /// byte-parity test
951    /// `derive_chart_ref_routes_through_caixa_oci_chart_ref_accessor`
952    /// against a future implementation of this method that reordered the
953    /// composition arguments, migrated the `<scheme>` segment to a
954    /// different constant (the [`crate::OCI_SCHEME_PREFIX`] axis a future
955    /// substrate-side registry-protocol rebrand may split off — the
956    /// constant's own docstring anticipates a substrate-side move once
957    /// Helm 3 / `FluxCD` introduce a successor scheme past `oci://`),
958    /// migrated the `<chart>` segment off the paired
959    /// [`crate::lareira_chart_name`] composer (a per-registry
960    /// namespace-qualification an M4 CR materializer might apply per-CR),
961    /// interposed a canonicalization pass on the `registry` axis (an OCI-
962    /// authority normalization once the M4 registry-alignment slot lands),
963    /// or silently absorbed an empty `:nome` arm (which cannot occur past
964    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
965    /// on the accessor path must not silently paper over).
966    ///
967    /// Owns per-call [`String`] allocation via the single
968    /// [`crate::oci_chart_ref`] `format!` invocation — the by-value return
969    /// matches every downstream consumer's field-fill shape (the caixa-
970    /// tatara `AplicacaoIntent.chart_ref: String` field-fill, every
971    /// future `intent.aplicacao.chart_ref: String` field-fill on the M4
972    /// CR materializer's chart-ref-carrier slot, every future
973    /// `HelmRelease.spec.chart.spec.chart: String` field-fill on the OCI-
974    /// source path).
975    #[must_use]
976    pub fn oci_chart_ref(&self, registry: &str) -> String {
977        crate::oci_chart_ref(registry, self.nome())
978    }
979
980    /// Substrate-canonical per-`Caixa` `:descricao` free-form-prose
981    /// chart-description scalar accessor every consumer of the top-level
982    /// manifest's Chart.yaml `description:` axis keys off — returns the
983    /// author-declared `:descricao` byte-string verbatim as an
984    /// `Option<&str>`, borrowed from the typed slot's own
985    /// `Option<String>` storage. `None` when the slot is absent (the
986    /// canonical "omit to defer to the per-renderer `caixa.nome`-derived
987    /// fallback" shape — [`caixa-helm`]'s `build_chart_yaml` folds the
988    /// omitted slot through a `format!("Generated chart for caixa Servico
989    /// {}", caixa.nome)` fallback, [`caixa-helm`]'s `build_readme` folds
990    /// it through a `format!("caixa Servico {}", caixa.nome)` fallback,
991    /// and [`caixa-feira`]'s `render_flake` folds it through a
992    /// `format!("caixa {}", c.nome)` `flake.nix` `description = ""`
993    /// fallback — each derived from `caixa.nome` on the null-carrier arm).
994    ///
995    /// The `:descricao` slot carries the universal-axis free-form-prose
996    /// chart-description identifier every kind of caixa emits under
997    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa` form
998    /// supplies) — the typed slot's `Option<String>` accept-set
999    /// (empty-string rejected through [`ManifestError::DescricaoEmpty`],
1000    /// chart-description-shape-invalid rejected through
1001    /// [`ManifestError::DescricaoInvalid`] past the shared
1002    /// [`crate::render::is_chart_description_shape`] predicate the peer
1003    /// per-`Caixa` `:descricao` axis also routes through) maps onto four
1004    /// load-bearing downstream consumers:
1005    ///
1006    ///   - [`Self::validate_descricao`]'s empty-arm + shape-predicate
1007    ///     gate binding — the universal-axis identity gate wired at
1008    ///     caixa-build time.
1009    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.description`
1010    ///     `Chart.yaml` field fold — the rendered `lareira-<nome>` Helm
1011    ///     chart's `Chart.yaml` `description:` field, which
1012    ///     `apiVersion: v2` charts require non-empty (`helm lint` fires
1013    ///     `WARNING [chart.metadata.description]: description is required`
1014    ///     when absent) and which every registry that ingests the chart
1015    ///     (ArtifactHub, chartmuseum, `helm search repo`) surfaces as the
1016    ///     chart's canonical one-line prose descriptor.
1017    ///   - [`caixa-helm`]'s `build_readme` chart-`README.md` header fold
1018    ///     — the rendered `lareira-<nome>` chart's `README.md` prose
1019    ///     header directly beneath the `# <chart-name>` title, which
1020    ///     every author who inspects the rendered chart bundle lands at.
1021    ///   - [`caixa-feira`]'s `render_flake` `flake.nix` `description = ""`
1022    ///     top-level fold — the emitted `flake.nix`'s `description`
1023    ///     field, which every Nix consumer (`nix flake show`,
1024    ///     `nix flake metadata`, downstream flake-registry ingestors)
1025    ///     surfaces as the flake's canonical descriptor.
1026    ///
1027    /// Prior to this lift the `.descricao` field was accessed inline at
1028    /// four production sites — [`Self::validate_descricao`]'s
1029    /// `self.descricao.as_deref()` empty-and-shape gate binding, the
1030    /// caixa-helm `build_chart_yaml`
1031    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
1032    /// `Chart.yaml` `description:` fold, the caixa-helm `build_readme`
1033    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
1034    /// `README.md` header fold, and the caixa-feira `render_flake`
1035    /// `c.descricao.clone().unwrap_or_else(|| format!(...))` `flake.nix`
1036    /// `description = ""` fold — four open-coded field-accesses that
1037    /// expressed no compile-time link back to the typed slot. A future
1038    /// extension of the `:descricao` axis to a richer author surface —
1039    /// a per-`:descricao` locale-tagged multi-language descriptor map
1040    /// (the "one caixa, N language-tagged prose descriptions" arm
1041    /// author-tooling internationalization anticipates), a
1042    /// per-registry-target length-and-shape overlay the M4 CR
1043    /// materializer resolves per-CR (the "ArtifactHub caps description
1044    /// at 512 bytes but the internal registry caps at 256" arm), a
1045    /// promotion of the plain `Option<String>` byte-string to a richer
1046    /// `ChartDescription` newtype guaranteeing the
1047    /// `is_chart_description_shape` predicate at the type level — would
1048    /// have had to be threaded through all four open-coded copies in
1049    /// lockstep or the validate gate and the three emit paths would
1050    /// silently disagree on which prose string a given [`Caixa`]
1051    /// resolves to (an author's
1052    /// `:descricao "Checkout flow orchestration."` would satisfy
1053    /// validate while one of the emit paths silently rendered a stale
1054    /// `caixa.nome`-derived fallback, or vice versa). Lifting the
1055    /// resolution to a typed method on the substrate primitive means
1056    /// every downstream consumer of the caixa's per-`Caixa`
1057    /// chart-description surface reaches for exactly one typed dispatch
1058    /// — the resolver's accept-set migrates as a unit on any future
1059    /// axis addition.
1060    ///
1061    /// Third outer top-level [`Caixa`] `Option<&str>`-return scalar
1062    /// accessor — sibling of [`Self::licenca`] (6d5bc28) and
1063    /// [`Self::repositorio`] (cc7332d), the accessors that opened the
1064    /// "outer [`Caixa`] `Option<&str>` scalar" projection pattern this
1065    /// lift folds on. Same "one typed dispatch on the substrate
1066    /// primitive, thin projections at each consumer" discipline the
1067    /// peer per-`:placement`
1068    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1069    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1070    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1071    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1072    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1073    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1074    /// typed-slot atom axes, extended here to the third outer top-level
1075    /// `Caixa` universal-axis surface. Named `descricao()` to match the
1076    /// storage field's name; the accessor's identity maps onto the
1077    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1078    /// carries. The one remaining universal `Option<String>` slot
1079    /// (`:edicao`) folds on this pattern next.
1080    #[must_use]
1081    pub const fn descricao(&self) -> Option<&str> {
1082        match &self.descricao {
1083            Some(s) => Some(s.as_str()),
1084            None => None,
1085        }
1086    }
1087
1088    /// Substrate-canonical per-`Caixa` `:edicao` language-edition scalar
1089    /// accessor every consumer of the top-level manifest's tatara-lisp
1090    /// edition-selector axis keys off — returns the author-declared
1091    /// `:edicao` byte-string verbatim as an `Option<&str>`, borrowed from
1092    /// the typed slot's own `Option<String>` storage. `None` when the
1093    /// slot is absent (the canonical "omit the slot to defer to the
1094    /// substrate's default edition" shape every existing
1095    /// [`caixa-resolver`] integration test fixture carries via
1096    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`;
1097    /// the peer [`Self::validate_edicao`] gate is a no-op on the omitted
1098    /// arm by construction, so an author-omitted `:edicao` round-trips
1099    /// to a build without triggering the year-shape predicate).
1100    ///
1101    /// The `:edicao` slot carries the universal-axis 4-digit-ASCII-
1102    /// decimal-year language-edition identifier every kind of caixa
1103    /// emits under (CAIXA-SDLC §I — the author-facing surface every
1104    /// `defcaixa` form supplies) — the typed slot's `Option<String>`
1105    /// accept-set (empty-string rejected through
1106    /// [`ManifestError::EdicaoEmpty`], year-shape-invalid rejected
1107    /// through [`ManifestError::EdicaoInvalid`] past the 4-digit-ASCII-
1108    /// decimal-year predicate [`Self::validate_edicao`] enforces) maps
1109    /// onto one load-bearing downstream consumer today
1110    /// ([`Self::validate_edicao`]'s empty-arm + year-shape-predicate
1111    /// gate binding at caixa-core/src/manifest.rs:1959) plus every
1112    /// future edition-aware substrate consumer the CAIXA-SDLC §I
1113    /// roadmap anticipates (the tatara-lisp compiler's macro-surface
1114    /// selector every edition-aware build step keys off, the future
1115    /// per-edition compatibility-flag overlay the M4 CR materializer
1116    /// resolves per-CR, the peer [`Caixa::template`] canonical
1117    /// `:edicao "2026"` scaffold every `feira init` emits verbatim,
1118    /// and the renderer-side fixtures at `caixa-helm/src/lib.rs:978` /
1119    /// `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208` that
1120    /// carry `edicao: Some("2026".into())` by construction).
1121    ///
1122    /// Prior to this lift the `.edicao` field was accessed inline at
1123    /// one production site — [`Self::validate_edicao`]'s
1124    /// `self.edicao.as_deref()` empty-and-shape gate binding — one
1125    /// open-coded field-access that expressed no compile-time link
1126    /// back to the typed slot. A future extension of the `:edicao`
1127    /// axis to a richer author surface — a per-`:edicao` known-
1128    /// edition allowlist (the future tightening
1129    /// [`Self::validate_edicao`]'s docstring acknowledges past the
1130    /// structural year-shape floor, rejecting year-shaped values that
1131    /// don't name a tatara-lisp edition the substrate actually
1132    /// understands — `"1999"` is year-shaped but no `1999` edition
1133    /// exists), a per-edition compatibility-flag overlay the M4 CR
1134    /// materializer resolves per-CR (the "edition `"2026"` enables
1135    /// macro-surface features the sibling `"2018"` gates behind a
1136    /// feature flag" arm the edition-selector story anticipates), a
1137    /// promotion of the plain `Option<String>` byte-string to a
1138    /// richer `CaixaEdition` enum discriminated on year once a sibling
1139    /// edition to `"2026"` lands — would have had to be threaded
1140    /// through the open-coded copy in lockstep with every future
1141    /// edition-aware consumer, or the validate gate and the future
1142    /// edition-aware consumer path would silently disagree on which
1143    /// edition a given [`Caixa`] resolves to (an author's
1144    /// `:edicao "2026"` would satisfy validate while a future
1145    /// edition-aware consumer silently defaulted to a stale edition,
1146    /// or vice versa). Lifting the resolution to a typed method on
1147    /// the substrate primitive means every downstream consumer of the
1148    /// caixa's per-`Caixa` edition surface reaches for exactly one
1149    /// typed dispatch — the resolver's accept-set migrates as a unit
1150    /// on any future axis addition.
1151    ///
1152    /// Fourth and final outer top-level [`Caixa`] `Option<&str>`-return
1153    /// scalar accessor — sibling of [`Self::licenca`] (6d5bc28),
1154    /// [`Self::repositorio`] (cc7332d), and [`Self::descricao`]
1155    /// (3f16e2f), the accessors that opened the "outer [`Caixa`]
1156    /// `Option<&str>` scalar" projection pattern this lift folds on.
1157    /// Same "one typed dispatch on the substrate primitive, thin
1158    /// projections at each consumer" discipline the peer per-`:placement`
1159    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1160    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1161    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1162    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1163    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1164    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1165    /// typed-slot atom axes, extended here to close the outer top-level
1166    /// `Caixa` universal-axis surface's last unlifted `Option<String>`
1167    /// slot. Named `edicao()` to match the storage field's name; the
1168    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1169    /// vocabulary the slot's docstring already carries.
1170    #[must_use]
1171    pub const fn edicao(&self) -> Option<&str> {
1172        match &self.edicao {
1173            Some(s) => Some(s.as_str()),
1174            None => None,
1175        }
1176    }
1177
1178    /// Substrate-canonical per-`Caixa` `:nome` universal-axis DNS-1123-
1179    /// label caixa-identity scalar accessor every consumer of the top-
1180    /// level manifest's identity axis keys off — returns the author-
1181    /// declared `:nome` byte-string verbatim as an `&str`, borrowed from
1182    /// the typed slot's own `String` storage. Non-optional (`:nome` is
1183    /// a required-axis scalar every `defcaixa` form must supply; the
1184    /// [`Self::from_lisp`] derive rejects an omitted / non-string
1185    /// `:nome` at parse time, so a `Caixa` past parse definitionally
1186    /// carries a non-`None` `:nome`).
1187    ///
1188    /// The `:nome` slot carries the universal-axis DNS-1123-label
1189    /// caixa-identity every kind of caixa emits under (CAIXA-SDLC §I —
1190    /// the primary identity axis every `defcaixa` form supplies
1191    /// alongside `:versao` / `:kind`; the substrate-wide identity every
1192    /// other typed surface that names a caixa reaches through — `:deps`
1193    /// entries, `:membros` entries, `:children` entries, the
1194    /// `lareira-<nome>` Helm chart name every per-Servico renderer
1195    /// derives, the `pleme-program-<nome>` label every per-Aplicacao
1196    /// renderer emits) — the typed slot's `String` accept-set (empty
1197    /// rejected through [`ManifestError::NomeEmpty`], DNS-1123-shape-
1198    /// invalid rejected through [`ManifestError::NomeInvalid`] past
1199    /// the shared [`crate::render::require_valid_dns_1123_label`] gate
1200    /// the peer name axes each land on, joint-length-with-`lareira-`-
1201    /// prefix rejected through
1202    /// [`ManifestError::NomeChartNameBudgetExceeded`] past
1203    /// [`crate::render::is_lareira_chart_name_shape`]) maps onto every
1204    /// load-bearing downstream consumer the substrate carries — the
1205    /// two universal-axis validate gates at caixa-build time
1206    /// ([`Self::validate_nome`] + [`Self::validate_nome_chart_name_budget`]),
1207    /// [`crate::lareira_chart_name`]'s `lareira-<nome>` Helm chart-name
1208    /// derivation every per-Servico renderer keys off, the caixa-helm
1209    /// `Chart.yaml`'s `name:` axis, caixa-flux's `programs.yaml` entry
1210    /// `name:` axis, caixa-mesh's Cilium `CiliumNetworkPolicy` /
1211    /// `HTTPRoute` per-Aplicacao name axes at
1212    /// caixa-mesh/src/lib.rs:{2650, 2797, 2919, 2925},
1213    /// [`crate::pleme_program_selector`] /
1214    /// [`crate::pleme_program_in_aplicacao_selector`] label-selector
1215    /// derivations, and every future substrate renderer that emits an
1216    /// artifact keyed by the caixa's identity.
1217    ///
1218    /// Prior to this lift the `.nome` field was accessed inline at a
1219    /// dozen production sites across `caixa-core` (the two universal-
1220    /// axis validate gates + [`Dep::validate`]-adjacent duplicate
1221    /// tracking), `caixa-helm` (the `lareira_chart_name` fold, the
1222    /// `ChartYaml.name` / `ChartYaml.description` / `Chart.yaml`
1223    /// `keywords` fallback), `caixa-flux` (the `programs.yaml`
1224    /// entry `name:` fold, the `flux_kustomization_source_subtree`
1225    /// per-cluster subpath derivation), and `caixa-mesh` (the
1226    /// `pleme_program_in_aplicacao_selector` label-selector fold, the
1227    /// `cilium_network_policy_name` / `gateway_api_http_route_name`
1228    /// per-CR name derivations, the `LABEL_APLICACAO` labels-map
1229    /// insert) — a dozen open-coded field-accesses that expressed no
1230    /// compile-time link back to the typed slot. A future extension of
1231    /// the `:nome` axis to a richer author surface — a per-`:nome`
1232    /// structured `CaixaIdentity` newtype that carries the joint-
1233    /// length-with-prefix invariant [`Self::validate_nome_chart_name_budget`]
1234    /// enforces at the type level (rather than as a validate-time
1235    /// gate), a per-registry `:nome` namespacing overlay the M4 CR
1236    /// materializer resolves per-CR (the "`pleme-io/checkout` vs
1237    /// `partner-org/checkout` collision" arm the multi-tenant-registry
1238    /// story acknowledges), a promotion of the plain `String` byte-
1239    /// string to a richer `CaixaNome` newtype discriminated on
1240    /// namespace prefix — would have had to be threaded through every
1241    /// open-coded copy in lockstep or the two validate gates and the
1242    /// dozen emit paths would silently disagree on which identity a
1243    /// given [`Caixa`] resolves to (an author's `:nome "checkout"`
1244    /// would satisfy validate while one of the emit paths silently
1245    /// rendered a drifted other identity, or vice versa). Lifting the
1246    /// resolution to a typed method on the substrate primitive means
1247    /// every downstream consumer of the caixa's per-`Caixa` identity
1248    /// surface reaches for exactly one typed dispatch — the resolver's
1249    /// accept-set migrates as a unit on any future axis addition.
1250    ///
1251    /// First outer top-level [`Caixa`] `&str`-return required-scalar
1252    /// accessor — opens the "outer [`Caixa`] `&str` required-scalar"
1253    /// projection pattern the sibling per-`Caixa` `:versao` future lift
1254    /// folds on. Sibling in shape to the peer per-`:membros`
1255    /// [`crate::aplicacao::Membro::nome`] (4a32abf) / per-`:contratos`
1256    /// [`crate::aplicacao::WitContract::source`] /
1257    /// [`crate::aplicacao::WitContract::destination`] (7f0fd43),
1258    /// [`crate::aplicacao::WitContract::world_ref`] (0804823),
1259    /// [`crate::aplicacao::Membro::versao_requirement`] (a40b0e3),
1260    /// [`crate::aplicacao::Entrada::destination`] (6db982c),
1261    /// [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062),
1262    /// per-sub-struct required-axis accessors carry on the sibling M3
1263    /// mesh-slot-atom scalar-value axes, extended here to open the
1264    /// outer top-level [`Caixa`] `&str`-return required-scalar surface.
1265    /// Named `nome()` to match the storage field's name; the accessor's
1266    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1267    /// slot's docstring already carries.
1268    #[must_use]
1269    pub const fn nome(&self) -> &str {
1270        self.nome.as_str()
1271    }
1272
1273    /// Substrate-canonical per-`Caixa` `:versao` universal-axis SemVer-2
1274    /// pinned-version scalar accessor every consumer of the top-level
1275    /// manifest's version axis keys off — returns the author-declared
1276    /// `:versao` byte-string verbatim as an `&str`, borrowed from the
1277    /// typed slot's own `String` storage. Non-optional (`:versao` is a
1278    /// required-axis scalar every `defcaixa` form must supply alongside
1279    /// `:nome` / `:kind`; the [`Self::from_lisp`] derive rejects an
1280    /// omitted / non-string `:versao` at parse time, so a `Caixa` past
1281    /// parse definitionally carries a non-`None` `:versao`).
1282    ///
1283    /// The `:versao` slot carries the universal-axis SemVer-2
1284    /// concrete-version body every kind of caixa emits under
1285    /// (CAIXA-SDLC §I — the required-scalar every `defcaixa` form
1286    /// supplies alongside `:nome` / `:kind`; the substrate-wide
1287    /// pinned-version every downstream artifact-emitting consumer
1288    /// composes under — the `lareira-<nome>` Helm chart's `Chart.yaml`
1289    /// `version:` + `appVersion:` axes, the `feira publish` Zig-style
1290    /// `v<versao>` git tag the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
1291    /// prefix composes on top of, the programs.yaml entry's `versao:`
1292    /// value the `lareira-fleet-programs` aggregator carries onto each
1293    /// rendered `ComputeUnit`, the OCI image's `:v<versao>` / `:latest`
1294    /// tags every substrate-side `skopeo push` writes, the lacre
1295    /// closure's pinned `concrete_versao`, and the `:upgrade-from :from`
1296    /// prior-version references peers in the exact same SemVer-2 shape).
1297    /// The typed slot's `String` accept-set (empty rejected through
1298    /// [`ManifestError::VersaoEmpty`], SemVer-2-shape-invalid rejected
1299    /// through [`ManifestError::VersaoInvalid`] past
1300    /// [`semver::Version::parse`]) maps onto every load-bearing
1301    /// downstream consumer the substrate carries — the [`Self::validate_versao`]
1302    /// universal-axis validate gate at caixa-build time, the
1303    /// [`crate::CaixaVersion::parse`] typed-wrapper resolver,
1304    /// [`caixa-helm`]'s `Chart.yaml` `version:` / `appVersion:` fold,
1305    /// [`caixa-flux`]'s `programs.yaml` entry `versao:` fold + the
1306    /// `cluster_bundle` `GitRepository` `ref: { tag: v<versao> }`
1307    /// derivation, [`caixa-mesh`]'s per-Aplicacao `programs.yaml` fan-
1308    /// out entry `versao:` fold, [`caixa-feira`]'s `feira publish` git-
1309    /// tag derivation (`format!("{prefix}{versao}")`), and every future
1310    /// substrate renderer that emits an artifact keyed by the caixa's
1311    /// pinned version.
1312    ///
1313    /// Prior to this lift the `.versao` field was accessed inline at a
1314    /// dozen production sites across `caixa-core` (the universal-axis
1315    /// [`Self::validate_versao`] gate + [`Dep::validate`]-adjacent
1316    /// version-shape gates), `caixa-helm` (the `ChartYaml.version` /
1317    /// `ChartYaml.app_version` folds), `caixa-flux` (the `programs.yaml`
1318    /// entry `versao:` fold, the `cluster_bundle` `GitRepository` `ref:
1319    /// { tag: v<versao> }` derivation), `caixa-mesh` (the per-Aplicacao
1320    /// `programs.yaml` fan-out entry `versao:` fold), and `caixa-feira`
1321    /// (the `feira publish` git-tag derivation + the `feira app graph` /
1322    /// `feira app deploy` diagnostic renderers) — a dozen open-coded
1323    /// field-accesses that expressed no compile-time link back to the
1324    /// typed slot. A future extension of the `:versao` axis to a richer
1325    /// author surface — a per-`:versao` structured `CaixaVersion` at the
1326    /// storage layer (the substrate already carries a `CaixaVersion`
1327    /// newtype at [`crate::version::CaixaVersion`], deferred until the
1328    /// serde-transparent-newtype-through-DeriveTataraDomain path lands),
1329    /// a per-registry `:versao` immutability overlay the M4 CR
1330    /// materializer enforces per-CR, a promotion of the plain `String`
1331    /// byte-string to a richer `PinnedVersao` newtype discriminated on
1332    /// SemVer-2 pre-release / build-metadata presence — would have had
1333    /// to be threaded through every open-coded copy in lockstep or the
1334    /// validate gate and the dozen emit paths would silently disagree
1335    /// on which version a given [`Caixa`] resolves to (an author's
1336    /// `:versao "0.1.0"` would satisfy validate while one of the emit
1337    /// paths silently rendered a drifted other version, or vice versa).
1338    /// Lifting the resolution to a typed method on the substrate
1339    /// primitive means every downstream consumer of the caixa's
1340    /// per-`Caixa` pinned-version surface reaches for exactly one typed
1341    /// dispatch — the resolver's accept-set migrates as a unit on any
1342    /// future axis addition.
1343    ///
1344    /// Second outer top-level [`Caixa`] `&str`-return required-scalar
1345    /// accessor — folds on the "outer [`Caixa`] `&str` required-scalar"
1346    /// projection pattern the sibling per-`Caixa` [`Self::nome`]
1347    /// (e6b7d97) opened. Sibling in shape to the peer per-`:membros`
1348    /// [`crate::aplicacao::Membro::versao_requirement`] (4127bb6) /
1349    /// per-`:children` [`crate::supervisor::ChildSpec::versao_requirement`]
1350    /// (2c053c8) / per-`:upgrade-from` [`crate::UpgradeFromEntry::prior_versao`]
1351    /// (75d27a8) per-sub-struct `:versao`-shaped `&str`-return accessors
1352    /// on the sibling per-typed-slot version-carrier axes, extended here
1353    /// to close the second outer top-level [`Caixa`] required-`&str`-
1354    /// carrying axis so the two universal-axis identity-carrying
1355    /// scalars every `defcaixa` form supplies (`:nome` + `:versao`)
1356    /// share the same "one typed dispatch per axis" discipline. Named
1357    /// `versao()` to match the storage field's name; the accessor's
1358    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1359    /// slot's docstring already carries.
1360    #[must_use]
1361    pub const fn versao(&self) -> &str {
1362        self.versao.as_str()
1363    }
1364
1365    /// Substrate-canonical per-`Caixa` `:kind` universal-axis
1366    /// closed-set-enum discriminant accessor every consumer of the top-
1367    /// level manifest's kind axis keys off — returns the author-declared
1368    /// `:kind` variant verbatim as a [`CaixaKind`], `Copy`-projected
1369    /// from the typed slot's own [`CaixaKind`] storage. Non-optional
1370    /// (`:kind` is a required-axis discriminant every `defcaixa` form
1371    /// must supply alongside `:nome` / `:versao`; the [`Self::from_lisp`]
1372    /// derive rejects an omitted / non-symbol `:kind` at parse time, so
1373    /// a `Caixa` past parse definitionally carries a valid [`CaixaKind`]
1374    /// variant).
1375    ///
1376    /// The `:kind` slot carries the universal-axis closed-set typed-
1377    /// discriminant every substrate-side dispatch keys off (CAIXA-SDLC
1378    /// §I — the primary shape gate every renderer / verifier /
1379    /// operator branches on; the five variants `Biblioteca` /
1380    /// `Binario` / `Servico` / `Supervisor` / `Aplicacao` partition
1381    /// the caixa surface into disjoint runtime contracts) — the typed
1382    /// slot's [`CaixaKind`] accept-set (parse-time-rejected non-symbol
1383    /// values through the derive-macro's symbol-arm gate, exhaustively
1384    /// matched at every downstream dispatch site) maps onto every
1385    /// load-bearing downstream consumer the substrate carries:
1386    ///
1387    ///   - [`crate::render::require_kind`]'s per-renderer entry-gate
1388    ///     predicate — the canonical two-line
1389    ///     `require_kind(caixa, Servico)?` prelude every per-Servico
1390    ///     renderer (`caixa-helm`, `caixa-flux`, the future `caixa-otel`
1391    ///     / per-Servico OCI packager / M4 `wasm.pleme.io/v1alpha1/
1392    ///     ComputeUnit` CR materializer) runs at its entry-point,
1393    ///     alongside the [`crate::render::KindMismatch`] error carrier's
1394    ///     `actual:` field the diagnostic surfaces to name the offending
1395    ///     caixa's variant.
1396    ///   - [`Self::aplicacao_view`]'s + [`Self::supervisor_view`]'s
1397    ///     per-view kind-gate binding — the two `Option<TypedSpec>`
1398    ///     `_view` composers that fold the flat mesh-slot / supervisor-
1399    ///     slot columns into their typed sub-spec only when the kind
1400    ///     matches (returns `None` otherwise); the future per-Servico
1401    ///     M2-view composer (`servico_view`) will follow the same shape.
1402    ///   - [`Self::declared_foreign_code_slots`]'s per-slot kind-
1403    ///     coherence gate — the `!self.kind.requires_exe()` /
1404    ///     `!self.kind.requires_servicos()` predicates that fence
1405    ///     each code-surface slot from the wrong owning kind.
1406    ///   - [`crate::LayoutInvariants::verify`]'s kind ↔ code-surface
1407    ///     coherence gates — the six `caixa.kind == CaixaKind::X` /
1408    ///     `caixa.kind != CaixaKind::X` predicates and the four kind-
1409    ///     coherence error carriers (`SupervisorOwnsCode` /
1410    ///     `AplicacaoOwnsCode` / `MeshSlotsOnNonAplicacao` /
1411    ///     `SupervisorSlotsOnNonSupervisor` / `ServicoSlotsOnNonServico`
1412    ///     / `ForeignCodeSlot`) which each name the offending caixa's
1413    ///     variant in their `kind:` field.
1414    ///
1415    /// Prior to this lift the `.kind` field was accessed inline at
1416    /// twenty-plus production sites across `caixa-core` (the
1417    /// [`crate::render::require_kind`] entry-gate predicate + the
1418    /// [`crate::render::KindMismatch`] `actual:` field, the two `_view`
1419    /// composers, the `declared_foreign_code_slots` per-slot kind-
1420    /// coherence gate, and the six [`crate::LayoutInvariants::verify`]
1421    /// kind ↔ code-surface predicates + four error carriers) — a score
1422    /// of open-coded field-accesses that expressed no compile-time link
1423    /// back to the typed slot. A future extension of the `:kind` axis
1424    /// to a richer author surface — a per-`:kind` sub-variant discriminant
1425    /// (e.g. `Servico(ServicoRuntime)` splitting the current single
1426    /// variant across the wasm-component / legacy-container / native-
1427    /// binary runtime axes the M5 roadmap acknowledges), a per-cluster
1428    /// kind-overlay the M4 CR materializer resolves per-CR (the
1429    /// "cluster policy demotes `Aplicacao` to `Servico` on a single-
1430    /// tenant cluster" arm), a promotion of the plain [`CaixaKind`]
1431    /// enum to a richer `KindWithRuntime` discriminated on the
1432    /// component-model world axis — would have had to be threaded
1433    /// through every open-coded copy in lockstep or the entry gate,
1434    /// the view composers, and the layout invariants would silently
1435    /// disagree on which kind a given [`Caixa`] resolves to. Lifting
1436    /// the resolution to a typed method on the substrate primitive
1437    /// means every downstream consumer of the caixa's per-`Caixa`
1438    /// kind surface reaches for exactly one typed dispatch — the
1439    /// resolver's accept-set migrates as a unit on any future axis
1440    /// addition.
1441    ///
1442    /// First outer top-level [`Caixa`] `Copy`-return required-enum-
1443    /// discriminant accessor — opens the "outer [`Caixa`] `Copy`-return
1444    /// required-discriminant" projection pattern. Sibling in shape to
1445    /// the peer per-`:supervisor` [`crate::supervisor::SupervisorSpec::estrategia`]
1446    /// (eafb619), per-`:placement` [`crate::aplicacao::Placement::estrategia`]
1447    /// (921fe1b), and per-`:children` [`crate::supervisor::ChildSpec::restart`]
1448    /// (dfb4a81) `Copy`-return closed-set-enum discriminant accessors
1449    /// on the sibling nested-spec typed-slot discriminator axes,
1450    /// extended here to the outer top-level [`Caixa`] universal-axis
1451    /// surface. Named `kind()` to match the storage field's name;
1452    /// the accessor's identity maps onto the canonical CAIXA-SDLC §I
1453    /// vocabulary the slot's docstring already carries.
1454    #[must_use]
1455    pub const fn kind(&self) -> CaixaKind {
1456        self.kind
1457    }
1458
1459    /// Substrate-canonical per-`Caixa` `:autores` universal-axis
1460    /// maintainer-name-list slice-accessor every consumer of the top-
1461    /// level manifest's maintainer axis keys off — returns the author-
1462    /// declared `:autores` list verbatim as a `&[String]` slice-view over
1463    /// the same backing buffer the raw `self.autores.as_slice()` field
1464    /// access borrows from. Empty-list-carrying (`:autores` is a default-
1465    /// empty axis every `defcaixa` form supplies with an empty `()` when
1466    /// unset; the [`Self::from_lisp`] derive folds an omitted `:autores`
1467    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1468    /// parse definitionally carries a `Vec<String>` slot — possibly
1469    /// empty — and the returned `&[String]` degenerates to an empty
1470    /// slice on that arm without any silent `None` collapse).
1471    ///
1472    /// The `:autores` slot carries the universal-axis maintainer-name
1473    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
1474    /// facing surface every `defcaixa` form supplies alongside `:nome` /
1475    /// `:versao` / `:kind`; the substrate-wide contact-carrying axis
1476    /// every downstream registry-facing artifact emits under) — the
1477    /// typed slot's `Vec<String>` accept-set (empty-per-entry rejected
1478    /// through [`ManifestError::AutorEmpty`], non-chart-maintainer-shape
1479    /// rejected through [`ManifestError::AutorInvalid`], cross-entry
1480    /// duplicate rejected through [`ManifestError::AutorDuplicate`]) maps
1481    /// onto every load-bearing downstream consumer the substrate carries
1482    /// — the [`Self::validate_autores`] universal-axis empty-per-entry +
1483    /// shape + duplicate gate at caixa-core/src/manifest.rs, the
1484    /// caixa-helm `build_chart_yaml` `maintainers:` fold at
1485    /// caixa-helm/src/lib.rs that walks each entry into a `Maintainer {
1486    /// name, email: None }` record, every future per-`Caixa` registry-
1487    /// facing renderer the CAIXA-SDLC §I roadmap acknowledges (the
1488    /// future `artifacthub.io/maintainers` `Chart.yaml` annotation the
1489    /// caixa-helm docstring alludes to at [`Self::validate_licenca`],
1490    /// the future per-cluster author-notification overlay the M4 CR
1491    /// materializer resolves per-CR).
1492    ///
1493    /// Prior to this lift the `.autores` field was accessed inline at
1494    /// two production sites — [`Self::validate_autores`]'s `for autor
1495    /// in &self.autores` walk that gates every entry through
1496    /// [`ManifestError::AutorEmpty`] / `AutorInvalid` / `AutorDuplicate`,
1497    /// and the caixa-helm `build_chart_yaml` `caixa.autores.iter().map(|a|
1498    /// Maintainer { name: a.clone(), email: None }).collect()` fold that
1499    /// materializes every entry into a `Chart.yaml` `maintainers:` row —
1500    /// two open-coded field-accesses that expressed no compile-time link
1501    /// back to the typed slot. A future extension of the `:autores` axis
1502    /// to a richer author surface — a per-`:autores` structured
1503    /// `Maintainer { name, email, url }` at the storage layer once the
1504    /// substrate absorbs `artifacthub.io/maintainers`' name+email+url
1505    /// tuple, a per-registry `:autores` allowlist the M4 CR materializer
1506    /// enforces per-CR (the "cluster policy demands every author declare
1507    /// an on-file `mailto:` contact" arm), a promotion of the plain
1508    /// `Vec<String>` byte-string list to a richer
1509    /// `Vec<ChartMaintainer>` newtype discriminated on the RFC-5322
1510    /// `<name> [<email>]` grammar the `is_chart_maintainer_name_shape`
1511    /// predicate already resolves through — would have had to be
1512    /// threaded through both open-coded copies in lockstep or the
1513    /// validate gate and the caixa-helm emit path would silently
1514    /// disagree on which authors a given [`Caixa`] resolves to (an
1515    /// author's `:autores ("alice" "bob")` would satisfy validate while
1516    /// the caixa-helm emit path silently rendered a drifted other
1517    /// maintainer list, or vice versa). Lifting the resolution to a
1518    /// typed method on the substrate primitive means every downstream
1519    /// consumer of the caixa's per-`Caixa` maintainer surface reaches
1520    /// for exactly one typed dispatch — the resolver's accept-set
1521    /// migrates as a unit on any future axis addition.
1522    ///
1523    /// First outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1524    /// opens the "outer [`Caixa`] `&[T]` slice" projection pattern the
1525    /// sibling per-`Caixa` `:etiquetas` / `:deps` / `:deps-dev` / `:exe`
1526    /// / `:bibliotecas` / `:servicos` / `:upgrade-from` / `:children`
1527    /// future lifts fold on. Sibling in shape to the peer per-`:supervisor`
1528    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce), per-`:placement`
1529    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7), per-`:membros`
1530    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36), per-`:contratos`
1531    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1532    /// per-`:upgrade-from :instructions` [`crate::upgrade::UpgradeFromEntry::instructions`]
1533    /// (0137e5a) `&[T]`-return slice accessors on the sibling per-M2 /
1534    /// per-M3 typed-slot list axes, extended here to the outer top-level
1535    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1536    /// `&Vec<String>`) because every downstream consumer of the author
1537    /// list treats it as a read-only sequence — the slice-view is the
1538    /// narrowest borrow that supports every present + roadmapped consumer
1539    /// (`.iter()`, `.len()`, `.is_empty()`) without leaking the backing
1540    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
1541    /// reaches for (the storage-side `Vec` remains reachable through the
1542    /// `pub autores` field for the mutation-carrying serde round-trip and
1543    /// per-test fixture-mutation paths). Named `autores()` to match the
1544    /// storage field's name; the accessor's identity maps onto the
1545    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1546    /// carries.
1547    #[must_use]
1548    pub const fn autores(&self) -> &[String] {
1549        self.autores.as_slice()
1550    }
1551
1552    /// Substrate-canonical per-`Caixa` `:etiquetas` universal-axis
1553    /// registry-search-tag-list slice-accessor every consumer of the
1554    /// top-level manifest's topical-tag axis keys off — returns the
1555    /// author-declared `:etiquetas` list verbatim as a `&[String]`
1556    /// slice-view over the same backing buffer the raw
1557    /// `self.etiquetas.as_slice()` field access borrows from. Empty-
1558    /// list-carrying (`:etiquetas` is a default-empty axis every
1559    /// `defcaixa` form supplies with an empty `()` when unset; the
1560    /// [`Self::from_lisp`] derive folds an omitted `:etiquetas` through
1561    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1562    /// definitionally carries a `Vec<String>` slot — possibly empty —
1563    /// and the returned `&[String]` degenerates to an empty slice on
1564    /// that arm without any silent `None` collapse).
1565    ///
1566    /// The `:etiquetas` slot carries the universal-axis topical-tag
1567    /// list every kind of caixa emits under (CAIXA-SDLC §I — the
1568    /// author-facing surface every `defcaixa` form supplies alongside
1569    /// `:nome` / `:versao` / `:kind`; the substrate-wide registry-
1570    /// search-facing axis every downstream registry-facing artifact
1571    /// emits under) — the typed slot's `Vec<String>` accept-set
1572    /// (empty-per-entry rejected through [`ManifestError::EtiquetaEmpty`],
1573    /// non-chart-keyword-shape rejected through
1574    /// [`ManifestError::EtiquetaInvalid`], cross-entry duplicate
1575    /// rejected through [`ManifestError::EtiquetaDuplicate`]) maps onto
1576    /// every load-bearing downstream consumer the substrate carries —
1577    /// the [`Self::validate_etiquetas`] universal-axis empty-per-entry
1578    /// + shape + duplicate gate at caixa-core/src/manifest.rs, the
1579    /// caixa-helm `build_chart_yaml` `keywords:` fold at
1580    /// caixa-helm/src/lib.rs that walks each entry into the rendered
1581    /// `Chart.yaml` `keywords:` array (chained with the
1582    /// [`crate::LAREIRA_CHART_KEYWORDS`] substrate-wide floor set and
1583    /// dedup'd through a `BTreeSet` at emit time), every future per-
1584    /// `Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
1585    /// acknowledges (the future `artifacthub.io/keywords` `Chart.yaml`
1586    /// annotation, the future per-cluster tag-notification overlay the
1587    /// M4 CR materializer resolves per-CR).
1588    ///
1589    /// Prior to this lift the `.etiquetas` field was accessed inline at
1590    /// two production sites — [`Self::validate_etiquetas`]'s `for
1591    /// etiqueta in &self.etiquetas` walk that gates every entry through
1592    /// [`ManifestError::EtiquetaEmpty`] / `EtiquetaInvalid` /
1593    /// `EtiquetaDuplicate`, and the caixa-helm `build_chart_yaml`
1594    /// `caixa.etiquetas.iter().cloned().chain(...)` fold that
1595    /// materializes every entry into a `Chart.yaml` `keywords:` row —
1596    /// two open-coded field-accesses that expressed no compile-time
1597    /// link back to the typed slot. A future extension of the
1598    /// `:etiquetas` axis to a richer tag surface — a per-`:etiquetas`
1599    /// structured `ChartKeyword { name, uri, category }` at the storage
1600    /// layer once the substrate absorbs `artifacthub.io/keywords`
1601    /// richer tag tuple, a per-registry `:etiquetas` allowlist the M4
1602    /// CR materializer enforces per-CR (the "cluster policy demands
1603    /// every tag come from a substrate-approved taxonomy" arm), a
1604    /// promotion of the plain `Vec<String>` byte-string list to a
1605    /// richer `Vec<ChartKeyword>` newtype discriminated on the DNS-
1606    /// 1123-label-shaped grammar the `is_chart_keyword_shape` predicate
1607    /// already resolves through — would have had to be threaded through
1608    /// both open-coded copies in lockstep or the validate gate and the
1609    /// caixa-helm emit path would silently disagree on which tags a
1610    /// given [`Caixa`] resolves to (an author's `:etiquetas ("demo"
1611    /// "aplicacao")` would satisfy validate while the caixa-helm emit
1612    /// path silently rendered a drifted other keyword list, or vice
1613    /// versa). Lifting the resolution to a typed method on the
1614    /// substrate primitive means every downstream consumer of the
1615    /// caixa's per-`Caixa` topical-tag surface reaches for exactly one
1616    /// typed dispatch — the resolver's accept-set migrates as a unit
1617    /// on any future axis addition.
1618    ///
1619    /// Second outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1620    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1621    /// [`Self::autores`] (b5d813f) opened, sibling in shape and
1622    /// idiom. The remaining unlifted outer-`Caixa` slice-carrying axes
1623    /// (`:deps` / `:deps-dev` / `:exe` / `:bibliotecas` / `:servicos`
1624    /// / `:upgrade-from` / `:children` / `:membros` / `:contratos`)
1625    /// fold onto the same pattern in future lifts. Sibling in shape to
1626    /// the peer per-`:supervisor`
1627    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1628    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1629    /// (a6e18d7), per-`:membros`
1630    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1631    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1632    /// (0dcc926), and per-`:upgrade-from :instructions`
1633    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1634    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1635    /// typed-slot list axes, extended here to the outer top-level
1636    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1637    /// `&Vec<String>`) because every downstream consumer of the tag
1638    /// list treats it as a read-only sequence — the slice-view is the
1639    /// narrowest borrow that supports every present + roadmapped
1640    /// consumer (`.iter()`, `.len()`, `.is_empty()`) without leaking
1641    /// the backing `Vec`'s grow/push/reserve surface no consumer of
1642    /// the typed view reaches for (the storage-side `Vec` remains
1643    /// reachable through the `pub etiquetas` field for the mutation-
1644    /// carrying serde round-trip and per-test fixture-mutation paths).
1645    /// Named `etiquetas()` to match the storage field's name; the
1646    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1647    /// vocabulary the slot's docstring already carries.
1648    #[must_use]
1649    pub const fn etiquetas(&self) -> &[String] {
1650        self.etiquetas.as_slice()
1651    }
1652
1653    /// Substrate-canonical per-`Caixa` `:bibliotecas` universal-axis
1654    /// library-source-path-list slice-accessor every consumer of the
1655    /// top-level manifest's Biblioteca-source axis keys off — returns
1656    /// the author-declared `:bibliotecas` list verbatim as a
1657    /// `&[String]` slice-view over the same backing buffer the raw
1658    /// `self.bibliotecas.as_slice()` field access borrows from. Empty-
1659    /// list-carrying (`:bibliotecas` is a default-empty axis every
1660    /// `defcaixa` form supplies with an empty `()` when unset; the
1661    /// [`Self::from_lisp`] derive folds an omitted `:bibliotecas`
1662    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1663    /// parse definitionally carries a `Vec<String>` slot — possibly
1664    /// empty — and the returned `&[String]` degenerates to an empty
1665    /// slice on that arm without any silent `None` collapse).
1666    ///
1667    /// The `:bibliotecas` slot carries the universal-axis lisp-library
1668    /// entry-path list every `:kind Biblioteca` caixa emits under
1669    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1670    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1671    /// substrate-wide library-carrier axis every downstream
1672    /// authoring-facing consumer keys off) — the typed slot's
1673    /// `Vec<String>` accept-set (empty-per-entry rejected through
1674    /// [`ManifestError::CodePathEmpty { slot: ":bibliotecas" }`],
1675    /// non-sandboxed-relative-shape rejected through
1676    /// [`ManifestError::CodePathShape`], non-`.lisp`-extension rejected
1677    /// through [`ManifestError::CodePathNonLispExtension`], cross-entry
1678    /// duplicate rejected through [`ManifestError::CodePathDuplicate`])
1679    /// maps onto every load-bearing downstream consumer the substrate
1680    /// carries — the [`crate::LayoutInvariants`] Biblioteca-arm
1681    /// empty-check + per-entry file-exists loop at
1682    /// caixa-core/src/layout.rs that gates each entry through
1683    /// [`crate::LayoutError::MissingLib`] / `MissingEntry`, the
1684    /// [`Self::validate_code_paths`] per-slot shape gate at
1685    /// caixa-core/src/manifest.rs that walks each entry through the
1686    /// sandbox-relative / `.lisp`-extension / cross-entry duplicate
1687    /// gates, the `feira build` per-entry `tatara_lisp::read` parse
1688    /// walk at caixa-feira/src/cmd/build.rs that phase-1-checks each
1689    /// declared library file for lexical / structural errors before
1690    /// downstream `importar` resolution, every future per-`Caixa`
1691    /// library-facing renderer the CAIXA-SDLC §I roadmap acknowledges
1692    /// (the future `tatara-lispc` compilation entry the docstring at
1693    /// caixa-feira/src/cmd/build.rs alludes to, the future per-cluster
1694    /// bytecode-caching overlay the M4 CR materializer resolves per-CR,
1695    /// the future `caixa-lsp` per-library semantic-token stream the
1696    /// caixa-lsp docstring roadmaps).
1697    ///
1698    /// Prior to this lift the `.bibliotecas` field was accessed inline
1699    /// at three production sites — [`crate::LayoutInvariants`]'s
1700    /// `caixa.bibliotecas.is_empty()` `MissingLib`-arm gate + `for p
1701    /// in &caixa.bibliotecas` `MissingEntry` walk that gates each
1702    /// declared library path through the on-disk-existence check,
1703    /// the compound-code-path `has_code = !caixa.bibliotecas.is_empty()
1704    /// || !caixa.exe.is_empty() || !caixa.servicos.is_empty()` OR-fold
1705    /// on the [`crate::LayoutError::SupervisorOwnsCode`] /
1706    /// `AplicacaoOwnsCode` kind-coherence gate, and the `feira build`
1707    /// per-entry `for entry in &caixa.bibliotecas` + `caixa.bibliotecas.
1708    /// len()` phase-1 tatara-lispc-precursor parse walk — three open-
1709    /// coded field-accesses that expressed no compile-time link back
1710    /// to the typed slot. A future extension of the `:bibliotecas`
1711    /// axis to a richer library surface — a per-`:bibliotecas`
1712    /// structured `BibliotecaEntry { path, edition, exports }` at the
1713    /// storage layer once the substrate absorbs the per-library
1714    /// language-edition + explicit-exports tuple the tatara-lisp
1715    /// module-system roadmap acknowledges, a per-registry
1716    /// `:bibliotecas` allowlist the M4 CR materializer enforces
1717    /// per-CR (the "cluster policy demands every biblioteca declare
1718    /// its own :edicao" arm), a promotion of the plain `Vec<String>`
1719    /// byte-string list to a richer `Vec<LibraryPath>` newtype
1720    /// discriminated on the `lib/<nome>.lisp`-shape grammar the
1721    /// [`crate::render::is_sandboxed_relative_path`] +
1722    /// [`crate::render::is_lisp_extension`] predicates already resolve
1723    /// through — would have had to be threaded through all three
1724    /// open-coded copies in lockstep or the layout gate, the shape
1725    /// validator, and the `feira build` phase-1 parse walk would
1726    /// silently disagree on which library paths a given [`Caixa`]
1727    /// resolves to (an author's `:bibliotecas ("lib/foo.lisp"
1728    /// "lib/bar.lisp")` would satisfy layout while `feira build`
1729    /// silently parsed a drifted other list, or vice versa). Lifting
1730    /// the resolution to a typed method on the substrate primitive
1731    /// means every downstream consumer of the caixa's per-`Caixa`
1732    /// library-source surface reaches for exactly one typed dispatch
1733    /// — the resolver's accept-set migrates as a unit on any future
1734    /// axis addition.
1735    ///
1736    /// Third outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1737    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1738    /// [`Self::autores`] (b5d813f) opened and [`Self::etiquetas`]
1739    /// (78c7d3c) folded on, sibling in shape and idiom. The remaining
1740    /// unlifted outer-`Caixa` slice-carrying axes (`:deps` /
1741    /// `:deps-dev` / `:exe` / `:servicos` / `:upgrade-from` /
1742    /// `:children` / `:membros` / `:contratos`) fold onto the same
1743    /// pattern in future lifts. Sibling in shape to the peer
1744    /// per-`:supervisor`
1745    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1746    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1747    /// (a6e18d7), per-`:membros`
1748    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1749    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1750    /// (0dcc926), and per-`:upgrade-from :instructions`
1751    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1752    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1753    /// typed-slot list axes, extended here to the outer top-level
1754    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1755    /// `&Vec<String>`) because every downstream consumer of the
1756    /// library-source list treats it as a read-only sequence — the
1757    /// slice-view is the narrowest borrow that supports every
1758    /// present + roadmapped consumer (`.iter()`, `.len()`,
1759    /// `.is_empty()`) without leaking the backing `Vec`'s
1760    /// grow/push/reserve surface no consumer of the typed view
1761    /// reaches for (the storage-side `Vec` remains reachable through
1762    /// the `pub bibliotecas` field for the mutation-carrying serde
1763    /// round-trip and per-test fixture-mutation paths). Named
1764    /// `bibliotecas()` to match the storage field's name; the
1765    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1766    /// vocabulary the slot's docstring already carries.
1767    #[must_use]
1768    pub const fn bibliotecas(&self) -> &[String] {
1769        self.bibliotecas.as_slice()
1770    }
1771
1772    /// Substrate-canonical per-`Caixa` `:exe` universal-axis
1773    /// nix-built-executable-entry-path-list slice-accessor every consumer
1774    /// of the top-level manifest's Binario-executable axis keys off —
1775    /// returns the author-declared `:exe` list verbatim as a `&[String]`
1776    /// slice-view over the same backing buffer the raw
1777    /// `self.exe.as_slice()` field access borrows from. Empty-list-
1778    /// carrying (`:exe` is a default-empty axis every `defcaixa` form
1779    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
1780    /// derive folds an omitted `:exe` through `#[serde(default)]` to
1781    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
1782    /// `Vec<String>` slot — possibly empty — and the returned `&[String]`
1783    /// degenerates to an empty slice on that arm without any silent
1784    /// `None` collapse).
1785    ///
1786    /// The `:exe` slot carries the universal-axis nix-built executable
1787    /// entry-path list every `:kind Binario` caixa emits under
1788    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1789    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1790    /// substrate-wide `exe/`-directory-fenced entry-carrier axis every
1791    /// downstream flake-build-facing consumer keys off) — the typed
1792    /// slot's `Vec<String>` accept-set (empty-per-entry rejected
1793    /// through [`ManifestError::CodePathEmpty { slot: ":exe" }`],
1794    /// non-sandboxed-relative-shape rejected through
1795    /// [`ManifestError::CodePathShape`], cross-entry duplicate rejected
1796    /// through [`ManifestError::CodePathDuplicate`], out-of-`exe/`-
1797    /// directory paths rejected past the layout's
1798    /// [`crate::LayoutError::ExeOutsideDir`] `starts_with` fence) maps
1799    /// onto every load-bearing downstream consumer the substrate carries
1800    /// — the [`crate::LayoutInvariants`] Binario-arm empty-check +
1801    /// per-entry file-exists + `exe/`-directory-fence loop at
1802    /// caixa-core/src/layout.rs that gates each entry through
1803    /// [`crate::LayoutError::BinarioWithoutExe`] / `MissingEntry` /
1804    /// `ExeOutsideDir`, the compound `has_code` OR-fold on the
1805    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1806    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1807    /// that fences code-surface slots off from the two no-code kinds,
1808    /// [`Self::declared_foreign_code_slots`]'s `!self.exe.is_empty()`
1809    /// arm on the [`crate::LayoutError::ForeignCodeSlot`] gate that
1810    /// fences the `:exe` code surface off from every non-Binario code-
1811    /// running kind, [`Self::validate_code_paths`]'s per-slot shape gate
1812    /// that walks each entry through the sandbox-relative / cross-entry
1813    /// duplicate gates, every future per-`Caixa` executable-facing
1814    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1815    /// `caixa-flake` per-Binario `packages.<system>.<nome>` derivation
1816    /// entry the caixa-flake docstring roadmaps, the future per-cluster
1817    /// `nix-store` overlay the M4 CR materializer resolves per-CR, the
1818    /// future `feira nix` per-executable Binario-target emit path).
1819    ///
1820    /// Prior to this lift the `.exe` field was accessed inline at three
1821    /// production sites — the compound-code-path `has_code =
1822    /// !caixa.bibliotecas().is_empty() || !caixa.exe.is_empty() ||
1823    /// !caixa.servicos.is_empty()` OR-fold on the
1824    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1825    /// `AplicacaoOwnsCode` kind-coherence gate, the Binario-arm
1826    /// `caixa.exe.is_empty()` [`crate::LayoutError::BinarioWithoutExe`]
1827    /// gate, the per-entry `for p in &caixa.exe`
1828    /// `MissingEntry`/`ExeOutsideDir` walk, and the
1829    /// [`Self::declared_foreign_code_slots`]'s
1830    /// `!self.exe.is_empty()` arm on the `ForeignCodeSlot` gate — four
1831    /// open-coded field-accesses that expressed no compile-time link
1832    /// back to the typed slot. A future extension of the `:exe` axis
1833    /// to a richer executable surface — a per-`:exe` structured
1834    /// `BinarioEntry { path, wrapper, capabilities }` at the storage
1835    /// layer once the substrate absorbs the per-executable
1836    /// nix-wrapper + linux-capabilities tuple the CAIXA-SDLC §I
1837    /// executable roadmap acknowledges, a per-registry `:exe` allowlist
1838    /// the M4 CR materializer enforces per-CR (the "cluster policy
1839    /// demands every Binario declare an explicit `:wrapper`" arm), a
1840    /// promotion of the plain `Vec<String>` byte-string list to a
1841    /// richer `Vec<ExecutablePath>` newtype discriminated on the
1842    /// `exe/<nome>`-shape grammar the layout's `starts_with(exe_dir)`
1843    /// fence already resolves through — would have had to be threaded
1844    /// through all four open-coded copies in lockstep or the layout
1845    /// gate, the shape validator, and the `feira nix` emit path would
1846    /// silently disagree on which executable paths a given [`Caixa`]
1847    /// resolves to (an author's `:exe ("exe/cli" "exe/serve")` would
1848    /// satisfy layout while `feira nix` silently packaged a drifted
1849    /// other list, or vice versa). Lifting the resolution to a typed
1850    /// method on the substrate primitive means every downstream
1851    /// consumer of the caixa's per-`Caixa` executable-source surface
1852    /// reaches for exactly one typed dispatch — the resolver's accept-
1853    /// set migrates as a unit on any future axis addition.
1854    ///
1855    /// Fourth outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1856    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1857    /// [`Self::autores`] (b5d813f) opened, [`Self::etiquetas`]
1858    /// (78c7d3c) folded on, and [`Self::bibliotecas`] (8a36c23) closed
1859    /// the universal-axis text-tag family of. Opens the outer-`Caixa`
1860    /// foreign-code-slot `&[T]` sub-family the sibling `:servicos`
1861    /// future lift closes onto (per the trio of code-surface list slots
1862    /// the [`Self::validate_code_paths`] per-slot dispatch tuple
1863    /// already carries — `:bibliotecas` + `:exe` + `:servicos`, of which
1864    /// `:bibliotecas` landed at 8a36c23 and `:servicos` remains as the
1865    /// last unlifted code-surface slot). Sibling in shape to the peer
1866    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
1867    /// (bc92bce), per-`:placement`
1868    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
1869    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
1870    /// (6c77e36), per-`:contratos`
1871    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1872    /// per-`:upgrade-from :instructions`
1873    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1874    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1875    /// typed-slot list axes, extended here to the outer top-level
1876    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1877    /// `&Vec<String>`) because every downstream consumer of the
1878    /// executable-source list treats it as a read-only sequence — the
1879    /// slice-view is the narrowest borrow that supports every
1880    /// present + roadmapped consumer (`.iter()`, `.len()`,
1881    /// `.is_empty()`) without leaking the backing `Vec`'s
1882    /// grow/push/reserve surface no consumer of the typed view
1883    /// reaches for (the storage-side `Vec` remains reachable through
1884    /// the `pub exe` field for the mutation-carrying serde
1885    /// round-trip and per-test fixture-mutation paths). Named `exe()`
1886    /// to match the storage field's name; the accessor's identity
1887    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
1888    /// docstring already carries.
1889    #[must_use]
1890    pub const fn exe(&self) -> &[String] {
1891        self.exe.as_slice()
1892    }
1893
1894    /// Substrate-canonical per-`Caixa` `:servicos` universal-axis
1895    /// ComputeUnit-CR-YAML-entry-path-list slice-accessor every consumer
1896    /// of the top-level manifest's Servico-component axis keys off —
1897    /// returns the author-declared `:servicos` list verbatim as a
1898    /// `&[String]` slice-view over the same backing buffer the raw
1899    /// `self.servicos.as_slice()` field access borrows from. Empty-list-
1900    /// carrying (`:servicos` is a default-empty axis every `defcaixa`
1901    /// form supplies with an empty `()` when unset; the
1902    /// [`Self::from_lisp`] derive folds an omitted `:servicos` through
1903    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1904    /// definitionally carries a `Vec<String>` slot — possibly empty —
1905    /// and the returned `&[String]` degenerates to an empty slice on
1906    /// that arm without any silent `None` collapse).
1907    ///
1908    /// The `:servicos` slot carries the universal-axis
1909    /// `.computeunit.yaml` ComputeUnit-CR entry-path list every
1910    /// `:kind Servico` caixa emits under (CAIXA-SDLC §I — the
1911    /// author-facing surface every `defcaixa` form supplies alongside
1912    /// `:nome` / `:versao` / `:kind`; the substrate-wide
1913    /// `servicos/`-directory-fenced entry-carrier axis every downstream
1914    /// Servico-facing renderer keys off) — the typed slot's
1915    /// `Vec<String>` accept-set (empty-per-entry rejected through
1916    /// [`ManifestError::CodePathEmpty { slot: ":servicos" }`],
1917    /// non-sandboxed-relative-shape rejected through
1918    /// [`ManifestError::CodePathShape`], non-`.computeunit.yaml`
1919    /// extension rejected through
1920    /// [`ManifestError::CodePathNonComputeUnitYamlExtension`], cross-
1921    /// entry duplicate rejected through
1922    /// [`ManifestError::CodePathDuplicate`], `len != 1` rejected by the
1923    /// V0 [`crate::ServicoCountMismatch`] gate on the per-Servico
1924    /// renderer entry-points, out-of-`servicos/`-directory paths
1925    /// rejected past the layout's [`crate::LayoutError::ServicoOutsideDir`]
1926    /// `starts_with` fence) maps onto every load-bearing downstream
1927    /// consumer the substrate carries — the [`crate::LayoutInvariants`]
1928    /// Servico-arm empty-check + per-entry file-exists + `servicos/`-
1929    /// directory-fence loop at caixa-core/src/layout.rs that gates each
1930    /// entry through [`crate::LayoutError::ServicoWithoutServicos`] /
1931    /// `MissingEntry` / `ServicoOutsideDir`, the compound `has_code`
1932    /// OR-fold on the [`crate::LayoutError::SupervisorOwnsCode`] /
1933    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1934    /// that fences code-surface slots off from the two no-code kinds,
1935    /// [`Self::declared_foreign_code_slots`]'s
1936    /// `!self.servicos.is_empty()` arm on the
1937    /// [`crate::LayoutError::ForeignCodeSlot`] gate that fences the
1938    /// `:servicos` code surface off from every non-Servico code-running
1939    /// kind, [`Self::validate_code_paths`]'s per-slot shape gate that
1940    /// walks each entry through the sandbox-relative / `.computeunit.
1941    /// yaml`-extension / cross-entry duplicate gates, the
1942    /// [`crate::require_single_servico`] V0 singularity gate every
1943    /// per-Servico renderer entry-point runs through
1944    /// [`crate::require_v0_servico_shape`], the `feira chart` /
1945    /// `feira deploy` per-verb `first_servico_path` walk at
1946    /// caixa-feira/src/cmd/chart.rs that resolves the singleton
1947    /// ComputeUnit-CR file, every future per-`Caixa` Servico-facing
1948    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1949    /// per-Servico OCI packager, the future M4
1950    /// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer, the future
1951    /// per-Servico OTel collector-config emit).
1952    ///
1953    /// Prior to this lift the `.servicos` field was accessed inline at
1954    /// five production sites — the compound-code-path `has_code =
1955    /// !caixa.bibliotecas().is_empty() || !caixa.exe().is_empty() ||
1956    /// !caixa.servicos.is_empty()` OR-fold on the
1957    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1958    /// `AplicacaoOwnsCode` kind-coherence gate, the Servico-arm
1959    /// `caixa.servicos.is_empty()`
1960    /// [`crate::LayoutError::ServicoWithoutServicos`] gate, the
1961    /// per-entry `for p in &caixa.servicos`
1962    /// `MissingEntry`/`ServicoOutsideDir` walk, the
1963    /// [`Self::declared_foreign_code_slots`]'s
1964    /// `!self.servicos.is_empty()` arm on the `ForeignCodeSlot` gate,
1965    /// and the [`crate::require_single_servico`] V0 count gate's
1966    /// `caixa.servicos.len() == 1` / `caixa.servicos.len()` count
1967    /// projection (both the accept-arm predicate and the
1968    /// diagnostic-carrying `ServicoCountMismatch { count }`
1969    /// projection) — five open-coded field-accesses across three
1970    /// crates that expressed no compile-time link back to the typed
1971    /// slot. A future extension of the `:servicos` axis to a richer
1972    /// component surface — a per-`:servicos` structured
1973    /// `ServicoEntry { path, world, capabilities }` at the storage
1974    /// layer once the substrate absorbs the per-component WIT-world +
1975    /// capability-set tuple the CAIXA-SDLC §I Servico roadmap
1976    /// acknowledges, a per-registry `:servicos` allowlist the M4 CR
1977    /// materializer enforces per-CR (the "cluster policy demands every
1978    /// Servico declare an explicit `:world`" arm), a promotion of the
1979    /// plain `Vec<String>` byte-string list to a richer
1980    /// `Vec<ComputeUnitPath>` newtype discriminated on the
1981    /// `servicos/<nome>.computeunit.yaml`-shape grammar the layout's
1982    /// `starts_with(servicos_dir)` fence and the
1983    /// [`crate::render::is_computeunit_yaml_extension`] predicate
1984    /// already resolve through, a promotion of the V0 singleton
1985    /// contract to a multi-component `Vec<ComputeUnitPath>` past the M5
1986    /// component-model multi-world boundary — would have had to be
1987    /// threaded through all five open-coded copies in lockstep or the
1988    /// layout gate, the shape validator, the V0 count gate, and the
1989    /// `feira chart` / `feira deploy` entry-point walks would silently
1990    /// disagree on which ComputeUnit-CR paths a given [`Caixa`]
1991    /// resolves to (an author's `:servicos ("servicos/foo.computeunit.
1992    /// yaml")` would satisfy layout while `feira chart` silently
1993    /// packaged a drifted other list, or vice versa). Lifting the
1994    /// resolution to a typed method on the substrate primitive means
1995    /// every downstream consumer of the caixa's per-`Caixa`
1996    /// ComputeUnit-CR-source surface reaches for exactly one typed
1997    /// dispatch — the resolver's accept-set migrates as a unit on any
1998    /// future axis addition.
1999    ///
2000    /// Fifth and final outer top-level [`Caixa`] `&[T]`-return slice-
2001    /// accessor — folds on the "outer [`Caixa`] `&[T]` slice"
2002    /// projection pattern [`Self::autores`] (b5d813f) opened,
2003    /// [`Self::etiquetas`] (78c7d3c) folded on, [`Self::bibliotecas`]
2004    /// (8a36c23) closed the universal-axis text-tag family of, and
2005    /// [`Self::exe`] (65d9527) opened the foreign-code-slot sub-family
2006    /// of. Closes the outer-`Caixa` foreign-code-slot `&[T]` sub-family
2007    /// — with `:bibliotecas`, `:exe`, and `:servicos` now each carrying
2008    /// a substrate-canonical slice accessor, the trio of code-surface
2009    /// list slots the [`Self::validate_code_paths`] per-slot dispatch
2010    /// tuple carries is complete on the typed dispatch surface (the
2011    /// internal `[(":bibliotecas", &self.bibliotecas, ..), (":exe",
2012    /// &self.exe, ..), (":servicos", &self.servicos, ..)]` per-slot
2013    /// dispatch tuple's homogeneous `&Vec<String>`-typed shape blocks a
2014    /// per-element accessor swap in isolation — a future companion lift
2015    /// promotes the tuple's element type to `&[String]` and threads the
2016    /// triple of typed dispatches through as a unit). Sibling in shape
2017    /// to the peer per-`:supervisor`
2018    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2019    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2020    /// (a6e18d7), per-`:membros`
2021    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2022    /// per-`:contratos`
2023    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2024    /// per-`:upgrade-from :instructions`
2025    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2026    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2027    /// typed-slot list axes, extended here to the outer top-level
2028    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
2029    /// `&Vec<String>`) because every downstream consumer of the
2030    /// ComputeUnit-CR-source list treats it as a read-only sequence —
2031    /// the slice-view is the narrowest borrow that supports every
2032    /// present + roadmapped consumer (`.iter()`, `.len()`,
2033    /// `.is_empty()`, `.first()`) without leaking the backing `Vec`'s
2034    /// grow/push/reserve surface no consumer of the typed view reaches
2035    /// for (the storage-side `Vec` remains reachable through the
2036    /// `pub servicos` field for the mutation-carrying serde round-trip
2037    /// and per-test fixture-mutation paths, and for the
2038    /// [`Self::validate_code_paths`] per-slot dispatch tuple whose
2039    /// homogeneous-element-type shape carries the raw field access
2040    /// until the trio-closure lift promotes the tuple as a unit).
2041    /// Named `servicos()` to match the storage field's name; the
2042    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
2043    /// vocabulary the slot's docstring already carries.
2044    #[must_use]
2045    pub const fn servicos(&self) -> &[String] {
2046        self.servicos.as_slice()
2047    }
2048
2049    /// Substrate-canonical per-`Caixa` `:deps` universal-axis
2050    /// runtime-dependency-declaration-list slice-accessor every consumer
2051    /// of the top-level manifest's runtime-dep-graph axis keys off —
2052    /// returns the author-declared `:deps` list verbatim as a `&[Dep]`
2053    /// slice-view over the same backing buffer the raw
2054    /// `self.deps.as_slice()` field access borrows from. Empty-list-
2055    /// carrying (`:deps` is a default-empty axis every `defcaixa` form
2056    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
2057    /// derive folds an omitted `:deps` through `#[serde(default)]` to
2058    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
2059    /// `Vec<Dep>` slot — possibly empty — and the returned `&[Dep]`
2060    /// degenerates to an empty slice on that arm without any silent
2061    /// `None` collapse).
2062    ///
2063    /// The `:deps` slot carries the universal-axis runtime dependency
2064    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
2065    /// facing surface every `defcaixa` form supplies alongside `:nome` /
2066    /// `:versao` / `:kind`; the substrate-wide runtime-closure-input axis
2067    /// every downstream resolver-facing artifact emits under) — the
2068    /// typed slot's `Vec<Dep>` accept-set (empty-`:nome` rejected through
2069    /// [`DepError::NomeEmpty`], non-DNS-1123-label `:nome` rejected
2070    /// through [`DepError::NomeInvalid`], malformed `:versao` rejected
2071    /// through [`DepError::VersaoInvalid`], empty `:fonte.repo` rejected
2072    /// through [`DepError::FonteRepoEmpty`], within-list duplicate `:nome`
2073    /// rejected through [`DepError::DuplicateNome { list: ":deps" }`])
2074    /// maps onto every load-bearing downstream consumer the substrate
2075    /// carries — the [`Self::validate_deps`] per-entry
2076    /// [`Dep::validate`] + within-list dedup walk at
2077    /// caixa-core/src/manifest.rs, the [`crate::dep::validate_no_self_dep`]
2078    /// cross-list self-reference gate at caixa-core/src/layout.rs that
2079    /// checks each entry against the caixa's own `:nome`, the
2080    /// caixa-resolver `for dep in &root.deps` closure walk at
2081    /// caixa-resolver/src/resolve.rs that seeds every git-clone target
2082    /// through the resolver's [`crate::Dep`]-keyed pipeline, the
2083    /// caixa-crd `caixa.deps.iter().map(dep_into_ref).collect()` fold at
2084    /// caixa-crd/src/conversion.rs that materializes each entry into the
2085    /// K8s `Caixa` CR's `spec.deps` field, every future per-`Caixa`
2086    /// resolver-facing renderer the CAIXA-SDLC §I roadmap acknowledges
2087    /// (the future per-cluster runtime-closure-audit overlay the M4 CR
2088    /// materializer resolves per-CR, the future `lacre.lisp` BLAKE3-
2089    /// closure emit walk the caixa-resolver docstring roadmaps).
2090    ///
2091    /// First outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2092    /// opens the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2093    /// sibling `:deps-dev` future lift closes on. Peer of the closed
2094    /// outer-`Caixa` foreign-code-slot `&[String]` sub-family
2095    /// ([`Self::bibliotecas`] 8a36c23, [`Self::exe`] 65d9527,
2096    /// [`Self::servicos`] 611f78b) and the outer-`Caixa` universal-axis
2097    /// text-tag family ([`Self::autores`] b5d813f, [`Self::etiquetas`]
2098    /// 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice" projection
2099    /// pattern onto a novel element-type axis (`Dep` composite vs the
2100    /// prior sibling family's `String` scalar). Sibling in shape to the
2101    /// peer per-`:supervisor`
2102    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2103    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2104    /// (a6e18d7), per-`:membros`
2105    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2106    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
2107    /// (0dcc926), and per-`:upgrade-from :instructions`
2108    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2109    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2110    /// typed-slot list axes, extended here to the outer top-level
2111    /// [`Caixa`] universal-axis dep-graph surface. Returns `&[Dep]`
2112    /// (not `&Vec<Dep>`) because every downstream consumer of the
2113    /// runtime-dep list treats it as a read-only sequence — the slice-
2114    /// view is the narrowest borrow that supports every present +
2115    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2116    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2117    /// of the typed view reaches for (the storage-side `Vec` remains
2118    /// reachable through the `pub deps` field for the mutation-carrying
2119    /// serde round-trip and per-test fixture-mutation paths). Named
2120    /// `deps()` to match the storage field's name; the accessor's
2121    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
2122    /// slot's docstring already carries.
2123    #[must_use]
2124    pub const fn deps(&self) -> &[Dep] {
2125        self.deps.as_slice()
2126    }
2127
2128    /// Substrate-canonical per-`Caixa` `:deps-dev` universal-axis
2129    /// development-only-dependency-declaration-list slice-accessor every
2130    /// consumer of the top-level manifest's dev-dep-graph axis keys off —
2131    /// returns the author-declared `:deps-dev` list verbatim as a `&[Dep]`
2132    /// slice-view over the same backing buffer the raw
2133    /// `self.deps_dev.as_slice()` field access borrows from. Empty-list-
2134    /// carrying (`:deps-dev` is a default-empty axis every `defcaixa`
2135    /// form supplies with an empty `()` when unset; the
2136    /// [`Self::from_lisp`] derive folds an omitted `:deps-dev` through
2137    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
2138    /// definitionally carries a `Vec<Dep>` slot — possibly empty — and
2139    /// the returned `&[Dep]` degenerates to an empty slice on that arm
2140    /// without any silent `None` collapse).
2141    ///
2142    /// The `:deps-dev` slot carries the universal-axis dev-only
2143    /// dependency list every kind of caixa emits under (CAIXA-SDLC §I —
2144    /// the author-facing sibling of `:deps` that every `defcaixa` form
2145    /// supplies to declare tests / lint / bench closures the runtime
2146    /// `:deps` axis does not carry; the substrate-wide dev-closure-input
2147    /// axis every downstream test-facing artifact emits under, matching
2148    /// Cargo's `[dev-dependencies]` table's dev-time-only visibility
2149    /// contract) — the typed slot's `Vec<Dep>` accept-set (empty-`:nome`
2150    /// rejected through [`DepError::NomeEmpty`], non-DNS-1123-label
2151    /// `:nome` rejected through [`DepError::NomeInvalid`], malformed
2152    /// `:versao` rejected through [`DepError::VersaoInvalid`], empty
2153    /// `:fonte.repo` rejected through [`DepError::FonteRepoEmpty`],
2154    /// within-list duplicate `:nome` rejected through
2155    /// [`DepError::DuplicateNome { list: ":deps-dev" }`]) maps onto every
2156    /// load-bearing downstream consumer the substrate carries — the
2157    /// [`Self::validate_deps`] per-entry [`Dep::validate`] + within-list
2158    /// dedup walk at caixa-core/src/manifest.rs, the
2159    /// [`crate::dep::validate_no_self_dep`] cross-list self-reference
2160    /// gate at caixa-core/src/layout.rs that checks each entry against
2161    /// the caixa's own `:nome`, the caixa-resolver
2162    /// `for dep in &root.deps_dev` closure walk at
2163    /// caixa-resolver/src/resolve.rs that seeds every dev-only git-clone
2164    /// target through the resolver's [`crate::Dep`]-keyed pipeline, and
2165    /// every future per-`Caixa` resolver-facing renderer the CAIXA-SDLC
2166    /// §I roadmap acknowledges (the future per-cluster dev-closure-audit
2167    /// overlay the M4 CR materializer resolves per-CR, the future
2168    /// `lacre.lisp` BLAKE3-closure emit walk the caixa-resolver docstring
2169    /// roadmaps).
2170    ///
2171    /// Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2172    /// closes the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2173    /// sibling [`Self::deps`] (ad34b4e) opened on. The two accessors
2174    /// jointly close the two-list dep-graph surface every downstream
2175    /// resolver-facing consumer keys off (runtime `:deps` +
2176    /// dev-only `:deps-dev`, the canonical Cargo-shaped dependency-table
2177    /// pair the [`Self::validate_deps`] gate already walks in canonical
2178    /// order). Peer of the closed outer-`Caixa` foreign-code-slot
2179    /// `&[String]` sub-family ([`Self::bibliotecas`] 8a36c23,
2180    /// [`Self::exe`] 65d9527, [`Self::servicos`] 611f78b) and the outer-
2181    /// `Caixa` universal-axis text-tag family ([`Self::autores`]
2182    /// b5d813f, [`Self::etiquetas`] 78c7d3c) — folds the "outer
2183    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
2184    /// dev-dep composite-element axis (`Dep` composite, matching the
2185    /// [`Self::deps`] element type). Sibling in shape to the peer
2186    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
2187    /// (bc92bce), per-`:placement`
2188    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
2189    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
2190    /// (6c77e36), per-`:contratos`
2191    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2192    /// per-`:upgrade-from :instructions`
2193    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2194    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2195    /// typed-slot list axes, folded here to the outer top-level
2196    /// [`Caixa`] universal-axis dev-dep-graph surface. Returns `&[Dep]`
2197    /// (not `&Vec<Dep>`) because every downstream consumer of the
2198    /// dev-dep list treats it as a read-only sequence — the slice-view
2199    /// is the narrowest borrow that supports every present +
2200    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2201    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2202    /// of the typed view reaches for (the storage-side `Vec` remains
2203    /// reachable through the `pub deps_dev` field for the mutation-
2204    /// carrying serde round-trip and per-test fixture-mutation paths).
2205    /// Named `deps_dev()` to match the storage field's `snake_case` name;
2206    /// the kebab-case author-surface tag `:deps-dev` is the same axis
2207    /// after tatara-lisp's kebab↔snake fold and the accessor's identity
2208    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
2209    /// docstring already carries.
2210    #[must_use]
2211    pub const fn deps_dev(&self) -> &[Dep] {
2212        self.deps_dev.as_slice()
2213    }
2214
2215    /// Substrate-canonical per-[`Caixa`] typed-dispatch read accessor
2216    /// every consumer that walks one of the two dep-list axes keyed on a
2217    /// [`crate::dep::DepList`] discriminant reaches for — routes the
2218    /// `(list: DepList) -> &[Dep]` projection through one typed method on
2219    /// the substrate primitive rather than the prior open-coded
2220    /// `match list { Prod => caixa.deps(), Dev => caixa.deps_dev() }`
2221    /// inline dispatch every per-axis walker would otherwise carry.
2222    /// Returns the author-declared per-list `Vec<Dep>` verbatim as a
2223    /// `&[Dep]` slice-view over the same backing buffer the sibling
2224    /// [`Self::deps`] (`Prod`) / [`Self::deps_dev`] (`Dev`) per-slot
2225    /// accessors borrow from, preserving the empty-list-carrying invariant
2226    /// each per-slot accessor already establishes (`:deps` / `:deps-dev`
2227    /// are default-empty axes every `defcaixa` form supplies with an empty
2228    /// `()` when unset; the [`Self::from_lisp`] derive folds an omitted
2229    /// list through `#[serde(default)]` to `Vec::new()`, so both arms
2230    /// definitionally carry a `Vec<Dep>` slot — possibly empty — and the
2231    /// returned `&[Dep]` degenerates to an empty slice on either arm
2232    /// without any silent `None` collapse).
2233    ///
2234    /// The [`crate::dep::DepList`] closed-set typed enum is the
2235    /// substrate's canonical discriminator for the "runtime-closure
2236    /// `:deps` vs dev-only-closure `:deps-dev`" axis every dep-list
2237    /// consumer dispatches on — the compiler-checked exhaustiveness on
2238    /// the enum's `match` arms is the build-time guarantee that no future
2239    /// per-list read-site regresses to a bare-`bool`-flag inline dispatch
2240    /// that a future third dep-list axis (a `:deps-build` build-only
2241    /// closure once the substrate grows cross-artifact heterogeneous
2242    /// dep-graphs, per CAIXA-SDLC §I) would silently split at every
2243    /// consumer. Prior to this the read side carried two per-slot
2244    /// accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`]) and no
2245    /// typed dispatch that a per-axis walker could parametrise on, so
2246    /// every per-list walker (the [`Self::validate_deps`] per-list
2247    /// [`crate::render::insert_first_seen`] dedup walk, a future
2248    /// `feira app graph` per-list dep summary, a future M4 per-cluster
2249    /// dev-closure-audit overlay the CR materializer resolves per-CR)
2250    /// open-coded the same two-block "run over `:deps`, then run over
2251    /// `:deps-dev`" pattern — a silent duplication that a future third
2252    /// dep-list axis would have had to grow a third block at every site.
2253    ///
2254    /// Peer of the sibling [`Self::push_dep`] typed-mutation dispatch
2255    /// (359fba5) — closes the two-side dispatch symmetry on the outer
2256    /// [`Caixa`] two-list dep-graph surface: `push_dep` on the mutation
2257    /// side, `deps_of` on the read side, both keyed on the same
2258    /// [`crate::dep::DepList`] discriminator. Same "one typed dispatch on
2259    /// the substrate primitive, thin projections at each consumer"
2260    /// discipline the sibling per-slot read accessors ([`Self::nome`]
2261    /// e6b7d97, [`Self::versao`], [`Self::kind`]) carry — extended onto
2262    /// the outer-[`Caixa`] typed-dispatch read surface.
2263    ///
2264    /// Declared `pub const fn` — every operator in the body is already
2265    /// `const`-callable (the [`crate::dep::DepList`] enum is a plain
2266    /// closed-set `#[derive(Copy)]` discriminator so the `match` arms
2267    /// are const-evaluable, and each arm forwards through the sibling
2268    /// `pub const fn` [`Self::deps`] / [`Self::deps_dev`] per-slot
2269    /// slice accessor). Pinned load-bearing by the paired
2270    /// [`caixa_deps_of_is_const_fn`][pin] wrapper test (a
2271    /// `const fn deps_of_via_const_fn(c: &Caixa, l: DepList) -> &[Dep]`
2272    /// that forwards through this accessor) — any future accidental
2273    /// downgrade to non-`const` fails the wrapper at caixa-core build
2274    /// time with E0015 (`cannot call non-const method`), strictly
2275    /// stronger than a runtime `assert!` and side-stepping the
2276    /// destructor-in-const restriction the `Caixa` fixture's owning
2277    /// carriers rule out on the direct-`const _: () = assert!(…)`
2278    /// residence. Peer of the sibling per-`Dep` outer-accessor
2279    /// family's parallel `const`-eval-surface pass and of the outer-
2280    /// `Caixa` slice-return accessor family's earlier pass (231a968)
2281    /// — same "one canonical dispatch per axis, `const`-eval posture
2282    /// pinned at the substrate primitive, thin projections at each
2283    /// consumer" discipline extended onto the outer-`Caixa`
2284    /// typed-dispatch read surface on the [`DepList`]-keyed dep-list
2285    /// axis.
2286    ///
2287    /// [DepList]: crate::dep::DepList
2288    /// [pin]: tests::caixa_deps_of_is_const_fn
2289    #[must_use]
2290    pub const fn deps_of(&self, list: crate::dep::DepList) -> &[Dep] {
2291        match list {
2292            crate::dep::DepList::Prod => self.deps(),
2293            crate::dep::DepList::Dev => self.deps_dev(),
2294        }
2295    }
2296
2297    /// Substrate-canonical per-[`Caixa`] typed-mutation dispatch every
2298    /// consumer that appends to one of the two dep-list axes keys off
2299    /// — routes the `(list: DepList, dep: Dep)` tuple through one typed
2300    /// method on the substrate primitive rather than the prior
2301    /// `feira add`-side open-coded `if self.dev { &mut caixa.deps_dev }
2302    /// else { &mut caixa.deps }` inline dispatch + open-coded
2303    /// `.iter().any(|d| d.nome == …)` dup-check cascade. Refuses the
2304    /// mutation with the canonical typed [`DepError::DuplicateNome`] on
2305    /// a within-list name collision — the same `list: &'static str`
2306    /// diagnostic shape [`Self::validate_deps`]'s per-list
2307    /// [`crate::render::insert_first_seen`] walk raises on the peer
2308    /// parse-time within-list dedup axis, so a future author reading a
2309    /// `feira add` refusal and a `feira build` refusal reaches for the
2310    /// same corrective surface without switching diagnostic idioms.
2311    ///
2312    /// The two-arm [`crate::dep::DepList`] enum is the substrate's
2313    /// closed-set typed carrier for the "runtime-closure `:deps` vs
2314    /// dev-only-closure `:deps-dev`" axis every dep-list consumer
2315    /// dispatches on — the compiler-checked exhaustiveness on the
2316    /// enum's `match` arms is the build-time guarantee that no future
2317    /// per-list mutation-site regresses to a bare-`bool`-flag
2318    /// (`is_dev: bool`) inline dispatch that a future third
2319    /// dep-list axis (a `:deps-build` build-only closure once the
2320    /// substrate grows cross-artifact heterogeneous dep-graphs, per
2321    /// CAIXA-SDLC §I) would silently split at every consumer.
2322    ///
2323    /// Same "one typed dispatch on the substrate primitive, thin
2324    /// projections at each consumer" discipline the sibling per-slot
2325    /// read accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`],
2326    /// [`Self::nome`] e6b7d97, [`Self::versao`], [`Self::kind`])
2327    /// carry — extended onto the outer-[`Caixa`] typed-mutation surface,
2328    /// the substrate's first typed-mutation dispatch on the top-level
2329    /// manifest. The prior `feira add` open-coded `&mut caixa.deps` /
2330    /// `&mut caixa.deps_dev` inline field-access + `bail!` string-
2331    /// diagnostic path routed no through-line back to the typed slot,
2332    /// so a future extension of either dep-list axis to a richer author
2333    /// surface (a per-cluster override the operator pins through a
2334    /// future `:placement`-scoped dep-list slot the CAIXA-SDLC §I
2335    /// roadmap acknowledges, an M4
2336    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
2337    /// admission-webhook that normalized the list at admission time)
2338    /// would have had to be threaded through the `feira add` mutation
2339    /// site in lockstep with every read consumer or one path would
2340    /// silently disagree with the other on which list a given dep lands
2341    /// in. Lifting the resolution rule to a typed method on the
2342    /// substrate primitive means every downstream dep-list-mutating
2343    /// consumer of the top-level manifest reaches for exactly one typed
2344    /// dispatch — the resolver's accept-set migrates as a unit on any
2345    /// future axis addition.
2346    ///
2347    /// # Errors
2348    ///
2349    /// Returns [`DepError::DuplicateNome`] with `list = list.as_str()`
2350    /// when another entry in the same list already carries the same
2351    /// `:nome` — the mutation is refused and the caller can surface the
2352    /// typed diagnostic to the author (the `feira add` verb routes the
2353    /// error through `anyhow::Error::from`, which preserves the
2354    /// canonical `#[error(...)]`-templated diagnostic body).
2355    pub fn push_dep(&mut self, list: crate::dep::DepList, dep: Dep) -> Result<(), DepError> {
2356        let target = match list {
2357            crate::dep::DepList::Prod => &mut self.deps,
2358            crate::dep::DepList::Dev => &mut self.deps_dev,
2359        };
2360        if target.iter().any(|d| d.nome() == dep.nome()) {
2361            return Err(DepError::duplicate_nome(dep.nome(), list.as_str()));
2362        }
2363        target.push(dep);
2364        Ok(())
2365    }
2366
2367    /// Substrate-canonical per-`Caixa` `:limits` M2 typed-slot outer-
2368    /// composite Lunatic-per-process wasm32-sandboxing-composite optional-
2369    /// composite-reference accessor every consumer of the top-level
2370    /// manifest's per-Servico [`LimitsSpec`] outer-composite reader keys
2371    /// off — returns the author-declared `:limits` typed composite
2372    /// verbatim as an `Option<&LimitsSpec>` reference over the same
2373    /// backing storage the raw `self.limits.as_ref()` field access
2374    /// borrows from, with `None` naming the "no `:limits` block
2375    /// authored — every per-axis Lunatic-sandbox cap defers to the
2376    /// wasm-engine-default arm named on the per-axis
2377    /// [`LimitsSpec::memory`] / [`LimitsSpec::fuel`] /
2378    /// [`LimitsSpec::wall_clock`] / [`LimitsSpec::cpu`] scalar-accessor
2379    /// docstrings" partition every downstream Servico-M2-overlay
2380    /// emitter treats as "emit nothing" and the sibling
2381    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate
2382    /// treats as "skip the per-axis
2383    /// [`crate::LimitsError::MemoryZero`] / `MemoryBelowWasm32Page` /
2384    /// `FuelZero` / `WallClockZero` / `CpuZero` refusal cascade".
2385    ///
2386    /// The outer `:limits` slot carries the M2 Servico-runtime typed
2387    /// composite — the load-bearing container of every Lunatic-shaped
2388    /// per-process wasm32-sandbox cap axis every long-running wasm
2389    /// component's runtime dispatches on (INSPIRATIONS §III.1 —
2390    /// Lunatic per-process linear-memory / fuel / wall-clock /
2391    /// millicore cap primitives translated onto pleme-io's typed
2392    /// `:limits :memory` / `:limits :fuel` / `:limits :wall-clock` /
2393    /// `:limits :cpu` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2394    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2395    /// chart both fan on). Every per-`:limits` axis threads through a
2396    /// lifted per-slot accessor on the [`LimitsSpec`] type: the
2397    /// [`LimitsSpec::memory`] wasm32 linear-memory byte-cap scalar
2398    /// accessor, the [`LimitsSpec::fuel`] wasmtime fuel-cap scalar
2399    /// accessor, the [`LimitsSpec::wall_clock`] per-call wall-clock
2400    /// deadline scalar accessor, and the [`LimitsSpec::cpu`]
2401    /// K8s-millicore soft-CPU-share scalar accessor. Every downstream
2402    /// consumer that reaches for a limits axis first passes through
2403    /// this outer accessor onto the composite and then dispatches
2404    /// onto the per-axis accessor — the two-level dispatch means
2405    /// every per-`:limits` reader now routes through a typed dispatch
2406    /// on the substrate primitive at both altitudes.
2407    ///
2408    /// Prior to this lift the `.limits` `Option<LimitsSpec>` composite
2409    /// was accessed inline at three production sites — the
2410    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate's
2411    /// `if let Some(l) = &caixa.limits { … }` traversal head
2412    /// (caixa-core/src/layout.rs:882, which drives the per-axis
2413    /// refusal cascade on the composite: the `LimitsError::MemoryZero`
2414    /// / `MemoryBelowWasm32Page` / `MemoryExceedsWasm32Max` /
2415    /// `FuelZero` / `FuelExceedsMax` / `WallClockZero` /
2416    /// `WallClockExceedsMax` / `CpuZero` / `CpuExceedsMax` refusals
2417    /// [`LimitsSpec::validate`] fans onto), the
2418    /// [`crate::render::servico_m2_overlay`] per-Servico M2 overlay
2419    /// emitter's `if let Some(limits) = &caixa.limits { … }` traversal
2420    /// head (caixa-core/src/render.rs:18504, which drives the
2421    /// `M2_KEY_LIMITS`-keyed `limits.is_empty()`-gated `serde_yaml`
2422    /// projection every `caixa-helm` / `caixa-flux` Servico values-
2423    /// block emitter fans on), and the
2424    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2425    /// set enumerator's `self.limits.is_some()` presence probe
2426    /// (caixa-core/src/manifest.rs:1788, which drives the
2427    /// `M2_AUTHOR_KEY_LIMITS` kebab-case author-label push every
2428    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2429    /// gate reads) — three open-coded outer-field accesses that
2430    /// expressed no compile-time link back to the typed slot at the
2431    /// [`Caixa`] altitude. A future extension of the `:limits` outer
2432    /// axis to a richer author surface (a multi-`:limits` list the M4
2433    /// CR materializer resolves per-CR at admission time so a Servico
2434    /// can expose a compute-heavy + IO-heavy limits pair, a per-
2435    /// cluster `:limits-overrides` slot the operator pins so a
2436    /// cluster-specific policy can tighten a caixa-declared cap
2437    /// without re-authoring the `caixa.lisp`, a promotion of the
2438    /// plain `Option<LimitsSpec>` to a richer
2439    /// `{static, dynamic}` partition once the wasm-engine's runtime-
2440    /// resolved dynamic-cap surface lands) would have had to be
2441    /// threaded through all three open-coded copies in lockstep or
2442    /// one consumer would silently disagree with the peers on which
2443    /// limits composite a given Caixa resolves to — the layout gate's
2444    /// per-axis bracket-dispatch seed reading the raw slot while the
2445    /// peer `servico_m2_overlay` emitter read an operator-resolved
2446    /// slot would silently split the build-time sandbox-shape gate
2447    /// from the runtime `ComputeUnit` CR emission gate, a three-
2448    /// consumer split at the layout gate, the M2 overlay emitter, and
2449    /// the declared-slot enumerator far from the source `caixa.lisp`
2450    /// with no field naming the limits-drift root cause. Lifting the
2451    /// resolution rule to a typed method on the substrate primitive
2452    /// means every downstream consumer of the caixa's per-`Caixa`
2453    /// Lunatic-sandboxing outer-composite surface reaches for exactly
2454    /// one typed dispatch — the resolver's accept-set migrates as a
2455    /// unit on any future axis addition.
2456    ///
2457    /// First outer top-level [`Caixa`] `Option<&Composite>`-return
2458    /// composite-reference accessor — opens the outer-`Caixa`
2459    /// `Option<&Composite>` composite-reference projection pattern the
2460    /// sibling per-`Caixa` `:behavior` [`crate::BehaviorSpec`] /
2461    /// `:politicas` [`crate::aplicacao::MeshPolicy`] / `:placement`
2462    /// [`crate::aplicacao::Placement`] / `:entrada`
2463    /// [`crate::aplicacao::Entrada`] future outer-composite lifts
2464    /// fold on. Peer of the M3 mesh-slot outer-composite family the
2465    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2466    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2467    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2468    /// accessors already close on the outer [`crate::AplicacaoSpec`]
2469    /// altitude — extends that "one typed dispatch on the substrate
2470    /// primitive, thin projections at each consumer" discipline onto
2471    /// the outer top-level [`Caixa`] altitude, opening the M2 Servico-
2472    /// runtime slot family's outer-composite axis. Returns
2473    /// `Option<&LimitsSpec>` (not the owning composite by copy or
2474    /// clone) because every downstream consumer of the limits
2475    /// composite treats it as a read-only per-axis dispatch source —
2476    /// the reference-view is the narrowest borrow that supports every
2477    /// present + roadmapped consumer (per-axis accessor dispatch,
2478    /// `.is_empty()`-gated overlay projection, presence-probe early
2479    /// return on the "author-omitted `:limits` ⇒ engine-default
2480    /// applies" partition) without cloning the composite through
2481    /// every consumer's fast path. The `Option` half of the return-
2482    /// type preserves the load-bearing "author-omitted `:limits` ⇒
2483    /// engine-default applies" partition (not a default composite the
2484    /// downstream must reject on emptiness) — the accessor projects
2485    /// the raw `Option<LimitsSpec>` slot's presence bit through the
2486    /// reference-return unchanged. Named `limits()` to match the
2487    /// storage field's name verbatim and the tatara-lisp author-
2488    /// surface term (`:limits`) the field's own docstring already
2489    /// carries.
2490    #[must_use]
2491    pub const fn limits(&self) -> Option<&LimitsSpec> {
2492        self.limits.as_ref()
2493    }
2494
2495    /// Substrate-canonical per-`Caixa` `:behavior` M2 typed-slot outer-
2496    /// composite OTP-`gen_server`-shaped callback-table optional-
2497    /// composite-reference accessor every consumer of the top-level
2498    /// manifest's per-Servico [`BehaviorSpec`] outer-composite reader
2499    /// keys off — returns the author-declared `:behavior` typed
2500    /// composite verbatim as an `Option<&BehaviorSpec>` reference over
2501    /// the same backing storage the raw `self.behavior.as_ref()` field
2502    /// access borrows from, with `None` naming the "no `:behavior`
2503    /// block authored — every per-callback OTP-shaped hook defers to
2504    /// the wasm-engine's runtime default arm named on the per-axis
2505    /// [`BehaviorSpec::on_init`] / [`BehaviorSpec::on_call`] /
2506    /// [`BehaviorSpec::on_cast`] / [`BehaviorSpec::on_info`] /
2507    /// [`BehaviorSpec::on_state_change`] /
2508    /// [`BehaviorSpec::on_terminate`] scalar-accessor docstrings"
2509    /// partition every downstream Servico-M2-overlay emitter treats as
2510    /// "emit nothing" and the sibling [`crate::StandardLayout::verify`]
2511    /// per-`:behavior` shape gate treats as "skip the per-arm
2512    /// [`crate::behavior::BehaviorError`] refusal cascade + the
2513    /// per-callback on-disk `MissingEntry` existence check".
2514    ///
2515    /// The outer `:behavior` slot carries the M2 Servico-runtime typed
2516    /// composite — the load-bearing container of every OTP-shaped
2517    /// per-Servico lifecycle-callback path axis every long-running wasm
2518    /// component's runtime dispatches on (INSPIRATIONS §II.3 — Erlang/
2519    /// OTP `gen_server:init/1` / `handle_call/3` / `handle_cast/2` /
2520    /// `handle_info/2` / `code_change/3` / `terminate/2` primitives
2521    /// translated onto pleme-io's typed `:behavior :on-init` /
2522    /// `:on-call` / `:on-cast` / `:on-info` / `:on-state-change` /
2523    /// `:on-terminate` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2524    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2525    /// chart both fan on). Every per-`:behavior` axis threads through a
2526    /// lifted per-callback accessor on the [`BehaviorSpec`] type
2527    /// (9b4ecde / d66c702 / 156ddbe / 99616ac / 4846cef / 701add7).
2528    /// Every downstream consumer that reaches for a behavior axis
2529    /// first passes through this outer accessor onto the composite
2530    /// and then dispatches onto the per-callback accessor — the
2531    /// two-level dispatch means every per-`:behavior` reader now
2532    /// routes through a typed dispatch on the substrate primitive at
2533    /// both altitudes.
2534    ///
2535    /// Composes cross-slot with the M2 `:upgrade-from` gate: the
2536    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
2537    /// cross-slot composition gate at [`crate::StandardLayout::verify`]
2538    /// keys the "per-version `:state-change` instruction must have a
2539    /// `:on-state-change` callback" precondition off this accessor's
2540    /// composite (the callback-side counterpart to the
2541    /// `:upgrade-from :instructions :state-change :script` refusal at
2542    /// the appup-side). Threading that gate's traversal input through
2543    /// this accessor closes the cross-slot invariant on the substrate
2544    /// primitive, not on the raw field.
2545    ///
2546    /// Prior to this lift the `.behavior` `Option<BehaviorSpec>`
2547    /// composite was accessed inline at four production sites — the
2548    /// [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
2549    /// `if let Some(b) = &caixa.behavior { … }` traversal head
2550    /// (caixa-core/src/layout.rs:896, which drives the per-arm
2551    /// `BehaviorError` refusal cascade + the per-callback on-disk
2552    /// [`crate::LayoutError::MissingEntry`] existence check under
2553    /// [`crate::render::LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`]),
2554    /// the [`crate::upgrade::validate_upgrade_from_against_behavior`]
2555    /// cross-slot composition gate's `caixa.behavior.as_ref()`
2556    /// traversal-input feed (caixa-core/src/layout.rs:1008, which
2557    /// drives the `:state-change` ↔ `:on-state-change` precondition
2558    /// refusal), the [`crate::render::servico_m2_overlay`] per-Servico
2559    /// M2 overlay emitter's `if let Some(behavior) = &caixa.behavior
2560    /// { … }` traversal head (caixa-core/src/render.rs:18513, which
2561    /// drives the `M2_KEY_BEHAVIOR`-keyed `behavior.is_empty()`-gated
2562    /// `serde_yaml` projection every `caixa-helm` / `caixa-flux`
2563    /// Servico values-block emitter fans on), and the
2564    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2565    /// set enumerator's `self.behavior.is_some()` presence probe
2566    /// (caixa-core/src/manifest.rs:1919, which drives the
2567    /// `M2_AUTHOR_KEY_BEHAVIOR` kebab-case author-label push every
2568    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2569    /// gate reads) — four open-coded outer-field accesses that
2570    /// expressed no compile-time link back to the typed slot at the
2571    /// [`Caixa`] altitude. A future extension of the `:behavior`
2572    /// outer axis to a richer author surface (a per-callback overlay
2573    /// resolver the operator materializes at admission time so a
2574    /// cluster-specific policy can inject a per-callback tracing
2575    /// interceptor without re-authoring the `caixa.lisp`, a promotion
2576    /// of the plain `Option<BehaviorSpec>` to a richer `{static,
2577    /// dynamic}` partition once a runtime-resolved behavior-swap
2578    /// surface lands, the M4 per-callback middleware chain the
2579    /// caixa-operator's per-Servico admission webhook keys off) would
2580    /// have had to be threaded through all four open-coded copies in
2581    /// lockstep or one consumer would silently disagree with the
2582    /// peers on which behavior composite a given Caixa resolves to —
2583    /// the layout gate's per-callback existence-check seed reading
2584    /// the raw slot while the peer `servico_m2_overlay` emitter read
2585    /// an operator-resolved slot would silently split the build-time
2586    /// callback-shape gate from the runtime `ComputeUnit` CR emission
2587    /// gate from the cross-slot `:state-change` composition gate from
2588    /// the M2 declared-slot enumerator, a four-consumer split far
2589    /// from the source `caixa.lisp` with no field naming the
2590    /// behavior-drift root cause. Lifting the resolution rule to a
2591    /// typed method on the substrate primitive means every downstream
2592    /// consumer of the caixa's per-`Caixa` OTP-callback-table outer-
2593    /// composite surface reaches for exactly one typed dispatch — the
2594    /// resolver's accept-set migrates as a unit on any future axis
2595    /// addition.
2596    ///
2597    /// Second outer top-level [`Caixa`] `Option<&Composite>`-return
2598    /// composite-reference accessor — sibling to the opening
2599    /// [`Self::limits`] (b2bd9d7) accessor on the outer-`Caixa`
2600    /// `Option<&Composite>` composite-reference sub-family, extends
2601    /// the "one typed dispatch on the substrate primitive, thin
2602    /// projections at each consumer" discipline onto the second of
2603    /// the three M2 Servico-runtime slots. The remaining
2604    /// `Option<&Composite>` axes at the outer top-level [`Caixa`]
2605    /// altitude — the M3 mesh-slot family (`:politicas`,
2606    /// `:placement`, `:entrada` — already closed on the inner
2607    /// [`crate::AplicacaoSpec`] altitude via 534dc21 / 9abb8f0 /
2608    /// d32111c) — remain the future sibling lifts on the outer
2609    /// top-level projection. Returns `Option<&BehaviorSpec>` (not
2610    /// the owning composite by copy or clone) because every
2611    /// downstream consumer of the behavior composite treats it as a
2612    /// read-only per-callback dispatch source — the reference-view is
2613    /// the narrowest borrow that supports every present + roadmapped
2614    /// consumer (per-callback accessor dispatch, `.is_empty()`-gated
2615    /// overlay projection, presence-probe early return on the
2616    /// "author-omitted `:behavior` ⇒ runtime-default applies"
2617    /// partition, cross-slot `:state-change` composition input)
2618    /// without cloning the composite through every consumer's fast
2619    /// path. The `Option` half of the return-type preserves the
2620    /// load-bearing "author-omitted `:behavior` ⇒ runtime-default
2621    /// applies" partition (not a default composite the downstream
2622    /// must reject on emptiness) — the accessor projects the raw
2623    /// `Option<BehaviorSpec>` slot's presence bit through the
2624    /// reference-return unchanged. Named `behavior()` to match the
2625    /// storage field's name verbatim and the tatara-lisp author-
2626    /// surface term (`:behavior`) the field's own docstring already
2627    /// carries.
2628    #[must_use]
2629    pub const fn behavior(&self) -> Option<&crate::BehaviorSpec> {
2630        self.behavior.as_ref()
2631    }
2632
2633    /// Substrate-canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
2634    /// composite MESH-COMPOSITION-shaped mesh-policy optional-composite-
2635    /// reference accessor every consumer of the top-level manifest's
2636    /// per-Aplicacao [`crate::aplicacao::MeshPolicy`] outer-composite
2637    /// reader keys off — returns the author-declared `:politicas` typed
2638    /// composite verbatim as an `Option<&MeshPolicy>` reference over the
2639    /// same backing storage the raw `self.politicas.as_ref()` field
2640    /// access borrows from, with `None` naming the "no `:politicas`
2641    /// block authored — every per-axis mesh-policy scalar defers to the
2642    /// cluster-default arm named on the per-axis
2643    /// [`crate::aplicacao::MeshPolicy::timeout`] /
2644    /// [`crate::aplicacao::MeshPolicy::retries`] /
2645    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] /
2646    /// [`crate::aplicacao::MeshPolicy::mtls_required`] /
2647    /// [`crate::aplicacao::MeshPolicy::rate_limit`] scalar-accessor
2648    /// docstrings" partition every downstream caixa-mesh /
2649    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2650    /// "emit no per-`:politicas` overlay" and the sibling
2651    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2652    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2653    /// arm.
2654    ///
2655    /// The outer `:politicas` slot carries the M3 mesh-slot per-
2656    /// Aplicacao typed composite — the load-bearing container of every
2657    /// mesh-level policy axis every Cilium NetworkPolicy / Gateway API
2658    /// v1.x HTTPRoute / future M4 per-edge policy overlay emitter fans
2659    /// on (MESH-COMPOSITION §III.2 — the Aplicacao's typed mesh-policy
2660    /// composite; §V — the "no infinite blocking" per-call deadline +
2661    /// "sandboxing-by-default" mTLS-enforcement CSE invariants; §III.3
2662    /// — the typed inter-Servico contrato-edge overlay the per-`(:de,
2663    /// :para)` mesh renderer keys off). Every per-`:politicas` axis
2664    /// threads through a lifted per-slot accessor on the
2665    /// [`crate::aplicacao::MeshPolicy`] type: the
2666    /// [`crate::aplicacao::MeshPolicy::mtls_required`] (c0110f1) Cilium
2667    /// mTLS-enforcement toggle, the
2668    /// [`crate::aplicacao::MeshPolicy::retries`] (bdfb399) transient-
2669    /// failure retry budget, the [`crate::aplicacao::MeshPolicy::timeout`]
2670    /// (7073d0f) Gateway-API per-call deadline, the
2671    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] (b0e741a)
2672    /// Envoy-outlier-detection composite. Every downstream consumer
2673    /// that reaches for a mesh-policy axis first passes through this
2674    /// outer accessor onto the composite and then dispatches onto the
2675    /// per-axis accessor — the two-level dispatch means every per-
2676    /// `:politicas` reader now routes through a typed dispatch on the
2677    /// substrate primitive at both altitudes.
2678    ///
2679    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2680    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2681    /// author-omitted arm onto the [`crate::aplicacao::MeshPolicy::default`]
2682    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::politicas`]
2683    /// (534dc21) `&MeshPolicy`-return accessor observes a typed
2684    /// composite whether or not the author declared the outer slot.
2685    /// The outer accessor preserves the "author-omitted vs authored-
2686    /// empty" partition the inner accessor's `is_empty()`-gated
2687    /// renderer overlay collapses — routing the presence bit through
2688    /// this accessor keeps the [`Self::declared_mesh_slots`] M3 kind-
2689    /// coherence enumerator's `M3_AUTHOR_KEY_POLITICAS` push separate
2690    /// from the inner `MeshPolicy::is_empty()`-gated overlay elision.
2691    ///
2692    /// Prior to this lift the `.politicas` `Option<MeshPolicy>`
2693    /// composite was accessed inline at two production sites — the
2694    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2695    /// `self.politicas.clone().unwrap_or_default()` traversal head
2696    /// (caixa-core/src/manifest.rs:1899, which drives the fold onto
2697    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2698    /// arm the inner [`crate::AplicacaoSpec::politicas`] accessor
2699    /// then observes), and the [`Self::declared_mesh_slots`] M3
2700    /// declared-slot-set enumerator's `self.politicas.is_some()`
2701    /// presence probe (caixa-core/src/manifest.rs:1961, which drives
2702    /// the `M3_AUTHOR_KEY_POLITICAS` kebab-case author-label push
2703    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2704    /// coherence gate reads) — two open-coded outer-field accesses
2705    /// that expressed no compile-time link back to the typed slot at
2706    /// the [`Caixa`] altitude. A future extension of the `:politicas`
2707    /// outer axis to a richer author surface (a per-cluster
2708    /// `:politicas-overrides` slot the operator materializes at
2709    /// admission time so a cluster-specific policy can tighten the
2710    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2711    /// promotion of the plain `Option<MeshPolicy>` to a richer
2712    /// `{static, dynamic}` partition once the M4 per-edge
2713    /// contrato-scoped policy-override surface lands, the M5 traffic-
2714    /// shaping composition the caixa-operator's per-Aplicacao mesh
2715    /// admission webhook keys off) would have had to be threaded
2716    /// through both open-coded copies in lockstep or the Aplicacao-
2717    /// composition seed's default-fold arm would silently disagree
2718    /// with the M3 declared-slot enumerator on which policy composite
2719    /// a given Caixa resolves to — the seed reading an operator-
2720    /// resolved slot while the enumerator's presence probe read the
2721    /// raw slot would silently split the build-time mesh-artifact
2722    /// emission gate from the M3 declared-slot enumerator's kind-
2723    /// coherence gate, a two-consumer split far from the source
2724    /// `caixa.lisp` with no field naming the policy-drift root cause.
2725    /// Lifting the resolution rule to a typed method on the substrate
2726    /// primitive means every downstream consumer of the caixa's per-
2727    /// `Caixa` MESH-COMPOSITION mesh-policy outer-composite surface
2728    /// reaches for exactly one typed dispatch — the resolver's
2729    /// accept-set migrates as a unit on any future axis addition.
2730    ///
2731    /// Third outer top-level [`Caixa`] `Option<&Composite>`-return
2732    /// composite-reference accessor — sibling to the opening
2733    /// [`Self::limits`] (b2bd9d7) and [`Self::behavior`] (35d8b52)
2734    /// accessors on the outer-`Caixa` `Option<&Composite>` composite-
2735    /// reference sub-family, extends the "one typed dispatch on the
2736    /// substrate primitive, thin projections at each consumer"
2737    /// discipline onto the first of the three M3 mesh-slot axes.
2738    /// Peer of the closed inner mesh-slot outer-composite family the
2739    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2740    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2741    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2742    /// accessor pins already close on the inner [`crate::AplicacaoSpec`]
2743    /// altitude — opens the outer top-level [`Caixa`] altitude's M3
2744    /// mesh-slot arm of the composite-reference family the remaining
2745    /// two axes (`:placement`, `:entrada`) fold onto in future
2746    /// sibling lifts. Returns `Option<&MeshPolicy>` (not the owning
2747    /// composite by copy or clone) because every downstream consumer
2748    /// of the mesh-policy composite treats it as a read-only per-axis
2749    /// dispatch source — the reference-view is the narrowest borrow
2750    /// that supports every present + roadmapped consumer (per-axis
2751    /// accessor dispatch, `.is_empty()`-gated overlay projection,
2752    /// presence-probe early return on the "author-omitted `:politicas`
2753    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2754    /// seed's default-fold arm) without cloning the composite through
2755    /// every consumer's fast path. The `Option` half of the return-
2756    /// type preserves the load-bearing "author-omitted `:politicas` ⇒
2757    /// cluster-default applies" partition (not a default composite
2758    /// the downstream must reject on emptiness) — the accessor
2759    /// projects the raw `Option<MeshPolicy>` slot's presence bit
2760    /// through the reference-return unchanged. Named `politicas()` to
2761    /// match the storage field's name verbatim and the tatara-lisp
2762    /// author-surface term (`:politicas`) the field's own docstring
2763    /// already carries.
2764    #[must_use]
2765    pub const fn politicas(&self) -> Option<&crate::aplicacao::MeshPolicy> {
2766        self.politicas.as_ref()
2767    }
2768
2769    /// Substrate-canonical per-`Caixa` `:placement` M3 mesh-slot outer-
2770    /// composite MESH-COMPOSITION-shaped distribution optional-composite-
2771    /// reference accessor every consumer of the top-level manifest's
2772    /// per-Aplicacao [`crate::aplicacao::Placement`] outer-composite
2773    /// reader keys off — returns the author-declared `:placement` typed
2774    /// composite verbatim as an `Option<&Placement>` reference over the
2775    /// same backing storage the raw `self.placement.as_ref()` field
2776    /// access borrows from, with `None` naming the "no `:placement`
2777    /// block authored — every per-axis placement scalar defers to the
2778    /// cluster-default arm named on the per-axis
2779    /// [`crate::aplicacao::Placement::estrategia`] /
2780    /// [`crate::aplicacao::Placement::clusters`] /
2781    /// [`crate::aplicacao::Placement::affinity`] /
2782    /// [`crate::aplicacao::Placement::shard_key`] scalar-accessor
2783    /// docstrings" partition every downstream caixa-mesh /
2784    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2785    /// "emit no per-`:placement` overlay" and the sibling
2786    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2787    /// the [`crate::aplicacao::Placement::default`] cluster-default arm.
2788    ///
2789    /// The outer `:placement` slot carries the M3 mesh-slot per-
2790    /// Aplicacao typed distribution composite — the load-bearing
2791    /// container of every where-does-this-Aplicacao-run axis every
2792    /// caixa-mesh programs.yaml per-cluster distribution overlay /
2793    /// caixa-flux per-Aplicacao GitRepository/HelmRelease fan-out /
2794    /// future M4 per-Aplicacao Akka-style cluster-sharding entity-id
2795    /// resolver emitter fans on (MESH-COMPOSITION §II.4 — the
2796    /// Aplicacao's typed distribution composite; §V CSE invariants —
2797    /// "distribution is a first-class typed composite, not a runtime
2798    /// scheduler hint" the per-axis scalars enforce; §III.3 — the
2799    /// typed inter-Servico contrato-edge overlay the per-cluster
2800    /// mesh renderer keys off). Every per-`:placement` axis threads
2801    /// through a lifted per-slot accessor on the
2802    /// [`crate::aplicacao::Placement`] type: the
2803    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
2804    /// MESH-COMPOSITION distribution-strategy scalar, the
2805    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7) per-cluster
2806    /// distribution-target slice, the [`crate::aplicacao::Placement::affinity`]
2807    /// M3-Adaptive-compression-hint optional-scalar, and the
2808    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) Akka-cluster-
2809    /// sharding extractor-expression optional-scalar. Every downstream
2810    /// consumer that reaches for a placement axis first passes through
2811    /// this outer accessor onto the composite and then dispatches onto
2812    /// the per-axis accessor — the two-level dispatch means every per-
2813    /// `:placement` reader now routes through a typed dispatch on the
2814    /// substrate primitive at both altitudes.
2815    ///
2816    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2817    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2818    /// author-omitted arm onto the [`crate::aplicacao::Placement::default`]
2819    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::placement`]
2820    /// (9abb8f0) `&Placement`-return accessor observes a typed composite
2821    /// whether or not the author declared the outer slot. The outer
2822    /// accessor preserves the "author-omitted vs authored-empty" partition
2823    /// the inner accessor collapses at the cluster-default fold —
2824    /// routing the presence bit through this accessor keeps the
2825    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2826    /// `M3_AUTHOR_KEY_PLACEMENT` push separate from the inner
2827    /// [`crate::AplicacaoSpec::validate_placement`]-gated overlay
2828    /// dispatch.
2829    ///
2830    /// Prior to this lift the `.placement` `Option<Placement>`
2831    /// composite was accessed inline at two production sites — the
2832    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2833    /// `self.placement.clone().unwrap_or_default()` traversal head
2834    /// (caixa-core/src/manifest.rs:2036, which drives the fold onto
2835    /// the [`crate::aplicacao::Placement::default`] cluster-default
2836    /// arm the inner [`crate::AplicacaoSpec::placement`] accessor
2837    /// then observes), and the [`Self::declared_mesh_slots`] M3
2838    /// declared-slot-set enumerator's `self.placement.is_some()`
2839    /// presence probe (caixa-core/src/manifest.rs:2100, which drives
2840    /// the `M3_AUTHOR_KEY_PLACEMENT` kebab-case author-label push
2841    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2842    /// coherence gate reads) — two open-coded outer-field accesses
2843    /// that expressed no compile-time link back to the typed slot at
2844    /// the [`Caixa`] altitude. A future extension of the `:placement`
2845    /// outer axis to a richer author surface (a per-cluster
2846    /// `:placement-overrides` slot the operator materializes at
2847    /// admission time so a cluster-specific placement can tighten the
2848    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2849    /// per-tenant placement-alias table the M4
2850    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer resolves
2851    /// per-CR at admission time, a promotion of the plain
2852    /// `Option<Placement>` to a richer `{static, dynamic}` partition
2853    /// once Orleans-style virtual-actor dynamic placement comes into
2854    /// typed scope) would have had to be threaded through both open-
2855    /// coded copies in lockstep or the Aplicacao-composition seed's
2856    /// default-fold arm would silently disagree with the M3 declared-
2857    /// slot enumerator on which distribution composite a given Caixa
2858    /// resolves to — the seed reading an operator-resolved slot while
2859    /// the enumerator's presence probe read the raw slot would
2860    /// silently split the build-time distribution-artifact emission
2861    /// gate from the M3 declared-slot enumerator's kind-coherence
2862    /// gate, a two-consumer split far from the source `caixa.lisp`
2863    /// with no field naming the distribution-drift root cause.
2864    /// Lifting the resolution rule to a typed method on the substrate
2865    /// primitive means every downstream consumer of the caixa's per-
2866    /// `Caixa` MESH-COMPOSITION distribution outer-composite surface
2867    /// reaches for exactly one typed dispatch — the resolver's
2868    /// accept-set migrates as a unit on any future axis addition.
2869    ///
2870    /// Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
2871    /// composite-reference accessor — sibling to the opening
2872    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) M2-
2873    /// Servico-runtime pair and the peer [`Self::politicas`] (5d23d29)
2874    /// M3-mesh-slot arm on the outer-`Caixa` `Option<&Composite>`
2875    /// composite-reference sub-family, folds on the "one typed
2876    /// dispatch on the substrate primitive, thin projections at each
2877    /// consumer" discipline extended onto the second of the three M3
2878    /// mesh-slot axes. Peer of the closed inner mesh-slot outer-
2879    /// composite family the sibling
2880    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2881    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2882    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2883    /// accessor pins already close on the inner
2884    /// [`crate::AplicacaoSpec`] altitude — folds on the outer top-
2885    /// level [`Caixa`] altitude's M3 mesh-slot arm the sibling
2886    /// [`Self::politicas`] opened, extending the discipline onto the
2887    /// second of the three M3 mesh-slot axes. The remaining M3
2888    /// mesh-slot axis (`:entrada`) folds onto this accessor's
2889    /// discipline in the final sibling lift, closing the outer top-
2890    /// level [`Caixa`] `Option<&Composite>` M3 mesh-slot sub-family.
2891    /// Returns `Option<&Placement>` (not the owning composite by copy
2892    /// or clone) because every downstream consumer of the placement
2893    /// composite treats it as a read-only per-axis dispatch source —
2894    /// the reference-view is the narrowest borrow that supports every
2895    /// present + roadmapped consumer (per-axis accessor dispatch,
2896    /// serde composite-serialization on the programs.yaml overlay,
2897    /// presence-probe early return on the "author-omitted `:placement`
2898    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2899    /// seed's default-fold arm) without cloning the composite through
2900    /// every consumer's fast path. The `Option` half of the return-
2901    /// type preserves the load-bearing "author-omitted `:placement` ⇒
2902    /// cluster-default applies" partition (not a default composite
2903    /// the downstream must reject on emptiness) — the accessor
2904    /// projects the raw `Option<Placement>` slot's presence bit
2905    /// through the reference-return unchanged. Named `placement()` to
2906    /// match the storage field's name verbatim and the tatara-lisp
2907    /// author-surface term (`:placement`) the field's own docstring
2908    /// already carries.
2909    #[must_use]
2910    pub const fn placement(&self) -> Option<&crate::aplicacao::Placement> {
2911        self.placement.as_ref()
2912    }
2913
2914    /// Substrate-canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
2915    /// composite MESH-COMPOSITION-shaped external-gateway optional-
2916    /// composite-reference accessor every consumer of the top-level
2917    /// manifest's per-Aplicacao [`crate::aplicacao::Entrada`] outer-
2918    /// composite reader keys off — returns the author-declared
2919    /// `:entrada` typed composite verbatim as an `Option<&Entrada>`
2920    /// reference over the same backing storage the raw
2921    /// `self.entrada.as_ref()` field access borrows from, with `None`
2922    /// naming the "no `:entrada` block authored — this Aplicacao is
2923    /// cluster-internal, no `Gateway`/`HTTPRoute` fan-out emitted"
2924    /// partition every downstream caixa-mesh Gateway-API artifact
2925    /// emitter treats as "emit no gateway-listener + no `HTTPRoute`
2926    /// backend for this Aplicacao" and the sibling
2927    /// [`Self::aplicacao_view`] Aplicacao-composition seed forwards
2928    /// verbatim (unlike the peer `:politicas` / `:placement` arms,
2929    /// `:entrada` has no cluster-default fold — an omitted `:entrada`
2930    /// stays `None` on the projected [`crate::AplicacaoSpec`] and the
2931    /// peer inner [`crate::AplicacaoSpec::entrada`] accessor observes
2932    /// the same `Option<&Entrada>` presence bit unchanged).
2933    ///
2934    /// The outer `:entrada` slot carries the M3 mesh-slot per-
2935    /// Aplicacao typed external-gateway composite — the load-bearing
2936    /// container of every how-does-the-outside-world-reach-this-
2937    /// Aplicacao axis every caixa-mesh `Gateway`/`HTTPRoute` fan-out
2938    /// emitter fans on (MESH-COMPOSITION §II.5 — the Aplicacao's typed
2939    /// external-entry composite; §V CSE invariants — "the external
2940    /// gateway is a first-class typed composite, not a per-Servico
2941    /// ingress annotation" the per-axis scalars enforce; §III.4 — the
2942    /// typed hostname + backend-Servico pair the per-cluster Gateway-
2943    /// API renderer keys off). Every per-`:entrada` axis threads
2944    /// through a lifted per-slot accessor on the
2945    /// [`crate::aplicacao::Entrada`] type: the
2946    /// [`crate::aplicacao::Entrada::host`] Gateway-API `Listener.hostname`
2947    /// scalar, the [`crate::aplicacao::Entrada::para`] backend-Servico
2948    /// caixa-name scalar, the [`crate::aplicacao::Entrada::paths`]
2949    /// per-rule `HTTPPathMatch` list, the [`crate::aplicacao::Entrada::port`]
2950    /// backend `trigger.service.port` scalar, and the
2951    /// [`crate::aplicacao::Entrada::resolved_paths`] URL-path fallback
2952    /// resolver every HTTPRoute-aware renderer consumes. Every
2953    /// downstream consumer that reaches for an entry axis first passes
2954    /// through this outer accessor onto the composite and then
2955    /// dispatches onto the per-axis accessor — the two-level dispatch
2956    /// means every per-`:entrada` reader now routes through a typed
2957    /// dispatch on the substrate primitive at both altitudes.
2958    ///
2959    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2960    /// seed: the Aplicacao-view builder forwards the outer `Option`
2961    /// arm verbatim (no default fold — `:entrada` is inherently
2962    /// optional; a cluster-internal Aplicacao has no external gateway
2963    /// at all, not "an external gateway that defaults to nothing"), so
2964    /// the peer inner [`crate::AplicacaoSpec::entrada`] (d32111c)
2965    /// `Option<&Entrada>`-return accessor observes the same presence
2966    /// bit whether or not the author declared the outer slot. Routing
2967    /// the presence bit through this accessor keeps the
2968    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2969    /// `M3_AUTHOR_KEY_ENTRADA` push separate from the inner
2970    /// [`crate::AplicacaoSpec::validate_entrada`]-gated
2971    /// hostname/backend/path emission dispatch.
2972    ///
2973    /// Prior to this lift the `.entrada` `Option<Entrada>` composite
2974    /// was accessed inline at two production sites — the
2975    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2976    /// `self.entrada.clone()` traversal head (caixa-core/src/manifest.rs:2182,
2977    /// which drives the forward onto the peer inner
2978    /// [`crate::AplicacaoSpec::entrada`] accessor the caixa-mesh
2979    /// Gateway-API fan-out then observes), and the
2980    /// [`Self::declared_mesh_slots`] M3 declared-slot-set enumerator's
2981    /// `self.entrada.is_some()` presence probe (caixa-core/src/manifest.rs:2248,
2982    /// which drives the `M3_AUTHOR_KEY_ENTRADA` kebab-case author-
2983    /// label push every [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
2984    /// kind-coherence gate reads) — two open-coded outer-field
2985    /// accesses that expressed no compile-time link back to the typed
2986    /// slot at the [`Caixa`] altitude. A future extension of the
2987    /// `:entrada` outer axis to a richer author surface (a per-cluster
2988    /// `:entrada-overrides` slot the operator materializes at admission
2989    /// time so a cluster-specific hostname can pin the caixa-declared
2990    /// bound without re-authoring the `caixa.lisp`, a per-tenant
2991    /// gateway-alias table the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
2992    /// CR materializer resolves per-CR at admission time, a promotion
2993    /// of the plain `Option<Entrada>` to a richer
2994    /// `{public, private, internal}` partition once Cilium-identity-
2995    /// scoped internal gateways come into typed scope) would have had
2996    /// to be threaded through both open-coded copies in lockstep or the
2997    /// Aplicacao-composition seed's forward arm would silently
2998    /// disagree with the M3 declared-slot enumerator on which external-
2999    /// gateway composite a given Caixa resolves to — the seed reading
3000    /// an operator-resolved slot while the enumerator's presence probe
3001    /// read the raw slot would silently split the build-time gateway-
3002    /// artifact emission gate from the M3 declared-slot enumerator's
3003    /// kind-coherence gate, a two-consumer split far from the source
3004    /// `caixa.lisp` with no field naming the entry-drift root cause.
3005    /// Lifting the resolution rule to a typed method on the substrate
3006    /// primitive means every downstream consumer of the caixa's per-
3007    /// `Caixa` MESH-COMPOSITION external-gateway outer-composite
3008    /// surface reaches for exactly one typed dispatch — the resolver's
3009    /// accept-set migrates as a unit on any future axis addition.
3010    ///
3011    /// Fifth and final outer top-level [`Caixa`] `Option<&Composite>`-
3012    /// return composite-reference accessor — closes the outer-`Caixa`
3013    /// `Option<&Composite>` composite-reference sub-family opened by
3014    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) on the
3015    /// M2 Servico-runtime arm and extended onto the M3 mesh-slot arm
3016    /// by [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074),
3017    /// folds on the "one typed dispatch on the substrate primitive,
3018    /// thin projections at each consumer" discipline extended onto the
3019    /// third and final M3 mesh-slot axis. Peer of the closed inner
3020    /// mesh-slot outer-composite family the sibling
3021    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
3022    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
3023    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
3024    /// accessor pins already close on the inner
3025    /// [`crate::AplicacaoSpec`] altitude — this lift closes the mirror
3026    /// sub-family on the outer top-level [`Caixa`] altitude, so both
3027    /// altitudes of the outer-composite reference-return discipline
3028    /// (per-`Caixa` outer-slot presence + per-`AplicacaoSpec` inner-
3029    /// slot presence) now carry the full five-arm accept-set behind a
3030    /// typed dispatch on the substrate primitive. Returns
3031    /// `Option<&Entrada>` (not the owning composite by copy or clone)
3032    /// because every downstream consumer of the entrada composite
3033    /// treats it as a read-only per-axis dispatch source — the
3034    /// reference-view is the narrowest borrow that supports every
3035    /// present + roadmapped consumer (per-axis accessor dispatch,
3036    /// serde composite-serialization on the programs.yaml overlay,
3037    /// presence-probe early return on the "author-omitted `:entrada`
3038    /// ⇒ cluster-internal Aplicacao" partition, `Aplicacao`-composition
3039    /// seed's forward arm) without cloning the composite through every
3040    /// consumer's fast path. The `Option` half of the return-type
3041    /// preserves the load-bearing "author-omitted `:entrada` ⇒
3042    /// cluster-internal Aplicacao" partition (not a default composite
3043    /// the downstream must reject on emptiness — a cluster-internal
3044    /// Aplicacao has no external gateway at all, not "a default gateway
3045    /// that emits nothing"); the accessor projects the raw
3046    /// `Option<Entrada>` slot's presence bit through the reference-
3047    /// return unchanged. Named `entrada()` to match the storage field's
3048    /// name verbatim and the tatara-lisp author-surface term
3049    /// (`:entrada`) the field's own docstring already carries.
3050    #[must_use]
3051    pub const fn entrada(&self) -> Option<&crate::aplicacao::Entrada> {
3052        self.entrada.as_ref()
3053    }
3054
3055    /// Substrate-canonical per-`Caixa` `:ci` slot accessor — returns the
3056    /// author-declared typed CI run (`canteiro_types::CiRun`) verbatim as
3057    /// an `Option<&CiRun>`, borrowed from the typed slot's own
3058    /// `Option<CiRun>` storage. `None` when the slot is absent (every
3059    /// non-`Acao` kind, and an `Acao` caixa that hasn't declared `:ci`
3060    /// yet — the latter is caught by [`crate::LayoutError::MissingCi`],
3061    /// not silently accepted).
3062    ///
3063    /// Named `ci()` to match the storage field's name and the
3064    /// tatara-lisp author surface (`:ci`); mirrors the sibling
3065    /// `Option<&Composite>` accessors on this same `Caixa` altitude
3066    /// ([`Self::limits`], [`Self::behavior`], [`Self::politicas`],
3067    /// [`Self::placement`], [`Self::entrada`]) — one typed dispatch on
3068    /// the substrate primitive rather than an open-coded `self.ci.as_ref()`
3069    /// at every consumer.
3070    #[must_use]
3071    pub const fn ci(&self) -> Option<&canteiro_types::CiRun> {
3072        self.ci.as_ref()
3073    }
3074
3075    /// Substrate-canonical per-`Caixa` `:estrategia` M2 supervisor-tree-
3076    /// slot flat-spread OTP-shaped sibling-restart-strategy discriminant
3077    /// accessor every consumer of the top-level manifest's per-Supervisor
3078    /// restart-strategy axis keys off — returns the author-declared
3079    /// `:estrategia` variant verbatim as an `Option<RestartStrategy>`,
3080    /// `Copy`-projected from the typed slot's own
3081    /// `Option<crate::supervisor::RestartStrategy>` storage. Optional
3082    /// (`:estrategia` is a flat-spread supervisor-only slot every
3083    /// non-`Supervisor`-kind `defcaixa` carries as `None` by
3084    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3085    /// still omit to defer to [`RestartStrategy::default`] —
3086    /// [`RestartStrategy::OneForOne`] — through the [`Self::supervisor_view`]
3087    /// `unwrap_or_default()` fold; a returned `None` degenerates to the
3088    /// [`SupervisorSpec::default`]-inherited strategy without any silent
3089    /// promotion to a fresh explicit variant at the accessor boundary).
3090    ///
3091    /// The `:estrategia` slot carries the M2 typed OTP-shaped sibling-
3092    /// restart-strategy discriminant every substrate-side per-Supervisor
3093    /// dispatch fans on (INSPIRATIONS §II.2 — OTP `supervisor:strategy`
3094    /// closed-set `one_for_one | one_for_all | rest_for_one |
3095    /// simple_one_for_one` algebra translated onto pleme-io's typed
3096    /// [`RestartStrategy`] enum; CAIXA-SDLC §II — the M2 supervisor-tree
3097    /// slot algebra the operator's hierarchical reconciliation scheduler
3098    /// fans on). The slot is *flat-spread* on the outer top-level `Caixa`
3099    /// (per the field-shape docstring at caixa-core/src/manifest.rs — "The
3100    /// supervisor slots are flat on Caixa (vs nested under a
3101    /// `SupervisorSpec` sub-form) to keep tatara-lisp authoring at one
3102    /// level of nesting"), so the accessor's altitude is the outer
3103    /// [`Caixa`] surface rather than the composed [`SupervisorSpec`]
3104    /// altitude the sibling [`crate::supervisor::SupervisorSpec::estrategia`]
3105    /// (eafb619) accessor keys off. The two typed axes — the outer
3106    /// author-surface `Option<RestartStrategy>` on the [`Caixa`] altitude
3107    /// (author-omitted arm carried as `None`) and the inner post-
3108    /// composition `RestartStrategy` on the [`SupervisorSpec`] altitude
3109    /// (`Option` collapsed through the [`Self::supervisor_view`]
3110    /// `unwrap_or_default()` fold) — now share one accessor discipline for
3111    /// the shared substrate concept "the author-declared OTP-shaped
3112    /// sibling-restart-strategy variant that partitions the downstream
3113    /// per-Supervisor renderer's per-arm fan-out"; the outer-altitude
3114    /// `None` arm is the pre-composition presence bit every declared-slot
3115    /// enumerator ([`Self::declared_supervisor_slots`]) reads, and the
3116    /// inner-altitude non-`Option` `RestartStrategy` is the post-
3117    /// composition partition-dispatch input every strategy-arm consumer
3118    /// ([`SupervisorSpec::validate`], the future wasm-operator's per-
3119    /// Supervisor sibling-restart branch, the future M4
3120    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
3121    /// webhook) fans on.
3122    ///
3123    /// Prior to this lift the `.estrategia` field was accessed inline at
3124    /// two production sites in `caixa-core/src/manifest.rs` — the
3125    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`
3126    /// presence-probe arm at `if self.estrategia.is_some()` (which drives
3127    /// the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3128    /// coherence gate's per-slot label push) and the [`Self::supervisor_view`]
3129    /// `SupervisorSpec` construction site at `estrategia:
3130    /// self.estrategia.unwrap_or_default()` (which composes the flat-
3131    /// spread outer author-surface `Option<RestartStrategy>` onto the
3132    /// inner post-composition [`SupervisorSpec`] `RestartStrategy` field
3133    /// the [`SupervisorSpec::estrategia`] accessor keys off) — two open-
3134    /// coded field-accesses that expressed no compile-time link back to
3135    /// the typed slot. A future extension of the outer `:estrategia` axis
3136    /// to a richer author surface (a per-cluster strategy override the
3137    /// operator pins through a future `:estrategia-overrides` overlay the
3138    /// MESH-COMPOSITION §III.2 supervision-canary roadmap acknowledges,
3139    /// a per-tenant strategy-alias table the M4 CR materializer resolves
3140    /// per-CR, a per-Supervisor dynamic strategy derivation the future
3141    /// adaptive-supervision engine computes from child-failure-history
3142    /// topology, a per-child-cohort strategy split the future
3143    /// `RestForCohort` extension the INSPIRATIONS.md §II.2 Erlang/OTP
3144    /// absorption roadmap acknowledges, a promotion of the plain
3145    /// `Option<RestartStrategy>` to a richer
3146    /// `AuthorDeclaredStrategy { declared, overlay }` newtype once the
3147    /// operator-resolved overlay lands) would have had to be threaded
3148    /// through both open-coded copies in lockstep or the enumerator's
3149    /// presence probe and the composition site's `unwrap_or_default()`
3150    /// fold would silently disagree on which strategy a given [`Caixa`]
3151    /// resolves to (an author's `:estrategia OneForAll` would satisfy
3152    /// the enumerator's presence probe while the composition site
3153    /// silently rendered a stale `OneForOne`, or vice versa). Lifting
3154    /// the resolution rule to a typed method on the substrate primitive
3155    /// means every downstream consumer of the caixa's per-`Caixa` outer-
3156    /// altitude sibling-restart-strategy surface reaches for exactly one
3157    /// typed dispatch — the resolver's accept-set migrates as a unit on
3158    /// any future axis addition.
3159    ///
3160    /// First outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3161    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3162    /// axes — opens the outer-`Caixa` `Option<Copy>` flat-spread
3163    /// projection pattern the sibling per-`Caixa` `:max-restarts`
3164    /// `Option<u32>` and (through the future duration-newtype landing)
3165    /// `:restart-window` `Option<Duration>` future outer-scalar lifts
3166    /// fold on. Peer of the inner-altitude [`crate::supervisor::SupervisorSpec::estrategia`]
3167    /// (eafb619) `Copy`-return sibling-restart-strategy scalar accessor on
3168    /// the post-composition [`SupervisorSpec`] altitude — same "one
3169    /// typed dispatch on the substrate primitive, thin projections at
3170    /// each consumer" discipline extended onto the pre-composition outer
3171    /// author-surface [`Caixa`] altitude for the same OTP-shaped
3172    /// sibling-restart-strategy axis. Peer of the closed outer-`Caixa`
3173    /// `Option<&Composite>` composite-reference family the sibling
3174    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3175    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3176    /// [`Self::entrada`] (e4128e4) accessor pins already carry on the
3177    /// outer `Option<&Composite>` altitude — extends the outer-`Caixa`
3178    /// typed-slot accessor discipline onto the flat-spread M2 supervisor-
3179    /// tree `Option<Copy>`-discriminant sub-family the sibling M3
3180    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
3181    /// `PlacementStrategy` `Copy`-composite-enum scalar accessor already
3182    /// pins on the inner-altitude per-`:placement` composite. Named
3183    /// `estrategia()` to match the storage field's name and the
3184    /// per-[`SupervisorSpec`] peer [`crate::supervisor::SupervisorSpec::estrategia`]
3185    /// / per-[`crate::aplicacao::Placement`] peer
3186    /// [`crate::aplicacao::Placement::estrategia`] method-name discipline
3187    /// verbatim; the accessor's identity name maps onto the canonical
3188    /// OTP-shape supervision vocabulary the [`RestartStrategy`] enum's
3189    /// docstring already carries.
3190    #[must_use]
3191    pub const fn estrategia(&self) -> Option<crate::supervisor::RestartStrategy> {
3192        self.estrategia
3193    }
3194
3195    /// Substrate-canonical per-`Caixa` `:max-restarts` M2 supervisor-tree-
3196    /// slot flat-spread OTP-`MaxIntensity`-shaped restart-budget-count
3197    /// scalar accessor every consumer of the top-level manifest's per-
3198    /// Supervisor `:max-restarts` restart-budget-count axis keys off —
3199    /// returns the author-declared `:max-restarts` typed `Option<u32>`
3200    /// verbatim, `Copy`-projected from the typed slot's own `Option<u32>`
3201    /// storage (`u32` is `Copy`, so `Option<u32>` is `Copy` and the
3202    /// accessor returns by value; no borrow of `&self` past the call).
3203    /// Optional (`:max-restarts` is a flat-spread supervisor-only slot
3204    /// every non-`Supervisor`-kind `defcaixa` carries as `None` by
3205    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3206    /// still omit to defer to the [`Self::supervisor_view`]
3207    /// `unwrap_or(5)` fold's OTP-canonical `{intensity, 5, 60}` default).
3208    ///
3209    /// The `:max-restarts` slot carries the M2 typed Erlang/OTP-shaped
3210    /// `MaxIntensity` restart-budget count that pairs with the sibling
3211    /// `:restart-window` `Period` to form the `MaxIntensity / Period`
3212    /// restart-intensity ratio the supervisor trips its own escalation on
3213    /// (INSPIRATIONS §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}`
3214    /// worker-supervisor default; RUNTIME-PATTERNS §II.2; CAIXA-SDLC §II
3215    /// — the M2 supervisor-tree slot algebra the operator's hierarchical
3216    /// reconciliation scheduler fans on). The slot is *flat-spread* on
3217    /// the outer top-level `Caixa` (per the field-shape docstring at
3218    /// caixa-core/src/manifest.rs — "The supervisor slots are flat on
3219    /// Caixa (vs nested under a `SupervisorSpec` sub-form)"), so the
3220    /// accessor's altitude is the outer [`Caixa`] surface rather than the
3221    /// composed [`SupervisorSpec`] altitude the sibling
3222    /// [`crate::supervisor::SupervisorSpec::max_restarts`] accessor keys
3223    /// off. The two typed axes — the outer author-surface `Option<u32>`
3224    /// on the [`Caixa`] altitude (author-omitted arm carried as `None`)
3225    /// and the inner post-composition `u32` on the [`SupervisorSpec`]
3226    /// altitude (`Option` collapsed through the [`Self::supervisor_view`]
3227    /// `unwrap_or(5)` fold) — now share one accessor discipline for the
3228    /// shared substrate concept "the author-declared OTP-shaped
3229    /// restart-budget count every downstream per-Supervisor consumer's
3230    /// restart-intensity budget-vs-count comparator fans on".
3231    ///
3232    /// Prior to this lift the `.max_restarts` field was accessed inline
3233    /// at two production sites in `caixa-core/src/manifest.rs` — the
3234    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`
3235    /// presence-probe arm at `if self.max_restarts.is_some()` (which
3236    /// drives the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3237    /// kind-coherence gate's per-slot label push) and the
3238    /// [`Self::supervisor_view`] `SupervisorSpec` construction site at
3239    /// `max_restarts: self.max_restarts.unwrap_or(5)` (which composes the
3240    /// flat-spread outer author-surface `Option<u32>` onto the inner
3241    /// post-composition [`SupervisorSpec`] `u32` field the
3242    /// [`SupervisorSpec::max_restarts`] accessor keys off) — two open-
3243    /// coded field-accesses that expressed no compile-time link back to
3244    /// the typed slot. A future extension of the outer `:max-restarts`
3245    /// axis to a richer author surface (a per-cluster restart-budget
3246    /// override the operator pins through a future `:max-restarts-overrides`
3247    /// overlay the MESH-COMPOSITION §III.2 supervision-canary roadmap
3248    /// acknowledges, a per-tenant restart-budget-alias table the M4 CR
3249    /// materializer resolves per-CR, a per-Supervisor dynamic restart-
3250    /// budget derivation the future adaptive-supervision engine computes
3251    /// from child-failure-history topology, a promotion of the plain
3252    /// `Option<u32>` count to a richer `{MaxR, MaxT}` per-child-cohort
3253    /// restart-budget-partition once the INSPIRATIONS §II.2 Erlang/OTP
3254    /// per-child-cohort roadmap lands) would have had to be threaded
3255    /// through both open-coded copies in lockstep or the enumerator's
3256    /// presence probe and the composition site's `unwrap_or(5)` fold
3257    /// would silently disagree on which restart-budget a given [`Caixa`]
3258    /// resolves to (an author's `:max-restarts 10` would satisfy the
3259    /// enumerator's presence probe while the composition site silently
3260    /// composed the OTP-canonical `5`, or vice versa). Lifting the
3261    /// resolution rule to a typed method on the substrate primitive means
3262    /// every downstream consumer of the caixa's per-`Caixa` outer-altitude
3263    /// restart-budget-count surface reaches for exactly one typed dispatch
3264    /// — the resolver's accept-set migrates as a unit on any future axis
3265    /// addition.
3266    ///
3267    /// Second outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3268    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3269    /// axes — folds on the outer-`Caixa` `Option<Copy>` flat-spread
3270    /// projection pattern the sibling per-`Caixa`
3271    /// [`Self::estrategia`] (ed04d3c) accessor opened, extends the
3272    /// sub-family onto the sibling `Option<u32>` restart-budget-count arm.
3273    /// Peer of the inner-altitude
3274    /// [`crate::supervisor::SupervisorSpec::max_restarts`] `u32` accessor
3275    /// on the post-composition [`SupervisorSpec`] altitude — same "one
3276    /// typed dispatch on the substrate primitive, thin projections at
3277    /// each consumer" discipline extended onto the pre-composition outer
3278    /// author-surface [`Caixa`] altitude for the same OTP-`MaxIntensity`-
3279    /// shaped restart-budget-count axis. Named `max_restarts()` to match
3280    /// the storage field's name and the per-[`SupervisorSpec`] peer
3281    /// [`crate::supervisor::SupervisorSpec::max_restarts`] method-name
3282    /// discipline verbatim; the accessor's identity maps onto the
3283    /// canonical OTP-shape supervision vocabulary the `:max-restarts`
3284    /// field's docstring already carries.
3285    #[must_use]
3286    pub const fn max_restarts(&self) -> Option<u32> {
3287        self.max_restarts
3288    }
3289
3290    /// Substrate-canonical per-`Caixa` `:restart-window` M2 supervisor-
3291    /// tree-slot flat-spread OTP-`Period`-shaped restart-intensity-
3292    /// denominator raw-duration-string scalar accessor every consumer of
3293    /// the top-level manifest's per-Supervisor `:restart-window` sliding-
3294    /// window axis keys off — returns the author-declared `:restart-window`
3295    /// typed `Option<String>` verbatim as an `Option<&str>`, borrowed
3296    /// from the typed slot's own `Option<String>` storage. `None` when
3297    /// the slot is absent (the canonical "never reset — every restart
3298    /// across the supervisor's lifetime counts against the sibling
3299    /// `:max-restarts` budget" sentinel every non-`Supervisor`-kind
3300    /// `defcaixa` carries by `#[serde(default)]` and every
3301    /// `Supervisor`-kind `defcaixa` may still omit to defer to the
3302    /// [`Self::supervisor_view`] `restart_window: None` composition
3303    /// through the [`crate::supervisor::duration_codec::parse`] soft-
3304    /// swallow `.and_then(|s| … .ok())` fold).
3305    ///
3306    /// The `:restart-window` slot carries the raw M2 typed Erlang/OTP-
3307    /// shaped `Period` sliding-observation-interval duration string that
3308    /// pairs with the sibling `:max-restarts` `MaxIntensity` restart-
3309    /// budget count to form the `MaxIntensity / Period` restart-intensity
3310    /// ratio the supervisor trips its own escalation on (INSPIRATIONS
3311    /// §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}` worker-
3312    /// supervisor default; RUNTIME-PATTERNS §II.2). The outer-`Caixa`
3313    /// slot stores the raw duration string (`"60s"`, `"5m"`, `"500ms"`)
3314    /// authored under `:restart-window` — the typed [`SupervisorSpec`]
3315    /// holds an `Option<Duration>` routed through the shared
3316    /// [`crate::supervisor::duration_codec`] via `with = "duration_codec"`
3317    /// — so the outer altitude's accessor returns `Option<&str>` (raw
3318    /// authoring surface) while the inner altitude's
3319    /// [`crate::supervisor::SupervisorSpec::restart_window`] returns
3320    /// `Option<Duration>` (parsed typed surface). The parse-refusal arm
3321    /// is closed by the sibling [`Self::validate_restart_window`] gate
3322    /// that surfaces [`ManifestError::RestartWindowMalformed`] naming
3323    /// the offending value; the view-construction path
3324    /// [`Self::supervisor_view`] soft-swallows the same parse error to
3325    /// `None` to keep the view best-effort.
3326    ///
3327    /// Prior to this lift the `.restart_window` field was accessed inline
3328    /// at three production sites in `caixa-core/src/manifest.rs` — the
3329    /// [`Self::declared_supervisor_slots`]
3330    /// `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` presence-probe arm at
3331    /// `if self.restart_window.is_some()` (which drives the
3332    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3333    /// coherence gate's per-slot label push), the
3334    /// [`Self::validate_restart_window`] `let Some(s) =
3335    /// self.restart_window.as_deref()` empty-and-shape gate binding
3336    /// (which folds the raw string through the shared
3337    /// [`crate::supervisor::duration_codec::parse`] to surface
3338    /// [`ManifestError::RestartWindowMalformed`] naming the offending
3339    /// value), and the [`Self::supervisor_view`] `self.restart_window
3340    /// .as_deref().and_then(…)` view-construction fold (which composes
3341    /// the flat-spread outer author-surface `Option<String>` onto the
3342    /// inner post-composition [`SupervisorSpec`] `Option<Duration>`
3343    /// field the [`SupervisorSpec::restart_window`] accessor keys off) —
3344    /// three open-coded field-accesses that expressed no compile-time
3345    /// link back to the typed slot. A future extension of the outer
3346    /// `:restart-window` axis to a richer author surface (a per-cluster
3347    /// window override, a per-tenant window-alias table, a per-Supervisor
3348    /// dynamic window derivation the future adaptive-supervision engine
3349    /// computes from child-failure-history topology, a promotion of the
3350    /// plain `Option<String>` raw duration to a typed `Option<Duration>`
3351    /// once the future author-surface parser lands at the [`Caixa`]
3352    /// altitude and the raw-string form is retired) would have had to be
3353    /// threaded through every open-coded copy in lockstep or the three
3354    /// consumers would silently disagree on which raw string a given
3355    /// [`Caixa`] resolves to. Lifting the resolution rule to a typed
3356    /// method on the substrate primitive means every downstream consumer
3357    /// of the caixa's per-`Caixa` outer-altitude restart-window raw-
3358    /// string surface reaches for exactly one typed dispatch — the
3359    /// resolver's accept-set migrates as a unit on any future axis
3360    /// addition.
3361    ///
3362    /// Third outer top-level [`Caixa`] supervisor-tree-slot flat-spread
3363    /// accessor — folds on the outer-`Caixa` M2 supervisor-tree flat-
3364    /// spread projection pattern the sibling per-`Caixa`
3365    /// [`Self::estrategia`] (ed04d3c) `Option<Copy>` and
3366    /// [`Self::max_restarts`] `Option<Copy>` accessors opened, extends
3367    /// the sub-family onto the sibling `Option<&str>` raw-duration-
3368    /// string arm (the outer altitude's raw-string form; the inner
3369    /// altitude's parsed [`Duration`] form is the peer
3370    /// [`crate::supervisor::SupervisorSpec::restart_window`] accessor).
3371    /// Peer of the sibling per-`Caixa` `Option<&str>`-return scalar
3372    /// accessors ([`Self::licenca`] / [`Self::repositorio`] /
3373    /// [`Self::descricao`] / [`Self::edicao`]) on the universal-axis
3374    /// outer scalar-projection family the outer-`Caixa` `Option<&str>`
3375    /// sub-family already carries — same "one typed dispatch on the
3376    /// substrate primitive, thin projections at each consumer"
3377    /// discipline extended onto the M2 supervisor-tree flat-spread
3378    /// `Option<&str>` raw-duration-string arm. Named `restart_window()`
3379    /// to match the storage field's name and the per-[`SupervisorSpec`]
3380    /// peer [`crate::supervisor::SupervisorSpec::restart_window`]
3381    /// method-name discipline verbatim; the accessor's identity maps
3382    /// onto the canonical OTP-shape supervision vocabulary the
3383    /// `:restart-window` field's docstring already carries.
3384    #[must_use]
3385    pub const fn restart_window(&self) -> Option<&str> {
3386        match &self.restart_window {
3387            Some(s) => Some(s.as_str()),
3388            None => None,
3389        }
3390    }
3391
3392    /// Substrate-canonical per-`Caixa` `:upgrade-from` M2 typed-slot
3393    /// outer-composite OTP-appup-shaped per-prior-version migration-
3394    /// entry-list slice accessor every consumer of the top-level
3395    /// manifest's per-Servico hot-upgrade-block `&[UpgradeFromEntry]`
3396    /// slice-view keys off — returns the author-declared `:upgrade-from`
3397    /// typed `Vec<UpgradeFromEntry>` verbatim as a
3398    /// `&[UpgradeFromEntry]` slice-view over the same backing buffer
3399    /// the raw `self.upgrade_from.as_slice()` field access borrows
3400    /// from. Empty-slice-carrying (the "no hot-upgrade path declared"
3401    /// arm every `defcaixa` without an `:upgrade-from` block carries;
3402    /// the [`Self::from_lisp`] derive folds an omitted `:upgrade-from`
3403    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
3404    /// parse definitionally carries a `Vec<UpgradeFromEntry>` slot —
3405    /// possibly empty — and the returned `&[UpgradeFromEntry]`
3406    /// degenerates to an empty slice on that arm without any silent
3407    /// `None` collapse).
3408    ///
3409    /// The outer `:upgrade-from` slot carries the M2 typed OTP-appup
3410    /// migration block — the load-bearing container of every per-
3411    /// prior-`:versao` migration-instruction list the wasm-operator
3412    /// dispatches on at hot-upgrade time (INSPIRATIONS §II.4 — OTP
3413    /// `.appup` per-prior-version `LoadModule | StateChange |
3414    /// SoftPurge | Purge | Restart` instruction algebra translated
3415    /// onto pleme-io's typed `:upgrade-from :from` + `:instructions`
3416    /// entry list; CAIXA-SDLC §II — the typed-M2 slot algebra the
3417    /// operator's hot-upgrade dispatch fans on). Every per-entry axis
3418    /// threads through a lifted per-entry accessor on the
3419    /// [`UpgradeFromEntry`] type: the
3420    /// [`UpgradeFromEntry::prior_versao`] SemVer-shaped previous-
3421    /// version scalar accessor and the
3422    /// [`UpgradeFromEntry::instructions`] `&[UpgradeInstruction]`-
3423    /// return per-entry instruction-list accessor (0137e5a). Every
3424    /// downstream consumer of the hot-upgrade path first passes
3425    /// through this outer accessor onto the slice and then dispatches
3426    /// per-entry through the inner accessors — the two-level dispatch
3427    /// means every per-`:upgrade-from` reader now routes through a
3428    /// typed dispatch on the substrate primitive at both altitudes.
3429    ///
3430    /// Prior to this lift the `.upgrade_from` `Vec<UpgradeFromEntry>`
3431    /// slot was accessed inline at production sites across three
3432    /// files — the [`Self::declared_servico_slots`] M2 declared-slot
3433    /// enumerator's `self.upgrade_from.is_empty()` presence probe
3434    /// (caixa-core/src/manifest.rs, which drives the
3435    /// `M2_AUTHOR_KEY_UPGRADE_FROM` kebab-case author-label push every
3436    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
3437    /// gate reads), the [`crate::StandardLayout::verify`] per-
3438    /// `:upgrade-from` three-stage validation pass (caixa-core/src/
3439    /// layout.rs, which fans onto the
3440    /// [`crate::upgrade::validate_upgrade_from`] per-entry shape +
3441    /// cross-entry duplicate gate, the
3442    /// [`crate::upgrade::validate_upgrade_from_against_versao`]
3443    /// SemVer-precedence cross-slot gate, the
3444    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
3445    /// `:state-change` ↔ `:on-state-change` cross-slot composition
3446    /// gate, and the per-instruction script-path existence-probe walk
3447    /// that reads each entry's [`UpgradeFromEntry::instructions`] to
3448    /// resolve every declared migration script against the layout
3449    /// root), and the [`crate::render::servico_m2_overlay`] per-
3450    /// Servico M2 overlay emitter's `!caixa.upgrade_from.is_empty()`
3451    /// presence gate + `serde_yaml::to_value(&caixa.upgrade_from)`
3452    /// projection (caixa-core/src/render.rs, which drives the
3453    /// `M2_KEY_UPGRADE_FROM`-keyed `serde_yaml` projection every
3454    /// `caixa-helm` / `caixa-flux` Servico values-block emitter fans
3455    /// on and lands as the ComputeUnit CR's `spec.upgradeFrom` field).
3456    /// A future extension of the outer `:upgrade-from` axis (a per-
3457    /// cluster `:upgrade-overrides` overlay the wasm-engine operator
3458    /// resolves at admission time so a cluster-specific migration
3459    /// policy can tighten a caixa-declared step without re-authoring
3460    /// the `caixa.lisp`, promotion of the plain
3461    /// `Vec<UpgradeFromEntry>` to a richer `{static, dynamic}`
3462    /// partition once runtime-resolved hot-upgrade instructions land,
3463    /// per-entry priority annotation once multi-strategy fan-out
3464    /// lands) would have had to be threaded through all six open-
3465    /// coded copies in lockstep or one consumer would silently
3466    /// disagree with the peers on which upgrade slice a given Caixa
3467    /// resolves to — a six-consumer split at the enumerator, the
3468    /// three-stage validate pass, the script-path probe walk, and the
3469    /// M2 overlay emitter, far from the source `caixa.lisp` with no
3470    /// field naming the upgrade-drift root cause. Lifting the
3471    /// resolution rule to a typed method on the substrate primitive
3472    /// means every downstream consumer of the caixa's per-`Caixa`
3473    /// OTP-appup outer-slice surface reaches for exactly one typed
3474    /// dispatch — the resolver's accept-set migrates as a unit on any
3475    /// future axis addition.
3476    ///
3477    /// First outer top-level [`Caixa`] `&[Composite]`-return slice
3478    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the
3479    /// outer-`Caixa` `&[Composite]` composite-slice projection
3480    /// pattern the sibling `:children`
3481    /// [`crate::supervisor::ChildSpec`] / `:membros`
3482    /// [`crate::aplicacao::Membro`] / `:contratos`
3483    /// [`crate::aplicacao::WitContract`] future outer-composite-slice
3484    /// lifts fold on. Peer of the closed outer-`Caixa` scalar
3485    /// `Option<&Composite>` composite-reference family the sibling
3486    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3487    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3488    /// [`Self::entrada`] (e4128e4) accessors closed on the outer
3489    /// `Option<&Composite>` altitude, extended here to the outer-
3490    /// `Caixa` `&[Composite]` vec-carry altitude. Peer at the inner
3491    /// altitude of [`crate::upgrade::UpgradeFromEntry::instructions`]
3492    /// (0137e5a) — same "one typed dispatch on the substrate
3493    /// primitive, thin projections at each consumer" discipline
3494    /// folded onto the outer top-level [`Caixa`] altitude, opening the
3495    /// M2 vec-carry slot family's outer-composite-slice axis. Sibling
3496    /// in shape to the peer outer-`Caixa` `&[Dep]`-return
3497    /// [`Self::deps`] (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and
3498    /// `&[String]`-return [`Self::autores`] (b5d813f) /
3499    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`]
3500    /// (8a36c23) / [`Self::exe`] (65d9527) / [`Self::servicos`]
3501    /// (611f78b) slice-accessors on the sibling outer-`Caixa` scalar-
3502    /// element vec-carry axes — folds the "outer [`Caixa`] `&[T]`
3503    /// slice" projection pattern onto the sibling M2 typed-composite-
3504    /// element axis (`UpgradeFromEntry` composite, matching the
3505    /// per-inner [`UpgradeFromEntry::instructions`] element type at a
3506    /// different altitude).
3507    ///
3508    /// Returns `&[UpgradeFromEntry]` (not `&Vec<UpgradeFromEntry>`)
3509    /// because every downstream consumer of the hot-upgrade list
3510    /// treats it as a read-only sequence — the slice-view is the
3511    /// narrowest borrow that supports every present + roadmapped
3512    /// consumer (`.iter()`, `.len()`, `.is_empty()`, `serde` slice-
3513    /// serialization through
3514    /// `serde_yaml::to_value(&[UpgradeFromEntry])`) without leaking
3515    /// the backing `Vec`'s grow/push/reserve surface no consumer of
3516    /// the typed view reaches for (the storage-side `Vec` remains
3517    /// reachable through the `pub upgrade_from` field for the
3518    /// mutation-carrying serde round-trip and per-test fixture-
3519    /// mutation paths). Named `upgrade_from()` to match the storage
3520    /// field's `snake_case` name; the kebab-case author-surface tag
3521    /// `:upgrade-from` is the same axis after tatara-lisp's
3522    /// kebab↔snake fold and the accessor's identity maps onto the
3523    /// canonical CAIXA-SDLC §II vocabulary the slot's docstring
3524    /// already carries.
3525    #[must_use]
3526    pub const fn upgrade_from(&self) -> &[UpgradeFromEntry] {
3527        self.upgrade_from.as_slice()
3528    }
3529
3530    /// Substrate-canonical per-`Caixa` `:children` M2 supervisor-tree-
3531    /// slot outer-composite OTP-shaped per-supervisor static-child-list
3532    /// slice accessor every consumer of the top-level manifest's per-
3533    /// Supervisor `&[ChildSpec]` slice-view keys off — returns the
3534    /// author-declared `:children` typed `Vec<crate::supervisor::ChildSpec>`
3535    /// verbatim as a `&[crate::supervisor::ChildSpec]` slice-view over
3536    /// the same backing buffer the raw `self.children.as_slice()` field
3537    /// access borrows from. Empty-slice-carrying (the "no static children
3538    /// declared" arm every non-`Supervisor`-kind `defcaixa` carries by
3539    /// #[serde(default)] and every `SimpleOneForOne` supervisor carries
3540    /// by [`crate::supervisor::SupervisorError::SimpleOneForOneWithStaticChildren`]
3541    /// gate; the returned `&[ChildSpec]` degenerates to an empty slice
3542    /// on those arms without any silent `None` collapse).
3543    ///
3544    /// The outer `:children` slot carries the M2 typed OTP-supervisor
3545    /// static-child list — the load-bearing container of every per-
3546    /// child `{caixa, versao, restart}` triple the wasm-operator's
3547    /// hierarchical reconciler dispatches on at supervisor-tree
3548    /// materialization time (INSPIRATIONS §II.2 — OTP `supervisor:init/1`
3549    /// static-child list translated onto pleme-io's typed
3550    /// [`crate::supervisor::ChildSpec`] entry list; CAIXA-SDLC §II —
3551    /// the typed-M2 slot algebra the operator's per-supervisor fan-out
3552    /// dispatch fans on). Every per-child axis threads through a lifted
3553    /// per-entry accessor on the [`crate::supervisor::ChildSpec`] type:
3554    /// the [`crate::supervisor::ChildSpec::nome`] DNS-1123-label
3555    /// child-caixa-identity scalar accessor, the peer versao SemVer-2
3556    /// version-requirement scalar accessor, and the
3557    /// [`crate::supervisor::ChildSpec::restart`] `Copy`-composite-enum
3558    /// per-child post-exit restart-decision-policy discriminant
3559    /// accessor (dfb4a81). Every downstream consumer of the supervisor-
3560    /// tree path first passes through this outer accessor onto the
3561    /// slice and then dispatches per-child through the inner accessors
3562    /// — the two-level dispatch means every per-`:children` reader now
3563    /// routes through a typed dispatch on the substrate primitive at
3564    /// both altitudes.
3565    ///
3566    /// Prior to this lift the `.children` `Vec<ChildSpec>` slot was
3567    /// accessed inline at three production sites across two files —
3568    /// the [`Self::declared_supervisor_slots`] supervisor-tree
3569    /// declared-slot enumerator's `!self.children.is_empty()` presence
3570    /// probe (caixa-core/src/manifest.rs, which drives the
3571    /// `SUPERVISOR_AUTHOR_KEY_CHILDREN` kebab-case author-label push
3572    /// every [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3573    /// kind-coherence gate reads), the [`Self::supervisor_view`]
3574    /// per-supervisor typed-view composer's `self.children.clone()`
3575    /// per-child fold-in path (caixa-core/src/manifest.rs, which
3576    /// materializes the typed [`crate::supervisor::SupervisorSpec`]
3577    /// view every [`crate::StandardLayout::verify`] Supervisor-arm gate
3578    /// dispatches on), and the [`crate::StandardLayout::verify`] per-
3579    /// `:children :caixa` self-parent refusal probe's
3580    /// `&caixa.children`-borrowed
3581    /// [`crate::supervisor::validate_no_self_supervision`] input
3582    /// (caixa-core/src/layout.rs, which pins the "no child names the
3583    /// supervisor's own `:nome`" cross-slot coherence gate). A future
3584    /// extension of the outer `:children` axis (a per-cluster
3585    /// `:children-overrides` overlay the wasm-engine operator resolves
3586    /// at admission time so a cluster-specific child-set can tighten
3587    /// a caixa-declared list without re-authoring the `caixa.lisp`,
3588    /// promotion of the plain `Vec<ChildSpec>` to a richer
3589    /// `{static, dynamic}` partition once Erlang/OTP's
3590    /// `simple_one_for_one`-shaped dynamic-child slot lands as a typed
3591    /// axis, per-child priority annotation once multi-strategy fan-out
3592    /// lands) would have had to be threaded through all three open-
3593    /// coded copies in lockstep or one consumer would silently
3594    /// disagree with the peers on which child slice a given Caixa
3595    /// resolves to — the enumerator's presence probe reading the raw
3596    /// slot while the peer view-composer's fold-in path read an
3597    /// operator-resolved slot would silently split the paired
3598    /// declared-slot enumerator and typed-view composition, and the
3599    /// [`crate::supervisor::validate_no_self_supervision`] self-parent
3600    /// refusal probe reading a third borrow would silently drift the
3601    /// cross-slot coherence gate's traversal input from the two peers,
3602    /// a three-consumer split at the enumerator, the view composer,
3603    /// and the self-parent gate far from the source `caixa.lisp` with
3604    /// no field naming the child-set-drift root cause. Lifting the
3605    /// resolution rule to a typed method on the substrate primitive
3606    /// means every downstream consumer of the caixa's per-`Caixa`
3607    /// OTP-supervisor outer-slice surface reaches for exactly one
3608    /// typed dispatch — the resolver's accept-set migrates as a unit
3609    /// on any future axis addition.
3610    ///
3611    /// Second outer top-level [`Caixa`] `&[Composite]`-return slice
3612    /// accessor for M2 / M3 typed-slot vec-carry axes — folds on the
3613    /// outer-`Caixa` `&[Composite]` composite-slice sub-family the
3614    /// sibling [`Self::upgrade_from`] (2a1f907) accessor opened, peer
3615    /// at the outer altitude of the closed inner-`SupervisorSpec`
3616    /// [`crate::SupervisorSpec::children`] (bc92bce) accessor on the
3617    /// same OTP-supervisor static-child-list axis — same "byte-equal,
3618    /// borrow-shared" outer-accessor discipline extended onto the
3619    /// second outer-`Caixa` `&[Composite]` vec-carry axis. Sibling in
3620    /// shape to the peer outer-`Caixa` `&[Dep]`-return [`Self::deps`]
3621    /// (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and `&[String]`-return
3622    /// [`Self::autores`] (b5d813f) / [`Self::etiquetas`] (78c7d3c) /
3623    /// [`Self::bibliotecas`] (8a36c23) / [`Self::exe`] (65d9527) /
3624    /// [`Self::servicos`] (611f78b) slice-accessors on the sibling
3625    /// outer-`Caixa` scalar-element vec-carry axes — folds the "outer
3626    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
3627    /// M2 typed-composite-element axis
3628    /// ([`crate::supervisor::ChildSpec`] composite, matching the
3629    /// per-inner [`crate::SupervisorSpec::children`] element type at a
3630    /// different altitude).
3631    ///
3632    /// Returns `&[crate::supervisor::ChildSpec]` (not
3633    /// `&Vec<ChildSpec>`) because every downstream consumer of the
3634    /// child list treats it as a read-only sequence — the slice-view
3635    /// is the narrowest borrow that supports every present +
3636    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`, the
3637    /// [`crate::supervisor::validate_no_self_supervision`] `&[ChildSpec]`
3638    /// input, `serde` slice-serialization) without leaking the backing
3639    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3640    /// reaches for (the storage-side `Vec` remains reachable through
3641    /// the `pub children` field for the mutation-carrying serde round-
3642    /// trip and per-test fixture-mutation paths, including the
3643    /// [`Self::supervisor_view`] fold-in path that clones the slot
3644    /// into the typed view). Named `children()` to match the storage
3645    /// field's name verbatim and the tatara-lisp author-surface term
3646    /// (`:children`) the field's own docstring already carries; the
3647    /// accessor's identity maps onto the canonical OTP supervision
3648    /// vocabulary the [`Caixa::children`] field's docstring already
3649    /// reaches for ("Static children of a supervisor").
3650    #[must_use]
3651    pub const fn children(&self) -> &[crate::supervisor::ChildSpec] {
3652        self.children.as_slice()
3653    }
3654
3655    /// Substrate-canonical per-`Caixa` `:membros` M3 mesh-slot outer-
3656    /// composite MESH-COMPOSITION-shaped per-Aplicacao member-list slice
3657    /// accessor every consumer of the top-level manifest's per-Aplicacao
3658    /// `&[crate::aplicacao::Membro]` slice-view keys off — returns the
3659    /// author-declared `:membros` typed `Vec<crate::aplicacao::Membro>`
3660    /// verbatim as a `&[crate::aplicacao::Membro]` slice-view over the
3661    /// same backing buffer the raw `self.membros.as_slice()` field access
3662    /// borrows from. Empty-slice-carrying (the "no members declared" arm
3663    /// every non-`Aplicacao`-kind `defcaixa` carries by `#[serde(default)]`
3664    /// and every partially-authored Aplicacao carries before the
3665    /// [`crate::AplicacaoError::MembrosEmpty`] gate fires; the returned
3666    /// `&[Membro]` degenerates to an empty slice on those arms without any
3667    /// silent `None` collapse).
3668    ///
3669    /// The outer `:membros` slot carries the M3 typed MESH-COMPOSITION
3670    /// per-Aplicacao member list — the load-bearing container of every
3671    /// per-member `{caixa, versao}` pair the caixa-mesh renderer's
3672    /// per-Aplicacao program-emission dispatch fans on at mesh-artifact
3673    /// materialization time (MESH-COMPOSITION §III.1 — the typed graph's
3674    /// vertex set the `:contratos` `:de`/`:para` edges resolve against and
3675    /// the `:entrada :para` external-gateway destination validates
3676    /// against; CAIXA-SDLC §II — the typed-M3 slot algebra the operator's
3677    /// per-Aplicacao fan-out dispatch fans on). Every per-member axis
3678    /// threads through a lifted per-entry accessor on the
3679    /// [`crate::aplicacao::Membro`] type: the
3680    /// [`crate::aplicacao::Membro::nome`] DNS-1123-label member-caixa-
3681    /// identity scalar accessor (4a32abf) and the peer
3682    /// [`crate::aplicacao::Membro::versao_requirement`] SemVer-2
3683    /// version-requirement scalar accessor (a40b0e3). Every downstream
3684    /// consumer of the mesh-graph path first passes through this outer
3685    /// accessor onto the slice and then dispatches per-member through
3686    /// the inner accessors — the two-level dispatch means every per-
3687    /// `:membros` reader now routes through a typed dispatch on the
3688    /// substrate primitive at both altitudes.
3689    ///
3690    /// Prior to this lift the `.membros` `Vec<Membro>` slot was accessed
3691    /// inline at three production sites across two files — the
3692    /// [`Self::declared_mesh_slots`] mesh-slot declared-slot
3693    /// enumerator's `!self.membros.is_empty()` presence probe
3694    /// (caixa-core/src/manifest.rs, which drives the
3695    /// `M3_AUTHOR_KEY_MEMBROS` kebab-case author-label push every
3696    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3697    /// gate reads), the [`Self::aplicacao_view`] per-Aplicacao typed-view
3698    /// composer's `self.membros.clone()` per-member fold-in path
3699    /// (caixa-core/src/manifest.rs, which materializes the typed
3700    /// [`crate::aplicacao::AplicacaoSpec`] view every
3701    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate dispatches
3702    /// on), and the [`crate::StandardLayout::verify`] per-`:membros
3703    /// :caixa` self-membership refusal probe's `&caixa.membros`-borrowed
3704    /// [`crate::aplicacao::validate_no_self_membership`] input
3705    /// (caixa-core/src/layout.rs, which pins the "no member names the
3706    /// Aplicacao's own `:nome`" cross-slot coherence gate). A future
3707    /// extension of the outer `:membros` axis (a per-cluster
3708    /// `:membros-overrides` overlay the wasm-engine operator resolves at
3709    /// admission time so a cluster-specific member-set can tighten a
3710    /// caixa-declared list without re-authoring the `caixa.lisp`,
3711    /// promotion of the plain `Vec<Membro>` to a richer
3712    /// `{static, dynamic}` partition once runtime-resolved Aplicacao
3713    /// members land as a typed axis, per-member priority annotation once
3714    /// multi-strategy fan-out lands) would have had to be threaded
3715    /// through all three open-coded copies in lockstep or one consumer
3716    /// would silently disagree with the peers on which member slice a
3717    /// given Caixa resolves to — the enumerator's presence probe reading
3718    /// the raw slot while the peer view-composer's fold-in path read an
3719    /// operator-resolved slot would silently split the paired
3720    /// declared-slot enumerator and typed-view composition, and the
3721    /// [`crate::aplicacao::validate_no_self_membership`] self-membership
3722    /// refusal probe reading a third borrow would silently drift the
3723    /// cross-slot coherence gate's traversal input from the two peers, a
3724    /// three-consumer split at the enumerator, the view composer, and
3725    /// the self-membership gate far from the source `caixa.lisp` with no
3726    /// field naming the member-set-drift root cause. Lifting the
3727    /// resolution rule to a typed method on the substrate primitive
3728    /// means every downstream consumer of the caixa's per-`Caixa`
3729    /// MESH-COMPOSITION outer-slice surface reaches for exactly one
3730    /// typed dispatch — the resolver's accept-set migrates as a unit on
3731    /// any future axis addition.
3732    ///
3733    /// Third outer top-level [`Caixa`] `&[Composite]`-return slice
3734    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the outer-
3735    /// `Caixa` M3 mesh-slot arm of the `&[Composite]` composite-slice
3736    /// sub-family the sibling M2 [`Self::upgrade_from`] (2a1f907) /
3737    /// [`Self::children`] (c17b51e) accessors opened for the M2 vec-carry
3738    /// altitude. Peer at the outer altitude of the closed inner-
3739    /// [`crate::AplicacaoSpec::membros`] (6c77e36) accessor on the same
3740    /// MESH-COMPOSITION per-Aplicacao member-list axis — the two
3741    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3742    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3743    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3744    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3745    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3746    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3747    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3748    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3749    /// pattern onto the sibling M3 typed-composite-element axis
3750    /// ([`crate::aplicacao::Membro`] composite, matching the per-inner
3751    /// [`crate::AplicacaoSpec::membros`] element type at a different
3752    /// altitude).
3753    ///
3754    /// Returns `&[crate::aplicacao::Membro]` (not `&Vec<Membro>`)
3755    /// because every downstream consumer of the member list treats it
3756    /// as a read-only sequence — the slice-view is the narrowest borrow
3757    /// that supports every present + roadmapped consumer (`.iter()`,
3758    /// `.len()`, `.is_empty()`, the
3759    /// [`crate::aplicacao::validate_no_self_membership`] `&[Membro]`
3760    /// input, `serde` slice-serialization) without leaking the backing
3761    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3762    /// reaches for (the storage-side `Vec` remains reachable through the
3763    /// `pub membros` field for the mutation-carrying serde round-trip
3764    /// and per-test fixture-mutation paths, including the
3765    /// [`Self::aplicacao_view`] fold-in path that clones the slot into
3766    /// the typed view). Named `membros()` to match the storage field's
3767    /// name verbatim and the tatara-lisp author-surface term
3768    /// (`:membros`) the field's own docstring already carries; the
3769    /// accessor's identity maps onto the canonical MESH-COMPOSITION
3770    /// vocabulary the [`Caixa::membros`] field's docstring already
3771    /// reaches for ("Member Servicos that make up this Aplicacao").
3772    #[must_use]
3773    pub const fn membros(&self) -> &[crate::aplicacao::Membro] {
3774        self.membros.as_slice()
3775    }
3776
3777    /// Substrate-canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
3778    /// composite MESH-COMPOSITION-shaped per-Aplicacao WIT-typed
3779    /// inter-Servico contract-list slice accessor every consumer of the
3780    /// top-level manifest's per-Aplicacao `&[crate::aplicacao::WitContract]`
3781    /// slice-view keys off — returns the author-declared `:contratos`
3782    /// typed `Vec<crate::aplicacao::WitContract>` verbatim as a
3783    /// `&[crate::aplicacao::WitContract]` slice-view over the same
3784    /// backing buffer the raw `self.contratos.as_slice()` field access
3785    /// borrows from. Empty-slice-carrying (the "no contracts declared"
3786    /// arm every non-`Aplicacao`-kind `defcaixa` carries by
3787    /// `#[serde(default)]` and every leaf Aplicacao carrying only a
3788    /// single member with no inter-Servico edge carries; the returned
3789    /// `&[WitContract]` degenerates to an empty slice on those arms
3790    /// without any silent `None` collapse).
3791    ///
3792    /// The outer `:contratos` slot carries the M3 typed MESH-COMPOSITION
3793    /// per-Aplicacao WIT-typed inter-Servico edge list — the load-bearing
3794    /// container of every per-edge `{de, para, wit, endpoint | subject |
3795    /// slot}` quadruple the caixa-mesh renderer's per-Aplicacao
3796    /// `CiliumNetworkPolicy` fan-out (one L7 policy per edge —
3797    /// MESH-COMPOSITION §III.2 point 2) and per-`(:de, :para)`
3798    /// adjacency-list seed dispatch on at mesh-artifact materialization
3799    /// time (MESH-COMPOSITION §III.1 — the typed graph's edge set the
3800    /// `:membros` vertex set resolves against, closed by the
3801    /// [`crate::AplicacaoError::ContractoUnknownMember`] / cycle-refusal
3802    /// gates in §III.3; CAIXA-SDLC §II — the typed-M3 slot algebra the
3803    /// operator's per-Aplicacao fan-out dispatch fans on). Every
3804    /// per-edge axis threads through a lifted per-entry accessor on the
3805    /// [`crate::aplicacao::WitContract`] type: the peer `de` / `para`
3806    /// DNS-1123-label member-caixa-name endpoint scalar accessors, the
3807    /// [`crate::aplicacao::WitContract::endpoint`] (7020470) HTTP-shape
3808    /// / [`crate::aplicacao::WitContract::subject`] (90de675)
3809    /// NATS-pub-sub-shape / [`crate::aplicacao::WitContract::slot`]
3810    /// (ed22b66) `wasi:keyvalue/store`-shape payload-carrier accessors,
3811    /// and the WIT-world discriminant. Every downstream consumer of the
3812    /// mesh-graph edge path first passes through this outer accessor
3813    /// onto the slice and then dispatches per-contract through the
3814    /// inner accessors — the two-level dispatch means every
3815    /// per-`:contratos` reader now routes through a typed dispatch on
3816    /// the substrate primitive at both altitudes.
3817    ///
3818    /// Prior to this lift the `.contratos` `Vec<WitContract>` slot was
3819    /// accessed inline at two production sites in
3820    /// caixa-core/src/manifest.rs — the [`Self::declared_mesh_slots`]
3821    /// mesh-slot declared-slot enumerator's
3822    /// `!self.contratos.is_empty()` presence probe (which drives the
3823    /// `M3_AUTHOR_KEY_CONTRATOS` kebab-case author-label push every
3824    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3825    /// gate reads) and the [`Self::aplicacao_view`] per-Aplicacao
3826    /// typed-view composer's `self.contratos.clone()` per-contract
3827    /// fold-in path (which materializes the typed
3828    /// [`crate::aplicacao::AplicacaoSpec`] view every
3829    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate and every
3830    /// downstream `caixa-mesh` renderer dispatches on). A future
3831    /// extension of the outer `:contratos` axis (a per-cluster
3832    /// `:contratos-overrides` overlay the wasm-engine operator resolves
3833    /// at admission time so a cluster-specific edge-set can tighten a
3834    /// caixa-declared list without re-authoring the `caixa.lisp`,
3835    /// promotion of the plain `Vec<WitContract>` to a richer
3836    /// `{static, dynamic}` partition once runtime-resolved contract
3837    /// edges land, per-edge policy annotation once the M4 per-edge
3838    /// policy overlay axis lands) would have had to be threaded through
3839    /// both open-coded copies in lockstep or one consumer would
3840    /// silently disagree with the peer on which edge slice a given
3841    /// Caixa resolves to — the enumerator's presence probe reading the
3842    /// raw slot while the peer view-composer's fold-in path read an
3843    /// operator-resolved slot would silently split the paired
3844    /// declared-slot enumerator and typed-view composition, a
3845    /// two-consumer split at the enumerator and the view composer far
3846    /// from the source `caixa.lisp` with no field naming the edge-set-
3847    /// drift root cause. Lifting the resolution rule to a typed method
3848    /// on the substrate primitive means every downstream consumer of
3849    /// the caixa's per-`Caixa` MESH-COMPOSITION outer-slice surface
3850    /// reaches for exactly one typed dispatch — the resolver's
3851    /// accept-set migrates as a unit on any future axis addition.
3852    ///
3853    /// Fourth and final outer top-level [`Caixa`] `&[Composite]`-return
3854    /// slice accessor for M2 / M3 typed-slot vec-carry axes — closes
3855    /// the outer-`Caixa` `&[Composite]` composite-slice sub-family the
3856    /// sibling M2 [`Self::upgrade_from`] (2a1f907) / [`Self::children`]
3857    /// (c17b51e) accessors opened and the M3 [`Self::membros`]
3858    /// (0f26987) accessor folded on, and closes the outer-`Caixa` M3
3859    /// mesh-slot arm of the composite-slice sub-family the sibling
3860    /// [`Self::membros`] accessor opened for the M3 vec-carry altitude.
3861    /// Peer at the outer altitude of the closed inner-
3862    /// [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
3863    /// same MESH-COMPOSITION per-Aplicacao contract-list axis — the two
3864    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3865    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3866    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3867    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3868    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3869    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3870    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3871    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3872    /// pattern onto the sibling M3 typed-composite-element axis
3873    /// ([`crate::aplicacao::WitContract`] composite, matching the
3874    /// per-inner [`crate::AplicacaoSpec::contratos`] element type at a
3875    /// different altitude).
3876    ///
3877    /// Returns `&[crate::aplicacao::WitContract]` (not
3878    /// `&Vec<WitContract>`) because every downstream consumer of the
3879    /// contract list treats it as a read-only sequence — the slice-view
3880    /// is the narrowest borrow that supports every present + roadmapped
3881    /// consumer (`.iter()`, `.len()`, `.is_empty()`, per-edge WIT-world
3882    /// discriminant dispatch, `serde` slice-serialization) without
3883    /// leaking the backing `Vec`'s grow/push/reserve surface no
3884    /// consumer of the typed view reaches for (the storage-side `Vec`
3885    /// remains reachable through the `pub contratos` field for the
3886    /// mutation-carrying serde round-trip and per-test fixture-mutation
3887    /// paths, including the [`Self::aplicacao_view`] fold-in path that
3888    /// clones the slot into the typed view). Named `contratos()` to
3889    /// match the storage field's name verbatim and the tatara-lisp
3890    /// author-surface term (`:contratos`) the field's own docstring
3891    /// already carries; the accessor's identity maps onto the canonical
3892    /// MESH-COMPOSITION vocabulary the [`Caixa::contratos`] field's
3893    /// docstring already reaches for ("WIT-typed inter-Servico
3894    /// contracts").
3895    #[must_use]
3896    pub const fn contratos(&self) -> &[crate::aplicacao::WitContract] {
3897        self.contratos.as_slice()
3898    }
3899
3900    /// Compose the Aplicacao-related flat slots into a single typed
3901    /// [`crate::aplicacao::AplicacaoSpec`] for validation +
3902    /// downstream renderer consumption. Returns `None` when the
3903    /// caixa isn't a `:kind Aplicacao`.
3904    #[must_use]
3905    pub fn aplicacao_view(&self) -> Option<crate::aplicacao::AplicacaoSpec> {
3906        if !self.kind().is_aplicacao() {
3907            return None;
3908        }
3909        Some(crate::aplicacao::AplicacaoSpec {
3910            membros: self.membros().to_vec(),
3911            contratos: self.contratos().to_vec(),
3912            politicas: self.politicas().cloned().unwrap_or_default(),
3913            placement: self.placement().cloned().unwrap_or_default(),
3914            entrada: self.entrada().cloned(),
3915        })
3916    }
3917
3918    /// The kebab-case `:slot` tags of every M3 mesh slot this caixa
3919    /// *declares* a value on, in canonical declaration order
3920    /// (`:membros` → `:contratos` → `:politicas` → `:placement` →
3921    /// `:entrada`). A slot counts as declared when its backing field
3922    /// carries a value — a non-empty `Vec`, or a `Some(...)`.
3923    ///
3924    /// The M3 mesh slots compose the typed graph of a `:kind Aplicacao`
3925    /// (MESH-COMPOSITION §III.1). [`Self::aplicacao_view`] only folds
3926    /// them into a validatable [`crate::aplicacao::AplicacaoSpec`] when
3927    /// the kind matches (returns `None` otherwise), and the caixa-mesh /
3928    /// caixa-flux / caixa-helm renderers only emit them for an
3929    /// Aplicacao. On any *other* kind a declared mesh slot is the
3930    /// manifest field's documented "ignored otherwise" (see the
3931    /// `:membros` … `:entrada` field docs): it silently passes
3932    /// [`Caixa::from_lisp`] and then vanishes — never validated, never
3933    /// rendered — far from the source caixa.lisp.
3934    /// [`crate::StandardLayout::verify`] consults this to reject that
3935    /// silent-drop at caixa-build time
3936    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]), mirroring the
3937    /// `SupervisorOwnsCode` / `AplicacaoOwnsCode` kind-coherence gates:
3938    /// a slot foreign to the kind is a build error, not a silent drop.
3939    ///
3940    /// Lifted as a typed method (rather than an inline disjunction at
3941    /// the verify call site) so the mesh-slot set lives in one place —
3942    /// a future M4 axis added to the Aplicacao surface (per-edge policy
3943    /// overlay, distributed-app takeover config) is one push here, and
3944    /// every consumer reaching for "which mesh slots are set" (the
3945    /// verify gate, a future `feira lint` kind-coherence advisory)
3946    /// inherits the canonical order without rolling its own.
3947    ///
3948    /// Each per-arm kebab-case label is routed through the peer
3949    /// [`crate::M3_AUTHOR_KEY_MEMBROS`] /
3950    /// [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
3951    /// [`crate::M3_AUTHOR_KEY_POLITICAS`] /
3952    /// [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
3953    /// [`crate::M3_AUTHOR_KEY_ENTRADA`] consts declared next to the
3954    /// [`crate::M3_KEY_PLACEMENT`] renderer-side wire-key peer, so both
3955    /// halves of every M3 top-level mesh slot's dual axis (author-facing
3956    /// kebab-case label + renderer-side artifact key) route through one
3957    /// canonical declaration per arm — same discipline the peer
3958    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`]
3959    /// / [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot consts
3960    /// (f49c8b0) establish on the sibling per-Servico M2 top-level slot
3961    /// axis, extended here to close the M3 mesh-slot author-facing-label
3962    /// axis so both altitudes of the typed-slot algebra
3963    /// (per-Servico M2 + per-Aplicacao M3) share the same
3964    /// "one canonical byte-string per arm, next to the axis" discipline.
3965    #[must_use]
3966    pub fn declared_mesh_slots(&self) -> Vec<&'static str> {
3967        let mut slots = Vec::new();
3968        if !self.membros().is_empty() {
3969            slots.push(crate::render::M3_AUTHOR_KEY_MEMBROS);
3970        }
3971        if !self.contratos().is_empty() {
3972            slots.push(crate::render::M3_AUTHOR_KEY_CONTRATOS);
3973        }
3974        if self.politicas().is_some() {
3975            slots.push(crate::render::M3_AUTHOR_KEY_POLITICAS);
3976        }
3977        if self.placement().is_some() {
3978            slots.push(crate::render::M3_AUTHOR_KEY_PLACEMENT);
3979        }
3980        if self.entrada().is_some() {
3981            slots.push(crate::render::M3_AUTHOR_KEY_ENTRADA);
3982        }
3983        slots
3984    }
3985
3986    /// The kebab-case `:slot` tags of every supervisor-tree slot this
3987    /// caixa *declares* a value on, in canonical declaration order
3988    /// (`:estrategia` → `:max-restarts` → `:restart-window` →
3989    /// `:children`). A slot counts as declared when its backing field
3990    /// carries a value — a `Some(...)`, or a non-empty `Vec`.
3991    ///
3992    /// The supervisor-tree slots compose the typed OTP supervisor of a
3993    /// `:kind Supervisor` (INSPIRATIONS §II.2; the `:estrategia` +
3994    /// `:children` field docs above). [`Self::supervisor_view`] only
3995    /// folds them into a validatable [`SupervisorSpec`] when the kind
3996    /// matches (returns `None` otherwise), and the wasm-operator's
3997    /// hierarchical reconciler only consumes them for a Supervisor. On
3998    /// any *other* kind a declared supervisor slot is the manifest
3999    /// field's documented "ignored otherwise" (see the `:estrategia` …
4000    /// `:children` field docs): it silently passes [`Caixa::from_lisp`]
4001    /// and then vanishes — never validated, never reconciled — far from
4002    /// the source caixa.lisp. [`crate::StandardLayout::verify`] consults
4003    /// this to reject that silent-drop at caixa-build time
4004    /// ([`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]), the
4005    /// exact mirror of the [`Self::declared_mesh_slots`] /
4006    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] gate on the
4007    /// Aplicacao-only slot set: a slot foreign to the kind is a build
4008    /// error, not a silent drop.
4009    #[must_use]
4010    pub fn declared_supervisor_slots(&self) -> Vec<&'static str> {
4011        let mut slots = Vec::new();
4012        if self.estrategia().is_some() {
4013            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA);
4014        }
4015        if self.max_restarts().is_some() {
4016            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS);
4017        }
4018        if self.restart_window().is_some() {
4019            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW);
4020        }
4021        if !self.children().is_empty() {
4022            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN);
4023        }
4024        slots
4025    }
4026
4027    /// The kebab-case `:slot` tags of every M2 Servico-runtime slot this
4028    /// caixa *declares* a value on, in canonical declaration order
4029    /// (`:limits` → `:behavior` → `:upgrade-from`). A slot counts as
4030    /// declared when its backing field carries a value — a `Some(...)`,
4031    /// or a non-empty `Vec`.
4032    ///
4033    /// The M2 slots configure the runtime of a long-running wasm
4034    /// component, i.e. a `:kind Servico`: `:limits` is Lunatic
4035    /// per-process sandboxing (INSPIRATIONS §III.1), `:behavior` is the
4036    /// OTP `gen_server` callback set (§II.3), `:upgrade-from` is the OTP
4037    /// appup hot-code-reload table (§II.4). The caixa-helm / caixa-flux
4038    /// renderers gate on [`crate::require_kind`]`(_, Servico)` and only
4039    /// emit these slots for a Servico; on any *other* kind a declared M2
4040    /// slot is the manifest field's documented "ignored otherwise": its
4041    /// well-formedness is checked by [`crate::StandardLayout::verify`]
4042    /// but the value is never rendered into a chart / programs.yaml entry
4043    /// — it silently passes [`Caixa::from_lisp`] + `feira build` and then
4044    /// vanishes, far from the source caixa.lisp.
4045    /// [`crate::StandardLayout::verify`] consults this to reject that
4046    /// silent-drop at caixa-build time
4047    /// ([`crate::LayoutError::ServicoSlotsOnNonServico`]), the exact
4048    /// mirror of the [`Self::declared_mesh_slots`] /
4049    /// [`Self::declared_supervisor_slots`] gates on the peer
4050    /// kind-exclusive slot sets: a slot foreign to the kind is a build
4051    /// error, not a silent drop.
4052    ///
4053    /// Each per-arm kebab-case label is routed through the peer
4054    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
4055    /// [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts declared next to the
4056    /// [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
4057    /// [`crate::M2_KEY_UPGRADE_FROM`] renderer-side wire-key peers, so
4058    /// both halves of the M2 top-level slot's dual axis (author-facing
4059    /// kebab-case label + renderer-side camelCase overlay-container wire
4060    /// key) route through one canonical declaration per arm — same
4061    /// discipline the peer [`crate::M2_BEHAVIOR_AUTHOR_KEY_ON_*`] sub-slot
4062    /// author-label consts (889dc18) establish on the sibling
4063    /// per-callback axis inside the `:behavior` overlay block.
4064    #[must_use]
4065    pub fn declared_servico_slots(&self) -> Vec<&'static str> {
4066        let mut slots = Vec::new();
4067        if self.limits().is_some() {
4068            slots.push(crate::render::M2_AUTHOR_KEY_LIMITS);
4069        }
4070        if self.behavior().is_some() {
4071            slots.push(crate::render::M2_AUTHOR_KEY_BEHAVIOR);
4072        }
4073        if !self.upgrade_from().is_empty() {
4074            slots.push(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM);
4075        }
4076        slots
4077    }
4078
4079    /// The kebab-case `:slot` tags of every code-surface slot this caixa
4080    /// declares a value on that its [`CaixaKind`] doesn't natively own,
4081    /// in canonical declaration order (`:exe` → `:servicos`). A
4082    /// code-surface slot is owned by exactly one kind: `:exe` by
4083    /// [`CaixaKind::Binario`] (the nix-built executable surface), and
4084    /// `:servicos` by [`CaixaKind::Servico`] (the wasm component +
4085    /// `ComputeUnit` daemon surface).
4086    ///
4087    /// Each is silently ignored when declared on the wrong kind: the
4088    /// caixa-helm / caixa-flux / caixa-flake renderers gate on
4089    /// [`crate::require_kind`]`(_, <owning-kind>)`, so on any *other*
4090    /// code-running kind a declared `:exe` / `:servicos` is the manifest
4091    /// field's documented "ignored otherwise" — its path is checked for
4092    /// existence by the layout's `bibliotecas`/`exe`/`servicos` loops
4093    /// (which run after [`Caixa::from_lisp`]), but the value is never
4094    /// rendered into a build target or programs.yaml entry. It silently
4095    /// passes [`Caixa::from_lisp`] + `feira build`, far from the source
4096    /// caixa.lisp, with no field naming which slot is foreign.
4097    ///
4098    /// [`crate::StandardLayout::verify`] consults this to reject that
4099    /// silent-drop at caixa-build time
4100    /// ([`crate::LayoutError::ForeignCodeSlot`]), beside the M2
4101    /// servico-runtime, supervisor-tree, and M3 mesh kind-coherence
4102    /// gates ([`Self::declared_servico_slots`] /
4103    /// [`Self::declared_supervisor_slots`] /
4104    /// [`Self::declared_mesh_slots`]): the fourth kind ↔ slot algebra
4105    /// axis to be closed on the typed surface. The Supervisor /
4106    /// Aplicacao "no code at all" cases ([`crate::LayoutError::SupervisorOwnsCode`]
4107    /// / [`crate::LayoutError::AplicacaoOwnsCode`]) keep their dedicated
4108    /// diagnostics — they fire ahead of this gate on the same `verify`
4109    /// pass, so for Supervisor / Aplicacao the `OwnCode` arm always wins
4110    /// and this method is moot. For Biblioteca / Binario / Servico, this
4111    /// gate fires when a code-running kind declares another code-running
4112    /// kind's exclusive code surface.
4113    ///
4114    /// `:bibliotecas` is deliberately excluded — a Binario or Servico
4115    /// may legitimately ship a `lib/` helper that the underlying
4116    /// substrate (the nix flake for Binario, the wasm component build
4117    /// for Servico) bundles into its build, so the slot's
4118    /// declared-on-wrong-kind cardinality isn't a structural error on
4119    /// either code-running kind. A Biblioteca declaring `:bibliotecas`
4120    /// is the native case (the slot's owning kind). Supervisor /
4121    /// Aplicacao declaring `:bibliotecas` is gated upstream by
4122    /// [`crate::LayoutError::SupervisorOwnsCode`] /
4123    /// [`crate::LayoutError::AplicacaoOwnsCode`].
4124    ///
4125    /// Lifted as a typed method (rather than an inline disjunction at
4126    /// the verify call site) so the foreign-code-slot set lives in one
4127    /// place — a future kind that gains its own code-surface slot is
4128    /// one push here, and every consumer reaching for "which code
4129    /// surfaces are foreign to this kind" (the verify gate, a future
4130    /// `feira lint` kind-coherence advisory, the future `app-operator`'s
4131    /// per-caixa build-target classifier) inherits the canonical order
4132    /// without rolling its own.
4133    #[must_use]
4134    pub fn declared_foreign_code_slots(&self) -> Vec<&'static str> {
4135        let mut slots = Vec::new();
4136        if !self.exe().is_empty() && !self.kind().requires_exe() {
4137            slots.push(":exe");
4138        }
4139        if !self.servicos().is_empty() && !self.kind().requires_servicos() {
4140            slots.push(":servicos");
4141        }
4142        slots
4143    }
4144
4145    /// Validate every entry of `:deps` and `:deps-dev` through
4146    /// [`Dep::validate`] — closing the parity loop with the per-axis
4147    /// `:versao` gates already wired into the typed-graph
4148    /// ([`crate::AplicacaoSpec::validate_membros`] for `:membros`,
4149    /// 9888b13) and typed supervisor tree
4150    /// ([`crate::SupervisorSpec::validate`] for `:children`, b38ff3a).
4151    ///
4152    /// Until this gate landed `:deps :versao` and `:deps-dev :versao`
4153    /// were the only `:versao` axes still untyped past
4154    /// [`Caixa::from_lisp`]: the derive macro stored the requirement
4155    /// as a String without parsing it, so a malformed-but-non-empty
4156    /// requirement (`"^bad-version"`, `"^^0.1"`, `"v0.1"`, `"not-a-req"`)
4157    /// silently passed parse and the `semver::Error` surfaced at
4158    /// lacre-resolve time, far from the source caixa.lisp, with no
4159    /// field naming which `:deps` entry carried the typo. Lifting the
4160    /// gate here makes the four `:versao` typed surfaces (`:deps`,
4161    /// `:deps-dev`, `:membros`, `:children`) structurally equivalent —
4162    /// every requirement string past `validate_deps` is round-trippable
4163    /// through [`crate::parse_requirement`] without re-checking at the
4164    /// resolver layer.
4165    ///
4166    /// Both lists run through the same per-entry validator so a typo
4167    /// in `:deps-dev` surfaces with the same diagnostic as one in
4168    /// `:deps` — neither axis is a second-class citizen of the typed
4169    /// surface.
4170    ///
4171    /// Within each list, [`DepError::DuplicateNome`] closes the
4172    /// set-not-multiset discipline on the `:nome` axis: two entries
4173    /// naming the same caixa carry two `:versao` / `:fonte` / feature
4174    /// triples that the caixa-resolver's lacre pipeline collapses to one
4175    /// via its `HashMap`-keyed-by-`:nome` consumption — the second entry
4176    /// silently overwrites the first at `concrete_versao`-resolve time
4177    /// (the same "second wins / one silently overwrites the other"
4178    /// shape the peer typed-graph duplicate gates already close on every
4179    /// other Vec-shaped authoring surface that keys by name). The
4180    /// duplicate check fires per-list and runs *after* each per-entry
4181    /// [`Dep::validate`] call so a malformed-and-duplicated entry
4182    /// surfaces its narrower per-entry diagnostic
4183    /// ([`DepError::NomeInvalid`], [`DepError::VersaoInvalid`],
4184    /// [`DepError::FonteRepoEmpty`], …) before the cross-entry duplicate
4185    /// diagnostic — the canonical "per-entry shape before cross-entry
4186    /// uniqueness" precedence the peer `:children :caixa`
4187    /// ([`crate::SupervisorSpec::validate`]), `:membros :caixa`
4188    /// ([`crate::AplicacaoSpec::validate_membros`]), `:contratos`
4189    /// ([`crate::AplicacaoSpec::validate`]), `:placement :clusters`
4190    /// ([`crate::AplicacaoSpec::validate_placement`]),
4191    /// `:entrada :paths` ([`crate::AplicacaoSpec::validate`]),
4192    /// `:upgrade-from :from` ([`crate::upgrade::validate_upgrade_from`]),
4193    /// and the within-`:upgrade-from`-entry per-instruction-class
4194    /// singularity gates ([`crate::UpgradeError::DuplicateLoadModule`],
4195    /// [`crate::UpgradeError::DuplicateStateChange`],
4196    /// [`crate::UpgradeError::DuplicateCleanup`]) all establish.
4197    ///
4198    /// Cross-list (`:deps` ↔ `:deps-dev`) coincidence is *not* gated
4199    /// here: Cargo's `[dependencies]` + `[dev-dependencies]` accept the
4200    /// same name in both tables (the dev table's pin overrides the
4201    /// runtime table's pin in test/dev contexts), and caixa's surface
4202    /// mirrors that convention until a deliberate choice retires the
4203    /// override pattern. Only within-list duplicates are structurally
4204    /// incoherent — those are what this gate closes.
4205    ///
4206    /// Compound per-`Caixa` entry gate on the dep-graph axis: folds the
4207    /// two standalone dep-list validators — the per-entry + within-list
4208    /// duplicate-`:nome` walk (the [`Dep::validate`] +
4209    /// [`crate::render::insert_first_seen`] cascade this method opened
4210    /// on) and the cross-slot self-edge gate
4211    /// ([`crate::dep::validate_no_self_dep`]) — onto one substrate
4212    /// primitive on [`Caixa`]. The two arms run in the same canonical
4213    /// order the layout pipeline
4214    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4215    /// author-time gate) has always sequenced them (per-entry +
4216    /// cross-entry duplicate → cross-slot self-edge), so the fold is
4217    /// byte-for-byte equivalent to the pre-fold two-block cascade at
4218    /// that call site (pinned by the paired
4219    /// `validate_deps_folds_per_entry_arm_matches_gate` /
4220    /// `validate_deps_folds_self_edge_arm_matches_gate` equivalence
4221    /// pins and the `validate_deps_per_entry_arm_fires_before_self_edge_arm`
4222    /// ordering pin). Self-contained on `&self` — resolves its three
4223    /// inputs ([`Self::deps`], [`Self::deps_dev`], [`Self::nome`])
4224    /// through the substrate primitives' own accessor family, the same
4225    /// posture every peer per-slot compound gate
4226    /// ([`crate::AplicacaoSpec::validate_contratos`],
4227    /// [`crate::MeshPolicy::validate`],
4228    /// [`crate::SupervisorSpec::validate_children`],
4229    /// [`Self::validate_upgrade_from`]) already carries.
4230    ///
4231    /// Prior to this lift [`crate::dep::validate_no_self_dep`] lived
4232    /// only open-coded at the layout wire-up site
4233    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs)
4234    /// as a standalone two-arg dispatch immediately after this method's
4235    /// per-entry + cross-entry walk, both wrapped through the same
4236    /// [`crate::LayoutError::DepsViolation`] envelope: every future
4237    /// consumer that wanted to gate the dep-graph as a whole — the
4238    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4239    /// per-CR admission webhook re-checking `:deps` / `:deps-dev` after
4240    /// a per-entry patch, a future `feira validate --deps` per-caixa
4241    /// admission verb, a per-`:deps` overlay resolver a per-cluster
4242    /// overlay lift would materialize (each the deferred consumer this
4243    /// method's peer [`Self::deps`] / [`Self::deps_dev`] accessors'
4244    /// docstrings already name) — was structurally forced to either
4245    /// re-inline the two-dispatch cascade in lockstep with the layout
4246    /// wire-up (the duplication the PRIME DIRECTIVE names as a bug) or
4247    /// call the whole [`crate::layout::StandardLayout::verify`] pipeline
4248    /// and pay every peer per-Caixa gate to re-check one slot. Post-fold
4249    /// each such consumer reaches the two-arm compound gate through one
4250    /// call on the substrate primitive.
4251    pub fn validate_deps(&self) -> Result<(), DepError> {
4252        for &list in crate::dep::DepList::ALL {
4253            let mut seen = std::collections::HashSet::new();
4254            for dep in self.deps_of(list) {
4255                dep.validate()?;
4256                crate::render::insert_first_seen(&mut seen, dep.nome(), || {
4257                    DepError::duplicate_nome(dep.nome(), list.as_str())
4258                })?;
4259            }
4260        }
4261        crate::dep::validate_no_self_dep(self.deps(), self.deps_dev(), self.nome())?;
4262        Ok(())
4263    }
4264
4265    /// Run a per-slot typed validator on `self` and, on the per-arm
4266    /// parser-side error arm, thread the error into a paired
4267    /// [`crate::LayoutError`] wrap under `self.nome()`. Substrate
4268    /// primitive folding the 18 self-similar layout-pipeline wire-up
4269    /// sites at [`crate::layout::StandardLayout::verify`] that carry
4270    /// the identical
4271    /// `caixa.validate_<slot>().map_err(|err| crate::LayoutError::<slot>_violation(caixa, err))?;`
4272    /// cascade onto one dispatch. Each of the eighteen sites (`:nome`,
4273    /// `:nome`-chart-name-budget, `:versao`, `:deps`, `:etiquetas`,
4274    /// `:autores`, `:repositorio`, `:descricao`, `:licenca`, `:edicao`,
4275    /// `:bibliotecas`/`:exe`/`:servicos` code-path shape, `:limits`,
4276    /// `:behavior`, `:upgrade-from`, `:restart-window`, per-Supervisor
4277    /// shape, per-Aplicacao shape, per-Acao shape) carried the same
4278    /// four-line "run a per-slot typed validator on `caixa` and, on the
4279    /// per-arm parser-side error arm, thread it into the paired
4280    /// [`crate::LayoutError`] one-slot envelope through the substrate-
4281    /// canonical `layout_violation_ctors!` family (131ca0d)" cascade,
4282    /// differing only in the two names bound at each site — the
4283    /// validator (`Caixa::validate_deps` / `validate_nome` / ...) and
4284    /// the paired ctor (`LayoutError::deps_violation` / ...). Eighteen
4285    /// consumers, one identical shape, one substrate primitive on
4286    /// [`Caixa`] closing the duplication the PRIME DIRECTIVE names as
4287    /// a bug — on the second half of the per-slot cascade the peer
4288    /// substrate primitives on the [`crate::LayoutError`]-wrap side
4289    /// (the `layout_violation_ctors!` macro 131ca0d, the
4290    /// `layout_slot_kind_ctors!` macro 0419438, the `layout_nome_only_ctors!`
4291    /// macro 3fe3dd7, the [`crate::LayoutError::missing_entry`] ctor
4292    /// 1b09f9d, the [`crate::layout::StandardLayout::probe_declared_entry`]
4293    /// primitive fda1e35) each closed on their sibling envelopes; the
4294    /// first half of the cascade (the per-slot compound gates
4295    /// [`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
4296    /// baa4688, [`Self::validate_behavior`] 0d2877a,
4297    /// [`Self::validate_upgrade_from`] d6801df,
4298    /// [`Self::validate_aplicacao_shape`] 949a7a0,
4299    /// [`Self::validate_supervisor_shape`] 4c70105,
4300    /// [`Self::validate_acao_shape`] 5d6df54,
4301    /// [`Self::validate_kind_slot_coherence`] f0d286e,
4302    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
4303    /// [`Self::validate_ci_kind_coherence`] 9b55beb,
4304    /// [`Self::validate_required_kind_slot`] 9c385d8) each closed on
4305    /// their per-slot compound gates.
4306    ///
4307    /// Composes the [`crate::layout::LayoutError`] wrap and the per-slot
4308    /// typed validator through two typed callables: `gate` runs on
4309    /// `self` and yields a per-slot error `E`; on the `Err(E)` arm
4310    /// `wrap` re-wraps that error under `self` into a
4311    /// [`crate::layout::LayoutError`]. The `Ok(())` arm passes through
4312    /// verbatim as the fold's identity element — byte-equal to the
4313    /// pre-lift `Result::map_err` short-circuit at the `?;` marker
4314    /// every wire-up site formerly carried. Every future consumer that
4315    /// wants to run one of the per-slot gates and thread its error
4316    /// through the layout wrap (the deferred
4317    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission-
4318    /// webhook per-slot re-check, a future `feira validate --<slot>`
4319    /// per-caixa admission verb, an overlay resolver re-running one
4320    /// gate after a per-slot patch) reaches the two-callable dispatch
4321    /// through one call rather than re-inlining the four-line cascade
4322    /// in lockstep with the pre-existing 18 wire-ups. The two callables
4323    /// reach the primitive as first-class type-checked references
4324    /// rather than the pre-lift `.map_err(|err| CTOR(caixa, err))`
4325    /// closure body — so a mismatch between the validator's `E` type
4326    /// and the ctor's `E` bound trips at the wire-up site (compile-
4327    /// time) rather than at the closure body (also compile-time, but
4328    /// with a diagnostic pointing at the closure expression rather
4329    /// than the two named callables).
4330    pub fn run_layout_gate<E, W>(
4331        &self,
4332        gate: impl FnOnce(&Caixa) -> Result<(), E>,
4333        wrap: W,
4334    ) -> Result<(), crate::LayoutError>
4335    where
4336        W: FnOnce(&Caixa, E) -> crate::LayoutError,
4337    {
4338        gate(self).map_err(|err| wrap(self, err))
4339    }
4340
4341    /// Run one arm of the cross-family kind ↔ owned-slot-family
4342    /// coherence cascade on `self`: on a caixa whose [`Self::kind`] does
4343    /// not own the typed-slot family named by `is_owner`, refuse when
4344    /// the paired `accumulator` reports any declared slot in that
4345    /// family; otherwise pass. Substrate primitive folding the three
4346    /// self-similar four-line
4347    /// `if !self.kind().is_<owner>() { let slots = self.declared_<family>_slots();
4348    /// if !slots.is_empty() { return Err(<wrap>(self, slots)); } }`
4349    /// arms at [`Self::validate_kind_slot_coherence`] onto one dispatch.
4350    /// Three consumers (M3 mesh — Aplicacao-owner, supervisor-tree —
4351    /// Supervisor-owner, M2 Servico-runtime — Servico-owner), one
4352    /// identical shape, one substrate primitive on [`Caixa`] closing
4353    /// the duplication the PRIME DIRECTIVE names as a bug on the
4354    /// outer kind-coherence arm shape — peer with the substrate
4355    /// primitives on the two adjacent halves of the same three-arm
4356    /// cascade the sibling [`Self::declared_mesh_slots`] /
4357    /// [`Self::declared_supervisor_slots`] /
4358    /// [`Self::declared_servico_slots`] accumulator family closes on
4359    /// the inner slot-set enumerator axis and the sibling
4360    /// [`crate::layout::layout_slot_kind_ctors!`] macro (0419438)
4361    /// closes on the inner wrap-envelope ctor axis. Each of the three
4362    /// [`Self::validate_kind_slot_coherence`] arms now reads through
4363    /// one call across every altitude of the per-arm cascade:
4364    /// one dispatch on this primitive for the outer guard shape, one
4365    /// dispatch on `Self::declared_<family>_slots` for the accumulator,
4366    /// one dispatch on `crate::LayoutError::<family>_on_non_<owner>`
4367    /// for the wrap ctor.
4368    ///
4369    /// Composes the outer owner-kind guard, the per-family accumulator,
4370    /// and the per-family wrap ctor through three typed callables:
4371    /// `is_owner` runs on `&self.kind()` (a `&CaixaKind` borrow so the
4372    /// `gen_platform::IsVariant`-derived `fn(&CaixaKind) -> bool`
4373    /// per-arm predicates — [`crate::CaixaKind::is_aplicacao`] /
4374    /// [`crate::CaixaKind::is_supervisor`] / [`crate::CaixaKind::is_servico`]
4375    /// — pass verbatim as function references), `accumulator` runs on
4376    /// `&self` and yields the
4377    /// per-family declared-slot list, and `wrap` runs on `(&self,
4378    /// Vec<&'static str>)` and yields the per-family
4379    /// [`crate::LayoutError`] wrap. The `is_owner` short-circuit fires
4380    /// before the accumulator dispatch (so the owner kind of each
4381    /// family passes without invoking `accumulator`, byte-equal to the
4382    /// pre-lift `if !self.kind().is_<owner>() { … }` outer guard's
4383    /// short-circuit — pinned by
4384    /// `run_kind_owned_slot_family_gate_owner_kind_short_circuits_before_accumulator`),
4385    /// and the accumulator's `is_empty` short-circuit fires before the
4386    /// wrap dispatch (so a non-owner kind with no declared slot in that
4387    /// family passes without invoking `wrap`, byte-equal to the pre-lift
4388    /// `if !<slots>.is_empty() { … }` inner guard's short-circuit —
4389    /// pinned by
4390    /// `run_kind_owned_slot_family_gate_empty_accumulator_short_circuits_before_wrap`).
4391    /// The wrap ctor is `FnOnce(&Caixa, Vec<&'static str>) ->
4392    /// crate::LayoutError` — matching the [`crate::layout::layout_slot_kind_ctors!`]
4393    /// macro's per-variant `fn(&Caixa, Vec<&'static str>) -> LayoutError`
4394    /// substrate-canonical ctor shape verbatim, so
4395    /// [`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
4396    /// [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
4397    /// [`crate::LayoutError::servico_slots_on_non_servico`] pass as
4398    /// function references without a closure wrap. A mismatch between
4399    /// the ctor's signature and this bound trips at the wire-up site
4400    /// (compile-time) rather than at a closure body.
4401    ///
4402    /// The sibling [`crate::LayoutError::ForeignCodeSlot`] gate on the
4403    /// code-surface family sits outside this primitive because
4404    /// [`Self::declared_foreign_code_slots`] bakes the per-arm kind-
4405    /// check into the accumulator itself (each arm's
4406    /// `!self.kind().requires_<slot>()` guard fires inside the
4407    /// accumulator, not around it), so the code-surface arm carries no
4408    /// outer `is_owner`-shaped guard and its dispatch reads through
4409    /// [`Self::validate_foreign_code_kind_coherence`] verbatim without
4410    /// this primitive — the same posture the `_no_code_` /
4411    /// `_ci_kind_` coherence axes take on their respective per-arm
4412    /// shapes. The primitive here is specific to the "outer
4413    /// non-owner-kind guard + inner accumulator + inner emptiness
4414    /// guard + wrap" arm shape that fires three times in
4415    /// [`Self::validate_kind_slot_coherence`].
4416    ///
4417    /// Every future consumer that wants to gate one kind-owned slot
4418    /// family as a unit outside the composed cascade (the deferred
4419    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission-
4420    /// webhook per-family re-check after a per-slot patch, a future
4421    /// `feira validate --<family>-coherence` per-caixa admission verb,
4422    /// a per-`Caixa` overlay resolver rejecting a kind-foreign patch
4423    /// on one family) reaches the four-line arm through one call
4424    /// rather than re-inlining the outer-guard + accumulator +
4425    /// emptiness-guard + wrap cascade in lockstep with the pre-existing
4426    /// three arms. Every future kind-owned typed-slot family (an
4427    /// `Actor`-owned per-virtual-actor grain slot the M5 Orleans-
4428    /// inspired kind reaches through, a per-Aplicacao overlay slot the
4429    /// M4 CR materializer consults) folds onto
4430    /// [`Self::validate_kind_slot_coherence`] as one additional
4431    /// dispatch on this primitive rather than a fourth open-coded
4432    /// four-line block.
4433    pub fn run_kind_owned_slot_family_gate<F, A, W>(
4434        &self,
4435        is_owner: F,
4436        accumulator: A,
4437        wrap: W,
4438    ) -> Result<(), crate::LayoutError>
4439    where
4440        F: FnOnce(&crate::CaixaKind) -> bool,
4441        A: FnOnce(&Caixa) -> Vec<&'static str>,
4442        W: FnOnce(&Caixa, Vec<&'static str>) -> crate::LayoutError,
4443    {
4444        if is_owner(&self.kind()) {
4445            return Ok(());
4446        }
4447        let slots = accumulator(self);
4448        if slots.is_empty() {
4449            return Ok(());
4450        }
4451        Err(wrap(self, slots))
4452    }
4453
4454    /// Reject `:nome` values the K8s apiserver would refuse at admission
4455    /// time. The top-level Caixa identity flows directly into every
4456    /// substrate-side artifact's `metadata.name` axis: the
4457    /// `lareira-<nome>` Helm chart name ([`caixa-helm::lib::chart_name`]),
4458    /// the programs.yaml `name:` entry the `lareira-fleet-programs`
4459    /// aggregator keys ComputeUnit derivation off
4460    /// ([`caixa-flux::lib::programs_yaml_entry`]), the
4461    /// `LABEL_APLICACAO` label value carried on every Aplicacao-owned
4462    /// pod and the per-`:contratos` CiliumNetworkPolicy `metadata.name`
4463    /// (`<aplicacao>-<de>-to-<para>`) and the per-`:entrada`
4464    /// `<aplicacao>-<para>` HTTPRoute `metadata.name`
4465    /// ([`caixa-mesh::lib::cilium_network_policies`],
4466    /// [`caixa-mesh::lib::gateway_routes`]), and the default
4467    /// `lib/<nome>.lisp` / `exe/<nome>` layout paths
4468    /// ([`crate::StandardLayout::verify`]). Each K8s apiserver-side
4469    /// schema enforces the DNS-1123 label rule on admission; a
4470    /// structurally invalid `:nome` (`"MyApp"` — the canonical
4471    /// "I copied the display name verbatim" footgun, `"my_app"` — the
4472    /// Python-/Postgres-leak, `"team.app"` — `:nome` is a single label
4473    /// not a subdomain, `"-app"` / `"app-"` — DNS-1123 boundary
4474    /// violations, `"my app"` — the paste-from-doc footgun, `"café"` —
4475    /// IDN must be pre-encoded as Punycode, the 64-byte UUID-shaped
4476    /// over-cap slug) silently passed [`Caixa::from_lisp`] and the
4477    /// failure surfaced at `kubectl apply` time as a `metadata.name:
4478    /// Invalid value` rejection on whichever derived artifact admitted
4479    /// first, far from the source `caixa.lisp` and without any field
4480    /// naming the offending `:nome`.
4481    ///
4482    /// Thin wrapper around [`crate::render::is_dns_1123_label`] (the
4483    /// substrate-side predicate the per-axis name gates already share:
4484    /// `:membros :caixa` 3f9d7a0, `:placement :clusters` 6cbb900,
4485    /// `:children :caixa` 31bfa43) that maps the shared parser-shaped
4486    /// reason into the [`ManifestError::NomeInvalid`] variant, so the
4487    /// diagnostic is self-locating (the offending `:nome` is named
4488    /// verbatim) and the author can grep their `caixa.lisp` for
4489    /// `:nome "<value>"` and fix it in one edit. Same diagnostic shape
4490    /// every per-axis sibling gate already exposes
4491    /// ([`crate::AplicacaoError::MembroCaixaInvalid`],
4492    /// [`crate::AplicacaoError::PlacementClusterInvalid`],
4493    /// [`crate::SupervisorError::ChildCaixaInvalid`]).
4494    ///
4495    /// Empty `:nome` (which [`Caixa::from_lisp`] does not reject — the
4496    /// derive macro stores the raw String) is gated by the narrower
4497    /// [`ManifestError::NomeEmpty`] arm before the predicate is
4498    /// consulted, mirroring the empty-first cascade every per-axis
4499    /// name gate already uses (e.g. `MembroCaixaEmpty` before
4500    /// `MembroCaixaInvalid`, `EmptyChildName` before `ChildCaixaInvalid`).
4501    pub fn validate_nome(&self) -> Result<(), ManifestError> {
4502        // Routes through the shared
4503        // [`crate::render::require_valid_dns_1123_label`] gate the peer
4504        // name axes each land on so drift between the eight axes'
4505        // accepted DNS-1123-label sets is structurally impossible.
4506        let nome = self.nome();
4507        crate::render::require_valid_dns_1123_label(
4508            nome,
4509            || ManifestError::NomeEmpty,
4510            |reason| ManifestError::nome_invalid(nome, reason),
4511        )
4512    }
4513
4514    /// Reject `:nome` values whose joint length with the canonical
4515    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] (`"lareira-"`) overflows
4516    /// the K8s DNS-1123 label cap [`crate::DNS_1123_LABEL_MAX_LEN`]
4517    /// (63 bytes). Every per-Servico / per-Aplicacao renderer the
4518    /// substrate carries materializes the caixa's `:nome` through the
4519    /// canonical [`crate::lareira_chart_name`] helper (f7320d7) into a
4520    /// `lareira-<nome>` artifact that lands as a K8s `metadata.name` /
4521    /// Helm chart name / `HelmRelease` `release_name`: `caixa-helm`'s
4522    /// `ChartDir.name` + `Chart.yaml::name`
4523    /// (caixa-helm/src/lib.rs:207), `caixa-flux`'s `cluster_bundle`
4524    /// `HelmRelease` `chart:` slot (caixa-flux/src/lib.rs:329),
4525    /// `caixa-tatara`'s `process_for_aplicacao` `release_name` +
4526    /// `oci://<registry>/lareira-<nome>` chart ref
4527    /// (caixa-tatara/src/lib.rs:124,178). Helm's own `Chart.yaml::name`
4528    /// admission rule strict-parses against DNS-1123-label, the Helm
4529    /// operator's tracking-secret name is derived from `release_name`
4530    /// and is itself DNS-1123-label-bounded, and the rendered chart's
4531    /// K8s object `metadata.name` axes embed the chart name as a
4532    /// prefix — every one fails admission on a > 63-byte chart name.
4533    ///
4534    /// The per-axis [`Self::validate_nome`] gate (6c992f8) already
4535    /// caps `:nome` itself at 63 bytes via [`is_dns_1123_label`], so a
4536    /// `:nome` of 56–63 bytes silently passed validate (the inner
4537    /// DNS-1123 check accepts the bare `:nome`) but produced a
4538    /// `lareira-<nome>` of 64–71 bytes that the apiserver / `helm lint`
4539    /// rejected at admission — far from the source `caixa.lisp`, with
4540    /// no field naming the overflow root cause. The
4541    /// [`lareira_chart_name`] helper's own doc comment
4542    /// (caixa-core/src/render.rs:3198) explicitly deferred the fix:
4543    /// "the M4 admission webhook will pin the joint-length invariant
4544    /// when it lands". This gate lands the invariant at the
4545    /// manifest-validate layer rather than waiting for the apiserver
4546    /// — the same fail-at-the-source posture every peer per-axis
4547    /// value-shape gate (DNS-1123 on `:nome`, SemVer-2 on `:versao`,
4548    /// SPDX-expression-shape on `:licenca`, 4-digit decimal year on
4549    /// `:edicao`, etc.) takes.
4550    ///
4551    /// Thin wrapper around
4552    /// [`crate::render::is_lareira_chart_name_shape`] (the
4553    /// substrate-side predicate that composes [`lareira_chart_name`] +
4554    /// [`is_dns_1123_label`] via the lifted
4555    /// [`crate::LAREIRA_CHART_NAME_NOME_MAX_LEN`] budget); maps the
4556    /// shared parser-shaped reason into the
4557    /// [`ManifestError::NomeChartNameBudgetExceeded`] variant so the
4558    /// diagnostic is self-locating (the offending `:nome` is named
4559    /// verbatim alongside the rendered chart name and the budget) and
4560    /// the author can shorten in one edit. The gate runs across every
4561    /// `:kind` — `:nome` is the substrate-wide identity axis any
4562    /// future renderer the substrate adds can derive a
4563    /// `lareira-<nome>` artifact from, and uniform enforcement closes
4564    /// the drift footgun where a future kind grows a chart-emitting
4565    /// render path while the validate cascade doesn't catch it.
4566    ///
4567    /// Runs *after* [`Self::validate_nome`] so the narrower
4568    /// `NomeEmpty` / `NomeInvalid` shape diagnostics fire first — a
4569    /// structurally-malformed `:nome` (empty, uppercase, underscore,
4570    /// dot, leading/trailing hyphen, Unicode, > 63 bytes) surfaces its
4571    /// specific shape error rather than the chart-name-budget error,
4572    /// preserving the legitimate "well-shaped `:nome` that happens to
4573    /// overflow the joint cap" arm for this gate.
4574    pub fn validate_nome_chart_name_budget(&self) -> Result<(), ManifestError> {
4575        let nome = self.nome();
4576        crate::render::is_lareira_chart_name_shape(nome)
4577            .map_err(|reason| ManifestError::nome_chart_name_budget_exceeded(nome, reason))
4578    }
4579
4580    /// Reject `:versao` values that don't parse as [`semver::Version`].
4581    /// The top-level Caixa version flows directly into every
4582    /// substrate-side artifact that carries a "this is which version of
4583    /// the caixa" axis: the `lareira-<nome>` Helm chart's `Chart.yaml`
4584    /// `version:` + `appVersion:` axes ([`caixa-helm::lib`] —
4585    /// SemVer-2-strict at `helm template` / `helm install` time per
4586    /// https://helm.sh/docs/topics/charts/#charts-and-versioning), the
4587    /// `feira publish` Zig-style `v<versao>` git tag
4588    /// ([`caixa-flux::lib::programs_yaml_entry`] / the
4589    /// `caixa-publish.yml` reusable workflow), the programs.yaml entry's
4590    /// `versao:` value the `lareira-fleet-programs` aggregator carries
4591    /// onto each rendered ComputeUnit, the OCI image's `:v<versao>` /
4592    /// `:latest` tags the substrate's `wasi-service-flake` builds with
4593    /// `skopeo push`, the lacre closure's pinned versions
4594    /// ([`caixa-resolver`] keys `concrete_versao`), and the
4595    /// `:upgrade-from :from` references peers in this exact `versao`
4596    /// shape (`semver::Version`, not `VersionReq`). Each consumer
4597    /// expects a strict three-part `MAJOR.MINOR.PATCH` (optionally
4598    /// `-prerelease` and/or `+build`); a structurally invalid `:versao`
4599    /// (`"0.1"` — missing patch, the canonical "I shortened it" footgun;
4600    /// `"v0.1.0"` — the git-tag-shape-leaking-into-versao typo;
4601    /// `"latest"` / `"main"` — the "I confused it with a docker tag"
4602    /// footgun; `"^0.1"` / `"~0.1.2"` — the requirement-shape leaking
4603    /// into the version field a peer `:deps :versao` accepts;
4604    /// `"0.1.0.0"` — the four-part Java/Microsoft convention DNS
4605    /// SemVer-2 forbids) silently passed [`Caixa::from_lisp`] (the
4606    /// derive macro stores the raw String) and the failure surfaced at
4607    /// the *first* downstream consumer that strict-parses it: at
4608    /// `helm install` time as a chart-version rejection, at
4609    /// `feira publish` time as a malformed git tag, at lacre-resolve
4610    /// time as a `semver::Error` not naming the offending caixa, at
4611    /// `feira upgrade --to <versao>` time as an unresolvable
4612    /// `:upgrade-from :from` match — far from the source `caixa.lisp`
4613    /// and without any field naming the offending `:versao`.
4614    ///
4615    /// Thin wrapper around [`semver::Version::parse`] — the same parser
4616    /// [`crate::CaixaVersion::parse`] (the typed `:versao` accessor)
4617    /// and [`crate::UpgradeFromEntry::validate`] (the peer
4618    /// `:upgrade-from :from` axis, 26da2c7) consume. Maps the
4619    /// `semver::Error` reason into the [`ManifestError::VersaoInvalid`]
4620    /// variant, carrying the offending `:versao` verbatim + a
4621    /// parser-shaped reason naming the specific violation, so the
4622    /// diagnostic is self-locating (the author can grep their
4623    /// `caixa.lisp` for `:versao "<value>"` and fix it in one edit).
4624    /// Same diagnostic shape as [`ManifestError::NomeInvalid`]
4625    /// (6c992f8) and [`crate::UpgradeError::FromInvalid`]
4626    /// (b0c8389) on the peer axes. With this gate, the typed `:versao`
4627    /// surfaces — top-level `:versao`, `:upgrade-from :from` — are
4628    /// now structurally equivalent (every value past validate is
4629    /// round-trippable through [`semver::Version::parse`] without
4630    /// re-checking at the renderer, resolver, or operator hot-upgrade
4631    /// layer), peer with the four `:versao` requirement axes (`:deps`,
4632    /// `:deps-dev`, `:membros`, `:children`) the prior commits
4633    /// (2420c44, 9888b13, b38ff3a) wired through `parse_requirement`.
4634    ///
4635    /// Empty `:versao` (which [`Caixa::from_lisp`] does not reject —
4636    /// the derive macro stores the raw String) is gated by the
4637    /// narrower [`ManifestError::VersaoEmpty`] arm before the parser is
4638    /// consulted, mirroring the empty-first cascade every per-axis
4639    /// version gate already uses (e.g. `MembroVersaoEmpty` before
4640    /// `MembroVersaoInvalid`, `EmptyChildVersion` before
4641    /// `ChildVersaoInvalid`, `NomeEmpty` before `NomeInvalid`).
4642    pub fn validate_versao(&self) -> Result<(), ManifestError> {
4643        let versao = self.versao();
4644        if versao.is_empty() {
4645            return Err(ManifestError::VersaoEmpty);
4646        }
4647        semver::Version::parse(versao)
4648            .map_err(|e| ManifestError::versao_invalid(versao, e.to_string()))?;
4649        Ok(())
4650    }
4651
4652    /// Compound per-`Caixa` entry gate on the M2 `:upgrade-from` slot:
4653    /// folds the three [`crate::upgrade`] top-level validators — the
4654    /// per-entry shape + cross-entry duplicate-`:from` gate
4655    /// ([`crate::upgrade::validate_upgrade_from`]), the cross-slot
4656    /// `:from < :versao` SemVer-2 precedence gate
4657    /// ([`crate::upgrade::validate_upgrade_from_against_versao`]), and the
4658    /// cross-slot `:state-change` ↔ `:on-state-change` composition gate
4659    /// ([`crate::upgrade::validate_upgrade_from_against_behavior`]) — onto
4660    /// one substrate primitive on [`Caixa`]. The three dispatches run in
4661    /// the same order the layout pipeline
4662    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4663    /// author-time gate) has always sequenced them, so the fold is
4664    /// byte-for-byte equivalent to the pre-fold three-block cascade at
4665    /// that call site (pinned by the per-arm
4666    /// `validate_upgrade_from_folds_per_entry_arm_matches_gate` /
4667    /// `_folds_versao_arm_matches_gate` / `_folds_behavior_arm_matches_gate`
4668    /// equivalence pins and by the cross-arm
4669    /// `validate_upgrade_from_per_entry_arm_fires_before_versao_arm` /
4670    /// `_versao_arm_fires_before_behavior_arm` ordering pins).
4671    ///
4672    /// Prior to this lift the three [`crate::upgrade`] top-level validators
4673    /// lived only open-coded at the layout wire-up site
4674    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4675    /// each threaded through the same `self.upgrade_from()` slice and each
4676    /// paired with the same [`crate::LayoutError::UpgradeViolation`]-wrap
4677    /// envelope: every future consumer that wanted to gate `:upgrade-from`
4678    /// as a whole — the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
4679    /// materializer's per-CR admission webhook re-checking `:upgrade-from`
4680    /// after a per-`(:from … :instructions …)` patch, a future `feira
4681    /// validate --upgrade` per-caixa admission verb, a per-`:upgrade-from`
4682    /// overlay resolver a per-cluster overlay lift would materialize —
4683    /// was structurally forced to either re-inline the three-dispatch
4684    /// cascade in lockstep with the layout wire-up (the duplication the
4685    /// PRIME DIRECTIVE names as a bug) or call the whole
4686    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4687    /// peer per-Caixa gate to re-check one slot. Post-fold each such
4688    /// consumer reaches the three-arm compound gate through one call on
4689    /// the substrate primitive.
4690    ///
4691    /// The three arms together name one contract with three axes:
4692    ///
4693    ///   - **per-entry + cross-entry graph-edge invariant** — every entry's
4694    ///     `:from` parses as SemVer-2 and every per-instruction / within-
4695    ///     entry ordering / singularity gate on each entry's
4696    ///     `:instructions` list passes, and no two entries share the same
4697    ///     parsed `:from` (the wasm-operator's OTP appup
4698    ///     `release_handler:install_release/1` analog picks at most one
4699    ///     matching block per running version — two entries with the same
4700    ///     parsed semver are an ambiguous edge in the typed upgrade graph).
4701    ///   - **cross-slot reachability invariant** — every entry's `:from`
4702    ///     is strictly less than the caixa's own `:versao` under SemVer-2
4703    ///     precedence. An entry whose `:from >= :versao` is structurally
4704    ///     unreachable by the operator's `:from`-match dispatch (the
4705    ///     operator loads the current `:versao` and matches the *running*
4706    ///     version against each entry's `:from`; an entry whose `:from >=
4707    ///     :versao` is never reached because the operator never runs a
4708    ///     version >= the current one that it could then upgrade *to* the
4709    ///     current one).
4710    ///   - **cross-slot composition invariant** — every entry carrying a
4711    ///     `(:state-change …)` instruction has a `:behavior
4712    ///     :on-state-change` callback declared on the same caixa. The
4713    ///     per-version migration script is the `gen_server:code_change/3`
4714    ///     analog and the runtime hook it is delivered through during hot
4715    ///     upgrade is the `:on-state-change` callback (the upgrade.rs
4716    ///     module doc pins the composition verbatim: "Composes with the
4717    ///     `:behavior :on-state-change` callback to deliver state migration
4718    ///     during hot upgrades").
4719    ///
4720    /// All three axes must hold together — every consumer's
4721    /// `:upgrade-from` accept-set past this compound gate is the same
4722    /// set the `feira build` author-time gate admits.
4723    ///
4724    /// The per-slot compound entry gate discipline lifted here onto the
4725    /// M2 `:upgrade-from` axis is the sibling of the peer per-kind
4726    /// compound entry gates ([`crate::render::require_supervisor_view`]
4727    /// / [`crate::render::require_aplicacao_view`] /
4728    /// [`crate::render::require_v0_servico_shape`]) that fold every
4729    /// per-kind cascade at the per-kind altitude, and of the peer
4730    /// per-slot compound gates ([`crate::AplicacaoSpec::validate_contratos`],
4731    /// [`crate::MeshPolicy::validate`],
4732    /// [`crate::SupervisorSpec::validate_children`]) that fold every
4733    /// structural axis on their slot onto one substrate primitive.
4734    /// Extended here to the last unlifted compound-cascade wire-up at
4735    /// the layout-pipeline altitude — the three-dispatch M2
4736    /// `:upgrade-from` cascade that lived only open-coded at the layout
4737    /// wire-up site.
4738    ///
4739    /// The per-instruction script-path on-disk existence-probe walk that
4740    /// [`crate::layout::StandardLayout::verify`] runs immediately after
4741    /// this gate (which resolves each entry's `:instructions
4742    /// (:state-change :script)` against the layout root) stays open-coded
4743    /// at the layout wire-up site — that arm needs the filesystem oracle
4744    /// on the [`crate::LayoutInvariants`] trait, not the pure per-Caixa
4745    /// typed-shape surface this compound gate folds. Same posture the
4746    /// peer [`Self::validate_code_paths`] takes on the sibling code-path
4747    /// axes: the typed-shape gate fires on the per-Caixa surface, the
4748    /// on-disk existence check fires on the [`crate::StandardLayout`]
4749    /// surface.
4750    ///
4751    /// # Errors
4752    ///
4753    /// Returns [`crate::UpgradeError::FromInvalid`] /
4754    /// [`crate::UpgradeError::ModuleEmpty`] /
4755    /// [`crate::UpgradeError::ModuleInvalid`] /
4756    /// [`crate::UpgradeError::EmptyScript`] /
4757    /// [`crate::UpgradeError::AbsoluteScript`] /
4758    /// [`crate::UpgradeError::ParentEscapeScript`] /
4759    /// [`crate::UpgradeError::NonLispExtensionScript`] /
4760    /// [`crate::UpgradeError::RestartNotExclusive`] /
4761    /// [`crate::UpgradeError::StateChangeWithoutPriorLoad`] /
4762    /// [`crate::UpgradeError::PurgeWithoutPriorLoad`] /
4763    /// [`crate::UpgradeError::StateChangeAfterCleanup`] /
4764    /// [`crate::UpgradeError::DuplicateLoadModule`] /
4765    /// [`crate::UpgradeError::DuplicateStateChange`] /
4766    /// [`crate::UpgradeError::DuplicateCleanup`] /
4767    /// [`crate::UpgradeError::DuplicateFrom`] on the per-entry +
4768    /// cross-entry axis; [`crate::UpgradeError::FromNotBeforeVersao`] on
4769    /// the cross-slot `:from ↔ :versao` axis;
4770    /// [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
4771    /// on the cross-slot `:state-change ↔ :on-state-change` axis.
4772    pub fn validate_upgrade_from(&self) -> Result<(), crate::UpgradeError> {
4773        crate::upgrade::validate_upgrade_from(self.upgrade_from())?;
4774        crate::upgrade::validate_upgrade_from_against_versao(self.upgrade_from(), self.versao())?;
4775        crate::upgrade::validate_upgrade_from_against_behavior(
4776            self.upgrade_from(),
4777            self.behavior(),
4778        )?;
4779        Ok(())
4780    }
4781
4782    /// Compound per-`Caixa` entry gate on the M2 `:limits` slot — folds
4783    /// the [`crate::LimitsSpec::validate`] four-axis cascade (`:memory`
4784    /// wasm32 zero-floor / below-page / above-cap / non-page-multiple;
4785    /// `:fuel` zero-floor / cap; `:wall-clock` zero-floor / cap; `:cpu`
4786    /// zero-floor / cap) onto one substrate primitive on [`Caixa`]. The
4787    /// `#[serde(default)]` absent-slot arm (`limits: None`, the
4788    /// canonical "no bound declared — engine-default applies" author
4789    /// shape [`crate::LimitsSpec::is_empty`]'s per-axis `None` cascade
4790    /// reads) is the fold's identity element and passes trivially; the
4791    /// present-slot arm (`limits: Some(l)`) dispatches to
4792    /// [`crate::LimitsSpec::validate`] verbatim, threading its per-axis
4793    /// [`crate::LimitsError`] Display through untouched.
4794    ///
4795    /// Prior to this lift the M2 `:limits` slot lived only wired
4796    /// open-coded at the layout wire-up site
4797    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4798    /// through the `if let Some(l) = caixa.limits() { l.validate() … }`
4799    /// three-line `Option::None → Ok(()) | Some(_) → …` unwrap-and-
4800    /// dispatch pattern paired with the same
4801    /// [`crate::LayoutError::LimitsViolation`]-wrap envelope: every
4802    /// future consumer that wanted to gate `:limits` as a whole — the
4803    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4804    /// per-CR admission webhook re-checking `:limits` after a per-
4805    /// `{:memory, :fuel, :wall-clock, :cpu}` patch (the exact case the
4806    /// [`Self::limits`] accessor docstring names as the second
4807    /// consumer of the slot), a future `feira validate --limits` per-
4808    /// caixa admission verb, a per-`:limits` overlay resolver a per-
4809    /// cluster `:limits-overrides` overlay lift would materialize — was
4810    /// structurally forced to either re-inline the two-line
4811    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4812    /// pattern in lockstep with the layout wire-up (the duplication the
4813    /// PRIME DIRECTIVE names as a bug) or call the whole
4814    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4815    /// peer per-Caixa gate ([`Self::validate_nome`],
4816    /// [`Self::validate_versao`], [`Self::validate_deps`],
4817    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4818    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4819    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4820    /// [`Self::validate_upgrade_from`], [`Self::validate_code_paths`],
4821    /// plus the per-kind `require_supervisor_view` /
4822    /// `require_aplicacao_view` gates, plus the on-disk existence
4823    /// walks) to re-check one slot. Post-lift each such consumer
4824    /// reaches the [`crate::LimitsSpec::validate`] four-axis cascade
4825    /// (and its identity-element on the absent slot) through one call
4826    /// on the substrate primitive.
4827    ///
4828    /// The per-slot compound entry-gate discipline lifted here onto the
4829    /// M2 `:limits` axis is the sibling of the peer per-slot compound
4830    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4831    /// [`crate::MeshPolicy::validate`],
4832    /// [`crate::SupervisorSpec::validate_children`],
4833    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`]) that
4834    /// fold every structural + cross-slot axis on their slot onto one
4835    /// substrate primitive. Extended here to the M2 `:limits` slot, the
4836    /// first of the two M2 typed slots (`:limits`, `:behavior`) whose
4837    /// per-Caixa compound-gate wire-up still lived open-coded at the
4838    /// layout altitude after the [`Self::validate_upgrade_from`] lift
4839    /// (d6801df) closed the sibling M2 slot's cascade.
4840    ///
4841    /// # Errors
4842    ///
4843    /// Returns every [`crate::LimitsError`] variant on the present-slot
4844    /// arm — verbatim from [`crate::LimitsSpec::validate`]. Passes
4845    /// trivially on the absent-slot arm (`limits: None`, the fold's
4846    /// identity element).
4847    pub fn validate_limits(&self) -> Result<(), crate::LimitsError> {
4848        match self.limits() {
4849            Some(l) => l.validate(),
4850            None => Ok(()),
4851        }
4852    }
4853
4854    /// Compound per-`Caixa` entry gate on the M2 `:behavior` slot's
4855    /// pure typed-shape surface — folds the
4856    /// [`crate::BehaviorSpec::validate`] six-slot value-shape cascade
4857    /// (each declared `:on-init` / `:on-call` / `:on-cast` / `:on-info`
4858    /// / `:on-state-change` / `:on-terminate` callback-path is
4859    /// non-empty / relative / no-`..`-parent-escape / terminating-
4860    /// `.lisp`-extension, routed through the shared
4861    /// [`crate::render::require_sandboxed_lisp_path`] arm-set) onto one
4862    /// substrate primitive on [`Caixa`]. The `#[serde(default)]`
4863    /// absent-slot arm (`behavior: None`, the canonical "no callback
4864    /// declared — the runtime falls back to the wasm-engine's default
4865    /// callback per arm" author shape [`crate::BehaviorSpec::is_empty`]'s
4866    /// per-slot `None` cascade reads) is the fold's identity element
4867    /// and passes trivially; the present-slot arm (`behavior: Some(b)`)
4868    /// dispatches to [`crate::BehaviorSpec::validate`] verbatim,
4869    /// threading its per-slot [`crate::BehaviorError`] Display through
4870    /// untouched.
4871    ///
4872    /// Scope note — the on-disk callback-path existence walk paired
4873    /// with the value-shape gate at
4874    /// [`crate::layout::StandardLayout::verify`] stays open-coded at
4875    /// the layout altitude, because it needs the
4876    /// [`crate::layout::LayoutInvariants`] filesystem oracle
4877    /// ([`crate::layout::LayoutInvariants::exists`]) that the pure
4878    /// per-Caixa typed-shape surface this compound gate folds onto has
4879    /// no reference to. Same posture the peer M2 `:upgrade-from`
4880    /// per-Caixa compound gate ([`Self::validate_upgrade_from`]
4881    /// d6801df) already carries: the pure typed-shape surface folds
4882    /// onto the substrate primitive; the per-instruction script-path
4883    /// existence probe on the paired axis (there `:state-change
4884    /// :script`; here `:on-*`) stays at the layout altitude.
4885    ///
4886    /// Prior to this lift the pure value-shape surface of the M2
4887    /// `:behavior` slot lived only wired open-coded at the layout
4888    /// wire-up site ([`crate::layout::StandardLayout::verify`],
4889    /// caixa-core/src/layout.rs), through the
4890    /// `if let Some(b) = caixa.behavior() { b.validate() … }`
4891    /// unwrap-and-dispatch pattern paired with the same
4892    /// [`crate::LayoutError::BehaviorViolation`]-wrap envelope: every
4893    /// future consumer that wanted to gate the `:behavior` slot's
4894    /// value-shape as a whole — the deferred
4895    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
4896    /// admission webhook re-checking `:behavior` after a per-`{:on-init,
4897    /// :on-call, :on-cast, :on-info, :on-state-change, :on-terminate}`
4898    /// patch (the exact case the peer `:on-*` accessor docstrings on
4899    /// [`crate::BehaviorSpec`] already name as deferred consumers of
4900    /// the slot), a future `feira validate --behavior` per-caixa
4901    /// admission verb, a per-`:behavior` overlay resolver a future
4902    /// per-cluster callback-overlay lift would materialize — was
4903    /// structurally forced to either re-inline the two-line
4904    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4905    /// pattern in lockstep with the layout wire-up (the duplication the
4906    /// PRIME DIRECTIVE names as a bug) or call the whole
4907    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4908    /// peer per-Caixa gate ([`Self::validate_nome`],
4909    /// [`Self::validate_versao`], [`Self::validate_deps`],
4910    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4911    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4912    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4913    /// [`Self::validate_limits`], [`Self::validate_upgrade_from`],
4914    /// [`Self::validate_code_paths`], plus the per-kind
4915    /// `require_supervisor_view` / `require_aplicacao_view` gates, plus
4916    /// the on-disk existence walks) to re-check one slot. Post-lift
4917    /// each such consumer reaches the [`crate::BehaviorSpec::validate`]
4918    /// six-slot cascade (and its identity-element on the absent slot)
4919    /// through one call on the substrate primitive.
4920    ///
4921    /// The per-slot compound entry-gate discipline lifted here onto the
4922    /// M2 `:behavior` axis is the sibling of the peer per-slot compound
4923    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4924    /// [`crate::MeshPolicy::validate`],
4925    /// [`crate::SupervisorSpec::validate_children`],
4926    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`],
4927    /// [`Self::validate_limits`]) that fold every structural + cross-
4928    /// slot axis on their slot onto one substrate primitive. Extended
4929    /// here to the M2 `:behavior` slot, the last of the four M2 typed
4930    /// slots (`:limits`, `:behavior`, `:upgrade-from`, plus the
4931    /// supervisor-only `:children` peer) whose per-Caixa compound-gate
4932    /// wire-up still lived open-coded at the layout altitude after the
4933    /// [`Self::validate_limits`] lift (baa4688) closed the sibling M2
4934    /// `:limits` slot's cascade. With this lift the "one named per-slot
4935    /// / per-Caixa compound gate per typed slot folding every structural
4936    /// axis on that slot (plus the `Option::None` identity element for
4937    /// the `Option`-shaped slots) onto one substrate primitive"
4938    /// discipline spans every M2 typed slot uniformly, so a reader who
4939    /// has learned any peer M2 gate reads `:behavior` without a per-
4940    /// slot exception carve-out.
4941    ///
4942    /// # Errors
4943    ///
4944    /// Returns every [`crate::BehaviorError`] variant on the present-
4945    /// slot arm — verbatim from [`crate::BehaviorSpec::validate`].
4946    /// Passes trivially on the absent-slot arm (`behavior: None`, the
4947    /// fold's identity element).
4948    pub fn validate_behavior(&self) -> Result<(), crate::BehaviorError> {
4949        match self.behavior() {
4950            Some(b) => b.validate(),
4951            None => Ok(()),
4952        }
4953    }
4954
4955    /// Reject `:restart-window` values the shared
4956    /// [`crate::supervisor::duration_codec::parse`] refuses. The flat
4957    /// `restart_window: Option<String>` slot on [`Caixa`] is stored
4958    /// raw by the derive macro (the typed [`SupervisorSpec`] holds an
4959    /// `Option<Duration>` routed through the shared codec via `with =
4960    /// "duration_codec"`); the inline `Caixa → SupervisorSpec`
4961    /// view-construction path ([`Self::supervisor_view`]) folds the
4962    /// raw string through the same shared codec and soft-swallows the
4963    /// parse error as `None` to keep the view best-effort. Without
4964    /// this gate a malformed `:restart-window` (`"1.5s"` — the
4965    /// fractional-seconds drift class; `"1.0s"` — the decimal-shaped
4966    /// integer drift; `"0.5m"` — the unit-fraction drift; `"+30s"` /
4967    /// `"-30s"` — the leading-sign drift; `"30x"` — the unknown-unit
4968    /// footgun; `"abc"` — pure garbage; `""` — the empty-after-trim
4969    /// edge case) silently produced a `SupervisorSpec` with
4970    /// `restart_window: None`, indistinguishable from the canonical
4971    /// "omit the slot to express no reset" authoring shape — Erlang/OTP's
4972    /// `MaxIntensity / Period` invariant turns into a never-reset
4973    /// supervisor far from the source `caixa.lisp`, with no field
4974    /// naming the offending `:restart-window`. Lifting the gate to a
4975    /// Caixa-level validator mirrors the trajectory of the peer
4976    /// per-axis identity gates ([`Self::validate_nome`] 6c992f8,
4977    /// [`Self::validate_versao`] 1fdaa02, [`Self::validate_deps`]
4978    /// a7f0d8c) and the ABSORPTION-ROADMAP.md M2.2 test pin
4979    /// (line 196: "reject invalid `:restart-window` (non-duration)").
4980    ///
4981    /// Thin wrapper around [`crate::supervisor::duration_codec::parse`]
4982    /// (the shared codec backing `:supervisor :restart-window` as
4983    /// serde-routed on [`SupervisorSpec`], `:politicas :timeout`, and
4984    /// `:politicas :circuit-breaker :window` — all three covered by
4985    /// the integer-magnitude gate 1c55a2a). Maps the codec's parse
4986    /// error verbatim into the [`ManifestError::RestartWindowMalformed`]
4987    /// variant, carrying the offending raw string + a parser-shaped
4988    /// reason naming the canonical authoring form, so the diagnostic
4989    /// is self-locating (the author can grep their `caixa.lisp` for
4990    /// `:restart-window "<value>"` and fix it in one edit) and
4991    /// uniform with every other manifest-level validate diagnostic.
4992    /// With this gate the four `:restart-window`-shaped surfaces (the
4993    /// flat raw string on [`Caixa`], the typed `Option<Duration>` on
4994    /// [`SupervisorSpec`], the two `MeshPolicy` peer durations) are
4995    /// now structurally equivalent — every value past the codec is in
4996    /// one accepted set, by construction.
4997    ///
4998    /// `None` (the canonical "omit the slot to express no reset"
4999    /// shape) is accepted trivially — the gate is a no-op when the
5000    /// author didn't author a window. The empty string is rejected by
5001    /// the shared codec (its digit-only gate refuses an empty
5002    /// magnitude), surfacing the same `RestartWindowMalformed`
5003    /// diagnostic as every other rejected non-canonical shape.
5004    pub fn validate_restart_window(&self) -> Result<(), ManifestError> {
5005        let Some(s) = self.restart_window() else {
5006            return Ok(());
5007        };
5008        crate::supervisor::duration_codec::parse(s)
5009            .map(|_| ())
5010            .map_err(|reason| ManifestError::restart_window_malformed(s, reason))
5011    }
5012
5013    /// Compound per-`Caixa` entry gate on the Aplicacao-kind mesh-slot
5014    /// family — folds the paired [`crate::AplicacaoSpec::validate`]
5015    /// typed-shape cascade (per-slot gates on `:membros`, `:contratos`,
5016    /// `:entrada`, `:placement`, `:politicas`, in that declared order)
5017    /// plus the cross-slot self-edge gate
5018    /// ([`crate::aplicacao::validate_no_self_membership`], the
5019    /// `:membros :caixa` ≠ `:nome` invariant the typed view cannot
5020    /// enforce on its own because it carries the membros but not the
5021    /// parent `:nome`) onto one substrate primitive on [`Caixa`]. On
5022    /// non-Aplicacao kinds the fold is the identity element — the paired
5023    /// [`Self::aplicacao_view`] accessor returns `None` off the
5024    /// Aplicacao arm (peer with the [`Self::validate_limits`] /
5025    /// [`Self::validate_behavior`] M2 `Option`-arm identity element),
5026    /// so the gate passes trivially without touching the mesh slots.
5027    ///
5028    /// Prior to this lift the paired cascade lived only wired open-coded
5029    /// at the layout wire-up site
5030    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
5031    /// as the three-line `let view = caixa.aplicacao_view().expect(...);
5032    /// view.validate() … validate_no_self_membership(...) …` pattern
5033    /// paired with two `.map_err(|err| LayoutError::AplicacaoViolation
5034    /// { caixa, issue })` wraps — every future consumer that wanted to
5035    /// gate the Aplicacao-shape cascade as a whole (the deferred
5036    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
5037    /// admission webhook re-checking `:membros` / `:contratos` after a
5038    /// per-slot patch, a future `feira validate --aplicacao` per-caixa
5039    /// admission verb, a per-Aplicacao overlay resolver) was structurally
5040    /// forced to either re-inline the two-dispatch cascade in lockstep
5041    /// with the layout wire-up (the duplication the PRIME DIRECTIVE
5042    /// names as a bug) or call the whole
5043    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
5044    /// peer per-Caixa gate to re-check one slot family. Post-fold each
5045    /// such consumer reaches the two-arm compound gate through one call
5046    /// on the substrate primitive.
5047    ///
5048    /// Peer to the [`crate::render::require_aplicacao_view`] compound
5049    /// entry gate every per-Aplicacao *renderer* routes through
5050    /// (3aefefb folded `validate_no_self_membership` onto the renderer
5051    /// path) — this gate mirrors the same fold on the *layout* path, so
5052    /// the two consumers of the Aplicacao-shape cascade (the author-time
5053    /// gate and every per-Aplicacao renderer) share one substrate
5054    /// primitive rather than two open-coded cascades kept in lockstep.
5055    /// Same lift discipline the peer per-slot compound gates
5056    /// ([`Self::validate_upgrade_from`] d6801df, [`Self::validate_deps`]
5057    /// b5dd55e, [`Self::validate_limits`] baa4688,
5058    /// [`Self::validate_behavior`] 0d2877a) each carry.
5059    ///
5060    /// # Errors
5061    ///
5062    /// Returns every [`crate::AplicacaoError`] variant on the present-
5063    /// kind arm — the typed-shape cascade's per-slot arms first
5064    /// (matching [`crate::AplicacaoSpec::validate`]'s declared order),
5065    /// then the cross-slot self-edge arm
5066    /// ([`crate::AplicacaoError::MembroIsSelfAplicacao`]). Passes
5067    /// trivially on non-Aplicacao kinds (the fold's identity element).
5068    pub fn validate_aplicacao_shape(&self) -> Result<(), crate::AplicacaoError> {
5069        let Some(view) = self.aplicacao_view() else {
5070            return Ok(());
5071        };
5072        view.validate()?;
5073        crate::aplicacao::validate_no_self_membership(self.membros(), self.nome())?;
5074        Ok(())
5075    }
5076
5077    /// Compound per-`Caixa` entry gate on the Supervisor-kind
5078    /// supervision-tree slot family — folds the paired
5079    /// [`crate::SupervisorSpec::validate`] typed-shape cascade
5080    /// (`:estrategia` ↔ `:children` invariants, `:max-restarts` /
5081    /// `:restart-window` bounds, per-child DNS-1123 `:caixa` names,
5082    /// semver-valid `:versao` constraints, the set-not-multiset
5083    /// duplicate-child gate) plus the cross-slot self-edge gate
5084    /// ([`crate::supervisor::validate_no_self_supervision`], the
5085    /// `:children :caixa` ≠ `:nome` invariant the typed view cannot
5086    /// enforce on its own because it carries the children but not the
5087    /// parent `:nome`) onto one substrate primitive on [`Caixa`]. On
5088    /// non-Supervisor kinds the fold is the identity element — the paired
5089    /// [`Self::supervisor_view`] accessor returns `None` off the
5090    /// Supervisor arm (peer with the [`Self::validate_limits`] /
5091    /// [`Self::validate_behavior`] M2 `Option`-arm identity element and
5092    /// the sibling per-Aplicacao [`Self::validate_aplicacao_shape`]),
5093    /// so the gate passes trivially without touching the supervision-tree
5094    /// slots.
5095    ///
5096    /// Prior to this lift the paired cascade lived only wired open-coded
5097    /// at the layout wire-up site
5098    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
5099    /// as the three-line `let view = caixa.supervisor_view().expect(...);
5100    /// view.validate() … validate_no_self_supervision(...) …` pattern
5101    /// paired with two `.map_err(|err| LayoutError::SupervisorViolation
5102    /// { caixa, issue })` wraps — every future consumer that wanted to
5103    /// gate the Supervisor-shape cascade as a whole (the wasm-operator's
5104    /// hierarchical reconciliation scheduler re-checking `:children` /
5105    /// `:estrategia` after a per-slot patch, the M4
5106    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
5107    /// webhook, a future `feira validate --supervisor` per-caixa
5108    /// admission verb, a per-Supervisor overlay resolver) was structurally
5109    /// forced to either re-inline the two-dispatch cascade in lockstep
5110    /// with the layout wire-up (the duplication the PRIME DIRECTIVE
5111    /// names as a bug) or call the whole
5112    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
5113    /// peer per-Caixa gate to re-check one slot family. Post-fold each
5114    /// such consumer reaches the two-arm compound gate through one call
5115    /// on the substrate primitive.
5116    ///
5117    /// Peer to the [`crate::render::require_supervisor_view`] compound
5118    /// entry gate every per-Supervisor *renderer* would route through
5119    /// (which already folds the same `spec.validate()` +
5120    /// `validate_no_self_supervision` two-arm cascade behind its
5121    /// `require_kind` + `validate_restart_window` prelude) — this gate
5122    /// mirrors the same fold on the *layout* path, so the two consumers
5123    /// of the Supervisor-shape cascade (the author-time gate and every
5124    /// per-Supervisor renderer) share one substrate primitive rather
5125    /// than two open-coded cascades kept in lockstep. Same lift
5126    /// discipline the peer per-slot compound gates
5127    /// ([`Self::validate_aplicacao_shape`] 949a7a0,
5128    /// [`Self::validate_upgrade_from`] d6801df,
5129    /// [`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5130    /// baa4688, [`Self::validate_behavior`] 0d2877a) each carry.
5131    ///
5132    /// # Errors
5133    ///
5134    /// Returns every [`crate::SupervisorError`] variant on the present-
5135    /// kind arm — the typed-shape cascade's per-slot arms first
5136    /// (matching [`crate::SupervisorSpec::validate`]'s declared order),
5137    /// then the cross-slot self-edge arm
5138    /// ([`crate::SupervisorError::ChildSupervisesSelf`]). Passes
5139    /// trivially on non-Supervisor kinds (the fold's identity element).
5140    pub fn validate_supervisor_shape(&self) -> Result<(), crate::SupervisorError> {
5141        let Some(view) = self.supervisor_view() else {
5142            return Ok(());
5143        };
5144        view.validate()?;
5145        crate::supervisor::validate_no_self_supervision(self.children(), self.nome())?;
5146        Ok(())
5147    }
5148
5149    /// Compound per-`Caixa` entry gate on the Acao-kind `:ci` slot
5150    /// family — folds the [`crate::decompose_ci`] typed decompose gate
5151    /// (`canteiro_types::decompose` refusing every illegal
5152    /// [`canteiro_types::CiRun`] shape: duplicate node name, dependency
5153    /// on an undeclared node, dependency cycle) onto one substrate
5154    /// primitive on [`Caixa`]. On non-`Acao` kinds the fold is the
5155    /// identity element — the paired [`Self::kind`] `is_acao()` guard
5156    /// short-circuits before the decompose gate ever fires (peer with
5157    /// the [`Self::validate_aplicacao_shape`] /
5158    /// [`Self::validate_supervisor_shape`] typed-view identity element
5159    /// and the [`Self::validate_limits`] / [`Self::validate_behavior`]
5160    /// M2 `Option`-arm identity element), so the gate passes trivially
5161    /// without touching the `:ci` slot. An `:kind Acao` caixa with
5162    /// `ci = None` is also an identity-element pass: the presence gate
5163    /// is the sibling axis owned by [`crate::LayoutError::MissingCi`] /
5164    /// [`crate::require_ci`] / [`crate::MissingCiSlot`], not by the
5165    /// decompose gate — a caixa that carries no `:ci` slot has no run
5166    /// to decompose. Same split the peer per-Servico
5167    /// [`crate::LayoutError::ServicoWithoutServicos`] presence gate and
5168    /// per-Binario [`crate::LayoutError::BinarioWithoutExe`] presence
5169    /// gate keep from their sibling per-slot shape gates, so the two
5170    /// axes stay separately diagnosable at the layout altitude.
5171    ///
5172    /// Prior to this lift the decompose gate lived only wired
5173    /// open-coded at the [`caixa_actions::validate`] renderer-side
5174    /// entry gate (routed through the substrate-canonical
5175    /// [`crate::require_acao_view`] compound helper) — the *layout*
5176    /// pipeline ([`crate::layout::StandardLayout::verify`], caixa-core/
5177    /// src/layout.rs) only checked `:ci` *presence* via
5178    /// [`crate::LayoutError::MissingCi`], so a `:kind Acao` caixa
5179    /// carrying a structurally illegal `:ci` (a duplicate node name, a
5180    /// dependency on an undeclared node, a dependency cycle) passed
5181    /// `feira build` cleanly and surfaced the diagnostic only when
5182    /// [`caixa_actions::validate`] later refused it — far from the
5183    /// source `caixa.lisp` on the author-time gate side. Every future
5184    /// consumer that wanted to gate the Acao-shape cascade as a whole
5185    /// (a per-`Acao` CR materializer's admission webhook re-checking
5186    /// `:ci` after a per-node patch, a future `feira validate --acao`
5187    /// per-caixa admission verb, a per-`Acao` overlay resolver
5188    /// rejecting an added / renamed node against a cluster-local
5189    /// snapshot) was structurally forced to either re-inline the
5190    /// decompose dispatch in lockstep with the renderer-side wire-up
5191    /// (the duplication the PRIME DIRECTIVE names as a bug) or call
5192    /// the whole [`caixa_actions::validate`] renderer and pay the
5193    /// per-node accumulation to re-check one slot. Post-fold each such
5194    /// consumer reaches the decompose gate through one call on the
5195    /// substrate primitive.
5196    ///
5197    /// Peer to the [`crate::require_acao_view`] compound entry gate
5198    /// every per-`Acao` *renderer* routes through (which already folds
5199    /// the same `require_ci + decompose_ci` two-arm cascade behind its
5200    /// `require_kind` prelude) — this gate mirrors the same fold on
5201    /// the *layout* path, so the two consumers of the Acao-shape
5202    /// cascade (the author-time gate and every per-`Acao` renderer)
5203    /// share one substrate primitive rather than two open-coded
5204    /// cascades kept in lockstep. Same lift discipline the peer
5205    /// per-kind compound gates ([`Self::validate_aplicacao_shape`]
5206    /// 949a7a0, [`Self::validate_supervisor_shape`] 4c70105,
5207    /// [`Self::validate_upgrade_from`] d6801df, [`Self::validate_deps`]
5208    /// b5dd55e, [`Self::validate_limits`] baa4688,
5209    /// [`Self::validate_behavior`] 0d2877a) each carry. Closes the
5210    /// last per-kind asymmetry: with this lift the four typed
5211    /// named-caixa kinds (`Servico` / `Aplicacao` / `Supervisor` /
5212    /// `Acao`) each carry a compound per-`Caixa` shape gate on the
5213    /// substrate, and the layout pipeline routes through the same one
5214    /// substrate primitive per kind rather than four open-coded
5215    /// cascades.
5216    ///
5217    /// # Errors
5218    ///
5219    /// Returns the [`crate::CiDecomposeFailure`] typed view on the
5220    /// present-slot arm — the caixa's `:nome` alongside the borrowed
5221    /// [`canteiro_types::DecomposeError`] source (`DuplicateNode` /
5222    /// `UnknownDep` / `Cycle`) verbatim, so a consumer that fans on
5223    /// the specific arm reaches for `err.source` directly rather than
5224    /// re-parsing the Display bytes. Passes trivially on non-`Acao`
5225    /// kinds and on `:kind Acao` caixas with absent `:ci` (the fold's
5226    /// two identity-element arms).
5227    pub fn validate_acao_shape(&self) -> Result<(), crate::CiDecomposeFailure> {
5228        if !self.kind().is_acao() {
5229            return Ok(());
5230        }
5231        let Some(ci) = self.ci() else {
5232            return Ok(());
5233        };
5234        crate::render::decompose_ci(self, ci).map(|_| ())
5235    }
5236
5237    /// Compound per-`Caixa` kind ↔ typed-slot coherence gate on the
5238    /// three "declared but ignored" typed-slot families — M3 mesh
5239    /// (`:membros` / `:contratos` / `:politicas` / `:placement` /
5240    /// `:entrada`, owned by `:kind Aplicacao`, MESH-COMPOSITION §III.1),
5241    /// supervisor-tree (`:estrategia` / `:max-restarts` /
5242    /// `:restart-window` / `:children`, owned by `:kind Supervisor`,
5243    /// INSPIRATIONS §II.2), and M2 Servico-runtime (`:limits` /
5244    /// `:behavior` / `:upgrade-from`, owned by `:kind Servico`,
5245    /// INSPIRATIONS §III.1 / §II.3 / §II.4). Folds the three sibling
5246    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5247    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5248    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
5249    /// gates — each pre-lift a self-similar five-line
5250    /// `if !caixa.kind().is_<owner>() { let slots = caixa.declared_
5251    /// <family>_slots(); if !slots.is_empty() { return
5252    /// Err(LayoutError::<family>_on_non_<owner>(caixa, slots)); } }`
5253    /// block at [`crate::layout::StandardLayout::verify`] — onto one
5254    /// substrate primitive on [`Caixa`]. Every arm passes as an
5255    /// identity element on the owner kind (the paired
5256    /// [`Self::kind`] `is_<owner>()` guard short-circuits before the
5257    /// per-family `declared_*_slots` gate fires) and on non-owner
5258    /// kinds carrying no declared slot in that family (the
5259    /// [`Vec::is_empty`] check short-circuits before the wrap fires),
5260    /// so a bare no-code caixa on any kind passes the fold trivially
5261    /// on all three arms.
5262    ///
5263    /// Prior to this lift the three-arm cascade lived only wired
5264    /// open-coded at the layout wire-up site
5265    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/
5266    /// layout.rs) as three self-similar five-line blocks paired with
5267    /// three [`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
5268    /// [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
5269    /// [`crate::LayoutError::servico_slots_on_non_servico`] ctor
5270    /// dispatches (each of which the peer
5271    /// [`crate::layout::layout_slot_kind_ctors!`] macro already folds
5272    /// onto one substrate primitive per typed variant, 0419438) —
5273    /// every future consumer that wanted to gate the whole
5274    /// kind-coherence cascade as a unit (the deferred
5275    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5276    /// webhook re-checking every typed-slot family after a per-slot
5277    /// patch, a future `feira validate --kind-coherence` per-caixa
5278    /// admission verb, a per-`Caixa` overlay resolver rejecting a
5279    /// kind-foreign patch against a cluster-local snapshot) was
5280    /// structurally forced to either re-inline the three-block
5281    /// cascade in lockstep with the layout wire-up (the duplication
5282    /// the PRIME DIRECTIVE names as a bug) or call the whole
5283    /// [`crate::layout::StandardLayout::verify`] pipeline and pay
5284    /// every peer per-`Caixa` gate to re-check three slot families.
5285    /// Post-fold each such consumer reaches the three-arm cascade
5286    /// through one call on the substrate primitive.
5287    ///
5288    /// Diagnostic order matches the pre-fold layout wire-up
5289    /// canonical sequence — mesh → supervisor → servico — pinned by
5290    /// the load-bearing
5291    /// `validate_kind_slot_coherence_mesh_arm_fires_before_supervisor_arm`
5292    /// / `_supervisor_arm_fires_before_servico_arm` ordering pins
5293    /// below. The three arms enumerate every typed-slot family the
5294    /// substrate carries whose "declared but ignored" footgun is
5295    /// gated at the layout altitude by a `{ caixa, kind, slots }`
5296    /// wrap variant — the peer
5297    /// [`crate::LayoutError::ForeignCodeSlot`] gate on the
5298    /// code-surface family sits outside this fold because
5299    /// [`Self::declared_foreign_code_slots`] bakes the kind-check
5300    /// into the helper (so the layout wire-up carries no outer
5301    /// `if !caixa.kind().is_<owner>()` guard), and the peer
5302    /// [`crate::LayoutError::CiOnNonAcao`] gate on the `:ci` axis
5303    /// carries a distinct `{ caixa, kind }` wrap shape (no `slots`
5304    /// field — `:ci` is a single `Option` not a `Vec`-of-named-slots)
5305    /// and rides on its own peer substrate primitive
5306    /// [`Self::validate_ci_kind_coherence`] (the direct sibling to
5307    /// this fold on the `:ci` axis) — the two folds share the same
5308    /// altitude and diagnostic order at the layout wire-up site but
5309    /// keep their distinct envelope shapes, so no consumer of
5310    /// `CiOnNonAcao` sees a variant rename.
5311    ///
5312    /// Peer to the per-kind compound entry gates every substrate
5313    /// primitive on the M2/M3 typed-slot family already carries
5314    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5315    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5316    /// [`Self::validate_upgrade_from`] d6801df,
5317    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5318    /// [`Self::validate_supervisor_shape`] 4c70105,
5319    /// [`Self::validate_acao_shape`] 5d6df54): the author-time gate
5320    /// axis on the *per-slot* algebra now shares one substrate
5321    /// primitive per compound gate, and this lift closes the
5322    /// symmetric axis on the *cross-family* kind ↔ slot coherence
5323    /// algebra so the layout pipeline routes the three self-similar
5324    /// gates through one substrate primitive rather than three
5325    /// open-coded blocks. Every future kind that adds its own
5326    /// exclusive typed-slot family (an `Actor`-owned per-virtual-
5327    /// actor grain slot the M5 Orleans-inspired kind reaches
5328    /// through, a per-Aplicacao overlay slot the M4 CR materializer
5329    /// consults) folds onto this compound gate as one arm addition
5330    /// rather than a fourth open-coded block at the wire-up site.
5331    ///
5332    /// # Errors
5333    ///
5334    /// Returns the first [`crate::LayoutError`] variant surfacing
5335    /// under the canonical mesh → supervisor → servico order:
5336    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] on a non-
5337    /// Aplicacao caixa with a declared M3 mesh slot,
5338    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] on a
5339    /// non-Supervisor caixa with a declared supervisor-tree slot,
5340    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] on a
5341    /// non-Servico caixa with a declared M2 slot. Passes trivially
5342    /// on the owner kind of each family and on non-owner kinds
5343    /// carrying no declared slot in that family (the fold's identity
5344    /// element on both axes).
5345    pub fn validate_kind_slot_coherence(&self) -> Result<(), crate::LayoutError> {
5346        // Each of the three arms routes through the shared
5347        // [`Self::run_kind_owned_slot_family_gate`] substrate primitive
5348        // — the outer non-owner-kind guard + inner accumulator + inner
5349        // emptiness-guard + wrap arm shape now lands on one dispatch
5350        // per family rather than a four-line open-coded block in
5351        // lockstep across all three arms. Canonical mesh → supervisor
5352        // → servico order preserved (the primitive short-circuits
5353        // arm-by-arm; the outer `?;` cascade at this altitude threads
5354        // the first surfaced arm's error verbatim). Each of the three
5355        // ctors ([`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
5356        // [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
5357        // [`crate::LayoutError::servico_slots_on_non_servico`]) was
5358        // already lifted onto the substrate by the peer
5359        // [`crate::layout::layout_slot_kind_ctors!`] macro, so each arm
5360        // routes through the same substrate-canonical
5361        // `Self::<variant> { caixa, kind, slots }` wrap per arm as the
5362        // pre-lift open-coded blocks — byte-equal, pinned by the
5363        // paired `validate_kind_slot_coherence_folds_<family>_arm_matches_gate`
5364        // equivalence pins and the peer
5365        // `validate_kind_slot_coherence_{mesh,supervisor}_arm_fires_before_<next>_arm`
5366        // ordering pins.
5367        self.run_kind_owned_slot_family_gate(
5368            crate::CaixaKind::is_aplicacao,
5369            Caixa::declared_mesh_slots,
5370            crate::LayoutError::mesh_slots_on_non_aplicacao,
5371        )?;
5372        self.run_kind_owned_slot_family_gate(
5373            crate::CaixaKind::is_supervisor,
5374            Caixa::declared_supervisor_slots,
5375            crate::LayoutError::supervisor_slots_on_non_supervisor,
5376        )?;
5377        self.run_kind_owned_slot_family_gate(
5378            crate::CaixaKind::is_servico,
5379            Caixa::declared_servico_slots,
5380            crate::LayoutError::servico_slots_on_non_servico,
5381        )?;
5382        Ok(())
5383    }
5384
5385    /// Compound per-`Caixa` kind ↔ code-surface coherence gate on
5386    /// the three no-code kinds — `Supervisor` (supervises other
5387    /// caixas, INSPIRATIONS §II.2), `Aplicacao` (composes Servicos,
5388    /// MESH-COMPOSITION §III.1), and `Acao` (owns a typed CI run,
5389    /// CANTEIRO §7.1-C). Each carries no code of its own, so
5390    /// declaring any of `:bibliotecas` / `:exe` / `:servicos`
5391    /// silently passes the layout's path-existence loops (the paths
5392    /// still resolve on disk) and then vanishes downstream — the
5393    /// per-kind renderers gate emission on
5394    /// [`crate::render::require_kind`] and only emit the code
5395    /// surface for its owning kind, so a declared code slot on a
5396    /// no-code kind is the manifest field's documented "ignored
5397    /// otherwise" footgun.
5398    ///
5399    /// Pre-lift each of the three arms lived as a self-similar
5400    /// `if !caixa.kind().is_<no-code-kind>() { … } else if has_code
5401    /// { return Err(LayoutError::<kind>_owns_code(caixa)); }` block
5402    /// at [`crate::layout::StandardLayout::verify`] — three
5403    /// consumers, three identical shapes. Every future consumer
5404    /// that wanted to gate the whole code-surface coherence cascade
5405    /// as a unit (the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
5406    /// materializer's admission webhook re-checking after a
5407    /// per-slot patch, a future `feira validate --no-code-kind`
5408    /// per-caixa admission verb, a per-`Caixa` overlay resolver
5409    /// rejecting a kind-foreign patch) was structurally forced to
5410    /// either re-inline the three-block cascade in lockstep with
5411    /// the layout wire-up (the duplication the PRIME DIRECTIVE
5412    /// names as a bug) or call the whole
5413    /// [`crate::layout::StandardLayout::verify`] pipeline. Post-fold
5414    /// each such consumer reaches the three-arm cascade through
5415    /// one call.
5416    ///
5417    /// Mirror of the sibling [`Self::validate_kind_slot_coherence`]
5418    /// fold (f0d286e) on the author-time typed-slot coherence axis:
5419    /// that gate closes the "non-owner kind declares owner-only
5420    /// typed slots" three-arm cascade on the M2 / supervisor-tree /
5421    /// M3 slot families; this gate closes the reciprocal
5422    /// "no-code kind declares code" three-arm cascade on the
5423    /// `:bibliotecas` / `:exe` / `:servicos` code surface. Together
5424    /// the two folds route every kind ↔ author-shape coherence
5425    /// diagnostic at the layout altitude through one substrate
5426    /// primitive per axis.
5427    ///
5428    /// The gate carries two identity elements:
5429    /// - **`has_code == false`** — any kind (including the three
5430    ///   no-code kinds) that declares no code passes the paired
5431    ///   `!has_code` short-circuit before every per-arm dispatch.
5432    /// - **Code-owning kinds** (`Biblioteca` owning
5433    ///   `:bibliotecas`, `Binario` owning `:exe`, `Servico` owning
5434    ///   `:servicos`) — the three no-code arm-firing predicates
5435    ///   short-circuit on every code-owning kind, so the gate
5436    ///   passes trivially regardless of what code they declare.
5437    ///   Foreign-code-slot violations on a code-owning kind (e.g.
5438    ///   `:kind Servico` declaring `:exe`) surface through the
5439    ///   sibling [`crate::LayoutError::ForeignCodeSlot`] gate on
5440    ///   [`Self::declared_foreign_code_slots`], not through this
5441    ///   gate.
5442    ///
5443    /// Unlike the sibling cross-family
5444    /// [`Self::validate_kind_slot_coherence`], the three arms of
5445    /// this fold are mutually exclusive by construction — `:kind`
5446    /// is a single-valued [`CaixaKind`] discriminator so at most
5447    /// one arm can fire per caixa — and no cross-arm ordering pin
5448    /// is meaningful (the pre-fold three-block cascade at the
5449    /// wire-up site was already unreachable past the first
5450    /// matching arm).
5451    ///
5452    /// Peer to the per-kind compound entry gates every substrate
5453    /// primitive on the M2/M3 typed-slot family already carries
5454    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5455    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5456    /// [`Self::validate_upgrade_from`] d6801df,
5457    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5458    /// [`Self::validate_supervisor_shape`] 4c70105,
5459    /// [`Self::validate_acao_shape`] 5d6df54,
5460    /// [`Self::validate_kind_slot_coherence`] f0d286e): the
5461    /// author-time gate axis on the *per-slot* and *cross-family
5462    /// typed-slot* algebras each share one substrate primitive per
5463    /// compound gate, and this lift closes the third axis on the
5464    /// *code-surface* algebra so the layout pipeline routes all
5465    /// three coherence axes through one substrate primitive rather
5466    /// than nine open-coded blocks. Every future no-code kind
5467    /// (an `Actor` virtual-actor arm the M5 Orleans-inspired kind
5468    /// reaches through if it lands as a no-code composer, a future
5469    /// `Namespace` grouping kind) folds onto this compound gate
5470    /// as one arm addition rather than a fourth open-coded block
5471    /// at the wire-up site.
5472    ///
5473    /// # Errors
5474    ///
5475    /// Returns the [`crate::LayoutError`] variant naming the
5476    /// offending no-code kind:
5477    /// [`crate::LayoutError::SupervisorOwnsCode`] on a `:kind
5478    /// Supervisor` caixa with any declared code,
5479    /// [`crate::LayoutError::AplicacaoOwnsCode`] on a `:kind
5480    /// Aplicacao` caixa with any declared code,
5481    /// [`crate::LayoutError::AcaoOwnsCode`] on a `:kind Acao` caixa
5482    /// with any declared code. Passes trivially on every kind with
5483    /// no declared code and on every code-owning kind regardless
5484    /// of declared code (the fold's two identity-element arms).
5485    pub fn validate_no_code_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5486        let has_code =
5487            !self.bibliotecas().is_empty() || !self.exe().is_empty() || !self.servicos().is_empty();
5488        if !has_code {
5489            return Ok(());
5490        }
5491        if self.kind().is_supervisor() {
5492            return Err(crate::LayoutError::supervisor_owns_code(self));
5493        }
5494        if self.kind().is_aplicacao() {
5495            return Err(crate::LayoutError::aplicacao_owns_code(self));
5496        }
5497        if self.kind().is_acao() {
5498            return Err(crate::LayoutError::acao_owns_code(self));
5499        }
5500        Ok(())
5501    }
5502
5503    /// Compound per-`Caixa` kind ↔ `:ci` coherence gate — the `Acao`
5504    /// axis-only companion to the sibling three-arm
5505    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) on the
5506    /// M3 mesh / supervisor-tree / M2 Servico-runtime typed-slot
5507    /// families. `:ci` carries a typed CI run
5508    /// ([`canteiro_types::CiRun`], CANTEIRO §7.1-C) that only the
5509    /// `caixa-actions` renderer decomposes + validates and only for a
5510    /// `:kind Acao`. On any *other* kind a declared `:ci` is the
5511    /// manifest field's documented "ignored otherwise" — it silently
5512    /// passes verify and then vanishes (never decomposed, never
5513    /// rendered), far from the source `caixa.lisp`.
5514    ///
5515    /// Pre-lift the arm lived as a self-similar
5516    /// `if caixa.ci().is_some() && !caixa.kind().is_acao() { return
5517    /// Err(LayoutError::CiOnNonAcao { caixa: caixa.nome().to_string(),
5518    /// kind: caixa.kind() }); }` block at
5519    /// [`crate::layout::StandardLayout::verify`] — one consumer today
5520    /// but every future consumer that wanted to gate the `:ci`
5521    /// coherence axis as a unit (the deferred
5522    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5523    /// webhook re-checking after a per-slot patch, a future
5524    /// `feira validate --ci-coherence` per-caixa admission verb, a
5525    /// per-`Caixa` overlay resolver rejecting a kind-foreign `:ci`
5526    /// patch) was structurally forced to either re-inline the
5527    /// two-condition guard in lockstep with the layout wire-up (the
5528    /// duplication the PRIME DIRECTIVE names as a bug) or call the
5529    /// whole [`crate::layout::StandardLayout::verify`] pipeline.
5530    /// Post-fold each such consumer reaches the arm through one call.
5531    ///
5532    /// Peer of the sibling three-arm
5533    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) — that
5534    /// gate carries the M3 mesh / supervisor-tree / M2 Servico-runtime
5535    /// axes under a uniform `{ caixa, kind, slots }` envelope
5536    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5537    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5538    /// [`crate::LayoutError::ServicoSlotsOnNonServico`]). The `:ci`
5539    /// axis stays on its own primitive because
5540    /// [`crate::LayoutError::CiOnNonAcao`] carries a distinct
5541    /// `{ caixa, kind }` wrap shape (no `slots` field — `:ci` is a
5542    /// single `Option` not a `Vec`-of-named-slots) whose reshape
5543    /// onto the sibling `{ caixa, kind, slots }` envelope would
5544    /// force a variant rename touching every consumer of
5545    /// `CiOnNonAcao`; the two folds share the same
5546    /// author-time-vs-renderer split and diagnostic altitude, and
5547    /// route through peer substrate primitives on the same
5548    /// [`Caixa`] surface.
5549    ///
5550    /// Peer to the per-kind compound entry gates every substrate
5551    /// primitive on the M2/M3 typed-slot family already carries
5552    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5553    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5554    /// [`Self::validate_upgrade_from`] d6801df,
5555    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5556    /// [`Self::validate_supervisor_shape`] 4c70105,
5557    /// [`Self::validate_acao_shape`] 5d6df54,
5558    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5559    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2): every
5560    /// author-time coherence axis on the typed [`Caixa`] surface now
5561    /// routes through one substrate primitive per axis rather than
5562    /// an open-coded block at the layout wire-up site.
5563    ///
5564    /// The gate carries two identity elements:
5565    /// - **`ci().is_none()`** — a caixa that declares no `:ci`
5566    ///   passes the first short-circuit before every per-arm
5567    ///   dispatch, on every kind. The canonical shape of the four
5568    ///   non-`Acao` kinds (`Biblioteca` / `Binario` / `Servico` /
5569    ///   `Supervisor` / `Aplicacao`) is `ci = None` — the arm
5570    ///   never fires on a well-shaped fixture.
5571    /// - **`:kind Acao`** — the owner-kind arm short-circuits on
5572    ///   every `Acao` caixa regardless of its `:ci` shape; a
5573    ///   malformed `:ci` on an `Acao` surfaces through the peer
5574    ///   [`Self::validate_acao_shape`] compound decompose gate
5575    ///   (5d6df54), not through this coherence gate.
5576    ///
5577    /// # Errors
5578    ///
5579    /// Returns [`crate::LayoutError::CiOnNonAcao`] naming the
5580    /// offending caixa's nome + kind on any non-`Acao` caixa with
5581    /// `:ci` declared. Passes trivially on every kind that declares
5582    /// no `:ci` and on every `:kind Acao` caixa regardless of
5583    /// declared `:ci` (the fold's two identity-element arms).
5584    pub fn validate_ci_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5585        if self.ci().is_some() && !self.kind().is_acao() {
5586            return Err(crate::LayoutError::ci_on_non_acao(self));
5587        }
5588        Ok(())
5589    }
5590
5591    /// Compound per-`Caixa` kind ↔ code-surface coherence gate on the
5592    /// two exclusive code-surface slots — `:exe` (owned only by
5593    /// [`crate::CaixaKind::Binario`], the nix-built executable surface)
5594    /// and `:servicos` (owned only by [`crate::CaixaKind::Servico`],
5595    /// the wasm-component + `ComputeUnit` daemon surface). The
5596    /// `caixa-helm` / `caixa-flux` / `caixa-flake` renderers gate
5597    /// emission on [`crate::render::require_kind`]`(_, <owning-kind>)`
5598    /// and only emit the slot for its owning kind — so on any *other*
5599    /// code-running kind a declared `:exe` / `:servicos` is the
5600    /// manifest field's documented "ignored otherwise": the path is
5601    /// validated by the per-kind path-existence loops in
5602    /// [`crate::layout::StandardLayout::verify`], but the value is
5603    /// never rendered into a build target or programs.yaml entry —
5604    /// it silently passes `feira build` and then vanishes, far from
5605    /// the source `caixa.lisp`, with no field naming which slot is
5606    /// foreign.
5607    ///
5608    /// Pre-lift the arm lived as a self-similar four-line `let
5609    /// foreign_code_slots = caixa.declared_foreign_code_slots(); if
5610    /// !foreign_code_slots.is_empty() { return
5611    /// Err(LayoutError::foreign_code_slot(caixa, foreign_code_slots));
5612    /// }` block at [`crate::layout::StandardLayout::verify`] — one
5613    /// consumer today but every future consumer that wanted to gate
5614    /// the code-surface coherence axis as a unit (the deferred
5615    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5616    /// webhook re-checking after a per-slot patch, a future
5617    /// `feira validate --foreign-code` per-caixa admission verb, a
5618    /// per-`Caixa` overlay resolver rejecting a kind-foreign code-
5619    /// slot patch) was structurally forced to either re-inline the
5620    /// two-condition guard in lockstep with the layout wire-up (the
5621    /// duplication the PRIME DIRECTIVE names as a bug) or call the
5622    /// whole [`crate::layout::StandardLayout::verify`] pipeline.
5623    /// Post-fold each such consumer reaches the arm through one call.
5624    ///
5625    /// Peer of the sibling three-arm
5626    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) — that
5627    /// gate carries the M3 mesh / supervisor-tree / M2 Servico-runtime
5628    /// axes under the uniform `{ caixa, kind, slots }` envelope
5629    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5630    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5631    /// [`crate::LayoutError::ServicoSlotsOnNonServico`]); this gate
5632    /// carries the code-surface axis under the same
5633    /// `{ caixa, kind, slots }` envelope
5634    /// ([`crate::LayoutError::ForeignCodeSlot`]). The two folds share
5635    /// the envelope shape but stay separate primitives because the
5636    /// per-arm predicate differs: the cross-family fold rides on the
5637    /// outer `!self.kind().is_<owner>()` guard *paired* with a
5638    /// per-family `declared_<family>_slots` accumulator, while this
5639    /// fold's per-arm kind-check is baked into
5640    /// [`Self::declared_foreign_code_slots`] itself (each arm's
5641    /// `!self.kind().requires_<slot>()` guard fires inside the
5642    /// accumulator, not around it) — so a `:kind Binario` declaring
5643    /// `:servicos` and a `:kind Servico` declaring `:exe` are both
5644    /// caught by one accumulator sweep rather than by two independent
5645    /// arm dispatches. Peer with [`Self::validate_ci_kind_coherence`]
5646    /// (9b55beb) which carries the `:ci` axis on its own primitive
5647    /// for the same "distinct per-arm predicate shape, shared
5648    /// diagnostic altitude" reason.
5649    ///
5650    /// Peer to the per-kind and per-slot compound entry gates every
5651    /// substrate primitive on the M2/M3 typed-slot family already
5652    /// carries ([`Self::validate_deps`] b5dd55e,
5653    /// [`Self::validate_limits`] baa4688,
5654    /// [`Self::validate_behavior`] 0d2877a,
5655    /// [`Self::validate_upgrade_from`] d6801df,
5656    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5657    /// [`Self::validate_supervisor_shape`] 4c70105,
5658    /// [`Self::validate_acao_shape`] 5d6df54,
5659    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5660    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
5661    /// [`Self::validate_ci_kind_coherence`] 9b55beb): every
5662    /// author-time coherence axis on the typed [`Caixa`] surface now
5663    /// routes through one substrate primitive per axis rather than an
5664    /// open-coded block at the layout wire-up site. This closes the
5665    /// last open-coded kind ↔ slot coherence gate at the layout
5666    /// altitude — every kind-coherence diagnostic is now a substrate
5667    /// primitive.
5668    ///
5669    /// The gate carries three identity elements:
5670    /// - **Code-owning kinds on their native slot** — a
5671    ///   [`crate::CaixaKind::Binario`] declaring `:exe`, a
5672    ///   [`crate::CaixaKind::Servico`] declaring `:servicos` — each
5673    ///   arm's `!requires_<slot>()` predicate short-circuits inside
5674    ///   [`Self::declared_foreign_code_slots`], so the accumulator
5675    ///   returns an empty `Vec` and the outer `is_empty` short-
5676    ///   circuits before the wrap fires.
5677    /// - **Bare caixas** — a caixa with no declared code on any kind
5678    ///   passes the same accumulator's `is_empty` short-circuit on
5679    ///   every arm.
5680    /// - **No-code kinds** ([`crate::CaixaKind::Supervisor`] /
5681    ///   [`crate::CaixaKind::Aplicacao`] / [`crate::CaixaKind::Acao`])
5682    ///   declaring code — dominated upstream by the sibling
5683    ///   [`Self::validate_no_code_kind_coherence`] (3bbf6a2) which
5684    ///   surfaces [`crate::LayoutError::SupervisorOwnsCode`] /
5685    ///   [`crate::LayoutError::AplicacaoOwnsCode`] /
5686    ///   [`crate::LayoutError::AcaoOwnsCode`] first at the layout
5687    ///   wire-up site, so this gate never fires on a no-code kind
5688    ///   through the layout pipeline. A standalone caller reaching
5689    ///   this primitive without the sibling `_no_code_` gate first
5690    ///   would see a no-code kind's declared `:exe` / `:servicos`
5691    ///   surface `ForeignCodeSlot` here (the two folds partition the
5692    ///   diagnostic responsibility along the "declared no-code slot"
5693    ///   axis: no-code kinds get `OwnsCode`, code-running kinds get
5694    ///   `ForeignCodeSlot`), and the layout wire-up's canonical
5695    ///   `_no_code_` → `_foreign_code_` ordering keeps the
5696    ///   [`crate::LayoutError::SupervisorOwnsCode`] / … arm the one
5697    ///   that surfaces in the composed pipeline.
5698    ///
5699    /// Diagnostic order within the arm matches the pre-fold layout
5700    /// wire-up canonical sequence — `:exe` → `:servicos` — pinned by
5701    /// [`Self::declared_foreign_code_slots`]'s per-arm push order.
5702    ///
5703    /// # Errors
5704    ///
5705    /// Returns [`crate::LayoutError::ForeignCodeSlot`] naming the
5706    /// offending caixa's nome + kind + declared foreign-code slot
5707    /// list on any code-running kind ([`crate::CaixaKind::Biblioteca`]
5708    /// / [`crate::CaixaKind::Binario`] / [`crate::CaixaKind::Servico`])
5709    /// declaring another code-running kind's exclusive code surface.
5710    /// Passes trivially on every native-slot declaration (Binario
5711    /// with `:exe`, Servico with `:servicos`), on every bare caixa,
5712    /// and on every no-code kind (dominated upstream by the sibling
5713    /// [`Self::validate_no_code_kind_coherence`] `OwnsCode` gates —
5714    /// see the identity-element notes above).
5715    pub fn validate_foreign_code_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5716        let foreign_code_slots = self.declared_foreign_code_slots();
5717        if !foreign_code_slots.is_empty() {
5718            return Err(crate::LayoutError::foreign_code_slot(
5719                self,
5720                foreign_code_slots,
5721            ));
5722        }
5723        Ok(())
5724    }
5725
5726    /// Compound per-`Caixa` required-slot gate on the three
5727    /// [`crate::CaixaKind`] arms whose sole payload is a canonical
5728    /// typed slot: `Binario`'s `:exe`, `Servico`'s `:servicos`,
5729    /// `Acao`'s `:ci`. Each arm refuses a caixa on its owner kind
5730    /// that declares no value in the corresponding required slot,
5731    /// so `feira build` (the canonical author-time gate) surfaces the
5732    /// self-locating "this kind needs this slot" diagnostic at the
5733    /// source `caixa.lisp` rather than deferring the failure to a
5734    /// downstream consumer (a nix build with no `:exe` to build, a
5735    /// programs.yaml fan-out with no `:servicos` to enumerate, a
5736    /// `caixa-actions` decompose with no `:ci` to walk).
5737    ///
5738    /// Pre-lift each of the three arms lived as a self-similar
5739    /// `if caixa.kind().requires_<slot>() && caixa.<slot>().is_<empty>() {
5740    /// return Err(LayoutError::<kind>_without_<slot>(caixa)); }`
5741    /// block at [`crate::layout::StandardLayout::verify`] — three
5742    /// consumers, three identical shapes, one substrate primitive on
5743    /// [`Caixa`] closing the duplication the PRIME DIRECTIVE names as
5744    /// a bug. Each of the three inner ctors
5745    /// ([`crate::LayoutError::binario_without_exe`] /
5746    /// [`crate::LayoutError::servico_without_servicos`] /
5747    /// [`crate::LayoutError::missing_ci`]) was already lifted onto
5748    /// the substrate by the peer [`crate::layout::layout_nome_only_ctors!`]
5749    /// macro, so the primitive routes through the same
5750    /// `Self::<variant>(caixa.nome().to_string())` tuple-literal
5751    /// wrap per arm as the pre-lift open-coded blocks.
5752    ///
5753    /// The paired `Biblioteca`-arm required-slot check
5754    /// ([`crate::LayoutError::MissingLib`]) stays open-coded at the
5755    /// layout wire-up site by design: it needs the filesystem oracle
5756    /// on [`crate::layout::LayoutInvariants`] to check the default
5757    /// `lib/<nome>.lisp` fallback path, which the pure per-`Caixa`
5758    /// typed-shape surface this fold rides on has no reference to.
5759    /// Same posture the peer [`Self::validate_no_code_kind_coherence`]
5760    /// fold takes on the on-disk existence loops.
5761    ///
5762    /// Diagnostic order at the primitive matches the pre-fold layout
5763    /// wire-up canonical sequence — `:exe` → `:servicos` → `:ci` —
5764    /// the same three-arm sweep the peer [`crate::CaixaKind`]
5765    /// discriminator carries at its `requires_*` accessors. Unlike
5766    /// the sibling cross-family [`Self::validate_kind_slot_coherence`]
5767    /// fold, the three arms of this fold are mutually exclusive by
5768    /// construction — `:kind` is a single-valued [`crate::CaixaKind`]
5769    /// discriminator so at most one arm can fire per caixa — and no
5770    /// cross-arm ordering pin is meaningful (the pre-fold three-block
5771    /// cascade at the wire-up site was already unreachable past the
5772    /// first matching arm).
5773    ///
5774    /// Peer to the per-kind and per-slot compound entry gates every
5775    /// substrate primitive on the M2/M3 typed-slot family already
5776    /// carries ([`Self::validate_deps`] b5dd55e,
5777    /// [`Self::validate_limits`] baa4688,
5778    /// [`Self::validate_behavior`] 0d2877a,
5779    /// [`Self::validate_upgrade_from`] d6801df,
5780    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5781    /// [`Self::validate_supervisor_shape`] 4c70105,
5782    /// [`Self::validate_acao_shape`] 5d6df54,
5783    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5784    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
5785    /// [`Self::validate_ci_kind_coherence`] 9b55beb): every
5786    /// author-time coherence axis on the typed [`Caixa`] surface
5787    /// now routes through one substrate primitive per axis rather
5788    /// than an open-coded block at the layout wire-up site.
5789    ///
5790    /// The gate carries two identity elements:
5791    /// - **Non-owner kinds** — each per-arm predicate is
5792    ///   `self.kind().requires_<slot>()`, which returns `true` only
5793    ///   for the owning kind ([`crate::CaixaKind::Binario`] on `:exe`,
5794    ///   [`crate::CaixaKind::Servico`] on `:servicos`,
5795    ///   [`crate::CaixaKind::Acao`] on `:ci`). Every non-owner kind
5796    ///   passes each per-arm dispatch trivially.
5797    /// - **Owner kinds with the required slot present** — a
5798    ///   [`crate::CaixaKind::Binario`] with a non-empty `:exe`, a
5799    ///   [`crate::CaixaKind::Servico`] with a non-empty `:servicos`,
5800    ///   an [`crate::CaixaKind::Acao`] with `ci = Some(_)` — passes
5801    ///   its arm's `is_empty` / `is_none` short-circuit.
5802    ///
5803    /// # Errors
5804    ///
5805    /// Returns the [`crate::LayoutError`] variant naming the
5806    /// offending owner kind:
5807    /// [`crate::LayoutError::BinarioWithoutExe`] on a
5808    /// [`crate::CaixaKind::Binario`] caixa with no declared `:exe`,
5809    /// [`crate::LayoutError::ServicoWithoutServicos`] on a
5810    /// [`crate::CaixaKind::Servico`] caixa with no declared
5811    /// `:servicos`, [`crate::LayoutError::MissingCi`] on a
5812    /// [`crate::CaixaKind::Acao`] caixa with no declared `:ci`.
5813    /// Passes trivially on every non-owner kind and on every owner
5814    /// kind with its required slot present.
5815    pub fn validate_required_kind_slot(&self) -> Result<(), crate::LayoutError> {
5816        if self.kind().requires_exe() && self.exe().is_empty() {
5817            return Err(crate::LayoutError::binario_without_exe(self));
5818        }
5819        if self.kind().requires_servicos() && self.servicos().is_empty() {
5820            return Err(crate::LayoutError::servico_without_servicos(self));
5821        }
5822        if self.kind().requires_ci() && self.ci().is_none() {
5823            return Err(crate::LayoutError::missing_ci(self));
5824        }
5825        Ok(())
5826    }
5827
5828    /// Reject per-entry values on the three Caixa-level code-surface
5829    /// path lists (`:bibliotecas`, `:exe`, `:servicos`) that the
5830    /// layout checker's `root.join(p)` sandbox would silently subvert.
5831    /// Same three structural footguns the peer
5832    /// [`BehaviorSpec::validate`] (b0c8389) and
5833    /// [`crate::UpgradeInstruction::validate`] `StateChange` arm
5834    /// (26da2c7) already close on the M2 `:behavior :on-*` and
5835    /// `:upgrade-from :state-change :script` axes, here lifted onto
5836    /// the three top-level code-path axes through the shared
5837    /// [`is_sandboxed_relative_path`] predicate:
5838    ///
5839    ///   - empty entry (`(:bibliotecas (""))` / `(:exe (""))` /
5840    ///     `(:servicos (""))`): `PathBuf::new()` round-trips through
5841    ///     [`Path::join`] as the base itself — `root.join("")` ==
5842    ///     `root`, so the existence check (`self.exists(&root)`)
5843    ///     trivially passes (the project root exists), and the layout
5844    ///     silently treats the project root as a biblioteca / exe /
5845    ///     servico entry. The `:bibliotecas` loop then hands the root
5846    ///     to `tatara_lisp::read` at `feira build` time as if the root
5847    ///     directory itself were a Lisp source file — a parse error
5848    ///     far from the source `caixa.lisp` with no field naming the
5849    ///     offending entry.
5850    ///   - absolute path (`(:bibliotecas ("/etc/passwd"))`):
5851    ///     [`Path::join`] *replaces* the base when the right-hand side
5852    ///     is absolute, so `root.join("/etc/passwd")` resolves to
5853    ///     `"/etc/passwd"` and escapes the project sandbox entirely.
5854    ///     The existence check then silently consults whatever the
5855    ///     escaped path resolves to — for `:bibliotecas`, the layout
5856    ///     has no `starts_with`-fence (only `:exe` is fenced under
5857    ///     `exe/` and `:servicos` under `servicos/`), so an absolute
5858    ///     `:bibliotecas` entry that happens to resolve on disk
5859    ///     silently passes. For `:exe` / `:servicos` the fence catches
5860    ///     the absolute case downstream as `ExeOutsideDir` /
5861    ///     `ServicoOutsideDir` (or `MissingEntry` if the absolute path
5862    ///     doesn't exist), but with a downstream-shaped diagnostic
5863    ///     that names the resolved escape path rather than the
5864    ///     authoring footgun at the source.
5865    ///   - parent-escape (`(:bibliotecas ("../sibling/x.lisp"))` /
5866    ///     `(:exe ("exe/../../escape.lisp"))`): a [`PathBuf`] with any
5867    ///     [`std::path::Component::ParentDir`] anywhere round-trips
5868    ///     through [`Path::join`] as a traversal above the caixa root.
5869    ///     The `:exe` / `:servicos` `starts_with(<dir>)` fence is
5870    ///     *component-aware* (not canonical-path-aware), so
5871    ///     `root.join("exe/../../escape.lisp")` `starts_with(exe_dir)`
5872    ///     is **true** even though the canonical resolution
5873    ///     `{parent of root}/escape.lisp` lives outside the caixa root
5874    ///     — the fence silently lets the parent-escape through, and
5875    ///     the existence check passes if that escape-target happens
5876    ///     to exist. Caught regardless of where the `..` sits
5877    ///     (leading, mid-path, trailing) so the gate matches the peer
5878    ///     predicate's full coverage.
5879    ///
5880    /// Same `Empty` → `Absolute` → `ParentEscape` arm-ordering every peer
5881    /// `is_sandboxed_relative_path` consumer follows (b0c8389 / 26da2c7);
5882    /// same per-slot diagnostic shape every peer per-axis path-gate
5883    /// exposes (`*Empty { slot }` / `*Absolute { slot, path }` /
5884    /// `*ParentEscape { slot, path }`). Cross-slot precedence is
5885    /// `:bibliotecas` → `:exe` → `:servicos` — the same declaration
5886    /// order [`Caixa::declared_foreign_code_slots`] uses for its
5887    /// canonical foreign-code-slot diagnostic, so a manifest with
5888    /// multiple malformed slots surfaces the lexicographically-earliest
5889    /// slot's diagnostic deterministically.
5890    ///
5891    /// Lifted to the typed surface as a Caixa-level validator (peer
5892    /// of [`Self::validate_nome`] / [`Self::validate_versao`] /
5893    /// [`Self::validate_deps`] / [`Self::validate_restart_window`])
5894    /// and wired into [`crate::StandardLayout::verify`] before the
5895    /// existence-check loops so the diagnostic names the offending
5896    /// slot at the source caixa.lisp rather than reporting a
5897    /// downstream `MissingEntry` / `ExeOutsideDir` /
5898    /// `ServicoOutsideDir` against the resolved sandbox-escape path.
5899    /// The fourth typed code-path surface — every author-supplied
5900    /// path on the manifest — is now structurally accept-shaped
5901    /// past validate, peer with `:behavior :on-*` and
5902    /// `:upgrade-from :state-change :script`.
5903    pub fn validate_code_paths(&self) -> Result<(), ManifestError> {
5904        /// Per-slot file-type contract for the three Caixa-level
5905        /// code-path surfaces (`:bibliotecas`, `:exe`, `:servicos`).
5906        /// Each variant names the predicate the per-entry file-type
5907        /// gate consults; [`Self::None`] opts the slot out of any
5908        /// file-type contract. Lifted as a typed local enum so the
5909        /// per-slot dispatch is exhaustive at the `match` — adding a
5910        /// future axis to the typed-substrate `:` slot set (the
5911        /// future `:assets` resource axis the M5 roadmap names, the
5912        /// future `:nix-flake` derivation axis the caixa-flake
5913        /// emitter consults) lands as one variant + one `match` arm,
5914        /// not a coordinated rewrite of every per-slot bool flag.
5915        ///
5916        /// Peer of the typed-substrate per-slot variant disciplines
5917        /// already established on this surface
5918        /// ([`crate::supervisor::RestartStrategy`] +
5919        /// [`crate::supervisor::RestartPolicy`] on the OTP-shape
5920        /// supervision-tree axis,
5921        /// [`crate::aplicacao::PlacementStrategy`] on the §III.1
5922        /// placement axis, [`crate::aplicacao::WitTarget`] on the
5923        /// `:contratos` payload-target axis): the typed `enum` is
5924        /// the substrate's single source of truth for the per-axis
5925        /// dispatch, and every consumer (the per-arm body here, the
5926        /// future feira-lint per-slot diagnostic renderer, the M4
5927        /// per-axis admission webhook) reaches for the same typed
5928        /// surface rather than re-deriving the partition from inline
5929        /// flag combinations.
5930        enum CodePathFileType {
5931            /// `:exe` — nix-build derivation output, no terminating-
5932            /// extension contract (the canonical `"exe/<name>"`
5933            /// fixtures the layout's `ExeOutsideDir` error message
5934            /// documents carry no extension by convention).
5935            None,
5936            /// `:bibliotecas` — tatara-lisp source files the
5937            /// `feira build` loop reads through `tatara_lisp::read`
5938            /// at parse time. Routes to [`is_lisp_extension`].
5939            LispSource,
5940            /// `:servicos` — ComputeUnit-CR YAML files the
5941            /// caixa-helm / caixa-flux renderers consume through
5942            /// `serde_yaml::from_str`. Routes to
5943            /// [`is_computeunit_yaml_extension`].
5944            ComputeUnitYaml,
5945        }
5946
5947        // The per-slot [`CodePathFileType`] selects which axes carry the
5948        // lifted file-type predicate. `:bibliotecas` is the tatara-lisp
5949        // source axis (the `feira build` loop at
5950        // `caixa-feira/src/cmd/build.rs:33` reads each entry through
5951        // `tatara_lisp::read` at parse time) — the lifted
5952        // [`is_lisp_extension`] predicate gates the `.lisp` extension.
5953        // `:exe` is the nix-built executable surface (per the canonical
5954        // `"exe/<name>"`-shaped fixtures the layout's `ExeOutsideDir`
5955        // error message documents and every in-tree
5956        // `caixa_with_code_paths` positive control uses) — its file-type
5957        // contract is "nix-build derivation output", not a typed source
5958        // file, so [`CodePathFileType::None`] opts the slot out of any
5959        // file-type gate. `:servicos` is the `.computeunit.yaml`
5960        // ComputeUnit-CR axis (the peer caixa-helm / caixa-flux
5961        // renderers consume each entry through `serde_yaml::from_str` as
5962        // a typed `ComputeUnit` CR) — the lifted
5963        // [`is_computeunit_yaml_extension`] predicate gates the compound
5964        // `.computeunit.yaml` suffix. All three axes are surfaced through
5965        // the same iteration so the sandbox-shape + duplicate gates
5966        // apply uniformly; the typed file-type dispatch fires per-slot
5967        // exactly where the downstream consumer's accepted set demands
5968        // it. The third file-type variant ([`ComputeUnitYaml`]) is the
5969        // compounding lift on the peer 64772a9 `:bibliotecas`
5970        // `.lisp`-gate trajectory — the second of the three code-path
5971        // axes to land on a typed compound-suffix gate, with the same
5972        // self-locating per-slot diagnostic shape every peer per-axis
5973        // file-type lift uses (`*NonLispExtension { slot, path }` /
5974        // `*NonComputeUnitYamlExtension { slot, path }`).
5975        for (slot, list, file_type) in [
5976            (
5977                ":bibliotecas",
5978                &self.bibliotecas,
5979                CodePathFileType::LispSource,
5980            ),
5981            (":exe", &self.exe, CodePathFileType::None),
5982            (
5983                ":servicos",
5984                &self.servicos,
5985                CodePathFileType::ComputeUnitYaml,
5986            ),
5987        ] {
5988            // Per-slot set-not-multiset gate on the typed code-path axis.
5989            // Every peer Vec-shaped author-supplied list past validate is
5990            // a set, not a multiset: `:membros :caixa`
5991            // ([`crate::AplicacaoError::MembroDuplicate`]), `:placement
5992            // :clusters` ([`crate::AplicacaoError::PlacementClusterDuplicate`]),
5993            // `:entrada :paths` ([`crate::AplicacaoError::EntradaPathDuplicate`]),
5994            // `:contratos` ([`crate::AplicacaoError::ContratoDuplicate`]),
5995            // `:children :caixa` ([`crate::SupervisorError::DuplicateChild`]),
5996            // `:deps` / `:deps-dev` `:nome` ([`crate::DepError::DuplicateNome`]
5997            // per 359fba5), `:upgrade-from :from` ([`crate::UpgradeError::DuplicateFrom`]),
5998            // `:etiquetas` ([`ManifestError::EtiquetaDuplicate`] per 360a499),
5999            // `:autores` ([`ManifestError::AutorDuplicate`] per 86c769b) —
6000            // the three code-path lists are the last Vec-shaped author-
6001            // supplied slots on the typed Caixa surface still admitting a
6002            // duplicate entry silently. Scope is per-list (`:bibliotecas`
6003            // duplicates are flagged within `:bibliotecas`, not across
6004            // `:bibliotecas` ↔ `:exe`) — the same per-list scope `:deps`
6005            // ↔ `:deps-dev` use (a `:nome` present in both lists is a
6006            // legitimate dev-vs-runtime shape on the dep axis, fenced
6007            // separately by [`crate::dep::validate_no_self_dep`]). On the
6008            // code-path axis a cross-slot collision is structurally
6009            // impossible by the layout's `starts_with(<exe|servicos>_dir)`
6010            // fence — `:exe` and `:servicos` entries are confined to their
6011            // own directory trees, so the only way a string could appear
6012            // on two code-path lists is the (rare, structurally invalid)
6013            // case where `:bibliotecas` carries an `"exe/<x>"` or
6014            // `"servicos/<x>.yaml"`-shaped path.
6015            //
6016            // Without the gate three authoring footguns silently passed:
6017            //
6018            //   - `:bibliotecas ("lib/foo.lisp" "lib/foo.lisp")` — the
6019            //     canonical copy-paste-the-wrong-file footgun. `feira
6020            //     build` (`caixa-feira/src/cmd/build.rs:33`) walks the
6021            //     list and re-parses the same file twice, wasting work
6022            //     and silently masking the author's intent to declare a
6023            //     *second* biblioteca.
6024            //   - `:exe ("exe/cli" "exe/cli")` — the same footgun on the
6025            //     Binario surface. The future `caixa-flake` `nix flake`
6026            //     emitter that materializes each `:exe` entry as a flake
6027            //     `packages.<exe-name>` derivation would collide on the
6028            //     duplicate package name and surface a flake-eval error
6029            //     far from the source `caixa.lisp`.
6030            //   - `:servicos ("servicos/x.computeunit.yaml"
6031            //     "servicos/x.computeunit.yaml")` — the same footgun on
6032            //     the Servico surface. The peer `caixa-helm` / `caixa-flux`
6033            //     renderers already refuse `:servicos.len() != 1` with
6034            //     the narrower [`UnsupportedServicoCount`] diagnostic, but
6035            //     that diagnostic surfaces "too many servicos" without
6036            //     naming "duplicate entry" — the typed self-locating
6037            //     "which entry is the duplicate" framing only lands at
6038            //     this gate.
6039            //
6040            // Same `seen.insert(entry.as_str())` shape every peer per-list
6041            // duplicate gate uses (`:etiquetas` 360a499, `:autores`
6042            // 86c769b, `:deps` 359fba5) and the same "structural shape
6043            // checks fire before the duplicate check on the same entry"
6044            // ordering (a `(:bibliotecas ("" "lib/x.lisp" "lib/x.lisp"))`
6045            // shape surfaces the narrower [`Self::CodePathEmpty`] for the
6046            // empty entry first, not the duplicate on the later pair).
6047            let mut seen = std::collections::HashSet::new();
6048            for entry in list {
6049                let path = Path::new(entry);
6050                match is_sandboxed_relative_path(path) {
6051                    Ok(()) => {}
6052                    Err(PathShapeViolation::Empty) => {
6053                        return Err(ManifestError::code_path_empty(slot));
6054                    }
6055                    Err(PathShapeViolation::Absolute) => {
6056                        return Err(ManifestError::code_path_absolute(slot, path));
6057                    }
6058                    Err(PathShapeViolation::ParentEscape) => {
6059                        return Err(ManifestError::code_path_parent_escape(slot, path));
6060                    }
6061                }
6062                // The per-slot file-type gate dispatched through the
6063                // typed [`CodePathFileType`] selector above. Each variant
6064                // routes to the lifted predicate the downstream consumer
6065                // demands:
6066                //
6067                //   - [`LispSource`] → [`is_lisp_extension`] for
6068                //     `:bibliotecas` (the `feira build` loop's
6069                //     `tatara_lisp::read` consumer);
6070                //   - [`ComputeUnitYaml`] → [`is_computeunit_yaml_extension`]
6071                //     for `:servicos` (the caixa-helm / caixa-flux
6072                //     `serde_yaml::from_str` consumer's `ComputeUnit` CR
6073                //     accepted set);
6074                //   - [`None`] for `:exe` — the nix-build derivation-
6075                //     output axis has no terminating-extension contract.
6076                //
6077                // Fires after the sandbox-shape arms so a path that is
6078                // *both* sandbox-escaping and wrong-extension surfaces
6079                // the more fundamental sandbox-shape diagnostic first
6080                // (mirrors the peer `EmptyPath` → `AbsolutePath` →
6081                // `ParentEscape` → `NonLispExtension` arm-ordering on
6082                // `:behavior :on-*` c97815a, and `EmptyScript` →
6083                // `AbsoluteScript` → `ParentEscapeScript` →
6084                // `NonLispExtensionScript` on
6085                // `:upgrade-from :state-change :script` 33cc830), and
6086                // before the duplicate gate so the narrower per-entry
6087                // file-type shape dominates the cross-entry uniqueness
6088                // diagnostic (a
6089                // `("servicos/x.yaml" "servicos/x.yaml")` shape on
6090                // `:servicos` surfaces
6091                // `CodePathNonComputeUnitYamlExtension` on the first
6092                // entry rather than `CodePathDuplicate` on the pair —
6093                // peer with the 64772a9 `:bibliotecas`
6094                // `("lib/x.txt" "lib/x.txt")` ordering).
6095                match file_type {
6096                    CodePathFileType::None => {}
6097                    CodePathFileType::LispSource => {
6098                        if !is_lisp_extension(path) {
6099                            return Err(ManifestError::code_path_non_lisp_extension(slot, path));
6100                        }
6101                    }
6102                    CodePathFileType::ComputeUnitYaml => {
6103                        if !is_computeunit_yaml_extension(path) {
6104                            return Err(ManifestError::code_path_non_computeunit_yaml_extension(
6105                                slot, path,
6106                            ));
6107                        }
6108                    }
6109                }
6110                crate::render::insert_first_seen(&mut seen, entry.as_str(), || {
6111                    ManifestError::code_path_duplicate(slot, path)
6112                })?;
6113            }
6114        }
6115        Ok(())
6116    }
6117
6118    /// Reject `:etiquetas` lists with an empty entry or with two entries
6119    /// agreeing on the same string. `:etiquetas` is the universal
6120    /// registry-search-tag axis on [`Caixa`] (every kind carries the
6121    /// `Vec<String>` slot) and lands verbatim as the Helm chart
6122    /// `Chart.yaml` `keywords:` array on every Servico (caixa-helm's
6123    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:236` folds it through
6124    /// a [`std::collections::BTreeSet`] alongside the four substrate-
6125    /// fixed tags `lareira` / `wasm` / `tatara-lisp` / `caixa-servico`).
6126    /// Two authoring footguns silently passed validate without this gate:
6127    ///
6128    ///   - Empty entry (`(:etiquetas (""))` — the canonical paste-from-
6129    ///     blank-doc footgun) rendered as `keywords: ["", "caixa-servico",
6130    ///     "lareira", "tatara-lisp", "wasm"]` in `Chart.yaml`. Helm's
6131    ///     `chart.metadata.keywords` admits the value without a strict
6132    ///     parser-side gate, but the empty keyword has no operational
6133    ///     meaning — it indexes nothing in the future caixa-registry
6134    ///     search axis and clutters the rendered chart with a no-op tag.
6135    ///   - Duplicate entries (`(:etiquetas ("demo" "demo"))` — the
6136    ///     copy-paste-the-wrong-tag footgun) silently passed validate
6137    ///     and were silently dedup'd by caixa-helm's `BTreeSet` collect
6138    ///     at chart render — a "second wins / one silently disappears"
6139    ///     shape divergent from every peer typed-graph set gate
6140    ///     ([`crate::AplicacaoError::MembroDuplicate`] on `:membros`,
6141    ///     [`crate::AplicacaoError::PlacementClusterDuplicate`] on
6142    ///     `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
6143    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
6144    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
6145    ///     `:deps` / `:deps-dev` per 359fba5, [`crate::UpgradeError::DuplicateFrom`]
6146    ///     on `:upgrade-from`, the per-instruction-class singularity
6147    ///     gates [`crate::UpgradeError::DuplicateLoadModule`] /
6148    ///     [`crate::UpgradeError::DuplicateStateChange`] /
6149    ///     [`crate::UpgradeError::DuplicateCleanup`]). The typed-graph
6150    ///     discipline is uniform: every Vec-shaped author-supplied list
6151    ///     past validate is set-not-multiset, by construction.
6152    ///
6153    /// Past the empty arm the gate enforces the chart-keyword shape
6154    /// predicate via [`crate::render::is_chart_keyword_shape`]: Cargo's
6155    /// crates.io `[package] keywords` grammar — 1..=20 bytes, starts
6156    /// with an ASCII letter, ASCII alphanumeric / `_` / `-`
6157    /// continuation. Closes the canonical paste-from-doc footguns the
6158    /// bare empty + duplicate arms left open: paste-from-aligned-doc
6159    /// whitespace (`" mesh"`, `"mesh "`), paste-from-multiline-doc
6160    /// newline (`"mesh\nhttp"` — the author pasted a multi-tag block
6161    /// into one entry instead of splitting), paste-from-Windows-CRLF-doc
6162    /// carriage return, CSV-list-separator confusion (`"mesh,http,grpc"`
6163    /// — the author meant three separate list entries), path-separator
6164    /// confusion (`"caixa/servico"`), namespace-suffix (`"http.1"`),
6165    /// leading-digit (`"1foo"`), kebab-leak (`"-foo"`), snake-leak
6166    /// (`"_foo"`), non-ASCII (`"café"`), and paste-from-binary-blob
6167    /// control bytes that would silently land as malformed search tags
6168    /// in the rendered Chart.yaml `keywords:` array and break the
6169    /// Artifact Hub keyword index lookup far from the source caixa.lisp.
6170    /// Mirrors the [`Self::validate_autores`] shape-predicate cascade
6171    /// established on the sibling universal-axis `Vec<String>` surface
6172    /// — the second universal-axis Vec<String> surface to land the
6173    /// empty-first-then-shape-then-duplicate per-entry cascade.
6174    ///
6175    /// Same empty-first cascade discipline every peer per-axis gate
6176    /// uses: the per-entry empty arm fires before the per-entry shape
6177    /// arm fires before the cross-entry duplicate arm, so an
6178    /// `("" "mesh" "mesh")` authoring shape surfaces the narrower
6179    /// [`ManifestError::EtiquetaEmpty`] (the structural "this entry
6180    /// has no value" defect) before either the shape or the duplicate
6181    /// diagnostic. Walks the list in declaration order so the
6182    /// first-collision diagnostic surfaces the lexicographically-
6183    /// earliest offending position, peer with every other duplicate
6184    /// gate on this surface.
6185    ///
6186    /// Universal-axis (every kind carries `:etiquetas`), so wired at the
6187    /// caixa-build gate alongside the peer universal gates
6188    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6189    /// [`Self::validate_deps`] / [`Self::validate_code_paths`] — before
6190    /// the kind-coherence gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]
6191    /// / [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6192    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6193    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
6194    /// slot sets. The future caixa-registry search axis can reach for
6195    /// `caixa.etiquetas` knowing every entry is a non-empty distinct
6196    /// chart-keyword-shaped string without re-deriving the precondition.
6197    pub fn validate_etiquetas(&self) -> Result<(), ManifestError> {
6198        let mut seen = std::collections::HashSet::new();
6199        for etiqueta in self.etiquetas() {
6200            if etiqueta.is_empty() {
6201                return Err(ManifestError::EtiquetaEmpty);
6202            }
6203            crate::render::is_chart_keyword_shape(etiqueta)
6204                .map_err(|reason| ManifestError::etiqueta_invalid(etiqueta, reason))?;
6205            crate::render::insert_first_seen(&mut seen, etiqueta.as_str(), || {
6206                ManifestError::etiqueta_duplicate(etiqueta)
6207            })?;
6208        }
6209        Ok(())
6210    }
6211
6212    /// Reject `:autores` lists with an empty entry or with two entries
6213    /// agreeing on the same string. `:autores` is the universal
6214    /// maintainer-axis on [`Caixa`] (every kind carries the
6215    /// `Vec<String>` slot) and lands verbatim as the Helm chart
6216    /// `Chart.yaml` `maintainers:` array on every Servico (caixa-helm's
6217    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:251` maps each entry
6218    /// to a `Maintainer { name, email: None }` without dedup). Two
6219    /// authoring footguns silently passed validate without this gate:
6220    ///
6221    ///   - Empty entry (`(:autores (""))` — the canonical paste-from-
6222    ///     blank-doc footgun) rendered as
6223    ///     `maintainers: [{name: "", email: null}]` in `Chart.yaml`. The
6224    ///     empty maintainer name has no operational meaning — it
6225    ///     identifies no one in the substrate's authorship index and
6226    ///     clutters the rendered chart with a no-op maintainer.
6227    ///   - Duplicate entries (`(:autores ("pleme-io" "pleme-io"))` —
6228    ///     the copy-paste-the-wrong-author footgun) silently passed
6229    ///     validate and rendered as two identical maintainer entries.
6230    ///     Unlike the [`Self::validate_etiquetas`] peer (caixa-helm's
6231    ///     `BTreeSet`-collect on `:etiquetas` silently dedups the
6232    ///     rendered `keywords:` array at chart-render time), the
6233    ///     `maintainers:` rendering has *no* dedup — duplicate `:autores`
6234    ///     entries stack verbatim in the chart, divergent from every
6235    ///     peer typed-graph set gate ([`crate::AplicacaoError::MembroDuplicate`]
6236    ///     on `:membros`, [`crate::AplicacaoError::PlacementClusterDuplicate`]
6237    ///     on `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
6238    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
6239    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
6240    ///     `:deps` / `:deps-dev`, [`crate::UpgradeError::DuplicateFrom`]
6241    ///     on `:upgrade-from`, [`ManifestError::EtiquetaDuplicate`] on
6242    ///     `:etiquetas`).
6243    ///
6244    /// Past the empty arm the gate enforces the chart-maintainer-name
6245    /// shape predicate via [`crate::render::is_chart_maintainer_name_shape`]:
6246    /// the structural single-line printable-UTF-8 floor every realistic
6247    /// Helm chart maintainer name carries — 1..=128 bytes, no leading
6248    /// or trailing whitespace, no ASCII control characters anywhere,
6249    /// Unicode bytes accepted. Closes the canonical paste-from-doc
6250    /// footguns the bare empty + duplicate arms left open:
6251    /// paste-from-aligned-doc whitespace (`" pleme-io"`, `"pleme-io "`),
6252    /// paste-from-multiline-doc newline (`"alice\nbob"` — the author
6253    /// pasted a multi-line block of author records into one `:autores`
6254    /// entry instead of splitting into one entry per author),
6255    /// paste-from-Windows-CRLF-doc carriage return, tab-from-aligned-doc,
6256    /// and the paste-from-binary-blob control bytes that would silently
6257    /// land as YAML-illegal byte sequences in the rendered Chart.yaml
6258    /// `maintainers:` array. Mirrors the shape-predicate cascade
6259    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
6260    /// [`Self::validate_edicao`] / [`Self::validate_repositorio`]
6261    /// establish past their own empty arms on the sibling universal-axis
6262    /// `Option<String>` surfaces — the first universal-axis Vec<String>
6263    /// surface to land the empty-first-then-shape-then-duplicate per-entry
6264    /// cascade.
6265    ///
6266    /// Same empty-first cascade discipline every peer per-axis gate
6267    /// uses: the per-entry empty arm fires before the per-entry shape
6268    /// arm before the cross-entry duplicate arm. Walks the list in
6269    /// declaration order so the first-collision diagnostic surfaces the
6270    /// lexicographically-earliest offending position, peer with every
6271    /// other duplicate gate on this surface.
6272    ///
6273    /// Universal-axis (every kind carries `:autores`), so wired at the
6274    /// caixa-build gate alongside the peer universal gates
6275    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6276    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6277    /// [`Self::validate_code_paths`] — before the kind-coherence gates
6278    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6279    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6280    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6281    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
6282    /// slot sets.
6283    pub fn validate_autores(&self) -> Result<(), ManifestError> {
6284        let mut seen = std::collections::HashSet::new();
6285        for autor in self.autores() {
6286            if autor.is_empty() {
6287                return Err(ManifestError::AutorEmpty);
6288            }
6289            crate::render::is_chart_maintainer_name_shape(autor)
6290                .map_err(|reason| ManifestError::autor_invalid(autor, reason))?;
6291            crate::render::insert_first_seen(&mut seen, autor.as_str(), || {
6292                ManifestError::autor_duplicate(autor)
6293            })?;
6294        }
6295        Ok(())
6296    }
6297
6298    /// Reject `:repositorio` values whose shape the shared
6299    /// [`crate::render::is_git_repo_url`] predicate refuses. The flat
6300    /// `repositorio: Option<String>` slot on [`Caixa`] is the
6301    /// universal git-shaped homepage axis every kind carries — the
6302    /// substrate routes the same string through two load-bearing
6303    /// consumers:
6304    ///
6305    ///   - [`caixa-helm`] folds it verbatim into the rendered
6306    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `home:` field
6307    ///     (`build_chart_yaml` at `caixa-helm/src/lib.rs:268`) and into
6308    ///     the chart `README.md` `repo = …` interpolation
6309    ///     (`caixa-helm/src/lib.rs:359`).
6310    ///   - [`caixa-flux`] folds it verbatim into the standalone
6311    ///     `ClusterBundleOpts::for_caixa` `git_url:` field
6312    ///     (`caixa-flux/src/lib.rs:293`), which becomes the `FluxCD`
6313    ///     `GitRepository.spec.url` the cluster's source-controller
6314    ///     polls — the load-bearing deploy-time axis.
6315    ///
6316    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
6317    /// substitute a placeholder when the slot is absent (`None` → the
6318    /// fallback fires); a `Some("")` *skips the fallback* and silently
6319    /// passes the empty string through to `Chart.yaml home: ""` /
6320    /// `GitRepository url: ""` — Helm's chart lint and `FluxCD`'s source
6321    /// controller both reject the empty URL far from the source
6322    /// `caixa.lisp`, with no field naming the offending `:repositorio`.
6323    /// Similarly a malformed `:repositorio` (whitespace, control char,
6324    /// missing `:` separator, leading `-`) silently lands in the
6325    /// rendered artifacts and breaks at `git clone` / `helm template`
6326    /// / `flux reconcile` time.
6327    ///
6328    /// Thin wrapper around [`crate::render::is_git_repo_url`] — the
6329    /// same shared predicate the peer [`crate::DepSource::validate`]
6330    /// routes the `:fonte (:tipo git :repo …)` axis through. With this
6331    /// gate the two `git URL`-shaped surfaces on the typed Caixa
6332    /// (`:repositorio` here, `:deps :fonte :repo` peer) are
6333    /// structurally equivalent: every value past validate is
6334    /// guaranteed-acceptable by the predicate's union of constraints
6335    /// (non-empty, length-bounded, no leading `-`, no whitespace, no
6336    /// control chars, ASCII only, no leading `:`, contains a `:`
6337    /// separator). The predicate accepts every documented authoring
6338    /// shape — `github:org/repo` shorthand, `https://host/path`,
6339    /// `ssh://[user@]host/path`, `git://host/path`, `git@host:path`
6340    /// scp-style SSH, `file:///path` — and refuses the canonical
6341    /// paste-from-blank-doc / paste-from-multiline-doc / CLI-arg-
6342    /// injection footguns at validate time. Maps the predicate's
6343    /// `String` reason verbatim into the
6344    /// [`ManifestError::RepositorioInvalid`] variant, carrying the
6345    /// offending value + parser-shaped reason so the diagnostic is
6346    /// self-locating (the author can grep their `caixa.lisp` for
6347    /// `:repositorio "<value>"` and fix it in one edit).
6348    ///
6349    /// `None` (the canonical "omit the slot to express no published
6350    /// homepage" shape) is accepted trivially — the gate is a no-op
6351    /// when the author didn't declare a value. `Some("")` is gated by
6352    /// the narrower [`ManifestError::RepositorioEmpty`] arm before the
6353    /// shape predicate is consulted, mirroring the empty-first cascade
6354    /// every peer per-axis identity gate uses
6355    /// ([`ManifestError::NomeEmpty`] → [`ManifestError::NomeInvalid`],
6356    /// [`ManifestError::VersaoEmpty`] → [`ManifestError::VersaoInvalid`],
6357    /// [`crate::DepError::FonteRepoEmpty`] →
6358    /// [`crate::DepError::FonteRepoInvalid`]).
6359    ///
6360    /// Universal-axis (every kind carries `:repositorio`), so wired at
6361    /// the caixa-build gate alongside the peer universal gates
6362    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6363    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6364    /// [`Self::validate_autores`] / [`Self::validate_code_paths`] —
6365    /// before the kind-coherence gates
6366    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6367    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6368    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6369    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6370    /// specific slot sets.
6371    pub fn validate_repositorio(&self) -> Result<(), ManifestError> {
6372        let Some(s) = self.repositorio() else {
6373            return Ok(());
6374        };
6375        if s.is_empty() {
6376            return Err(ManifestError::RepositorioEmpty);
6377        }
6378        is_git_repo_url(s).map_err(|reason| ManifestError::repositorio_invalid(s, reason))
6379    }
6380
6381    /// Reject `:descricao` values that are the empty string. The flat
6382    /// `descricao: Option<String>` slot on [`Caixa`] is the universal
6383    /// free-form-prose homepage axis every kind carries — the
6384    /// substrate routes the same string through two load-bearing
6385    /// consumers in the [`caixa-helm`] renderer:
6386    ///
6387    ///   - `build_chart_yaml` folds it verbatim into the rendered
6388    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `description:`
6389    ///     field (`caixa-helm/src/lib.rs:232-235`).
6390    ///   - `build_readme` folds it verbatim into the rendered chart
6391    ///     `README.md` header (`caixa-helm/src/lib.rs:333-336`).
6392    ///
6393    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
6394    /// substitute a `caixa.nome`-derived placeholder when the slot is
6395    /// absent (`None` → the fallback fires); a `Some("")` *skips the
6396    /// fallback* and silently passes the empty string through to
6397    /// `Chart.yaml description: ""` / a blank chart `README.md`
6398    /// header. Helm's chart spec requires a non-empty `description:`
6399    /// field on `apiVersion: v2` charts (`helm lint` surfaces it as
6400    /// `WARNING [chart.metadata.description]: description is required`),
6401    /// so the empty `Some("")` silently lands in the rendered
6402    /// artifacts and breaks at `helm lint` / `helm install` time far
6403    /// from the source `caixa.lisp`, with no field naming the
6404    /// offending `:descricao`.
6405    ///
6406    /// `None` (the canonical "omit the slot to defer to the renderer's
6407    /// `caixa.nome`-derived fallback" shape) is accepted trivially —
6408    /// the gate is a no-op when the author didn't declare a value.
6409    /// `Some("")` is gated by the narrower
6410    /// [`ManifestError::DescricaoEmpty`] arm, mirroring the empty-arm
6411    /// shape every peer per-axis empty gate uses
6412    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6413    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6414    /// [`ManifestError::RepositorioEmpty`]).
6415    ///
6416    /// Universal-axis (every kind carries `:descricao`), so wired at
6417    /// the caixa-build gate alongside the peer universal gates
6418    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6419    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6420    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6421    /// [`Self::validate_code_paths`] — before the kind-coherence
6422    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6423    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6424    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6425    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6426    /// specific slot sets.
6427    ///
6428    /// Past the empty arm the gate enforces the chart-description
6429    /// shape predicate via [`crate::render::is_chart_description_shape`]:
6430    /// the structural single-line UTF-8 floor every realistic chart
6431    /// description in the wild matches — 1..=512 bytes, no leading
6432    /// or trailing whitespace, no ASCII control characters anywhere
6433    /// (`0x00..=0x1F` plus `0x7F` DEL — banning tab, newline,
6434    /// carriage return, and every other control byte), Unicode
6435    /// continuation bytes accepted (the canonical fixtures carry
6436    /// `→` and `—`). Closes the canonical paste-from-doc footguns
6437    /// the bare empty-arm gate left open: paste-from-aligned-doc
6438    /// leading / trailing whitespace (`" Checkout flow."`,
6439    /// `"Checkout flow. "`), paste-from-multiline-doc newline
6440    /// (`"Checkout\nflow."`), paste-from-Windows-CRLF-doc CR
6441    /// (`"Checkout\rflow."`), tab-from-aligned-doc
6442    /// (`"Checkout\tflow."`), and paste-from-binary-blob NUL / BEL /
6443    /// ESC / DEL bytes. Mirrors the shape-predicate cascade
6444    /// [`Self::validate_repositorio`] / [`Self::validate_licenca`] /
6445    /// [`Self::validate_edicao`] establish past their own empty arms
6446    /// on the sibling universal-axis `Option<String>` Caixa-level
6447    /// value-shape surfaces.
6448    ///
6449    /// The empty-first cascade discipline mirrors every peer per-axis
6450    /// identity gate: [`ManifestError::DescricaoEmpty`] runs before
6451    /// [`ManifestError::DescricaoInvalid`], so the narrower empty
6452    /// diagnostic surfaces on `Some("")` rather than the broader
6453    /// shape-predicate diagnostic — peer with how
6454    /// [`ManifestError::LicencaEmpty`] runs before
6455    /// [`ManifestError::LicencaInvalid`],
6456    /// [`ManifestError::EdicaoEmpty`] runs before
6457    /// [`ManifestError::EdicaoInvalid`],
6458    /// [`ManifestError::RepositorioEmpty`] runs before
6459    /// [`ManifestError::RepositorioInvalid`].
6460    pub fn validate_descricao(&self) -> Result<(), ManifestError> {
6461        let Some(s) = self.descricao() else {
6462            return Ok(());
6463        };
6464        if s.is_empty() {
6465            return Err(ManifestError::DescricaoEmpty);
6466        }
6467        crate::render::is_chart_description_shape(s)
6468            .map_err(|reason| ManifestError::descricao_invalid(s, reason))?;
6469        Ok(())
6470    }
6471
6472    /// Reject `:licenca` values that are the empty string. The flat
6473    /// `licenca: Option<String>` slot on [`Caixa`] is the universal
6474    /// SPDX-shaped license-expression axis every kind carries — the
6475    /// substrate routes the same string through the [`caixa-helm`]
6476    /// renderer's `build_readme` which folds it verbatim into the
6477    /// rendered `lareira-<nome>` Helm chart's `README.md` `## License`
6478    /// section (`caixa-helm/src/lib.rs:361`) via
6479    /// `caixa.licenca.clone().unwrap_or_else(|| "MIT".into())`. The
6480    /// fallback only fires on `None`; a `Some("")` *skips the
6481    /// fallback* and silently passes the empty string through to a
6482    /// chart `README.md` whose `License` section renders as the bare
6483    /// trailing period (`.\n`) — peer footgun with the
6484    /// `Some("")`-skips-`unwrap_or_else` shape the
6485    /// [`Self::validate_descricao`] and [`Self::validate_repositorio`]
6486    /// gates close on the sibling free-form-prose and git-URL axes.
6487    ///
6488    /// `None` (the canonical "omit the slot to defer to the
6489    /// renderer's `MIT` fallback" shape every existing fixture
6490    /// carries) is accepted trivially — the gate is a no-op when the
6491    /// author didn't declare a value. `Some("")` is gated by the
6492    /// narrower [`ManifestError::LicencaEmpty`] arm, mirroring the
6493    /// empty-arm shape every peer per-axis empty gate uses
6494    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6495    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6496    /// [`ManifestError::RepositorioEmpty`],
6497    /// [`ManifestError::DescricaoEmpty`]).
6498    ///
6499    /// Universal-axis (every kind carries `:licenca`), so wired at
6500    /// the caixa-build gate alongside the peer universal gates
6501    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6502    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6503    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6504    /// [`Self::validate_descricao`] / [`Self::validate_code_paths`]
6505    /// — before the kind-coherence gates
6506    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6507    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6508    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6509    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6510    /// specific slot sets.
6511    ///
6512    /// Past the empty arm the gate enforces the SPDX-expression shape
6513    /// predicate via [`crate::render::is_spdx_expression_shape`]: the
6514    /// structural alphabet floor every realistic SPDX expression in
6515    /// the wild uses — ASCII alphanumeric plus `.`, `-`, `+`, `(`,
6516    /// `)`, `:` (the `DocumentRef-…:LicenseRef-…` separator), and a
6517    /// single ASCII space (token separator). Closes the canonical
6518    /// paste-from-doc footguns the bare empty-arm gate left open:
6519    /// paste-from-doc whitespace (`"MIT "`, `" MIT"`), paste-from-
6520    /// multiline-doc CRLF (`"MIT\n"`), tab-from-aligned-doc
6521    /// (`"MIT\tOR Apache-2.0"`), non-ASCII smart-quote paste,
6522    /// underscore-instead-of-hyphen typo (`"Apache_2.0"`),
6523    /// comma-instead-of-`OR`-keyword colloquial idiom (`"MIT,
6524    /// Apache-2.0"`), slash-dual-license colloquial idiom (`"MIT/
6525    /// Apache-2.0"`), and semicolon-list-separator confusion
6526    /// (`"MIT; Apache-2.0"`). Mirrors the shape-predicate cascade
6527    /// [`Self::validate_repositorio`] / [`Self::validate_edicao`]
6528    /// establish past their own empty arms.
6529    ///
6530    /// The empty-first cascade discipline mirrors every peer per-axis
6531    /// identity gate: [`ManifestError::LicencaEmpty`] runs before
6532    /// [`ManifestError::LicencaInvalid`], so the narrower empty
6533    /// diagnostic surfaces on `Some("")` rather than the broader
6534    /// shape-predicate diagnostic — peer with how
6535    /// [`ManifestError::EdicaoEmpty`] runs before
6536    /// [`ManifestError::EdicaoInvalid`],
6537    /// [`ManifestError::RepositorioEmpty`] runs before
6538    /// [`ManifestError::RepositorioInvalid`].
6539    ///
6540    /// A future tightening on this axis can extend the alphabet
6541    /// floor into a full SPDX expression parser + license-id
6542    /// allowlist (rejecting alphabet-valid values that don't name a
6543    /// real SPDX license identifier — e.g., `"NotAReal"` is
6544    /// alphabet-valid but no `NotAReal` license-id exists). That
6545    /// parser only becomes meaningful past a real SPDX-spec
6546    /// dependency; this gate establishes the structural floor by
6547    /// refusing every non-SPDX-alphabet value at validate time.
6548    pub fn validate_licenca(&self) -> Result<(), ManifestError> {
6549        let Some(s) = self.licenca() else {
6550            return Ok(());
6551        };
6552        if s.is_empty() {
6553            return Err(ManifestError::LicencaEmpty);
6554        }
6555        crate::render::is_spdx_expression_shape(s)
6556            .map_err(|reason| ManifestError::licenca_invalid(s, reason))?;
6557        Ok(())
6558    }
6559
6560    /// Reject `:edicao` values that are the empty string. The flat
6561    /// `edicao: Option<String>` slot on [`Caixa`] is the universal
6562    /// language-edition axis every kind carries — it determines the
6563    /// tatara-lisp macro surface + compatibility flags the substrate
6564    /// applies when building a caixa, and lands verbatim in the
6565    /// `Caixa::template` author-time scaffold (the canonical
6566    /// `:edicao "2026"` line every `feira init` emits via
6567    /// [`Caixa::template`] at `caixa-core/src/manifest.rs:1193`) and
6568    /// in every renderer-side fixture (`caixa-helm/src/lib.rs:375`,
6569    /// `caixa-flux/src/lib.rs:445`, `caixa-mesh/src/lib.rs:629`,
6570    /// `caixa-core/src/render.rs:2510`) via
6571    /// `edicao: Some("2026".into())`.
6572    ///
6573    /// `None` (the canonical "omit the slot to defer to the
6574    /// substrate's default edition" shape every existing
6575    /// [`caixa-resolver`] integration test fixture carries via
6576    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
6577    /// is accepted trivially — the gate is a no-op when the author
6578    /// didn't declare a value. `Some("")` is gated by the narrower
6579    /// [`ManifestError::EdicaoEmpty`] arm, mirroring the empty-arm
6580    /// shape every peer per-axis empty gate uses
6581    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6582    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6583    /// [`ManifestError::RepositorioEmpty`],
6584    /// [`ManifestError::DescricaoEmpty`], [`ManifestError::LicencaEmpty`]).
6585    ///
6586    /// Universal-axis (every kind carries `:edicao`), so wired at
6587    /// the caixa-build gate alongside the peer universal gates
6588    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6589    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6590    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6591    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
6592    /// [`Self::validate_code_paths`] — before the kind-coherence
6593    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6594    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6595    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6596    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6597    /// specific slot sets.
6598    ///
6599    /// Past the empty arm the gate enforces the canonical year-shape
6600    /// predicate: every documented tatara-lisp edition is a 4-digit
6601    /// ASCII decimal year (`"2026"` is the only edition currently
6602    /// minted; future-introduced siblings will follow the same
6603    /// shape, peer with Cargo's `[package] edition` grammar which
6604    /// every value Cargo has ever accepted matches — `"2015"`,
6605    /// `"2018"`, `"2021"`, `"2024"`). Any value that's not exactly
6606    /// 4 ASCII decimal bytes is rejected with the narrower
6607    /// [`ManifestError::EdicaoInvalid`] arm, mirroring the
6608    /// shape-predicate cascade [`Self::validate_repositorio`]
6609    /// establishes past its own empty arm
6610    /// ([`ManifestError::RepositorioEmpty`] →
6611    /// [`ManifestError::RepositorioInvalid`]). Closes the canonical
6612    /// paste-from-doc footguns the bare empty-arm gate left open:
6613    ///
6614    ///   - leading / trailing whitespace from a paste-from-doc
6615    ///     (`"2026 "`, `" 2026"`)
6616    ///   - control characters / CRLF from a paste-from-multiline-doc
6617    ///     (`"2026\n"`)
6618    ///   - non-ASCII look-alikes from a fullwidth keyboard
6619    ///     (`"2026"`) which would silently land as a non-ASCII
6620    ///     string in the rendered caixa.lisp
6621    ///   - free-form non-year values (`"x"`, `"latest"`,
6622    ///     `"nightly"`) that have no operational meaning on the
6623    ///     substrate's build-time edition selector
6624    ///   - leading non-digit prefixes (`"v2026"`, `"e2026"`,
6625    ///     `"r2026"`) — common version-tag idioms that don't apply
6626    ///     to the year-shaped edition axis
6627    ///   - decimal-shaped values (`"2026.1"`, `"2026.0"`) — every
6628    ///     edition is a year, not a fractional version
6629    ///   - wrong-length numeric values (`"26"`, `"202"`, `"20260"`,
6630    ///     `"00026"`) that don't name a year
6631    ///
6632    /// `None` (the canonical "omit the slot to defer to the
6633    /// substrate's default edition" shape every existing
6634    /// [`caixa-resolver`] integration test fixture carries via
6635    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
6636    /// is accepted trivially — the gate is a no-op when the author
6637    /// didn't declare a value. The empty-first cascade discipline
6638    /// mirrors every peer per-axis identity gate:
6639    /// [`ManifestError::EdicaoEmpty`] runs before
6640    /// [`ManifestError::EdicaoInvalid`], so the narrower empty
6641    /// diagnostic surfaces on `Some("")` rather than the broader
6642    /// shape-predicate diagnostic — peer with how
6643    /// [`ManifestError::NomeEmpty`] runs before
6644    /// [`ManifestError::NomeInvalid`],
6645    /// [`ManifestError::VersaoEmpty`] runs before
6646    /// [`ManifestError::VersaoInvalid`],
6647    /// [`ManifestError::RepositorioEmpty`] runs before
6648    /// [`ManifestError::RepositorioInvalid`].
6649    ///
6650    /// A future tightening on this axis can extend the shape
6651    /// predicate into a known-edition allowlist (rejecting
6652    /// year-shaped values that don't name a tatara-lisp edition
6653    /// the substrate actually understands — e.g., `"1999"` is
6654    /// year-shaped but no `1999` edition exists). That allowlist
6655    /// only becomes meaningful past the introduction of a sibling
6656    /// edition to `"2026"`; this gate establishes the structural
6657    /// floor by refusing every non-year-shaped value at validate
6658    /// time.
6659    pub fn validate_edicao(&self) -> Result<(), ManifestError> {
6660        let Some(s) = self.edicao() else {
6661            return Ok(());
6662        };
6663        if s.is_empty() {
6664            return Err(ManifestError::EdicaoEmpty);
6665        }
6666        if s.len() != 4 || !s.bytes().all(|b| b.is_ascii_digit()) {
6667            return Err(ManifestError::edicao_invalid(
6668                s,
6669                "must be a 4-digit ASCII decimal year (canonical \"2026\")",
6670            ));
6671        }
6672        Ok(())
6673    }
6674
6675    /// Compose the supervisor-related flat slots into a single
6676    /// [`SupervisorSpec`] for validation. Returns `None` when the
6677    /// caixa isn't a `:kind Supervisor`.
6678    ///
6679    /// The flat representation in [`Caixa`] keeps tatara-lisp authoring
6680    /// simple (one form, no nested `:supervisor (…)` block); this view
6681    /// is the "typed shape" the operator + supervisor reconciler
6682    /// consume.
6683    #[must_use]
6684    pub fn supervisor_view(&self) -> Option<SupervisorSpec> {
6685        if !self.kind().is_supervisor() {
6686            return None;
6687        }
6688        // Fold through the shared `supervisor::duration_codec::parse`
6689        // — the same parser the serde-routed `with = "duration_codec"`
6690        // on `SupervisorSpec::restart_window`, the `:politicas
6691        // :timeout` codec, and the `:politicas :circuit-breaker
6692        // :window` codec all consume. The prior inline f64-shaped
6693        // duplicate (`parse_window_inline`) admitted every magnitude
6694        // the integer-magnitude gate (1c55a2a) rejects on the three
6695        // serde-routed siblings — `"1.5s"`, `"1.0s"`, `"0.5m"`,
6696        // `"+30s"`, `"-30s"` — and silently dropped malformed input as
6697        // `None` (i.e. "no reset"), divergent from the shared codec's
6698        // integer-magnitude discipline by construction. The fold
6699        // closes the divergence: every value the typed
6700        // `SupervisorSpec` carries past `supervisor_view` is in the
6701        // shared codec's accepted set. The `.ok()` here preserves the
6702        // existing soft-swallow shape on this view-construction path;
6703        // the new [`Caixa::validate_restart_window`] (sibling of
6704        // [`Self::validate_nome`] / [`Self::validate_versao`]) names
6705        // the offending raw string at build time so authoring tools
6706        // (`feira lint`, the future layout-side wire-up) surface a
6707        // self-locating diagnostic instead of a silently dropped
6708        // window.
6709        let restart_window = self
6710            .restart_window()
6711            .and_then(|s| crate::supervisor::duration_codec::parse(s).ok());
6712        Some(SupervisorSpec {
6713            // Route the author-omitted `:estrategia` arm through the
6714            // substrate-canonical
6715            // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
6716            // `pub const` rather than the transitively-derived
6717            // [`RestartStrategy::default`] route the prior
6718            // `.unwrap_or_default()` fold reached for — one source of
6719            // truth for the Erlang/OTP `one_for_one` half of Learn You
6720            // Some Erlang's `{one_for_one, intensity, 5, 60}` worker-
6721            // supervisor canonical default that also backs the
6722            // [`crate::supervisor::Default for RestartStrategy`] impl
6723            // and the [`crate::supervisor::Default for SupervisorSpec`]
6724            // impl's struct-literal `estrategia` field, all now routed
6725            // through the same lifted constant. Prior to the lift the
6726            // composition site carried `.unwrap_or_default()` with no
6727            // compile-time link back to the shared OTP-canonical
6728            // default that the peer paired
6729            // `.unwrap_or(SUPERVISOR_MAX_RESTARTS_DEFAULT)` (b698ec0)
6730            // arm on the sibling `:max-restarts` axis routes through —
6731            // so a future rebrand of the OTP-canonical strategy default
6732            // (a widening to `rest_for_one` once the substrate
6733            // discovers startup-order-coupled child cohorts as the more
6734            // common shape, a per-cluster overlay the operator pins
6735            // through the MESH-COMPOSITION §III.2 supervision-canary
6736            // `:estrategia-overrides` roadmap slot) would have had to
6737            // migrate the paired `MaxIntensity` + `Period` halves
6738            // through the lifted constants and the `one_for_one` half
6739            // through a `RestartStrategy::default()` route in lockstep
6740            // or the three halves of the same OTP-canonical default
6741            // would silently drift out of pairing. Byte-parity against
6742            // the lifted constant closes the split. Pinned by
6743            // [`supervisor_view_estrategia_fallback_routes_through_lifted_default`]
6744            // in the tests module.
6745            estrategia: self
6746                .estrategia()
6747                .unwrap_or(crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT),
6748            // Route the author-omitted `:max-restarts` arm through the
6749            // substrate-canonical [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`]
6750            // typed `pub const` rather than the raw `5` literal — one
6751            // source of truth for the Erlang/OTP-canonical
6752            // `{intensity, 5, 60}` `MaxIntensity` default that also
6753            // backs the serde-side wire-format author-omitted arm on
6754            // [`crate::supervisor::SupervisorSpec::max_restarts`] via
6755            // `#[serde(default = "default_max_restarts")]` and the
6756            // [`Default for SupervisorSpec`] impl's struct-literal
6757            // default field. Prior to the lift the composition site
6758            // carried a raw `5` with no compile-time link back to the
6759            // serde-side default, so a future rebrand of the OTP-
6760            // canonical default (a tightening to Elixir's `3`, a
6761            // widening to a per-cluster overlay the operator pins
6762            // through the MESH-COMPOSITION §III.2 supervision-canary
6763            // `:supervisor :max-restarts-overrides` roadmap slot)
6764            // would have had to be threaded through both open-coded
6765            // copies in lockstep or the wire-format author-omitted arm
6766            // and this view-construction author-omitted arm would
6767            // silently disagree on which restart-budget an omitted
6768            // `:max-restarts` resolves to. Pinned by
6769            // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
6770            // in the tests module.
6771            max_restarts: self
6772                .max_restarts()
6773                .unwrap_or(crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT),
6774            restart_window,
6775            children: self.children().to_vec(),
6776        })
6777    }
6778
6779    /// A minimal starter manifest emitted by `feira init`.
6780    #[must_use]
6781    pub fn template(nome: &str) -> String {
6782        format!(
6783            "(defcaixa\n  \
6784               :nome        {nome:?}\n  \
6785               :versao      \"0.1.0\"\n  \
6786               :kind        Biblioteca\n  \
6787               :edicao      \"2026\"\n  \
6788               :descricao   \"FIXME — describe this caixa\"\n  \
6789               :autores     ()\n  \
6790               :etiquetas   ()\n  \
6791               :deps        ()\n  \
6792               :deps-dev    ()\n  \
6793               :bibliotecas (\"lib/{nome}.lisp\"))\n"
6794        )
6795    }
6796
6797    /// Serialize to a canonical `caixa.lisp` source — suitable for writing
6798    /// back after mutation (e.g. `feira add`).
6799    ///
6800    /// Goes through serde JSON → canonical Sexp → per-field pretty print.
6801    /// The derive-macro `compile_from_sexp` path is the inverse, so any
6802    /// `Caixa` round-trips through `to_lisp` + `from_lisp`.
6803    #[must_use]
6804    pub fn to_lisp(&self) -> String {
6805        let json = serde_json::to_value(self).expect("Caixa serialize");
6806        let sexp = tatara_lisp::domain::json_to_sexp(&json);
6807        let tatara_lisp::Sexp::List(items) = sexp else {
6808            return format!("(defcaixa {sexp})\n");
6809        };
6810        let mut out = String::from("(defcaixa");
6811        let mut i = 0;
6812        while i + 1 < items.len() {
6813            out.push_str("\n  ");
6814            out.push_str(&items[i].to_string());
6815            out.push(' ');
6816            out.push_str(&items[i + 1].to_string());
6817            i += 2;
6818        }
6819        out.push_str(")\n");
6820        out
6821    }
6822}
6823
6824/// Errors raised by top-level [`Caixa`] validators that don't fit
6825/// the per-axis [`DepError`] / [`crate::AplicacaoError`] /
6826/// [`crate::SupervisorError`] / [`crate::LayoutError`] families —
6827/// the Caixa's own identity axes (`:nome`, `:versao`) that flow
6828/// through every substrate-side artifact's `metadata.name` /
6829/// version derivation.
6830///
6831/// A future top-level sum (the M4 `CaixaError` the [`DepError`]
6832/// doc-comment anticipates) can hold one of each per-axis error
6833/// family without reshaping individual diagnostics; this enum is
6834/// the first such per-Caixa-identity family.
6835#[derive(Debug, Error, PartialEq, Eq)]
6836pub enum ManifestError {
6837    #[error(
6838        ":nome is empty (every caixa must name itself; the value flows \
6839         into every K8s artifact's `metadata.name` derivation and into \
6840         the default `lib/<nome>.lisp` / `exe/<nome>` layout paths)"
6841    )]
6842    NomeEmpty,
6843    #[error(
6844        ":nome {nome:?} is not a valid DNS-1123 label: {reason} (the K8s \
6845         apiserver enforces this rule on every `metadata.name` the \
6846         caixa's substrate-side renderers derive from `:nome` — the \
6847         `lareira-<nome>` Helm chart name, the programs.yaml entry \
6848         name, the `LABEL_APLICACAO` label value, the `<aplicacao>-<de>-to-<para>` \
6849         CiliumNetworkPolicy name, the `<aplicacao>-<para>` HTTPRoute \
6850         name; use a lowercase alphanumeric + hyphen identifier like \
6851         `\"checkout\"` or `\"cart-v2\"`)"
6852    )]
6853    NomeInvalid { nome: String, reason: String },
6854    #[error(
6855        ":nome {nome:?} overflows the joint-length budget on the canonical \
6856         `lareira-<nome>` chart-name shape: {reason} (every per-Servico / \
6857         per-Aplicacao renderer the substrate carries — `caixa-helm`'s \
6858         `Chart.yaml::name`, `caixa-flux`'s `cluster_bundle` HelmRelease \
6859         `chart:` slot, `caixa-tatara`'s `release_name` + \
6860         `oci://<registry>/lareira-<nome>` chart ref — derives the same \
6861         joint name through the canonical `lareira_chart_name` helper, and \
6862         Helm's `Chart.yaml::name` admission rule + the K8s apiserver's \
6863         DNS-1123 label cap on every chart-name-derived `metadata.name` \
6864         reject any joint name exceeding 63 bytes; the narrower \
6865         `:nome` shape (`NomeInvalid`) gates the bare-`:nome` budget, this \
6866         arm gates the chart-name budget downstream renderers inherit)"
6867    )]
6868    NomeChartNameBudgetExceeded { nome: String, reason: String },
6869    #[error(
6870        ":versao is empty (every caixa must pin its own version; the value flows \
6871         into the `lareira-<nome>` Helm chart's `Chart.yaml` version + appVersion, \
6872         the `feira publish` `v<versao>` git tag, the OCI image's `:v<versao>` / \
6873         `:latest` tags, the lacre closure's `concrete_versao`, and the \
6874         `:upgrade-from :from` peers — use a SemVer-2 literal like `\"0.1.0\"`)"
6875    )]
6876    VersaoEmpty,
6877    #[error(
6878        ":versao {versao:?} is not a valid SemVer-2 version: {reason} (the substrate \
6879         consumes this string as `semver::Version` — three-part `MAJOR.MINOR.PATCH` \
6880         with optional `-prerelease` and `+build` — across every artifact derived \
6881         from `:versao`: the `lareira-<nome>` Helm chart's `Chart.yaml` version + \
6882         appVersion (Helm SemVer-2-strict), the `feira publish` `v<versao>` git tag, \
6883         the OCI image's `:v<versao>` tag, the lacre closure's `concrete_versao`, \
6884         and the `:upgrade-from :from` peers that match against this exact shape; \
6885         use a literal like `\"0.1.0\"`, `\"0.2.0-rc.1\"`, or `\"1.0.0+build.42\"` — \
6886         not a git-tag-shape like `\"v0.1.0\"`, a docker-tag-shape like `\"latest\"`, \
6887         a requirement-shape like `\"^0.1\"`, or a four-part `\"0.1.0.0\"`)"
6888    )]
6889    VersaoInvalid { versao: String, reason: String },
6890    #[error(
6891        ":restart-window {restart_window:?} is not a valid duration: {reason} (the \
6892         substrate consumes this string through the shared \
6893         `supervisor::duration_codec` — the same parser routed via `with = \
6894         \"duration_codec\"` onto the typed `SupervisorSpec::restart_window`, \
6895         `:politicas :timeout`, and `:politicas :circuit-breaker :window` slots; \
6896         the canonical authoring form is `<integer><unit>` where the unit is one \
6897         of `ms` / `s` / `m` / `h` and the magnitude has no decimal point and no \
6898         leading `+` / `-` sign — e.g. `\"60s\"`, `\"5m\"`, `\"1h\"`, `\"500ms\"`. \
6899         Without this gate a malformed `:restart-window` silently produced a \
6900         supervisor with `restart_window: None` (\"never reset\"), turning OTP's \
6901         `MaxIntensity / Period` invariant into a never-reset supervisor far from \
6902         the source `caixa.lisp`; the gate moves the diagnostic to the manifest \
6903         layer with the offending value named verbatim. Omit the slot entirely to \
6904         express \"no reset\"; carry a positive integer duration to express the \
6905         sliding window)"
6906    )]
6907    RestartWindowMalformed {
6908        restart_window: String,
6909        reason: String,
6910    },
6911    #[error(
6912        "{slot} entry is an empty path string — every {slot} entry must name \
6913         a file relative to the caixa root; omit the entry to omit the file \
6914         (the layout checker's `root.join(\"\")` resolves to the caixa root \
6915         itself, so an empty entry silently aliases the project root as a \
6916         declared {slot} file, then fails downstream at parse / existence \
6917         time with a diagnostic that names the root rather than the offending \
6918         entry)"
6919    )]
6920    CodePathEmpty { slot: &'static str },
6921    #[error(
6922        "{slot} entry {} is an absolute path — entries must be relative to \
6923         the caixa root, since `Path::join` replaces the base with an absolute \
6924         right-hand side and `root.join(\"/abs/...\")` resolves to \"/abs/...\" \
6925         outside the caixa root sandbox; rewrite the entry as a relative path \
6926         under the caixa root (e.g. `\"lib/<name>.lisp\"`, `\"exe/<name>\"`, \
6927         `\"servicos/<name>.computeunit.yaml\"`)",
6928        path.display()
6929    )]
6930    CodePathAbsolute { slot: &'static str, path: PathBuf },
6931    #[error(
6932        "{slot} entry {} contains a `..` component — entries must not traverse \
6933         above the caixa root (the layout's `starts_with(<dir>)` fence on \
6934         `:exe` / `:servicos` is component-aware, not canonical-path-aware, \
6935         so a mid-path `..` silently traverses the sandbox; `:bibliotecas` \
6936         has no such fence, so a leading `..` escapes unconditionally if the \
6937         resolved target happens to exist)",
6938        path.display()
6939    )]
6940    CodePathParentEscape { slot: &'static str, path: PathBuf },
6941    #[error(
6942        "{slot} entry {} does not terminate in the `.lisp` extension — every \
6943         `:bibliotecas` entry is a tatara-lisp source file the `feira build` \
6944         loop reads through `tatara_lisp::read` at parse time, so any other \
6945         extension (`.rs`, `.txt`, `.lisp.bak`) or no-extension shape is \
6946         structurally a parser error far from the source caixa.lisp, with \
6947         no field naming the offending `:bibliotecas` entry. Pin a relative \
6948         path under the caixa root whose terminating extension is \
6949         lowercase-`.lisp` (e.g. `\"lib/<name>.lisp\"`, \
6950         `\"lib/handlers.lisp\"`) — the same file-type contract the peer \
6951         `:behavior :on-*` (c97815a) and `:upgrade-from :state-change :script` \
6952         (33cc830) axes already carry through the same lifted \
6953         `is_lisp_extension` predicate",
6954        path.display()
6955    )]
6956    CodePathNonLispExtension { slot: &'static str, path: PathBuf },
6957    #[error(
6958        "{slot} entry {} does not terminate in the `.computeunit.yaml` \
6959         compound suffix — every `:servicos` entry is a typed `ComputeUnit` \
6960         CR YAML file the peer caixa-helm / caixa-flux renderers consume \
6961         through `serde_yaml::from_str` at chart / FluxCD bundle render \
6962         time, so any other extension (`.yaml`, `.yml`, `.json`, the \
6963         off-by-one-segment `.computeunit-yaml`, the editor-backup \
6964         `.computeunit.yaml.bak`) or no-extension shape is structurally a \
6965         YAML-parser error / `ComputeUnit` schema-mismatch far from the \
6966         source caixa.lisp, with no field naming the offending `:servicos` \
6967         entry. Pin a relative path under the caixa root whose terminating \
6968         compound suffix is lowercase-`.computeunit.yaml` (e.g. \
6969         `\"servicos/<name>.computeunit.yaml\"`, \
6970         `\"servicos/hello-rio.computeunit.yaml\"`) — the same file-type \
6971         contract the sibling `:bibliotecas` axis (64772a9) already carries \
6972         on the tatara-lisp-source axis through the peer lifted \
6973         `is_lisp_extension` predicate, here on the compound-suffix axis \
6974         `Path::extension` can't express on its own through the lifted \
6975         `is_computeunit_yaml_extension` predicate",
6976        path.display()
6977    )]
6978    CodePathNonComputeUnitYamlExtension { slot: &'static str, path: PathBuf },
6979    #[error(
6980        "{slot} entry {} appears more than once (the code-path list is \
6981         a set, not a multiset; every peer Vec-shaped author-supplied \
6982         list past validate is set-not-multiset — `:membros :caixa`, \
6983         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
6984         `:children :caixa`, `:deps` / `:deps-dev` `:nome`, \
6985         `:upgrade-from :from`, `:etiquetas`, `:autores` — and the three \
6986         code-path lists are the last Vec-shaped author-supplied slots on \
6987         the typed Caixa surface still admitting a duplicate entry. \
6988         `:bibliotecas` duplicates re-parse the same file at \
6989         `feira build` time and silently mask the author's intent to \
6990         declare a *second* biblioteca; `:exe` duplicates collide on the \
6991         flake `packages.<name>` derivation key at the future \
6992         `caixa-flake` materializer; `:servicos` duplicates surface as the \
6993         narrower [`caixa-helm`] / [`caixa-flux`] `UnsupportedServicoCount` \
6994         rejection far from the source `caixa.lisp`. Drop the duplicate \
6995         or rename it to the actual second file intended)",
6996        path.display()
6997    )]
6998    CodePathDuplicate { slot: &'static str, path: PathBuf },
6999    #[error(
7000        ":etiquetas entry is empty (every tag must carry a non-empty \
7001         registry-search identifier; the empty entry has no operational \
7002         meaning — it indexes nothing in the future caixa-registry search \
7003         axis and clutters the rendered Helm `Chart.yaml` `keywords:` array \
7004         with a no-op tag; omit the entry to express \"no tag on this \
7005         position\")"
7006    )]
7007    EtiquetaEmpty,
7008    #[error(
7009        ":etiquetas entry {etiqueta:?} appears more than once (the \
7010         registry-search tag set is a set, not a multiset; duplicate \
7011         entries are silently dedup'd by caixa-helm's `BTreeSet` collect \
7012         at chart render — a \"second wins / one silently disappears\" \
7013         shape divergent from every peer typed-graph set gate \
7014         (`:membros :caixa`, `:placement :clusters`, `:entrada :paths`, \
7015         `:contratos`, `:deps :nome`, `:upgrade-from :from`); drop the \
7016         duplicate or rename it to the actual tag intended)"
7017    )]
7018    EtiquetaDuplicate { etiqueta: String },
7019    #[error(
7020        ":etiquetas entry {etiqueta:?} is not a valid chart-keyword shape: \
7021         {reason} (the substrate consumes this string through the shared \
7022         `crate::render::is_chart_keyword_shape` predicate — the same \
7023         Cargo crates.io `[package] keywords` grammar entry shape: 1..=20 \
7024         bytes, starts with an ASCII letter, ASCII alphanumeric / `_` / `-` \
7025         continuation. The canonical authoring shapes are short kebab-case \
7026         identifiers like `\"mesh\"`, `\"wasm\"`, `\"tatara-lisp\"`, \
7027         `\"hello-world\"`, `\"caixa-servico\"`, `\"infrastructure\"`. \
7028         Without this gate a malformed `:etiquetas` entry (paste-from-doc \
7029         leading / trailing whitespace `\" mesh\"` / `\"mesh \"`; \
7030         paste-from-multiline-doc newline `\"mesh\\nhttp\"`; \
7031         paste-from-Windows-CRLF-doc CR; CSV-list-separator confusion \
7032         `\"mesh,http,grpc\"` — the author meant to author three separate \
7033         list entries; path-separator confusion `\"caixa/servico\"`; \
7034         namespace-suffix `\"http.1\"`; leading-digit `\"1foo\"`; \
7035         kebab-leak `\"-foo\"`; snake-leak `\"_foo\"`; non-ASCII \
7036         `\"café\"` — every legitimate search tag is strict ASCII; \
7037         paste-from-binary-blob NUL / BEL / ESC / DEL byte) silently \
7038         passed `from_lisp` + `validate_etiquetas` + \
7039         `StandardLayout::verify` and landed in the rendered \
7040         `lareira-<nome>` Helm chart's `Chart.yaml keywords:` array as a \
7041         malformed search tag — Artifact Hub's keyword index + the future \
7042         caixa-registry's keyword index would either silently drop the \
7043         tag or fail to index it far from the source caixa.lisp; the gate \
7044         moves the diagnostic to the manifest layer with the offending \
7045         value named verbatim)"
7046    )]
7047    EtiquetaInvalid { etiqueta: String, reason: String },
7048    #[error(
7049        ":autores entry is empty (every maintainer must carry a non-empty \
7050         identifier; the empty entry has no operational meaning — it \
7051         identifies no one in the substrate's authorship index and renders \
7052         as `maintainers: [{{name: \"\", email: null}}]` in the Helm chart's \
7053         `Chart.yaml`, a no-op maintainer the substrate cannot route to; \
7054         omit the entry to express \"no maintainer on this position\")"
7055    )]
7056    AutorEmpty,
7057    #[error(
7058        ":autores entry {autor:?} appears more than once (the maintainer \
7059         set is a set, not a multiset; unlike `:etiquetas`, caixa-helm's \
7060         `maintainers:` rendering does *no* dedup — duplicate entries \
7061         stack verbatim in `Chart.yaml` as two identical \
7062         `Maintainer {{ name, email: None }}` records, divergent from every \
7063         peer typed-graph set gate (`:etiquetas`, `:membros :caixa`, \
7064         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
7065         `:deps :nome`, `:upgrade-from :from`); drop the duplicate or \
7066         rename it to the actual author intended)"
7067    )]
7068    AutorDuplicate { autor: String },
7069    #[error(
7070        ":autores entry {autor:?} is not a valid chart-maintainer-name shape: \
7071         {reason} (the substrate consumes this string through the shared \
7072         `crate::render::is_chart_maintainer_name_shape` predicate — the same \
7073         single-line-UTF-8 floor every realistic chart maintainer name carries: \
7074         1..=128 bytes, no leading or trailing whitespace, no ASCII control \
7075         characters anywhere, Unicode bytes accepted. The canonical authoring \
7076         shapes are short single-line identifiers like `\"pleme-io\"`, \
7077         `\"Pleme Contributors\"`, `\"alice <alice@example.com>\"`, \
7078         `\"François Dupont\"`. Without this gate a malformed `:autores` entry \
7079         (paste-from-aligned-doc leading whitespace `\" pleme-io\"` / trailing \
7080         whitespace `\"pleme-io \"`; paste-from-multiline-doc newline \
7081         `\"alice\\nbob\"` — the author pasted a multi-line block of author \
7082         records into one entry instead of splitting into one entry per author; \
7083         paste-from-Windows-CRLF-doc carriage return `\"alice\\rbob\"`; \
7084         tab-from-aligned-doc `\"Pleme\\tContributors\"`; paste-from-binary-blob \
7085         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
7086         `validate_autores` + `StandardLayout::verify` and landed in the \
7087         rendered `lareira-<nome>` Helm chart's `Chart.yaml maintainers:` array \
7088         as a YAML-illegal multi-line scalar or a silently-trimmed whitespace \
7089         round-trip — every chart-aware UI (`helm list`, `helm search`, \
7090         Artifact Hub maintainer index) would render the maintainer name in a \
7091         single-line column far from the source caixa.lisp; the gate moves the \
7092         diagnostic to the manifest layer with the offending value named \
7093         verbatim)"
7094    )]
7095    AutorInvalid { autor: String, reason: String },
7096    #[error(
7097        ":repositorio is the empty string (every published caixa names its \
7098         git source via a non-empty `:repositorio` locator — the value \
7099         flows verbatim into the rendered `lareira-<nome>` Helm chart's \
7100         `Chart.yaml` `home:` field via `caixa-helm` and into the FluxCD \
7101         `GitRepository.spec.url` via `caixa-flux`'s \
7102         `ClusterBundleOpts::for_caixa`; both consumers' \
7103         `Option::unwrap_or_else` fallbacks only fire when the slot is \
7104         `None`, so an empty `Some(\"\")` silently lands as `home: \"\"` / \
7105         `url: \"\"` in the rendered artifacts and breaks at `helm \
7106         template` / FluxCD source-controller reconcile time far from the \
7107         source caixa.lisp; omit the slot entirely to defer to the \
7108         renderer's `https://github.com/pleme-io/<nome>` / \
7109         `caixa.nome`-derived fallback, or carry a canonical authoring \
7110         shape like `\"github:org/repo\"`, `\"https://host/path\"`, \
7111         `\"ssh://[user@]host/path\"`, `\"git@host:path\"`, or \
7112         `\"file:///path\"`)"
7113    )]
7114    RepositorioEmpty,
7115    #[error(
7116        ":repositorio {repositorio:?} is not a valid git repo URL: {reason} \
7117         (the substrate consumes this string through the shared \
7118         `crate::render::is_git_repo_url` predicate — the same parser the \
7119         peer `:deps :fonte (:tipo git :repo …)` axis routes its `:repo` \
7120         value through via `DepSource::validate`; the canonical authoring \
7121         shapes are `\"github:org/repo\"` shorthand, `\"https://host/path\"` \
7122         / `\"ssh://[user@]host/path\"` / `\"git://host/path\"` / \
7123         `\"file:///path\"` URL schemes, or the `\"git@host:path\"` \
7124         scp-style SSH form. Without this gate a malformed `:repositorio` \
7125         (whitespace from a paste-from-doc; control characters / CRLF \
7126         from a paste-from-multiline-doc; a leading `-` from a \
7127         CLI-argument-injection footgun; a missing `:` separator from a \
7128         bare `org/repo` shape git treats as a relative filesystem path) \
7129         silently landed in the rendered `Chart.yaml home:` and the \
7130         FluxCD `GitRepository.spec.url` and broke at `git clone` / \
7131         FluxCD reconcile time far from the source caixa.lisp; the gate \
7132         moves the diagnostic to the manifest layer with the offending \
7133         value named verbatim)"
7134    )]
7135    RepositorioInvalid { repositorio: String, reason: String },
7136    #[error(
7137        ":descricao is the empty string (every published caixa names \
7138         its purpose via a non-empty `:descricao` summary — the value \
7139         flows verbatim into the rendered `lareira-<nome>` Helm \
7140         chart's `Chart.yaml` `description:` field via `caixa-helm`'s \
7141         `build_chart_yaml` and into the chart `README.md` header via \
7142         `build_readme`; both consumers' `Option::unwrap_or_else` \
7143         `caixa.nome`-derived fallbacks only fire when the slot is \
7144         `None`, so an empty `Some(\"\")` silently lands as \
7145         `description: \"\"` / a blank `README.md` header in the \
7146         rendered artifacts and breaks at `helm lint` time \
7147         (`WARNING [chart.metadata.description]: description is \
7148         required` on `apiVersion: v2` charts) far from the source \
7149         caixa.lisp; omit the slot entirely to defer to the \
7150         renderer's `\"Generated chart for caixa Servico <nome>\"` / \
7151         `\"caixa Servico <nome>\"` fallbacks, or carry a non-empty \
7152         summary like `\"Canonical Rust→wasm32-wasip2 caixa \
7153         Servico.\"`)"
7154    )]
7155    DescricaoEmpty,
7156    #[error(
7157        ":descricao {descricao:?} is not a valid chart-description shape: \
7158         {reason} (the substrate consumes this string through the shared \
7159         `crate::render::is_chart_description_shape` predicate — the same \
7160         single-line-UTF-8 floor every realistic chart description carries: \
7161         1..=512 bytes, no leading or trailing whitespace, no ASCII control \
7162         characters anywhere, Unicode prose bytes accepted. The canonical \
7163         authoring shapes are short single-line summaries like `\"Canonical \
7164         Rust→wasm32-wasip2 caixa Servico.\"`, `\"Checkout flow.\"`, \
7165         `\"AWS provider caixa for tatara-lisp\"`. Without this gate a \
7166         malformed `:descricao` (paste-from-aligned-doc leading whitespace \
7167         `\" Checkout flow.\"` / trailing whitespace `\"Checkout flow. \"`; \
7168         paste-from-multiline-doc newline `\"Checkout\\nflow.\"`; \
7169         paste-from-Windows-CRLF-doc carriage return `\"Checkout\\rflow.\"`; \
7170         tab-from-aligned-doc `\"Checkout\\tflow.\"`; paste-from-binary-blob \
7171         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
7172         `validate_descricao` + `StandardLayout::verify` and landed in the \
7173         rendered `lareira-<nome>` Helm chart's `Chart.yaml description:` \
7174         field + `README.md` header paragraph as a YAML-illegal multi-line \
7175         scalar or a silently-trimmed whitespace round-trip — every \
7176         chart-aware UI (`helm list`, `helm search`, Artifact Hub) would \
7177         render the description in a single-line column far from the source \
7178         caixa.lisp; the gate moves the diagnostic to the manifest layer \
7179         with the offending value named verbatim)"
7180    )]
7181    DescricaoInvalid { descricao: String, reason: String },
7182    #[error(
7183        ":licenca is the empty string (every published caixa names \
7184         its license via a non-empty `:licenca` SPDX expression — the \
7185         value flows verbatim into the rendered `lareira-<nome>` Helm \
7186         chart's `README.md` `## License` section via `caixa-helm`'s \
7187         `build_readme` at `caixa-helm/src/lib.rs:361`; the consumer's \
7188         `Option::unwrap_or_else(|| \"MIT\".into())` `MIT` fallback \
7189         only fires when the slot is `None`, so an empty `Some(\"\")` \
7190         silently lands as a bare trailing period in the rendered \
7191         chart `README.md` `License` section far from the source \
7192         caixa.lisp; omit the slot entirely to defer to the \
7193         renderer's `MIT` fallback, or carry a canonical SPDX \
7194         expression like `\"MIT\"`, `\"Apache-2.0\"`, \
7195         `\"Apache-2.0 OR MIT\"`)"
7196    )]
7197    LicencaEmpty,
7198    #[error(
7199        ":licenca {licenca:?} is not a valid SPDX expression shape: {reason} \
7200         (the substrate consumes this string through the shared \
7201         `crate::render::is_spdx_expression_shape` predicate — the same \
7202         alphabet-floor parser every peer per-axis value-shape gate routes \
7203         its value through; the canonical authoring shapes are single \
7204         license identifiers like `\"MIT\"`, `\"Apache-2.0\"`, `\"BSD-3-Clause\"`, \
7205         compound expressions like `\"Apache-2.0 OR MIT\"`, \
7206         `\"MIT AND BSD-3-Clause\"`, `\"(MIT OR Apache-2.0) AND ISC\"`, \
7207         license-with-exception forms like `\"Apache-2.0 WITH LLVM-exception\"`, \
7208         `+`-suffix variants like `\"GPL-2.0+\"`, and user-defined references \
7209         like `\"LicenseRef-MyLicense\"` / \
7210         `\"DocumentRef-doc:LicenseRef-MyLicense\"`. Without this gate a \
7211         malformed `:licenca` (paste-from-doc whitespace `\"MIT \"` / \
7212         `\" MIT\"`; paste-from-multiline-doc CRLF `\"MIT\\n\"`; \
7213         tab-from-aligned-doc `\"MIT\\tOR Apache-2.0\"`; non-ASCII byte from \
7214         a smart-quote paste; underscore-instead-of-hyphen typo \
7215         `\"Apache_2.0\"`; comma-instead-of-`OR`-keyword colloquial idiom \
7216         `\"MIT, Apache-2.0\"`; slash-dual-license colloquial idiom \
7217         `\"MIT/Apache-2.0\"`; semicolon-list-separator confusion \
7218         `\"MIT; Apache-2.0\"`) silently landed in the rendered chart \
7219         `README.md` `## License` section + a future SPDX-aware \
7220         `Chart.yaml license:` emitter would refuse the value at \
7221         `helm lint` time far from the source caixa.lisp; the gate moves \
7222         the diagnostic to the manifest layer with the offending value \
7223         named verbatim)"
7224    )]
7225    LicencaInvalid { licenca: String, reason: String },
7226    #[error(
7227        ":edicao is the empty string (every published caixa names \
7228         its language edition via a non-empty `:edicao` value — the \
7229         edition determines the tatara-lisp macro surface + \
7230         compatibility flags the substrate applies when building \
7231         the caixa; the canonical `Caixa::template` scaffold every \
7232         `feira init` emits carries `:edicao \"2026\"` verbatim and \
7233         every renderer-side fixture (`caixa-helm`, `caixa-flux`, \
7234         `caixa-mesh`) carries `edicao: Some(\"2026\".into())` by \
7235         construction, so an empty `Some(\"\")` silently lands as a \
7236         bare `(:edicao \"\")` line in the rendered `caixa.lisp` and \
7237         a future renderer-side consumer that folds it through \
7238         `Option::unwrap_or_else` will skip the fallback and pass the \
7239         empty edition through to the substrate's build-time edition \
7240         selector far from the source caixa.lisp; omit the slot \
7241         entirely to defer to the substrate's default edition, or \
7242         carry a canonical edition like `\"2026\"`)"
7243    )]
7244    EdicaoEmpty,
7245    #[error(
7246        ":edicao {edicao:?} is not a valid edition: {reason} (every \
7247         documented tatara-lisp edition is a 4-digit ASCII decimal \
7248         year — `\"2026\"` is the only edition currently minted; \
7249         future-introduced siblings will follow the same shape, peer \
7250         with Cargo's `[package] edition` grammar which every value \
7251         Cargo has ever accepted matches: `\"2015\"`, `\"2018\"`, \
7252         `\"2021\"`, `\"2024\"`. Without this gate the canonical \
7253         paste-from-doc footguns silently passed: a trailing space \
7254         (`\"2026 \"`) from a paste-from-doc, a CRLF (`\"2026\\n\"`) \
7255         from a paste-from-multiline-doc, a fullwidth-keyboard \
7256         look-alike (`\"2026\"`), a free-form non-year value \
7257         (`\"x\"`, `\"latest\"`, `\"nightly\"`), a leading non-digit \
7258         version-tag prefix (`\"v2026\"`, `\"e2026\"`), a \
7259         decimal-shaped pseudo-version (`\"2026.1\"`), or a \
7260         wrong-length numeric value (`\"26\"`, `\"202\"`, \
7261         `\"20260\"`) all landed as `(:edicao \"<garbage>\")` in the \
7262         rendered caixa.lisp and broke at the substrate's \
7263         build-time edition selector far from the source caixa.lisp; \
7264         omit the slot entirely to defer to the substrate's default \
7265         edition, or carry a canonical 4-digit ASCII decimal year \
7266         like `\"2026\"`)"
7267    )]
7268    EdicaoInvalid { edicao: String, reason: String },
7269}
7270
7271// Fold the five `Err(ManifestError::CodePath{Absolute,ParentEscape,
7272// NonLispExtension,NonComputeUnitYamlExtension,Duplicate} { slot,
7273// path: path.to_path_buf() })` four-line struct-variant wire-up sites at
7274// [`Caixa::validate_code_path_lists`]'s per-slot per-entry cascade onto
7275// one substrate-primitive family on the `ManifestError` envelope — the
7276// five open-coded ctor sites remaining on the `:bibliotecas` / `:exe` /
7277// `:servicos` code-path-list value-shape trajectory this envelope carries,
7278// and the family sibling of the peer [`crate::behavior::behavior_slot_path_ctors!`]
7279// (67c31ec) two-slot `{ slot: &'static str, path: PathBuf }` envelope on
7280// the [`crate::BehaviorError`] surface that keys off the exact same
7281// `(slot: &'static str, path: &Path)` argument tuple.
7282//
7283// The five wire-up sites this fold closes are the sandbox-shape
7284// absolute-path arm (`return Err(ManifestError::CodePathAbsolute { slot,
7285// path: path.to_path_buf() })` on the [`is_sandboxed_relative_path`]
7286// `PathShapeViolation::Absolute` branch), the sandbox-shape
7287// parent-escape arm (`return Err(ManifestError::CodePathParentEscape {
7288// slot, path: path.to_path_buf() })` on the sibling
7289// `PathShapeViolation::ParentEscape` branch), the LispSource
7290// terminating-extension arm (`return Err(ManifestError::CodePathNonLispExtension {
7291// slot, path: path.to_path_buf() })` on the `!is_lisp_extension(path)`
7292// branch of the `:bibliotecas` file-type gate), the ComputeUnitYaml
7293// compound-suffix arm (`return Err(ManifestError::CodePathNonComputeUnitYamlExtension
7294// { slot, path: path.to_path_buf() })` on the
7295// `!is_computeunit_yaml_extension(path)` branch of the `:servicos`
7296// file-type gate), and the cross-entry duplicate arm
7297// (`ManifestError::CodePathDuplicate { slot, path: path.to_path_buf() }`
7298// inside the closure passed to [`crate::render::insert_first_seen`]) —
7299// each opened the identical `ManifestError::CodePath* { slot,
7300// path: path.to_path_buf() }` four-line struct-literal against the same
7301// `(slot: &'static str, path: &Path)` local tuple, the exact "same
7302// block re-inlined at every consumer" shape the PRIME DIRECTIVE names
7303// as a bug. The variant discriminator is the only thing that varies
7304// between the five sites; the rest of the struct-literal is a
7305// byte-for-byte re-inline.
7306//
7307// The macro below generates one `#[must_use]` inherent constructor per
7308// variant of shape `fn <ctor>(slot: &'static str, path: &std::path::Path)
7309// -> Self`, so every wire-up site collapses onto one dispatch:
7310// `ManifestError::<ctor>(slot, path)`, byte-equal to the pre-lift
7311// struct-literal on the same `(&'static str, &Path)` fixture. The
7312// uniform two-field construction (`slot` verbatim as `&'static str`,
7313// `path.to_path_buf()`) is spelled once — inside the macro — rather
7314// than at every wire-up site. The `slot` parameter stays `&'static str`
7315// (not `&str`) so every arm continues to carry a program-lifetime
7316// `:bibliotecas` / `:exe` / `:servicos` author-key label — one of the
7317// three `&'static str` literals threaded through the outer per-slot
7318// iterator at [`Caixa::validate_code_path_lists`] — matching the
7319// enum-field type. A runtime-borrowed `&str` would silently downgrade
7320// the label lifetime and let a caller stash a non-`'static` borrow into
7321// the returned error. The `&Path` parameter accepts both
7322// `&Path` and `&PathBuf` (via Deref coercion), so every existing
7323// wire-up — each already binds `let path = Path::new(entry);` from the
7324// per-entry loop — threads through the ctor without a pre-conversion.
7325//
7326// Every future consumer that wants to construct one of these five
7327// variants outside the five in-crate wire-up sites (a deferred
7328// `feira validate --code-paths` per-caixa admission verb re-checking
7329// each declared `:bibliotecas` / `:exe` / `:servicos` entry against the
7330// same sandbox-shape + file-type + duplicate cascade, a future
7331// caixa-registry per-lacre code-path re-validator at lacre-resolve
7332// time, a per-`Caixa` overlay resolver rejecting an author-supplied
7333// code-path against a cluster-local snapshot) now reaches each variant
7334// through one call rather than re-inlining the four-line struct-literal
7335// in lockstep with the five in-crate wire-up sites.
7336macro_rules! manifest_code_path_slot_path_ctors {
7337    ($($ctor:ident => $variant:ident),* $(,)?) => {
7338        impl ManifestError {
7339            $(
7340                #[doc = concat!(
7341                    "Construct a [`ManifestError::",
7342                    stringify!($variant),
7343                    "`] naming the offending `:bibliotecas` / `:exe` / ",
7344                    "`:servicos` code-path list `slot` label and the ",
7345                    "offending entry `path`. Folds the uniform `Self::",
7346                    stringify!($variant),
7347                    " { slot, path: path.to_path_buf() }` two-field ",
7348                    "struct-literal onto one substrate primitive so ",
7349                    "every wire-up on this variant at ",
7350                    "[`Caixa::validate_code_path_lists`] reads through ",
7351                    "one dispatch rather than the pre-lift four-line ",
7352                    "open-coded block. The `slot` label threads verbatim ",
7353                    "from the outer per-slot iterator (one of the three ",
7354                    "code-path author-key `&'static str` consts) and the ",
7355                    "`path` from the per-entry inner iterator's ",
7356                    "`Path::new(entry)` binding."
7357                )]
7358                #[must_use]
7359                pub fn $ctor(slot: &'static str, path: &std::path::Path) -> Self {
7360                    Self::$variant {
7361                        slot,
7362                        path: path.to_path_buf(),
7363                    }
7364                }
7365            )*
7366        }
7367    };
7368}
7369
7370manifest_code_path_slot_path_ctors! {
7371    code_path_absolute => CodePathAbsolute,
7372    code_path_parent_escape => CodePathParentEscape,
7373    code_path_non_lisp_extension => CodePathNonLispExtension,
7374    code_path_non_computeunit_yaml_extension => CodePathNonComputeUnitYamlExtension,
7375    code_path_duplicate => CodePathDuplicate,
7376}
7377
7378// Fold the last `ManifestError::CodePathEmpty { slot: <&'static str> }` single-
7379// slot struct-variant wire-up site at [`Caixa::validate_code_path_lists`]'s
7380// per-slot [`PathShapeViolation::Empty`] arm onto one substrate primitive on
7381// `ManifestError` — the last open-coded single-slot `{ slot: &'static str }`
7382// struct-literal on the `:bibliotecas` / `:exe` / `:servicos` code-path-list
7383// value-shape trajectory this envelope carries, matching the peer five-variant
7384// [`manifest_code_path_slot_path_ctors!`] family fold (de11917, 5 variants on
7385// `{ slot: &'static str, path: PathBuf }`) already closed on the sibling
7386// two-slot envelope of the same `ManifestError`, and mirror-symmetric sibling
7387// of the peer [`crate::behavior::BehaviorError::empty_path`] (0e33b37,
7388// `EmptyPath { slot: &'static str }`) ctor on the sibling M2 `:behavior`
7389// envelope's identical one-slot shape. After this lift every wire-up on every
7390// `ManifestError` variant carried by [`Caixa::validate_code_path_lists`]'s
7391// per-slot [`PathShapeViolation`] cascade reads through one substrate-primitive
7392// ctor dispatch per typed variant rather than one macro closing four sites
7393// plus a hand-written empty-slot open-coding the fifth.
7394//
7395// A macro is not warranted on the one-variant envelope shape
7396// `{ slot: &'static str }` — unlike the peer five-variant
7397// `{ slot: &'static str, path: PathBuf }` shape the
7398// [`manifest_code_path_slot_path_ctors!`] macro closes — but the same
7399// substrate-primitive discipline applies: every future consumer that wants to
7400// construct a `CodePathEmpty` outside [`Caixa::validate_code_path_lists`] (a
7401// deferred `feira validate --code-paths` per-caixa admission verb re-checking
7402// each declared `:bibliotecas` / `:exe` / `:servicos` entry against the same
7403// sandbox-shape + file-type + duplicate cascade, a future caixa-registry
7404// per-lacre code-path re-validator at lacre-resolve time, a per-`Caixa`
7405// overlay resolver rejecting an author-supplied empty code-path against a
7406// cluster-local snapshot) reaches the variant through one call rather than
7407// re-inlining the one-line struct-literal in lockstep with the in-crate
7408// wire-up site.
7409//
7410// The `slot` parameter stays `&'static str` (not `&str`) so the constructor
7411// continues to carry a program-lifetime `:bibliotecas` / `:exe` / `:servicos`
7412// author-key label — one of the three `&'static str` literals threaded through
7413// the outer per-slot iterator at [`Caixa::validate_code_path_lists`] — matching
7414// the enum-field type and the peer [`manifest_code_path_slot_path_ctors!`]-
7415// generated arms' `slot: &'static str` parameter verbatim. A runtime-borrowed
7416// `&str` would silently downgrade the label lifetime and let a caller stash a
7417// non-`'static` borrow into the returned error. `const fn` preserves the
7418// zero-runtime-work property of the pre-lift struct-literal verbatim, matching
7419// the peer [`crate::behavior::BehaviorError::empty_path`] `const fn` on the
7420// sibling M2 envelope and the sibling
7421// [`crate::supervisor::supervisor_scalar_ctors!`] / peer
7422// [`crate::aplicacao::aplicacao_policy_scalar_ctors!`] `Copy`-scalar
7423// discipline on their sibling envelopes.
7424impl ManifestError {
7425    /// Construct a [`ManifestError::CodePathEmpty`] naming the offending
7426    /// `:bibliotecas` / `:exe` / `:servicos` code-path list `slot` label.
7427    /// Folds the uniform `Self::CodePathEmpty { slot }` one-field
7428    /// struct-literal onto one substrate primitive so the wire-up at
7429    /// [`Caixa::validate_code_path_lists`]'s per-slot
7430    /// [`PathShapeViolation::Empty`] arm on this variant reads through one
7431    /// dispatch rather than the pre-lift open-coded struct-literal block.
7432    /// Peer of the sibling [`ManifestError::code_path_absolute`] /
7433    /// [`ManifestError::code_path_parent_escape`] /
7434    /// [`ManifestError::code_path_non_lisp_extension`] /
7435    /// [`ManifestError::code_path_non_computeunit_yaml_extension`] /
7436    /// [`ManifestError::code_path_duplicate`] ctors the
7437    /// [`manifest_code_path_slot_path_ctors!`] macro closed on the paired
7438    /// two-slot `{ slot: &'static str, path: PathBuf }` envelope of the same
7439    /// `ManifestError`, and mirror-symmetric sibling of the peer
7440    /// [`crate::behavior::BehaviorError::empty_path`] ctor on the sibling M2
7441    /// `:behavior` envelope's identical one-slot shape — the per-slot
7442    /// [`PathShapeViolation`] cascade at [`Caixa::validate_code_path_lists`]
7443    /// now routes every arm through one substrate-primitive ctor per typed
7444    /// variant.
7445    #[must_use]
7446    pub const fn code_path_empty(slot: &'static str) -> Self {
7447        Self::CodePathEmpty { slot }
7448    }
7449}
7450
7451// Fold the ten `ManifestError::{Nome, NomeChartNameBudgetExceeded, Versao,
7452// Etiqueta, Autor, Repositorio, Descricao, Licenca, Edicao}Invalid +
7453// RestartWindowMalformed
7454// { <field>: <val>.to_string() | <val>.clone(), reason: <expr> }` wire-up
7455// sites at the per-axis [`Caixa::validate_*`] cascade onto one substrate-
7456// primitive family per typed variant — the direct sibling on the
7457// [`ManifestError`] envelope of the peer
7458// [`crate::aplicacao::aplicacao_field_reason_ctors!`] (981060b, 7 variants
7459// on `AplicacaoError` at `MembroCaixaInvalid` / `EntradaParaInvalid` /
7460// `EntradaHostInvalid` / `EntradaPathInvalid` / `PlacementClusterInvalid` /
7461// `PlacementAffinityInvalid` / `ShardKeyInvalid`) on the M3 mesh side, and
7462// of the peer [`crate::dep::dep_nome_axis_reason_ctors!`] (5621f8a,
7463// 3 variants on `DepError` at `VersaoInvalid` / `FonteRepoShape` /
7464// `CaracteristicaInvalid`) on the sibling `:deps` envelope's mirror-
7465// symmetric `{ nome: String, <axis>: String, reason: String }` three-slot
7466// shape (the `nome` axis added at the per-dep-owned altitude). Every one
7467// of the peer four-family `LayoutError` ctor set
7468// ([`crate::layout::layout_violation_ctors!`] 131ca0d — 16 variants on
7469// `{ caixa, issue }`, [`crate::layout::layout_slot_kind_ctors!`] 0419438
7470// — 4 variants on `{ caixa, kind, slots }`,
7471// [`crate::LayoutError::missing_entry`] 1b09f9d — 1 variant on
7472// `{ kind, path }`, [`crate::layout::layout_nome_only_ctors!`] 3fe3dd7 —
7473// 6 variants on `<Variant>(String)`) and the peer three
7474// [`crate::limits::limits_codec_value_*_ctors!`] codec families (81c856c)
7475// each carry the same discipline on their sibling envelopes.
7476//
7477// The ten variants share the identical `{ <field>: String,
7478// reason: String }` two-slot shape:
7479//   - `NomeInvalid { nome, reason }` at [`Caixa::validate_nome`]
7480//     (`|reason| ManifestError::NomeInvalid { nome: nome.to_string(),
7481//     reason }` inside [`crate::render::require_valid_dns_1123_label`]'s
7482//     `on_invalid` bracket-closure slot);
7483//   - `NomeChartNameBudgetExceeded { nome, reason }` at
7484//     [`Caixa::validate_nome_chart_name_budget`]
7485//     (`|reason| ManifestError::NomeChartNameBudgetExceeded { nome:
7486//     nome.to_string(), reason }` after
7487//     [`crate::render::is_lareira_chart_name_shape`] rejects the offending
7488//     `:nome`);
7489//   - `VersaoInvalid { versao, reason }` at [`Caixa::validate_versao`]
7490//     (`|e| ManifestError::VersaoInvalid { versao: versao.to_string(),
7491//     reason: e.to_string() }` after [`semver::Version::parse`] rejects
7492//     the offending `:versao`);
7493//   - `EtiquetaInvalid { etiqueta, reason }` at
7494//     [`Caixa::validate_etiquetas`]
7495//     (`|reason| ManifestError::EtiquetaInvalid { etiqueta:
7496//     etiqueta.clone(), reason }` after
7497//     [`crate::render::is_chart_keyword_shape`] rejects the offending
7498//     `:etiquetas` entry);
7499//   - `AutorInvalid { autor, reason }` at [`Caixa::validate_autores`]
7500//     (`|reason| ManifestError::AutorInvalid { autor: autor.clone(),
7501//     reason }` after [`crate::render::is_chart_maintainer_name_shape`]
7502//     rejects the offending `:autores` entry);
7503//   - `RepositorioInvalid { repositorio, reason }` at
7504//     [`Caixa::validate_repositorio`]
7505//     (`|reason| ManifestError::RepositorioInvalid { repositorio:
7506//     s.to_string(), reason }` after
7507//     [`crate::render::is_git_repo_url`] rejects the offending
7508//     `:repositorio`);
7509//   - `DescricaoInvalid { descricao, reason }` at
7510//     [`Caixa::validate_descricao`]
7511//     (`|reason| ManifestError::DescricaoInvalid { descricao:
7512//     s.to_string(), reason }` after
7513//     [`crate::render::is_chart_description_shape`] rejects the offending
7514//     `:descricao`);
7515//   - `LicencaInvalid { licenca, reason }` at [`Caixa::validate_licenca`]
7516//     (`|reason| ManifestError::LicencaInvalid { licenca: s.to_string(),
7517//     reason }` after [`crate::render::is_spdx_expression_shape`] rejects
7518//     the offending `:licenca`);
7519//   - `EdicaoInvalid { edicao, reason }` at [`Caixa::validate_edicao`]
7520//     (`return Err(ManifestError::EdicaoInvalid { edicao: s.to_string(),
7521//     reason: "must be a 4-digit ASCII decimal year (canonical
7522//     \"2026\")".to_string() })` on the direct year-shape arm);
7523//   - `RestartWindowMalformed { restart_window, reason }` at
7524//     [`Caixa::validate_restart_window`]
7525//     (`|reason| ManifestError::RestartWindowMalformed { restart_window:
7526//     s.to_string(), reason }` after
7527//     [`crate::supervisor::duration_codec::parse`] rejects the offending
7528//     `:restart-window` raw string).
7529//
7530// Each opened the identical four-line
7531// `ManifestError::<Variant> { <field>: <val>.to_string() | .clone(),
7532// reason: <expr> }` struct-literal against the caller-side `<field>: &str`
7533// / `<field>: &String` local — the exact "same block re-inlined at every
7534// consumer" shape the PRIME DIRECTIVE names as a bug, on the same altitude
7535// the peer `aplicacao_field_reason_ctors!` / `dep_nome_axis_reason_ctors!`
7536// / `LayoutError` / `LimitsError` / `BehaviorError` / `UpgradeError`
7537// families each closed on their sibling envelopes.
7538//
7539// The macro below generates one `#[must_use]` inherent constructor per
7540// variant of shape `fn <ctor>(<field>: &str, reason: impl Into<String>)
7541// -> Self`, collapsing every site onto one dispatch per arm:
7542// `ManifestError::<ctor>(<val>, <reason>)`, byte-equal to the pre-lift
7543// struct-literal on the same `(<field>, reason)` pair. The uniform
7544// two-field construction (`<field>: <field>.to_string()`,
7545// `reason: reason.into()`) is spelled once — inside the macro — rather
7546// than at every wire-up site. The `reason: impl Into<String>` bound
7547// accepts owned `String` (the parser-shaped reason every predicate
7548// returns via `Result<(), String>`; the `e.to_string()` result the
7549// `semver::Version::parse` arm passes; the literal `"…".to_string()` the
7550// `EdicaoInvalid` direct arm passes), `&str` literals, and `format!(…)`
7551// outputs verbatim so no wire-up site changes its per-arm diagnostic
7552// shape at the lift, matching the peer
7553// [`crate::aplicacao::aplicacao_field_reason_ctors!`] and
7554// [`crate::dep::dep_nome_axis_reason_ctors!`] bounds on the sibling
7555// two- and three-slot envelopes. The `<field>: &str` parameter accepts
7556// both `&str` (from the [`Caixa::nome`] / [`Caixa::versao`] /
7557// [`Caixa::repositorio`] / [`Caixa::descricao`] / [`Caixa::licenca`] /
7558// [`Caixa::edicao`] accessors) and `&String` (from the
7559// [`Caixa::etiquetas`] / [`Caixa::autores`] slice iterators) via Deref
7560// coercion, so every existing wire-up threads through the ctor without a
7561// pre-conversion. `#[must_use]` fires a compile warning at any wire-up
7562// that mistakenly discards the constructed error rather than routing it
7563// through `return Err(…)` / `.map_err(…)` / a closure return.
7564//
7565// Every future consumer that wants to construct one of these ten
7566// variants outside the current in-crate wire-up sites (a deferred
7567// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-manifest-axis
7568// admission validators re-checking each declared identity / metadata
7569// axis against a cluster-local snapshot, a future `feira validate
7570// --manifest` per-caixa admission verb re-running the same
7571// value-shape gates on demand, a per-lacre overlay resolver rejecting
7572// an author-supplied manifest override against a cluster-local snapshot
7573// the M4 CR materializer projects, a future
7574// `caixa-registry` per-lacre re-validator at lacre-resolve time
7575// re-checking each declared axis against the same predicates) now
7576// reaches each variant through one call rather than re-inlining the
7577// four-line struct-literal in lockstep with the ten in-crate wire-up
7578// sites.
7579macro_rules! manifest_field_reason_ctors {
7580    ($($ctor:ident => $variant:ident { $field:ident }),* $(,)?) => {
7581        impl ManifestError {
7582            $(
7583                #[doc = concat!(
7584                    "Construct a [`ManifestError::",
7585                    stringify!($variant),
7586                    "`] naming the offending `",
7587                    stringify!($field),
7588                    "` under the given `reason`. Folds the uniform ",
7589                    "`Self::",
7590                    stringify!($variant),
7591                    " { ",
7592                    stringify!($field),
7593                    ": ",
7594                    stringify!($field),
7595                    ".to_string(), reason: reason.into() }` two-slot ",
7596                    "construction onto one substrate primitive so every ",
7597                    "wire-up on this variant reads through one dispatch ",
7598                    "rather than the pre-lift four-line struct-literal ",
7599                    "block. `reason` accepts owned `String`, `&str` ",
7600                    "literals, and `format!(…)` outputs through the ",
7601                    "`impl Into<String>` bound; the `",
7602                    stringify!($field),
7603                    ": &str` parameter accepts both `&str` and `&String` ",
7604                    "via Deref coercion."
7605                )]
7606                #[must_use]
7607                pub fn $ctor($field: &str, reason: impl Into<String>) -> Self {
7608                    Self::$variant {
7609                        $field: $field.to_string(),
7610                        reason: reason.into(),
7611                    }
7612                }
7613            )*
7614        }
7615    };
7616}
7617
7618manifest_field_reason_ctors! {
7619    nome_invalid => NomeInvalid { nome },
7620    nome_chart_name_budget_exceeded => NomeChartNameBudgetExceeded { nome },
7621    versao_invalid => VersaoInvalid { versao },
7622    etiqueta_invalid => EtiquetaInvalid { etiqueta },
7623    autor_invalid => AutorInvalid { autor },
7624    repositorio_invalid => RepositorioInvalid { repositorio },
7625    descricao_invalid => DescricaoInvalid { descricao },
7626    licenca_invalid => LicencaInvalid { licenca },
7627    edicao_invalid => EdicaoInvalid { edicao },
7628    restart_window_malformed => RestartWindowMalformed { restart_window },
7629}
7630
7631// Fold the two `ManifestError::{EtiquetaDuplicate, AutorDuplicate}
7632// { <field>: <val>.clone() }` single-`String`-slot wire-up sites at
7633// [`Caixa::validate_etiquetas`] and [`Caixa::validate_autores`] onto one
7634// substrate-primitive family per typed variant — the direct sibling on
7635// the [`ManifestError`] envelope of the peer
7636// [`crate::aplicacao::aplicacao_caixa_only_ctors!`] (d9f6867, 4 variants
7637// on `AplicacaoError` at `ContratoMemberMissing` / `MembroVersaoEmpty` /
7638// `MembroDuplicate` / `MembroIsSelfAplicacao` on the `{ caixa: String }`
7639// shape) and [`crate::aplicacao::aplicacao_path_only_ctors!`] (3ba8de6,
7640// 2 variants on `AplicacaoError` at `EntradaPathNotAbsolute` /
7641// `EntradaPathDuplicate` on the `{ path: String }` shape) on the sibling
7642// M3 mesh `AplicacaoError` envelope, and of the peer
7643// [`crate::supervisor::supervisor_caixa_only_ctors!`] (db09650, 3 variants
7644// on the sibling M2 `SupervisorError` envelope's `{ caixa: String }`
7645// shape), [`crate::dep::dep_nome_only_ctors!`] (792aa92, 5 variants on
7646// `DepError { nome: String }`), and [`crate::upgrade::upgrade_script_only_ctors!`]
7647// (7468ca9, 3 variants on `UpgradeError { script: PathBuf }`) folds on
7648// the sibling envelopes — the last two open-coded single-slot
7649// `{ <field>: String }` struct-literal sites on `ManifestError` fold
7650// onto one substrate primitive per typed variant, matching the
7651// "one substrate primitive per typed variant on the single-slot
7652// `{ <ident>: String }` envelope shape" fold discipline every peer
7653// per-Caixa-identity family already carries.
7654//
7655// Both wire-up sites — one at [`Caixa::validate_etiquetas`]'s per-entry
7656// [`crate::render::insert_first_seen`] dedup closure
7657// (`|| ManifestError::EtiquetaDuplicate { etiqueta: etiqueta.clone() }`
7658// against the per-`:etiquetas` `&String` loop head) and one at
7659// [`Caixa::validate_autores`]'s per-entry [`crate::render::insert_first_seen`]
7660// dedup closure (`|| ManifestError::AutorDuplicate
7661// { autor: autor.clone() }` against the per-`:autores` `&String` loop
7662// head) — opened the identical `ManifestError::<Variant>Duplicate
7663// { <field>: <val>.clone() }` three-line struct-literal against a
7664// caller-side `&String`, the exact "same block re-inlined at every
7665// consumer" shape the PRIME DIRECTIVE names as a bug. The two variants
7666// share one `{ <field>: String }` shape, so the fold routes each wire-up
7667// site through one dispatch per typed variant.
7668//
7669// The macro below generates one `#[must_use]` inherent constructor per
7670// variant of shape `fn <ctor>(<field>: &str) -> ManifestError`, so every
7671// wire-up site collapses onto one dispatch:
7672// `ManifestError::<ctor>(<&str>)`, byte-equal to the pre-lift
7673// struct-literal on the same `&str` fixture. The uniform one-field
7674// construction (`<field>: <field>.to_string()`) is spelled once — inside
7675// the macro — rather than at every wire-up site. The `<field>: &str`
7676// parameter accepts both `&str` and `&String` (via Deref coercion), so
7677// each existing dedup-closure wire-up threading `<val>.as_str()` — or a
7678// bare `&String` head — through the ctor routes through one dispatch
7679// without a pre-conversion, and the `.clone()` the pre-lift wire-up
7680// carried at the closure body folds into the ctor's canonical
7681// `.to_string()` (byte-equal on the same underlying bytes). Every
7682// constructor is `#[must_use]` so a caller who mistakenly discards the
7683// constructed error trips a compile warning at the wire-up site.
7684//
7685// Every future consumer that wants to construct one of these two
7686// variants outside the current in-crate wire-up sites — a deferred
7687// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission webhook
7688// re-checking one added/renamed `:etiquetas` / `:autores` entry against
7689// the same dedup axis, a future `feira validate --etiquetas` /
7690// `--autores` per-caixa admission verb re-running the same per-entry
7691// dedup gate on demand, a per-lacre overlay resolver rejecting an
7692// author-supplied duplicate `:etiquetas` / `:autores` entry against a
7693// cluster-local snapshot the M4 CR materializer projects, a future
7694// `caixa-registry` per-lacre re-validator at lacre-resolve time
7695// re-checking each declared list against the same dedup predicate — now
7696// reaches each variant through one call rather than re-inlining the
7697// three-line struct-literal in lockstep with the two in-crate wire-up
7698// sites.
7699macro_rules! manifest_field_only_ctors {
7700    ($($ctor:ident => $variant:ident { $field:ident }),* $(,)?) => {
7701        impl ManifestError {
7702            $(
7703                #[doc = concat!(
7704                    "Construct a [`ManifestError::",
7705                    stringify!($variant),
7706                    "`] naming the offending `",
7707                    stringify!($field),
7708                    "` entry. Folds the uniform `Self::",
7709                    stringify!($variant),
7710                    " { ",
7711                    stringify!($field),
7712                    ": ",
7713                    stringify!($field),
7714                    ".to_string() }` one-field struct-literal onto one ",
7715                    "substrate primitive so every wire-up on this variant ",
7716                    "reads through one dispatch rather than the pre-lift ",
7717                    "three-line open-coded struct-literal block. The `",
7718                    stringify!($field),
7719                    ": &str` parameter accepts both `&str` and `&String` ",
7720                    "via Deref coercion."
7721                )]
7722                #[must_use]
7723                pub fn $ctor($field: &str) -> Self {
7724                    Self::$variant {
7725                        $field: $field.to_string(),
7726                    }
7727                }
7728            )*
7729        }
7730    };
7731}
7732
7733manifest_field_only_ctors! {
7734    etiqueta_duplicate => EtiquetaDuplicate { etiqueta },
7735    autor_duplicate => AutorDuplicate { autor },
7736}
7737
7738#[cfg(test)]
7739mod tests {
7740    use super::*;
7741
7742    #[test]
7743    fn template_round_trips() {
7744        let src = Caixa::template("demo");
7745        let c = Caixa::from_lisp(&src).expect("template must parse");
7746        assert_eq!(c.nome, "demo");
7747        assert_eq!(c.versao, "0.1.0");
7748        assert_eq!(c.kind, CaixaKind::Biblioteca);
7749        assert_eq!(c.bibliotecas, vec!["lib/demo.lisp".to_string()]);
7750        assert!(c.deps.is_empty());
7751        assert!(c.deps_dev.is_empty());
7752    }
7753
7754    #[test]
7755    fn caixa_universal_axis_scalar_accessor_pair_is_const_fn() {
7756        // Fail-before-pass-after pin on [`Caixa::nome`] +
7757        // [`Caixa::versao`]'s `const`-eval-surface posture. Each
7758        // accessor projects the top-level manifest's per-`:nome` /
7759        // per-`:versao` [`String`] storage through the `pub const fn`
7760        // [`String::as_str`] (const-stable since Rust 1.87, well within
7761        // the workspace MSRV) — any future accidental downgrade to
7762        // non-`const` fails the corresponding `<name>_via_const_fn`
7763        // wrapper at caixa-core build time with E0015 (`cannot call
7764        // non-const method`), strictly stronger than a runtime
7765        // `assert!`. Sibling of the peer per-M2/M3-slot `String → &str`
7766        // scalar-accessor family pins on the sibling `const`-eval-
7767        // surface passes ([`crate::CaixaVersion::as_str`] at the
7768        // typed-newtype wrapper, [`crate::aplicacao::Membro::nome`] /
7769        // [`crate::aplicacao::Membro::versao_requirement`] at the M3
7770        // membership axis, [`crate::aplicacao::Entrada::hostname`] /
7771        // [`crate::aplicacao::Entrada::destination`] at the M3 ingress
7772        // axis, [`crate::supervisor::ChildSpec::nome`] /
7773        // [`crate::supervisor::ChildSpec::versao_requirement`] at the
7774        // M2 supervisor-tree axis,
7775        // [`crate::upgrade::UpgradeFromEntry::prior_versao`] at the M2
7776        // upgrade axis, [`crate::dep::Dep::nome`] /
7777        // [`crate::dep::Dep::versao_requirement`] at the dep-graph
7778        // axis, and the per-`:contratos`
7779        // [`crate::aplicacao::WitContract::source`] /
7780        // [`crate::aplicacao::WitContract::destination`] /
7781        // [`crate::aplicacao::WitContract::world_ref`] trio the
7782        // sibling pin at 279823b already anchors).
7783        const fn nome_via_const_fn(c: &Caixa) -> &str {
7784            c.nome()
7785        }
7786        const fn versao_via_const_fn(c: &Caixa) -> &str {
7787            c.versao()
7788        }
7789        let src = Caixa::template("demo");
7790        let c = Caixa::from_lisp(&src).expect("template must parse");
7791        assert_eq!(nome_via_const_fn(&c), c.nome());
7792        assert_eq!(versao_via_const_fn(&c), c.versao());
7793        assert_eq!(c.nome(), "demo");
7794        assert_eq!(c.versao(), "0.1.0");
7795    }
7796
7797    #[test]
7798    fn caixa_option_string_scalar_accessor_family_is_const_fn() {
7799        // Fail-before-pass-after pin on the five per-`Caixa`
7800        // `Option<String> → Option<&str>` scalar accessors
7801        // ([`Caixa::licenca`] / [`Caixa::repositorio`] /
7802        // [`Caixa::descricao`] / [`Caixa::edicao`] on the top-level
7803        // manifest's optional universal-axis surface, plus
7804        // [`Caixa::restart_window`] on the M2 supervisor-tree
7805        // per-`SupervisorSpec` peer raw-window-string projection axis).
7806        // Each accessor destructures the typed slot's `Option<String>`
7807        // storage through the `match &self.<field> { Some(s) =>
7808        // Some(s.as_str()), None => None }` shape — routing through
7809        // [`String::as_str`] (const-stable since Rust 1.87, well within
7810        // the workspace MSRV) rather than the non-const
7811        // [`Option::as_deref`] the pre-lift bodies carried — and any
7812        // future accidental downgrade to non-`const` fails the
7813        // corresponding `<name>_via_const_fn` wrapper at caixa-core
7814        // build time with E0015 (`cannot call non-const method`),
7815        // strictly stronger than a runtime `assert!` and strictly
7816        // stronger than a module-scope `const _: () = assert!(…)` pin
7817        // (which cannot be formed on a `&Caixa` fixture because the
7818        // type's `String` / `Option<String>` carriers rule out
7819        // `const`-context value construction; the `const fn` wrapper
7820        // is the load-bearing shape that side-steps the destructor-in-
7821        // const restriction on the value axis while still pinning the
7822        // `const`-fn posture on the callee — mirror of the sibling
7823        // [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
7824        // pin's discipline verbatim on the peer non-`Option`
7825        // `String → &str` axis at the same struct).
7826        //
7827        // Peer of the sibling per-M2/M3-slot `Option<String> →
7828        // Option<&str>` accessor family pin
7829        // [`m3_option_string_scalar_accessor_family_is_const_fn`] on
7830        // the M3 mesh-slot atom axes ([`WitContract::endpoint`] /
7831        // [`WitContract::subject`] / [`WitContract::slot`] on the
7832        // per-`:contratos` payload-carrier trio,
7833        // [`Placement::shard_key`] / [`Placement::affinity`] on the
7834        // per-`:placement` optional-scalar pair).
7835        const fn licenca_via_const_fn(c: &Caixa) -> Option<&str> {
7836            c.licenca()
7837        }
7838        const fn repositorio_via_const_fn(c: &Caixa) -> Option<&str> {
7839            c.repositorio()
7840        }
7841        const fn descricao_via_const_fn(c: &Caixa) -> Option<&str> {
7842            c.descricao()
7843        }
7844        const fn edicao_via_const_fn(c: &Caixa) -> Option<&str> {
7845            c.edicao()
7846        }
7847        const fn restart_window_via_const_fn(c: &Caixa) -> Option<&str> {
7848            c.restart_window()
7849        }
7850        // Sweep both the `Some`-carrying arm (author-declared slot,
7851        // the byte-string projection payload) and the `None`-carrying
7852        // arm (author-omitted slot, the default-path projection) on
7853        // every accessor so the `const fn` wrapper family pins each
7854        // axis's canonical two-arm partition through the same const
7855        // dispatch as the runtime path.
7856        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7857        c1.licenca = Some("MIT".to_string());
7858        c1.repositorio = Some("https://github.com/pleme-io/demo".to_string());
7859        c1.descricao = Some("demo caixa".to_string());
7860        c1.edicao = Some("2024".to_string());
7861        c1.restart_window = Some("60s".to_string());
7862        assert_eq!(licenca_via_const_fn(&c1), c1.licenca());
7863        assert_eq!(repositorio_via_const_fn(&c1), c1.repositorio());
7864        assert_eq!(descricao_via_const_fn(&c1), c1.descricao());
7865        assert_eq!(edicao_via_const_fn(&c1), c1.edicao());
7866        assert_eq!(restart_window_via_const_fn(&c1), c1.restart_window());
7867        assert_eq!(c1.licenca(), Some("MIT"));
7868        assert_eq!(c1.repositorio(), Some("https://github.com/pleme-io/demo"));
7869        assert_eq!(c1.descricao(), Some("demo caixa"));
7870        assert_eq!(c1.edicao(), Some("2024"));
7871        assert_eq!(c1.restart_window(), Some("60s"));
7872        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7873        c2.licenca = None;
7874        c2.repositorio = None;
7875        c2.descricao = None;
7876        c2.edicao = None;
7877        c2.restart_window = None;
7878        assert_eq!(licenca_via_const_fn(&c2), None);
7879        assert_eq!(repositorio_via_const_fn(&c2), None);
7880        assert_eq!(descricao_via_const_fn(&c2), None);
7881        assert_eq!(edicao_via_const_fn(&c2), None);
7882        assert_eq!(restart_window_via_const_fn(&c2), None);
7883    }
7884
7885    #[test]
7886    fn caixa_outer_copy_return_accessor_pair_is_const_fn() {
7887        // Fail-before-pass-after pin on the two outer-[`Caixa`]
7888        // `Copy`-return accessors — [`Caixa::kind`] on the required
7889        // [`CaixaKind`] enum-discriminant axis and [`Caixa::estrategia`]
7890        // on the M2 supervisor-tree flat-spread `Option<RestartStrategy>`
7891        // axis. Both accessors project a `Copy`-carrier field
7892        // (`CaixaKind: Copy` at caixa-core/src/kind.rs:17,
7893        // `RestartStrategy: Copy` at caixa-core/src/supervisor.rs:33 →
7894        // `Option<RestartStrategy>: Copy`) by value through a bare
7895        // `self.<field>` field-access — no dispatch, no destructor, no
7896        // heap. Any future accidental downgrade to non-`const` fails
7897        // the corresponding `<name>_via_const_fn` wrapper at caixa-core
7898        // build time with E0015 (`cannot call non-const method`),
7899        // strictly stronger than a runtime `assert!` and strictly
7900        // stronger than a module-scope `const _: () = assert!(…)` pin
7901        // (which cannot be formed on a `&Caixa` fixture because the
7902        // type's `String` / `Vec` / `Option<Composite>` carriers rule
7903        // out `const`-context value construction; the `const fn`
7904        // wrapper is the load-bearing shape that side-steps the
7905        // destructor-in-const restriction on the value axis while still
7906        // pinning the `const`-fn posture on the callee — mirror of the
7907        // sibling [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
7908        // + [`caixa_option_string_scalar_accessor_family_is_const_fn`]
7909        // pins' discipline verbatim on the peer outer-`Caixa`
7910        // `String → &str` + `Option<String> → Option<&str>` axes at the
7911        // same struct).
7912        //
7913        // Peer of the sibling per-M2/M3-slot `Copy`-return accessor pin
7914        // family on the inner-altitude nested-spec typed-slot
7915        // discriminator axes: [`crate::supervisor::SupervisorSpec::estrategia`]
7916        // + [`crate::supervisor::ChildSpec::restart`] on the M2
7917        // supervisor-tree axis (pinned at 152c868), and
7918        // [`crate::aplicacao::Placement::estrategia`] +
7919        // [`crate::aplicacao::Entrada::port`] on the M3 mesh-slot axis
7920        // (pinned at bafa004) — the outer-`Caixa` altitude is the last
7921        // unlifted altitude for the `Copy`-return-accessor family.
7922        const fn kind_via_const_fn(c: &Caixa) -> CaixaKind {
7923            c.kind()
7924        }
7925        const fn estrategia_via_const_fn(c: &Caixa) -> Option<crate::supervisor::RestartStrategy> {
7926            c.estrategia()
7927        }
7928        // Sweep every arm of both discriminant partitions the accessors
7929        // fan on — every [`CaixaKind`] variant the six-arm required
7930        // discriminant carries (Biblioteca / Binario / Servico /
7931        // Supervisor / Aplicacao / Acao) and both arms of the
7932        // [`Option<RestartStrategy>`] flat-spread supervisor-tree slot
7933        // (`Some(<strategy>)` on an author-declared supervisor and
7934        // `None` on the author-omitted default arm every non-Supervisor
7935        // caixa carries by `#[serde(default)]`) — so the `const fn`
7936        // wrapper family pins the closed-set partition through the
7937        // same const dispatch as the runtime path.
7938        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7939        c1.kind = CaixaKind::Servico;
7940        c1.estrategia = Some(crate::supervisor::RestartStrategy::OneForAll);
7941        assert_eq!(kind_via_const_fn(&c1), c1.kind());
7942        assert_eq!(estrategia_via_const_fn(&c1), c1.estrategia());
7943        assert_eq!(c1.kind(), CaixaKind::Servico);
7944        assert_eq!(
7945            c1.estrategia(),
7946            Some(crate::supervisor::RestartStrategy::OneForAll)
7947        );
7948        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7949        c2.kind = CaixaKind::Aplicacao;
7950        c2.estrategia = None;
7951        assert_eq!(kind_via_const_fn(&c2), CaixaKind::Aplicacao);
7952        assert_eq!(estrategia_via_const_fn(&c2), None);
7953        // Anchor the remaining discriminant arms so any future
7954        // reordering of [`CaixaKind`]'s six-variant enum surfaces
7955        // through the wrapper dispatch, not just through the direct
7956        // method call.
7957        for kind in [
7958            CaixaKind::Biblioteca,
7959            CaixaKind::Binario,
7960            CaixaKind::Servico,
7961            CaixaKind::Supervisor,
7962            CaixaKind::Aplicacao,
7963            CaixaKind::Acao,
7964        ] {
7965            let mut c = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7966            c.kind = kind;
7967            assert_eq!(kind_via_const_fn(&c), kind);
7968        }
7969    }
7970
7971    #[test]
7972    fn caixa_outer_string_slice_return_accessor_family_is_const_fn() {
7973        // Fail-before-pass-after pin on the five outer-[`Caixa`]
7974        // `Vec<String> → &[String]` slice-return accessors on the
7975        // universal-axis surface — [`Caixa::autores`] / [`Caixa::etiquetas`]
7976        // / [`Caixa::bibliotecas`] / [`Caixa::exe`] / [`Caixa::servicos`].
7977        // Each body is a bare `self.<field>.as_slice()` dispatch through
7978        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
7979        // the workspace MSRV). Any future accidental downgrade to
7980        // non-`const` fails the corresponding `<name>_via_const_fn`
7981        // wrapper at caixa-core build time with E0015 (`cannot call
7982        // non-const method`) — mirror of the sibling
7983        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] pin's
7984        // discipline on the peer outer-`Caixa` `Copy`-return accessor
7985        // axis, and peer of the sibling composite-carrier slice-return
7986        // pin below on the peer outer-`Caixa` composite-slice axis.
7987        const fn autores_via_const_fn(c: &Caixa) -> &[String] {
7988            c.autores()
7989        }
7990        const fn etiquetas_via_const_fn(c: &Caixa) -> &[String] {
7991            c.etiquetas()
7992        }
7993        const fn bibliotecas_via_const_fn(c: &Caixa) -> &[String] {
7994            c.bibliotecas()
7995        }
7996        const fn exe_via_const_fn(c: &Caixa) -> &[String] {
7997            c.exe()
7998        }
7999        const fn servicos_via_const_fn(c: &Caixa) -> &[String] {
8000            c.servicos()
8001        }
8002        // Sweep the empty arm (`autores` / `etiquetas` / `exe` /
8003        // `servicos` — the template's `Vec::new()` default) and the
8004        // populated arm (mutated below) on every accessor so the
8005        // `const fn` wrapper family pins each axis's two-arm partition
8006        // through the same const dispatch as the runtime path.
8007        // [`Caixa::template`] seeds `lib/demo.lisp` into `:bibliotecas`,
8008        // so that arm's "empty" fixture is the populated arm the
8009        // mutation sweep covers.
8010        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8011        assert!(autores_via_const_fn(&c_empty).is_empty());
8012        assert!(etiquetas_via_const_fn(&c_empty).is_empty());
8013        assert!(exe_via_const_fn(&c_empty).is_empty());
8014        assert!(servicos_via_const_fn(&c_empty).is_empty());
8015        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8016        c_full.autores = vec!["ada".to_string(), "erlang".to_string()];
8017        c_full.etiquetas = vec!["compounding".to_string()];
8018        c_full.bibliotecas = vec!["lib/one.lisp".to_string(), "lib/two.lisp".to_string()];
8019        c_full.exe = vec!["exe/cli.lisp".to_string()];
8020        c_full.servicos = vec!["servicos/one.computeunit.yaml".to_string()];
8021        assert_eq!(autores_via_const_fn(&c_full), c_full.autores());
8022        assert_eq!(autores_via_const_fn(&c_full), &["ada", "erlang"]);
8023        assert_eq!(etiquetas_via_const_fn(&c_full), c_full.etiquetas());
8024        assert_eq!(etiquetas_via_const_fn(&c_full), &["compounding"]);
8025        assert_eq!(bibliotecas_via_const_fn(&c_full), c_full.bibliotecas());
8026        assert_eq!(
8027            bibliotecas_via_const_fn(&c_full),
8028            &["lib/one.lisp", "lib/two.lisp"]
8029        );
8030        assert_eq!(exe_via_const_fn(&c_full), c_full.exe());
8031        assert_eq!(exe_via_const_fn(&c_full), &["exe/cli.lisp"]);
8032        assert_eq!(servicos_via_const_fn(&c_full), c_full.servicos());
8033        assert_eq!(
8034            servicos_via_const_fn(&c_full),
8035            &["servicos/one.computeunit.yaml"]
8036        );
8037    }
8038
8039    #[test]
8040    fn caixa_outer_composite_slice_return_accessor_family_is_const_fn() {
8041        // Fail-before-pass-after pin on the six outer-[`Caixa`] composite-
8042        // carrier `Vec<T> → &[T]` slice-return accessors — [`Caixa::deps`]
8043        // / [`Caixa::deps_dev`] on the dep-graph axis,
8044        // [`Caixa::upgrade_from`] on the M2 appup axis, [`Caixa::children`]
8045        // on the M2 supervisor-tree axis, and [`Caixa::membros`] /
8046        // [`Caixa::contratos`] on the M3 mesh-slot axis. Each body is a
8047        // bare `self.<field>.as_slice()` dispatch through
8048        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
8049        // the workspace MSRV) — peer of the sibling `String`-payload
8050        // slice-return pin above on the peer outer-`Caixa` universal-
8051        // axis surface, and peer of the sibling inner-composite-
8052        // altitude reference-return pin family
8053        // [`crate::aplicacao::tests::m3_aplicacao_spec_reference_return_accessor_family_is_const_fn`]
8054        // + [`crate::supervisor::tests::supervisor_children_slice_return_accessor_is_const_fn`]
8055        // + [`crate::upgrade::tests::upgrade_from_entry_instructions_slice_return_accessor_is_const_fn`]
8056        // (all pinned at 0b23e0f).
8057        const fn deps_via_const_fn(c: &Caixa) -> &[Dep] {
8058            c.deps()
8059        }
8060        const fn deps_dev_via_const_fn(c: &Caixa) -> &[Dep] {
8061            c.deps_dev()
8062        }
8063        const fn upgrade_from_via_const_fn(c: &Caixa) -> &[UpgradeFromEntry] {
8064            c.upgrade_from()
8065        }
8066        const fn children_via_const_fn(c: &Caixa) -> &[crate::supervisor::ChildSpec] {
8067            c.children()
8068        }
8069        const fn membros_via_const_fn(c: &Caixa) -> &[crate::aplicacao::Membro] {
8070            c.membros()
8071        }
8072        const fn contratos_via_const_fn(c: &Caixa) -> &[crate::aplicacao::WitContract] {
8073            c.contratos()
8074        }
8075        // Empty-arm sweep on all six composite-carrier axes — every
8076        // `Caixa::template` starts with `Vec::new()` on each.
8077        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8078        assert!(deps_via_const_fn(&c_empty).is_empty());
8079        assert!(deps_dev_via_const_fn(&c_empty).is_empty());
8080        assert!(upgrade_from_via_const_fn(&c_empty).is_empty());
8081        assert!(children_via_const_fn(&c_empty).is_empty());
8082        assert!(membros_via_const_fn(&c_empty).is_empty());
8083        assert!(contratos_via_const_fn(&c_empty).is_empty());
8084        // Populate `:membros` / `:contratos` directly via struct literals
8085        // — the parser-side validation path fans on `:kind`-gated cross-
8086        // slot invariants irrelevant to the accessor dispatch under test.
8087        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8088        c_full.membros = vec![
8089            crate::aplicacao::Membro {
8090                caixa: "demo-a".to_string(),
8091                versao: "^0.1.0".to_string(),
8092            },
8093            crate::aplicacao::Membro {
8094                caixa: "demo-b".to_string(),
8095                versao: "^0.2.0".to_string(),
8096            },
8097        ];
8098        c_full.contratos = vec![crate::aplicacao::WitContract {
8099            de: "demo-a".to_string(),
8100            para: "demo-b".to_string(),
8101            wit: "wasi:http/proxy".to_string(),
8102            endpoint: Some("/edge".to_string()),
8103            subject: None,
8104            slot: None,
8105        }];
8106        assert_eq!(membros_via_const_fn(&c_full), c_full.membros());
8107        assert_eq!(contratos_via_const_fn(&c_full), c_full.contratos());
8108        assert_eq!(membros_via_const_fn(&c_full).len(), 2);
8109        assert_eq!(contratos_via_const_fn(&c_full).len(), 1);
8110        // Alias-borrow check on the four remaining composite-carrier
8111        // slice-return arms — the wrapper's return borrow must alias the
8112        // caller's borrow so any future accessor re-routing that skips
8113        // the storage field surfaces through the assertion.
8114        assert!(std::ptr::eq(deps_via_const_fn(&c_full), c_full.deps()));
8115        assert!(std::ptr::eq(
8116            deps_dev_via_const_fn(&c_full),
8117            c_full.deps_dev()
8118        ));
8119        assert!(std::ptr::eq(
8120            upgrade_from_via_const_fn(&c_full),
8121            c_full.upgrade_from()
8122        ));
8123        assert!(std::ptr::eq(
8124            children_via_const_fn(&c_full),
8125            c_full.children()
8126        ));
8127    }
8128
8129    #[test]
8130    fn caixa_outer_option_composite_reference_return_accessor_family_is_const_fn() {
8131        // Fail-before-pass-after pin on the six outer-[`Caixa`]
8132        // `Option<Composite> → Option<&Composite>` reference-return
8133        // accessors — [`Caixa::limits`] / [`Caixa::behavior`] on the M2
8134        // Servico-runtime typed-slot axis, [`Caixa::politicas`] /
8135        // [`Caixa::placement`] / [`Caixa::entrada`] on the M3 mesh-slot
8136        // axis, and [`Caixa::ci`] on the Acao-kind typed-CI-run axis.
8137        // Each body is a bare `self.<field>.as_ref()` dispatch through
8138        // [`Option::as_ref`] (const-stable since Rust 1.83, well within
8139        // the workspace MSRV of 1.89). Any future accidental downgrade
8140        // to non-`const` fails the corresponding `<name>_via_const_fn`
8141        // wrapper at caixa-core build time with E0015 (`cannot call
8142        // non-const method`), strictly stronger than a runtime `assert!`
8143        // and strictly stronger than a module-scope `const _: () =
8144        // assert!(…)` pin (which cannot be formed on a `&Caixa` fixture
8145        // because the type's `String` / `Vec` / `Option<Composite>`
8146        // carriers rule out `const`-context value construction; the
8147        // `const fn` wrapper is the load-bearing shape that side-steps
8148        // the destructor-in-const restriction on the value axis while
8149        // still pinning the `const`-fn posture on the callee — mirror
8150        // of the sibling
8151        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] +
8152        // [`caixa_outer_string_slice_return_accessor_family_is_const_fn`] +
8153        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
8154        // pins' discipline verbatim on the peer outer-`Caixa` axes at
8155        // the same struct).
8156        //
8157        // Closes the outer-`Caixa` `Option<&Composite>` composite-
8158        // reference-return sub-family — the last unlifted altitude on
8159        // the outer-`Caixa` accessor-family const-eval surface after
8160        // the sibling `Copy`-return / universal-axis-`&str` /
8161        // `Option<&str>` / `&[String]` / composite-`&[T]` pins already
8162        // closed the sibling arms at 866d1d5 / 29c5d7e / 0650f64 /
8163        // 231a968 (the last of these pins the `Vec<T> → &[T]`
8164        // composite-slice arm the six accessors here close as their
8165        // `Option<Composite> → Option<&Composite>` peer). Peer of the
8166        // sibling inner-altitude nested-spec composite-reference-return
8167        // pin family — [`crate::AplicacaoSpec::politicas`] /
8168        // [`crate::AplicacaoSpec::placement`] /
8169        // [`crate::AplicacaoSpec::entrada`] on the inner
8170        // [`crate::AplicacaoSpec`] altitude (already `pub const fn`
8171        // per 0b23e0f), and the outer-`Caixa` altitude here now carries
8172        // the same shape so both altitudes of the reference-return
8173        // discipline (per-`Caixa` outer-slot presence + per-
8174        // `AplicacaoSpec` inner-slot presence) route through one typed
8175        // const dispatch on the substrate primitive.
8176        const fn limits_via_const_fn(c: &Caixa) -> Option<&LimitsSpec> {
8177            c.limits()
8178        }
8179        const fn behavior_via_const_fn(c: &Caixa) -> Option<&crate::BehaviorSpec> {
8180            c.behavior()
8181        }
8182        const fn politicas_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::MeshPolicy> {
8183            c.politicas()
8184        }
8185        const fn placement_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Placement> {
8186            c.placement()
8187        }
8188        const fn entrada_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Entrada> {
8189            c.entrada()
8190        }
8191        const fn ci_via_const_fn(c: &Caixa) -> Option<&canteiro_types::CiRun> {
8192            c.ci()
8193        }
8194        // Both-arm sweep on every accessor: the `None` author-omitted
8195        // arm (template default — no M2/M3/CI slot declared) and the
8196        // `Some(<composite>)` authored arm (mutated below via struct-
8197        // literal seeds, side-stepping the parser-side `:kind`-gated
8198        // cross-slot invariants irrelevant to the accessor dispatch
8199        // under test). Both arms route through the `const fn` wrapper
8200        // family so the two-arm `Option` partition is pinned through
8201        // the same const dispatch as the runtime path.
8202        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8203        assert!(limits_via_const_fn(&c_empty).is_none());
8204        assert!(behavior_via_const_fn(&c_empty).is_none());
8205        assert!(politicas_via_const_fn(&c_empty).is_none());
8206        assert!(placement_via_const_fn(&c_empty).is_none());
8207        assert!(entrada_via_const_fn(&c_empty).is_none());
8208        assert!(ci_via_const_fn(&c_empty).is_none());
8209        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8210        c_full.limits = Some(LimitsSpec::default());
8211        c_full.behavior = Some(crate::BehaviorSpec::default());
8212        c_full.politicas = Some(crate::aplicacao::MeshPolicy::default());
8213        c_full.placement = Some(crate::aplicacao::Placement::default());
8214        c_full.entrada = Some(crate::aplicacao::Entrada {
8215            host: "demo.quero.cloud".to_string(),
8216            para: "demo".to_string(),
8217            paths: Vec::new(),
8218            port: crate::aplicacao::DEFAULT_SERVICO_PORT,
8219        });
8220        c_full.ci = Some(canteiro_types::CiRun {
8221            workspace: "pleme-io".into(),
8222            repo: "caixa".into(),
8223            nodes: vec![],
8224        });
8225        assert!(limits_via_const_fn(&c_full).is_some());
8226        assert!(behavior_via_const_fn(&c_full).is_some());
8227        assert!(politicas_via_const_fn(&c_full).is_some());
8228        assert!(placement_via_const_fn(&c_full).is_some());
8229        assert!(entrada_via_const_fn(&c_full).is_some());
8230        assert!(ci_via_const_fn(&c_full).is_some());
8231        // Alias-borrow check on every arm: the wrapper's inner-`Option`
8232        // reference must alias the caller's borrow so any future accessor
8233        // re-routing that skips the storage field surfaces through the
8234        // assertion.
8235        assert!(std::ptr::eq(
8236            limits_via_const_fn(&c_full).unwrap(),
8237            c_full.limits().unwrap()
8238        ));
8239        assert!(std::ptr::eq(
8240            behavior_via_const_fn(&c_full).unwrap(),
8241            c_full.behavior().unwrap()
8242        ));
8243        assert!(std::ptr::eq(
8244            politicas_via_const_fn(&c_full).unwrap(),
8245            c_full.politicas().unwrap()
8246        ));
8247        assert!(std::ptr::eq(
8248            placement_via_const_fn(&c_full).unwrap(),
8249            c_full.placement().unwrap()
8250        ));
8251        assert!(std::ptr::eq(
8252            entrada_via_const_fn(&c_full).unwrap(),
8253            c_full.entrada().unwrap()
8254        ));
8255        assert!(std::ptr::eq(
8256            ci_via_const_fn(&c_full).unwrap(),
8257            c_full.ci().unwrap()
8258        ));
8259    }
8260
8261    #[test]
8262    fn register_populates_registry() {
8263        Caixa::register().expect("first register call in this test process must succeed");
8264        let kws = tatara_lisp::domain::registered_keywords();
8265        assert!(kws.contains(&"defcaixa"));
8266    }
8267
8268    #[test]
8269    fn to_lisp_round_trips() {
8270        let src = Caixa::template("demo");
8271        let c1 = Caixa::from_lisp(&src).unwrap();
8272        let emitted = c1.to_lisp();
8273        let c2 = Caixa::from_lisp(&emitted).expect("emitted lisp parses back");
8274        assert_eq!(c1, c2);
8275    }
8276
8277    // ── DialetoEstrangeiro carries a single typed axis ────────────────────
8278    //
8279    // The compounding pin: the variant stores only the typed
8280    // [`crate::dialeto::CaixaDialeto`], and every user-facing byte-string
8281    // (canonical keyword, description, consumer) routes through the enum's
8282    // own accessors at Display time. Prior to that closure the variant
8283    // carried each accessor's return value as a stored `&'static str`
8284    // snapshot alongside `dialeto`; a caller could construct the variant
8285    // with a snapshot that drifted from what `dialeto`'s accessors would
8286    // return, and every downstream user-facing projection would silently
8287    // disagree with the classification. Storing only the axis makes the
8288    // drift structurally impossible.
8289
8290    #[test]
8291    fn dialeto_estrangeiro_variant_carries_only_the_typed_dialeto_axis() {
8292        // Single-field construction is the whole compounding shape — a
8293        // future re-introduction of a snapshot field (a `palavra_canonica:
8294        // &'static str`, a stored `descricao:`, a stored `consumidor:`)
8295        // would re-open the drift surface and this construction would fail
8296        // to compile with "missing field" until every snapshot was seeded
8297        // at the call site again. The compile-time guarantee is the
8298        // invariant; the assertion below only witnesses that the
8299        // construction is well-formed after the closure.
8300        let err = LeituraError::DialetoEstrangeiro {
8301            dialeto: crate::dialeto::CaixaDialeto::Molde,
8302        };
8303        assert!(matches!(
8304            err,
8305            LeituraError::DialetoEstrangeiro {
8306                dialeto: crate::dialeto::CaixaDialeto::Molde,
8307            }
8308        ));
8309    }
8310
8311    #[test]
8312    fn dialeto_estrangeiro_display_routes_through_typed_dialeto_accessors() {
8313        // For every foreign-dialect classification the variant surfaces —
8314        // [`crate::dialeto::CaixaDialeto::Molde`] and
8315        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two
8316        // variants [`Caixa::from_lisp`] raises this error for — the
8317        // rendered [`std::fmt::Display`] byte-string must interpolate each
8318        // typed accessor's return verbatim. A future re-introduction of a
8319        // stored `&'static str` snapshot alongside `dialeto` that Display
8320        // read instead of the accessor would fail this pin as soon as the
8321        // two disagreed; a future accessor rebrand (a per-dialect
8322        // consumer rename, a canonical-keyword shift once the substrate
8323        // migration named in [`crate::dialeto`] completes) reaches every
8324        // consumer through one typed dispatch and this pin verifies the
8325        // display path is one of them.
8326        for d in [
8327            crate::dialeto::CaixaDialeto::Molde,
8328            crate::dialeto::CaixaDialeto::MoldePosicional,
8329        ] {
8330            let rendered = LeituraError::DialetoEstrangeiro { dialeto: d }.to_string();
8331            assert!(
8332                rendered.contains(d.palavra_canonica()),
8333                "Display must interpolate `dialeto.palavra_canonica()` \
8334                 verbatim — a stored snapshot would silently drift from \
8335                 the typed accessor. dialect: {d}, rendered: {rendered:?}"
8336            );
8337            assert!(
8338                rendered.contains(d.descricao()),
8339                "Display must interpolate `dialeto.descricao()` verbatim. \
8340                 dialect: {d}, rendered: {rendered:?}"
8341            );
8342            assert!(
8343                rendered.contains(d.consumidor()),
8344                "Display must interpolate `dialeto.consumidor()` verbatim. \
8345                 dialect: {d}, rendered: {rendered:?}"
8346            );
8347        }
8348    }
8349
8350    #[test]
8351    fn from_lisp_rejects_molde_dialect_via_typed_variant() {
8352        // The end-to-end pin the compounding closure defends: a
8353        // Molde-dialect source lands as [`LeituraError::DialetoEstrangeiro`]
8354        // carrying [`crate::dialeto::CaixaDialeto::Molde`], and the
8355        // rendered Display byte-string names the Molde accessors'
8356        // returns verbatim. Any future path that constructed the variant
8357        // with a mismatched snapshot (a stored `palavra_canonica:
8358        // "defcaixa"` on a `Molde` classification) would land Display
8359        // pointing at `defcaixa` while the typed axis said `Molde` — the
8360        // exact drift the closure removes.
8361        let src = r#"
8362          (defcaixa
8363            :name "x"
8364            :kind :Biblioteca
8365            :ecosystem :rust-single-crate
8366            :package {:name "x" :version "0.1.0"})
8367        "#;
8368        let err = Caixa::from_lisp(src).expect_err("Molde dialect must not parse as Pacote");
8369        match err {
8370            LeituraError::DialetoEstrangeiro { dialeto } => {
8371                assert_eq!(dialeto, crate::dialeto::CaixaDialeto::Molde);
8372                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
8373                assert!(rendered.contains(dialeto.palavra_canonica()));
8374                assert!(rendered.contains(dialeto.consumidor()));
8375                assert!(rendered.contains(dialeto.descricao()));
8376            }
8377            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
8378        }
8379    }
8380
8381    #[test]
8382    fn from_lisp_rejects_molde_posicional_dialect_via_typed_variant() {
8383        // Coverage pin for the [`crate::dialeto::CaixaDialeto::MoldePosicional`]
8384        // arm of the [`Caixa::from_lisp`] foreign-dialect gate — the
8385        // positional-arity `defmolde` form written under a `(defcaixa …)`
8386        // head (`(defcaixa todoku-go :kind :Biblioteca :ecosystem :go
8387        // …)`). Pre-lift this arm rode the same `foreign =>` wildcard
8388        // the [`crate::dialeto::CaixaDialeto::Molde`] sibling arm rode,
8389        // so no test exercised the positional-arity path through
8390        // `Caixa::from_lisp` specifically; the sibling
8391        // [`from_lisp_rejects_molde_dialect_via_typed_variant`] only
8392        // covered [`crate::dialeto::CaixaDialeto::Molde`]. Post-lift the
8393        // two arms route through the lifted
8394        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
8395        // typed predicate — the same predicate the pre-lift `foreign =>`
8396        // wildcard resolved to today — and this pin makes the
8397        // positional-arity arm's byte-shape at the gate explicit rather
8398        // than implied by wildcard-absorption. A future regression that
8399        // silently reordered [`crate::dialeto::CaixaDialeto::is_molde_family`]'s
8400        // arm-set (dropped [`crate::dialeto::CaixaDialeto::MoldePosicional`]
8401        // from the two-arity closure) would fail this pin at caixa-core
8402        // test time rather than surfacing far from the change as a
8403        // `caixa.lisp` carrying a `(defcaixa todoku-go :ecosystem :go
8404        // …)` silently parsing past the derive.
8405        let src = r#"
8406          (defcaixa todoku-go
8407            :kind :Biblioteca
8408            :ecosystem :go
8409            :package {:name "todoku-go" :version "0.3.0"})
8410        "#;
8411        let err =
8412            Caixa::from_lisp(src).expect_err("MoldePosicional dialect must not parse as Pacote");
8413        match err {
8414            LeituraError::DialetoEstrangeiro { dialeto } => {
8415                assert_eq!(
8416                    dialeto,
8417                    crate::dialeto::CaixaDialeto::MoldePosicional,
8418                    "DialetoEstrangeiro must carry the MoldePosicional \
8419                     variant verbatim — the positional-arity `defmolde` \
8420                     form under a `(defcaixa …)` head is the \
8421                     `MoldePosicional` arm's canonical byte-shape"
8422                );
8423                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
8424                assert!(
8425                    rendered.contains(dialeto.palavra_canonica()),
8426                    "Display must interpolate `dialeto.palavra_canonica()` \
8427                     verbatim on the MoldePosicional arm; rendered: \
8428                     {rendered:?}"
8429                );
8430                assert!(
8431                    rendered.contains(dialeto.consumidor()),
8432                    "Display must interpolate `dialeto.consumidor()` \
8433                     verbatim on the MoldePosicional arm; rendered: \
8434                     {rendered:?}"
8435                );
8436                assert!(
8437                    rendered.contains(dialeto.descricao()),
8438                    "Display must interpolate `dialeto.descricao()` \
8439                     verbatim on the MoldePosicional arm; rendered: \
8440                     {rendered:?}"
8441                );
8442            }
8443            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
8444        }
8445    }
8446
8447    #[test]
8448    fn from_lisp_dialect_gate_dispatches_through_caixa_dialeto_is_molde_family_predicate() {
8449        // Load-bearing byte-parity pin: for every arm in
8450        // [`crate::dialeto::CaixaDialeto::ALL`], the
8451        // [`Caixa::from_lisp`] foreign-dialect gate's DialetoEstrangeiro
8452        // partition must agree with the lifted
8453        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
8454        // typed predicate — i.e. from_lisp raises
8455        // [`LeituraError::DialetoEstrangeiro`] carrying `d` iff
8456        // `d.is_molde_family()` returns `true`, and does NOT raise
8457        // [`LeituraError::DialetoEstrangeiro`] on any arm where the
8458        // predicate returns `false` (the arm's source falls through to
8459        // the derive — parses cleanly on
8460        // [`crate::dialeto::CaixaDialeto::Pacote`], surfaces a
8461        // [`LeituraError::Leitura`] on
8462        // [`crate::dialeto::CaixaDialeto::Desconhecido`]).
8463        //
8464        // Pre-lift the gate hand-rolled a three-arm match
8465        // (`Pacote => {}`, `Desconhecido => {}`, `foreign => Err(…)`)
8466        // whose `foreign =>` wildcard expressed no compile-time link
8467        // back to the substrate primitive's arm-family; a future fifth
8468        // dialect the [`crate::dialeto`] module doc's "third dialect"
8469        // hazard actualises would fall silently onto the wildcard
8470        // regardless of whether it belonged to the `defmolde` family or
8471        // to a distinct `defcaixa`-family. Post-lift the partition
8472        // resolves through
8473        // [`crate::dialeto::CaixaDialeto::is_molde_family`]'s single
8474        // typed dispatch, and this pin refuses any future regression
8475        // that silently split the from_lisp partition from the typed
8476        // predicate — the two paths now migrate as one on any future
8477        // arm addition.
8478        //
8479        // Sibling in shape to the peer
8480        // [`crate::dialeto::tests::caixa_dialeto_is_molde_family_agrees_with_palavra_canonica_defmolde_projection`]
8481        // (e9d2315) that pins the same byte-parity between
8482        // [`crate::dialeto::CaixaDialeto::is_molde_family`] and the
8483        // sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
8484        // `== "defmolde"` classifier — extends the discipline from the
8485        // two paths within the [`crate::dialeto`] primitive onto the
8486        // third external consumer of the `defmolde`-family partition
8487        // (the [`Caixa::from_lisp`] gate that raises
8488        // [`LeituraError::DialetoEstrangeiro`]).
8489        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
8490            (
8491                crate::dialeto::CaixaDialeto::Pacote,
8492                r#"
8493                  (defcaixa
8494                    :nome   "checkout"
8495                    :versao "0.1.0"
8496                    :kind   Biblioteca
8497                    :edicao "2026"
8498                    :descricao "canonical Pacote source"
8499                    :autores ()
8500                    :etiquetas ()
8501                    :deps ()
8502                    :deps-dev ()
8503                    :bibliotecas ("lib/checkout.lisp"))
8504                "#,
8505            ),
8506            (
8507                crate::dialeto::CaixaDialeto::Molde,
8508                r#"
8509                  (defcaixa
8510                    :name "base64"
8511                    :kind :Biblioteca
8512                    :ecosystem :rust-single-crate
8513                    :package {:name "base64" :version "0.22.1"}
8514                    :workflows [:auto-release])
8515                "#,
8516            ),
8517            (
8518                crate::dialeto::CaixaDialeto::MoldePosicional,
8519                r#"
8520                  (defcaixa todoku-go
8521                    :kind :Biblioteca
8522                    :ecosystem :go
8523                    :package {:name "todoku-go" :version "0.3.0"})
8524                "#,
8525            ),
8526            (
8527                crate::dialeto::CaixaDialeto::Desconhecido,
8528                r#"(defcaixa :licenca "MIT")"#,
8529            ),
8530        ];
8531
8532        // Coverage: every arm in [`crate::dialeto::CaixaDialeto::ALL`]
8533        // must appear in the fixture table so the pin's arm-set stays
8534        // synchronised with the enum's arm-set. Fails at test time if a
8535        // future fifth arm added to [`crate::dialeto::CaixaDialeto`]
8536        // (with a corresponding `is_molde_family` return) forgot to
8537        // extend this fixture table with a canonical source for the new
8538        // arm — the pin cannot cover an arm it has no source for.
8539        for &expected in crate::dialeto::CaixaDialeto::ALL {
8540            assert!(
8541                fixtures.iter().any(|(d, _)| *d == expected),
8542                "fixture table must carry a canonical source for every \
8543                 CaixaDialeto arm; missing: {expected:?}"
8544            );
8545        }
8546
8547        for &(expected_dialect, src) in fixtures {
8548            let classified = crate::dialeto::classify(src.trim()).unwrap_or_else(|err| {
8549                panic!(
8550                    "fixture source for {expected_dialect:?} must classify \
8551                     cleanly, got err: {err:?}"
8552                )
8553            });
8554            assert_eq!(
8555                classified, expected_dialect,
8556                "fixture source for {expected_dialect:?} must classify as \
8557                 {expected_dialect:?} (drift here defeats the byte-parity \
8558                 pin below — a source labelled for one arm but classifying \
8559                 as another would silently satisfy or violate the pin for \
8560                 the wrong reason)"
8561            );
8562
8563            let outcome = Caixa::from_lisp(src);
8564            match (expected_dialect.is_molde_family(), &outcome) {
8565                (true, Err(LeituraError::DialetoEstrangeiro { dialeto })) => {
8566                    assert_eq!(
8567                        *dialeto, expected_dialect,
8568                        "DialetoEstrangeiro must carry the same typed arm \
8569                         the classifier returned — a drift here would let \
8570                         from_lisp raise the error while pointing at the \
8571                         wrong dialect (e.g. rejecting a \
8572                         MoldePosicional source as Molde). arm: \
8573                         {expected_dialect:?}"
8574                    );
8575                }
8576                (true, other) => panic!(
8577                    "arm {expected_dialect:?} has is_molde_family() = true \
8578                     so from_lisp must raise DialetoEstrangeiro carrying \
8579                     {expected_dialect:?}; got: {other:?}"
8580                ),
8581                (false, Err(LeituraError::DialetoEstrangeiro { dialeto })) => panic!(
8582                    "arm {expected_dialect:?} has is_molde_family() = false \
8583                     so from_lisp must NOT raise DialetoEstrangeiro; got \
8584                     one carrying: {dialeto:?}. This means the typed \
8585                     predicate and the from_lisp partition disagree on \
8586                     this arm — exactly the drift this pin refuses."
8587                ),
8588                (false, _) => {
8589                    // A non-molde arm's source falls through to the
8590                    // derive: Pacote sources parse to Ok(_); Desconhecido
8591                    // sources surface as LeituraError::Leitura from the
8592                    // derive's own unknown-keyword rejection. Either
8593                    // shape is acceptable here — the pin's promise is
8594                    // narrower: "no DialetoEstrangeiro on
8595                    // is_molde_family() == false".
8596                }
8597            }
8598        }
8599    }
8600
8601    // ── M2 typed-substrate slot tests (limits, behavior, upgrade-from, supervisor) ──
8602
8603    #[test]
8604    fn limits_round_trip_via_json() {
8605        use crate::LimitsSpec;
8606        use std::time::Duration;
8607        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8608        c.limits = Some(LimitsSpec {
8609            memory: Some(64 * 1024 * 1024),
8610            fuel: Some(1_000_000),
8611            wall_clock: Some(Duration::from_secs(30)),
8612            cpu: Some(500),
8613        });
8614        let json = serde_json::to_string(&c).unwrap();
8615        assert!(json.contains("\"limits\""));
8616        assert!(json.contains("\"64MiB\""));
8617        assert!(json.contains("\"30s\""));
8618        assert!(json.contains("\"500m\""));
8619        let back: Caixa = serde_json::from_str(&json).unwrap();
8620        assert_eq!(c.limits, back.limits);
8621    }
8622
8623    #[test]
8624    fn behavior_round_trip_via_json() {
8625        use crate::BehaviorSpec;
8626        use std::path::PathBuf;
8627        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8628        c.behavior = Some(BehaviorSpec {
8629            on_init: Some(PathBuf::from("lib/init.lisp")),
8630            on_call: Some(PathBuf::from("lib/handlers.lisp")),
8631            ..Default::default()
8632        });
8633        let json = serde_json::to_string(&c).unwrap();
8634        let back: Caixa = serde_json::from_str(&json).unwrap();
8635        assert_eq!(c.behavior, back.behavior);
8636    }
8637
8638    #[test]
8639    fn upgrade_from_round_trip_via_json() {
8640        use crate::{UpgradeFromEntry, UpgradeInstruction};
8641        use std::path::PathBuf;
8642        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8643        c.upgrade_from = vec![UpgradeFromEntry {
8644            from: "0.1.0".into(),
8645            instructions: vec![
8646                UpgradeInstruction::LoadModule {
8647                    module: "demo".into(),
8648                },
8649                UpgradeInstruction::StateChange {
8650                    script: PathBuf::from("lib/migrations/v01-to-v02.lisp"),
8651                },
8652                UpgradeInstruction::SoftPurge {
8653                    module: "demo-old".into(),
8654                },
8655            ],
8656        }];
8657        let json = serde_json::to_string(&c).unwrap();
8658        let back: Caixa = serde_json::from_str(&json).unwrap();
8659        assert_eq!(c.upgrade_from, back.upgrade_from);
8660    }
8661
8662    #[test]
8663    fn supervisor_view_returns_typed_shape() {
8664        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
8665        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
8666        c.kind = CaixaKind::Supervisor;
8667        c.bibliotecas.clear();
8668        c.estrategia = Some(RestartStrategy::OneForOne);
8669        c.max_restarts = Some(5);
8670        c.restart_window = Some("60s".into());
8671        c.children = vec![ChildSpec {
8672            caixa: "worker".into(),
8673            versao: "^0.1".into(),
8674            restart: RestartPolicy::Permanent,
8675        }];
8676        let view = c.supervisor_view().expect("Supervisor kind has a view");
8677        assert_eq!(view.estrategia, RestartStrategy::OneForOne);
8678        assert_eq!(view.max_restarts, 5);
8679        assert_eq!(
8680            view.restart_window,
8681            Some(std::time::Duration::from_secs(60))
8682        );
8683        assert_eq!(view.children.len(), 1);
8684        view.validate().unwrap();
8685    }
8686
8687    #[test]
8688    fn supervisor_view_none_for_non_supervisor_kinds() {
8689        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8690        assert!(c.supervisor_view().is_none());
8691    }
8692
8693    #[test]
8694    fn declared_mesh_slots_empty_for_bare_caixa() {
8695        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8696        assert!(c.declared_mesh_slots().is_empty());
8697    }
8698
8699    #[test]
8700    fn declared_mesh_slots_reports_only_set_slots_in_canonical_order() {
8701        use crate::{Entrada, Membro};
8702        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8703        // Set a non-adjacent pair (:membros + :entrada) to pin that the
8704        // canonical declaration order is preserved regardless of which
8705        // subset is populated.
8706        c.membros = vec![Membro {
8707            caixa: "a".into(),
8708            versao: "^0.1".into(),
8709        }];
8710        c.entrada = Some(Entrada {
8711            host: "x.example.com".into(),
8712            para: "a".into(),
8713            paths: vec![],
8714            port: 8080,
8715        });
8716        assert_eq!(
8717            c.declared_mesh_slots(),
8718            vec![
8719                crate::render::M3_AUTHOR_KEY_MEMBROS,
8720                crate::render::M3_AUTHOR_KEY_ENTRADA,
8721            ]
8722        );
8723    }
8724
8725    #[test]
8726    fn m3_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8727        // Scalar-value pin: the five author-facing kebab-case labels the
8728        // `(defcaixa … :<slot> (…))` surface admits on the M3 top-level
8729        // mesh slot axis, one arm per typed slot. Mirrors the peer
8730        // scalar-value pin the sibling
8731        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
8732        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
8733        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] M2 top-level slot consts
8734        // carry (f49c8b0), so both altitudes of the typed-slot algebra
8735        // (per-Servico M2 + per-Aplicacao M3) share the same
8736        // "one canonical byte-string per arm" discipline. A future
8737        // rebrand (`:membros` → `:members`, `:contratos` → `:contracts`,
8738        // `:politicas` → `:policies`, `:placement` → `:distribution`,
8739        // `:entrada` → `:ingress`) lands as an edit to exactly one const,
8740        // and every consumer that reaches for the label picks it up at
8741        // build time rather than at runtime as a downstream mismatch.
8742        assert_eq!(crate::render::M3_AUTHOR_KEY_MEMBROS, ":membros");
8743        assert_eq!(crate::render::M3_AUTHOR_KEY_CONTRATOS, ":contratos");
8744        assert_eq!(crate::render::M3_AUTHOR_KEY_POLITICAS, ":politicas");
8745        assert_eq!(crate::render::M3_AUTHOR_KEY_PLACEMENT, ":placement");
8746        assert_eq!(crate::render::M3_AUTHOR_KEY_ENTRADA, ":entrada");
8747    }
8748
8749    #[test]
8750    fn declared_mesh_slots_route_through_lifted_m3_author_key_consts() {
8751        // Production-through-const pin: the five per-arm labels the
8752        // [`Caixa::declared_mesh_slots`] tagger pushes onto its return
8753        // `Vec` route through the lifted
8754        // [`crate::M3_AUTHOR_KEY_MEMBROS`] /
8755        // [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
8756        // [`crate::M3_AUTHOR_KEY_POLITICAS`] /
8757        // [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
8758        // [`crate::M3_AUTHOR_KEY_ENTRADA`] consts, in canonical
8759        // declaration order. A future re-order or drift at the tagger
8760        // (a rename that reaches the tagger but not the const, or vice
8761        // versa) surfaces here at build time rather than at runtime as
8762        // a [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
8763        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8764        // commit. Mirror of the peer
8765        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
8766        // pin (f49c8b0) on the sibling per-Servico M2 top-level slot
8767        // axis.
8768        use crate::{Entrada, Membro, MeshPolicy, Placement, PlacementStrategy, WitContract};
8769        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8770        c.membros = vec![Membro {
8771            caixa: "a".into(),
8772            versao: "^0.1".into(),
8773        }];
8774        c.contratos = vec![WitContract {
8775            de: "a".into(),
8776            para: "a".into(),
8777            wit: "wasi:http/proxy".into(),
8778            endpoint: Some("/x".into()),
8779            subject: None,
8780            slot: None,
8781        }];
8782        c.politicas = Some(MeshPolicy::default());
8783        c.placement = Some(Placement {
8784            estrategia: PlacementStrategy::Replicated,
8785            clusters: vec!["rio".into()],
8786            affinity: None,
8787            shard_key: None,
8788        });
8789        c.entrada = Some(Entrada {
8790            host: "x.example.com".into(),
8791            para: "a".into(),
8792            paths: vec![],
8793            port: 8080,
8794        });
8795        assert_eq!(
8796            c.declared_mesh_slots(),
8797            vec![
8798                crate::render::M3_AUTHOR_KEY_MEMBROS,
8799                crate::render::M3_AUTHOR_KEY_CONTRATOS,
8800                crate::render::M3_AUTHOR_KEY_POLITICAS,
8801                crate::render::M3_AUTHOR_KEY_PLACEMENT,
8802                crate::render::M3_AUTHOR_KEY_ENTRADA,
8803            ]
8804        );
8805    }
8806
8807    #[test]
8808    fn declared_supervisor_slots_empty_for_bare_caixa() {
8809        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8810        assert!(c.declared_supervisor_slots().is_empty());
8811    }
8812
8813    #[test]
8814    fn declared_supervisor_slots_reports_only_set_slots_in_canonical_order() {
8815        use crate::RestartStrategy;
8816        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8817        // Set a non-adjacent pair (:estrategia + :restart-window) to pin
8818        // that the canonical declaration order is preserved regardless
8819        // of which subset is populated.
8820        c.estrategia = Some(RestartStrategy::OneForOne);
8821        c.restart_window = Some("60s".into());
8822        assert_eq!(
8823            c.declared_supervisor_slots(),
8824            vec![
8825                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8826                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8827            ]
8828        );
8829    }
8830
8831    #[test]
8832    fn supervisor_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8833        // Scalar-value pin: the four author-facing kebab-case labels the
8834        // `(defcaixa … :<slot> (…))` surface admits on the Supervisor
8835        // supervision-tree slot axis, one arm per typed slot. Mirrors the
8836        // peer scalar-value pins the sibling
8837        // [`crate::render::M2_AUTHOR_KEY_LIMITS`] /
8838        // [`crate::render::M2_AUTHOR_KEY_BEHAVIOR`] /
8839        // [`crate::render::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot
8840        // consts and [`crate::render::M3_AUTHOR_KEY_MEMBROS`] etc.
8841        // top-level M3 slot consts carry, so all three kind-scoped
8842        // typed-slot-family author-facing-label axes route through one
8843        // canonical per-arm declaration. A future rebrand
8844        // (`:estrategia` → `:strategy` for English uniformity,
8845        // `:max-restarts` → `:max-intensity` matching Erlang/OTP's
8846        // `MaxIntensity` name, `:restart-window` → `:period` matching
8847        // OTP's `Period` name, `:children` → `:workers` matching Elixir
8848        // idiom) lands as an edit to exactly one const, and every
8849        // consumer that reaches for the label picks it up at build time
8850        // rather than at runtime as a downstream mismatch.
8851        assert_eq!(
8852            crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8853            ":estrategia"
8854        );
8855        assert_eq!(
8856            crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
8857            ":max-restarts"
8858        );
8859        assert_eq!(
8860            crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8861            ":restart-window"
8862        );
8863        assert_eq!(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN, ":children");
8864    }
8865
8866    #[test]
8867    fn declared_supervisor_slots_route_through_lifted_supervisor_author_key_consts() {
8868        // Production-through-const pin: the four per-arm labels the
8869        // [`Caixa::declared_supervisor_slots`] tagger pushes onto its
8870        // return `Vec` route through the lifted
8871        // [`crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] /
8872        // [`crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`] /
8873        // [`crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW`] /
8874        // [`crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN`] consts, in
8875        // canonical declaration order. A future re-order or drift at the
8876        // tagger (a rename that reaches the tagger but not the const, or
8877        // vice versa) surfaces here at build time rather than at runtime
8878        // as a [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
8879        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8880        // commit. Mirror of the peer
8881        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
8882        // (f49c8b0) and
8883        // [`declared_mesh_slots_route_through_lifted_m3_author_key_consts`]
8884        // (882f498) pins on the sibling M2 / M3 top-level slot axes.
8885        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
8886        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8887        c.estrategia = Some(RestartStrategy::OneForOne);
8888        c.max_restarts = Some(5);
8889        c.restart_window = Some("60s".into());
8890        c.children = vec![ChildSpec {
8891            caixa: "worker".into(),
8892            versao: "^0.1".into(),
8893            restart: RestartPolicy::Permanent,
8894        }];
8895        assert_eq!(
8896            c.declared_supervisor_slots(),
8897            vec![
8898                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8899                crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
8900                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8901                crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN,
8902            ]
8903        );
8904    }
8905
8906    #[test]
8907    fn declared_servico_slots_empty_for_bare_caixa() {
8908        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8909        assert!(c.declared_servico_slots().is_empty());
8910    }
8911
8912    #[test]
8913    fn declared_servico_slots_reports_only_set_slots_in_canonical_order() {
8914        use crate::{UpgradeFromEntry, UpgradeInstruction};
8915        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8916        // Set a non-adjacent pair (:limits + :upgrade-from) to pin that
8917        // the canonical declaration order is preserved regardless of
8918        // which subset is populated.
8919        c.limits = Some(crate::LimitsSpec {
8920            fuel: Some(1_000_000),
8921            ..Default::default()
8922        });
8923        c.upgrade_from = vec![UpgradeFromEntry {
8924            from: "0.1.0".into(),
8925            instructions: vec![UpgradeInstruction::Restart],
8926        }];
8927        assert_eq!(
8928            c.declared_servico_slots(),
8929            vec![
8930                crate::render::M2_AUTHOR_KEY_LIMITS,
8931                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
8932            ]
8933        );
8934    }
8935
8936    #[test]
8937    fn m2_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8938        // Scalar-value pin: the three author-facing kebab-case labels
8939        // the `(defcaixa … :<slot> (…))` surface admits on the M2
8940        // top-level slot axis, one arm per typed slot. Mirrors the peer
8941        // scalar-value pin the sibling renderer-side
8942        // [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
8943        // [`crate::M2_KEY_UPGRADE_FROM`] camelCase overlay-container
8944        // consts carry, so both halves of the M2 top-level slot dual
8945        // axis (author-facing kebab-case label + renderer-side
8946        // camelCase overlay-container wire key) route through one
8947        // canonical per-arm declaration. A future rebrand
8948        // (`:limits` → `:sandbox` matching Lunatic per-process
8949        // terminology INSPIRATIONS §III.1, `:behavior` → `:gen-server`
8950        // matching Erlang's verbatim name, `:upgrade-from` → `:appup`
8951        // matching Erlang's verbatim appup name) lands as an edit to
8952        // exactly one const, and every consumer that reaches for the
8953        // label picks it up at build time rather than at runtime as a
8954        // downstream mismatch.
8955        assert_eq!(crate::render::M2_AUTHOR_KEY_LIMITS, ":limits");
8956        assert_eq!(crate::render::M2_AUTHOR_KEY_BEHAVIOR, ":behavior");
8957        assert_eq!(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM, ":upgrade-from");
8958    }
8959
8960    #[test]
8961    fn declared_servico_slots_route_through_lifted_m2_author_key_consts() {
8962        // Production-through-const pin: the three per-arm labels the
8963        // [`Caixa::declared_servico_slots`] tagger pushes onto its
8964        // return `Vec` route through the lifted
8965        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
8966        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
8967        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts, in canonical
8968        // declaration order. A future re-order or drift at the tagger
8969        // (a rename that reaches the tagger but not the const, or vice
8970        // versa) surfaces here at build time rather than at runtime as
8971        // a [`crate::LayoutError::ServicoSlotsOnNonServico`]
8972        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8973        // commit. Mirror of the peer
8974        // [`crate::behavior::BehaviorSpec::declared_slots`] production
8975        // tagger pin (889dc18) on the sibling per-callback axis.
8976        use crate::{BehaviorSpec, UpgradeFromEntry, UpgradeInstruction};
8977        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8978        c.limits = Some(crate::LimitsSpec {
8979            fuel: Some(1_000_000),
8980            ..Default::default()
8981        });
8982        c.behavior = Some(BehaviorSpec {
8983            on_init: Some(PathBuf::from("lib/init.lisp")),
8984            ..Default::default()
8985        });
8986        c.upgrade_from = vec![UpgradeFromEntry {
8987            from: "0.1.0".into(),
8988            instructions: vec![UpgradeInstruction::Restart],
8989        }];
8990        assert_eq!(
8991            c.declared_servico_slots(),
8992            vec![
8993                crate::render::M2_AUTHOR_KEY_LIMITS,
8994                crate::render::M2_AUTHOR_KEY_BEHAVIOR,
8995                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
8996            ]
8997        );
8998    }
8999
9000    #[test]
9001    fn existing_manifests_unaffected_by_new_optional_slots() {
9002        // Regression test: a caixa.lisp authored before M2 typed slots
9003        // should still parse + serialize cleanly. The bare `defcaixa`
9004        // emitted by `Caixa::template` has none of the new fields.
9005        let src = Caixa::template("legacy");
9006        let c = Caixa::from_lisp(&src).unwrap();
9007        assert!(c.limits.is_none());
9008        assert!(c.behavior.is_none());
9009        assert!(c.upgrade_from.is_empty());
9010        assert!(c.estrategia.is_none());
9011        assert!(c.children.is_empty());
9012
9013        // And to_lisp emits a manifest with the new slots in the
9014        // empty/default state — round-trippable.
9015        let emitted = c.to_lisp();
9016        let back = Caixa::from_lisp(&emitted).unwrap();
9017        assert_eq!(c, back);
9018    }
9019
9020    #[test]
9021    fn validate_deps_accepts_canonical_caixa() {
9022        // Positive control: the bare template — zero deps, zero
9023        // deps_dev — passes the gate trivially. A future axis added to
9024        // `Dep::validate` mustn't regress an empty-deps caixa to a
9025        // build error.
9026        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9027        c.validate_deps().unwrap();
9028    }
9029
9030    #[test]
9031    fn validate_deps_rejects_invalid_versao_in_deps() {
9032        // Fail-before-pass-after pin: a malformed `:deps :versao`
9033        // surfaces at validate_deps() time, not at lacre-resolve time.
9034        // Mirrors `rejects_invalid_membro_versao_requirement` and
9035        // `validate_rejects_invalid_child_versao_requirement` on the
9036        // other two `:versao` axes.
9037        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9038        c.deps = vec![Dep::simple("caixa-teia", "^bad-version")];
9039        let err = c.validate_deps().unwrap_err();
9040        assert!(
9041            matches!(
9042                err,
9043                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9044                    if nome == "caixa-teia" && versao == "^bad-version"
9045            ),
9046            "got {err:?}"
9047        );
9048    }
9049
9050    #[test]
9051    fn validate_deps_rejects_invalid_versao_in_deps_dev() {
9052        // Parity pin: `:deps-dev` must run through the same per-entry
9053        // validator as `:deps` — a typo in either axis surfaces the
9054        // same diagnostic. Without this leg, `:deps-dev` would be a
9055        // second-class citizen of the typed surface and an author
9056        // could land a build that passes validate_deps but fails at
9057        // `feira lock`-time when the dev-dep is resolved for a test
9058        // build.
9059        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9060        c.deps_dev = vec![Dep::simple("tatara-check", "^^0.1")];
9061        let err = c.validate_deps().unwrap_err();
9062        assert!(
9063            matches!(
9064                err,
9065                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9066                    if nome == "tatara-check" && versao == "^^0.1"
9067            ),
9068            "got {err:?}"
9069        );
9070    }
9071
9072    #[test]
9073    fn validate_deps_runs_deps_before_deps_dev() {
9074        // Order pin: when both lists carry typos, the `:deps`
9075        // diagnostic surfaces first. The author's mental model is
9076        // "runtime deps are load-bearing; dev deps are scaffolding";
9077        // surfacing the runtime axis first matches that hierarchy.
9078        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9079        c.deps = vec![Dep::simple("runtime-dep", "^bad-runtime")];
9080        c.deps_dev = vec![Dep::simple("dev-dep", "^bad-dev")];
9081        let err = c.validate_deps().unwrap_err();
9082        assert!(
9083            matches!(
9084                err,
9085                crate::dep::DepError::VersaoInvalid { ref nome, .. }
9086                    if nome == "runtime-dep"
9087            ),
9088            "expected `:deps` typo to surface first, got {err:?}"
9089        );
9090    }
9091
9092    #[test]
9093    fn validate_deps_accepts_canonical_versao_forms_in_both_lists() {
9094        // Positive control sweep across both lists. Pin every
9095        // canonical Cargo-shaped form so a future tightening of the
9096        // accepted set surfaces here as a test failure (parity with
9097        // `accepts_canonical_membro_versao_forms` and
9098        // `validate_accepts_canonical_child_versao_forms`).
9099        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9100        c.deps = vec![
9101            Dep::simple("caret", "^0.1"),
9102            Dep::simple("tilde", "~0.1.2"),
9103            Dep::simple("exact", "0.1.0"),
9104            Dep::simple("wildcard", "*"),
9105            Dep::simple("multi-range", ">=0.1, <2"),
9106        ];
9107        c.deps_dev = vec![
9108            Dep::simple("dev-caret", "^0.1"),
9109            Dep::simple("dev-wildcard", "*"),
9110        ];
9111        c.validate_deps().unwrap();
9112    }
9113
9114    #[test]
9115    fn validate_deps_diagnostic_carries_offending_dep() {
9116        // Diagnostic-shape pin: the error names the offending entry's
9117        // `:nome` + `:versao` verbatim and carries a non-empty
9118        // `reason` from `semver::VersionReq::parse`, so a `feira lint`
9119        // run can render the diagnostic without re-parsing.
9120        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9121        c.deps = vec![Dep::simple("caixa-teia", "not-a-req")];
9122        let err = c.validate_deps().unwrap_err();
9123        let crate::dep::DepError::VersaoInvalid {
9124            nome,
9125            versao,
9126            reason,
9127        } = err
9128        else {
9129            panic!("expected VersaoInvalid, got other variant");
9130        };
9131        assert_eq!(nome, "caixa-teia");
9132        assert_eq!(versao, "not-a-req");
9133        assert!(
9134            !reason.is_empty(),
9135            "VersaoInvalid `reason` must carry the parser's wording verbatim"
9136        );
9137    }
9138
9139    #[test]
9140    fn validate_deps_rejects_ambiguous_fonte_in_deps_dev() {
9141        // Cross-axis pin: `validate_deps` walks both :deps and
9142        // :deps-dev through `Dep::validate`, and the new fonte gate
9143        // (`:tag` + `:branch` both set — the canonical "pin drift"
9144        // footgun) must surface from the :deps-dev arm with the
9145        // offending entry's :nome named. Pin the :deps-dev arm
9146        // explicitly so a future shortcut that only walks :deps
9147        // surfaces here as a regression.
9148        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9149        c.deps_dev = vec![Dep {
9150            nome: "dev-only".into(),
9151            versao: "^0.1".into(),
9152            fonte: Some(crate::DepSource::Git {
9153                repo: "github:p/x".into(),
9154                tag: Some("v1".into()),
9155                rev: None,
9156                branch: Some("main".into()),
9157            }),
9158            opcional: false,
9159            caracteristicas: vec![],
9160        }];
9161        let err = c.validate_deps().unwrap_err();
9162        let crate::dep::DepError::FontePinAmbiguous { nome, pins } = err else {
9163            panic!("expected FontePinAmbiguous from :deps-dev walk");
9164        };
9165        assert_eq!(nome, "dev-only");
9166        assert!(pins.contains(":tag") && pins.contains(":branch"));
9167    }
9168
9169    #[test]
9170    fn validate_deps_rejects_empty_repo_in_deps() {
9171        // Parity pin on the :deps arm: an empty :repo on the runtime
9172        // deps list surfaces the same FonteRepoEmpty diagnostic the
9173        // dep.rs per-entry tests pin, naming the offending entry.
9174        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9175        c.deps = vec![Dep {
9176            nome: "runtime".into(),
9177            versao: "^0.1".into(),
9178            fonte: Some(crate::DepSource::Git {
9179                repo: String::new(),
9180                tag: Some("v1".into()),
9181                rev: None,
9182                branch: None,
9183            }),
9184            opcional: false,
9185            caracteristicas: vec![],
9186        }];
9187        let err = c.validate_deps().unwrap_err();
9188        assert!(
9189            matches!(
9190                err,
9191                crate::dep::DepError::FonteRepoEmpty { ref nome }
9192                    if nome == "runtime"
9193            ),
9194            "got {err:?}"
9195        );
9196    }
9197
9198    // ── validate_deps: within-list :nome set-not-multiset gate ─────────
9199
9200    #[test]
9201    fn validate_deps_rejects_duplicate_nome_in_deps() {
9202        // Fail-before-pass-after pin: two `:deps` entries naming the same
9203        // caixa carry two `:versao` / `:fonte` / feature triples that the
9204        // caixa-resolver's lacre pipeline collapses (the second silently
9205        // overwrites the first at `concrete_versao`-resolve time). The
9206        // gate surfaces the duplicate at validate-time, naming the
9207        // offending caixa + the list, before the resolver-side silent
9208        // drop. Mirrors the peer typed-graph duplicate gates
9209        // (`DuplicateChildCaixa`, `MembroDuplicate`, `DuplicateFrom`, …).
9210        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9211        c.deps = vec![
9212            Dep::simple("caixa-teia", "^0.1"),
9213            Dep::simple("caixa-teia", "^0.2"),
9214        ];
9215        let err = c.validate_deps().unwrap_err();
9216        assert!(
9217            matches!(
9218                err,
9219                crate::dep::DepError::DuplicateNome { ref nome, list }
9220                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9221            ),
9222            "got {err:?}"
9223        );
9224    }
9225
9226    #[test]
9227    fn validate_deps_rejects_duplicate_nome_in_deps_dev() {
9228        // Parity pin: `:deps-dev` runs through the same per-list
9229        // duplicate check as `:deps` — neither axis is a second-class
9230        // citizen of the set-not-multiset discipline.
9231        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9232        c.deps_dev = vec![
9233            Dep::simple("tatara-check", "*"),
9234            Dep::simple("tatara-check", "^0.1"),
9235        ];
9236        let err = c.validate_deps().unwrap_err();
9237        assert!(
9238            matches!(
9239                err,
9240                crate::dep::DepError::DuplicateNome { ref nome, list }
9241                    if nome == "tatara-check" && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
9242            ),
9243            "got {err:?}"
9244        );
9245    }
9246
9247    #[test]
9248    fn validate_deps_accepts_cross_list_same_nome() {
9249        // The Cargo `[dependencies]` + `[dev-dependencies]` override
9250        // convention is preserved: a name appearing in *both* lists is
9251        // valid (the dev-pin overrides at test/dev time). Only
9252        // within-list duplicates are structurally incoherent — pin the
9253        // permissive cross-list semantics so a future shortcut that
9254        // collapses the two seen-sets into one surfaces here as a test
9255        // failure.
9256        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9257        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
9258        c.deps_dev = vec![Dep::simple("caixa-teia", "^0.2")];
9259        c.validate_deps().unwrap();
9260    }
9261
9262    #[test]
9263    fn validate_deps_accepts_distinct_nome_in_both_lists() {
9264        // Positive control: distinct names within each list pass — the
9265        // gate's identity element on the canonical authoring shape.
9266        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9267        c.deps = vec![
9268            Dep::simple("caixa-teia", "^0.1"),
9269            Dep::simple("pleme-mesh", "*"),
9270        ];
9271        c.deps_dev = vec![
9272            Dep::simple("tatara-check", "*"),
9273            Dep::simple("dev-shim", "^0.1"),
9274        ];
9275        c.validate_deps().unwrap();
9276    }
9277
9278    #[test]
9279    fn validate_deps_per_entry_validate_fires_before_duplicate_in_deps() {
9280        // Diagnostic-precedence pin: a malformed `:versao` on the
9281        // duplicating entry surfaces its narrower `VersaoInvalid`
9282        // diagnostic first, before the cross-entry duplicate gate fires
9283        // — the canonical "per-entry shape before cross-entry uniqueness"
9284        // precedence every peer set-not-multiset gate establishes
9285        // (`*_invalid_fires_before_duplicate_check` pins on
9286        // `SupervisorSpec::validate`, `AplicacaoSpec::validate_membros`,
9287        // `validate_upgrade_from`).
9288        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9289        c.deps = vec![
9290            Dep::simple("caixa-teia", "^0.1"),
9291            Dep::simple("caixa-teia", "^bad-version"),
9292        ];
9293        let err = c.validate_deps().unwrap_err();
9294        assert!(
9295            matches!(
9296                err,
9297                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9298                    if nome == "caixa-teia" && versao == "^bad-version"
9299            ),
9300            "expected VersaoInvalid to surface before DuplicateNome, got {err:?}"
9301        );
9302    }
9303
9304    #[test]
9305    fn validate_deps_duplicate_diagnostic_names_first_collision() {
9306        // First-collision determinism pin: with three entries naming the
9307        // same caixa, the first colliding pair surfaces — not the last.
9308        // Mirrors the peer first-collision posture on every
9309        // duplicate-target gate
9310        // (`validate_upgrade_from_duplicate_diagnostic_names_second_collision`
9311        // — the second entry is the first collision; this gate uses the
9312        // same shape: the second entry's `:nome` lands in the diagnostic
9313        // because `seen.insert(first.nome)` already populated the set).
9314        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9315        c.deps = vec![
9316            Dep::simple("caixa-teia", "^0.1"),
9317            Dep::simple("caixa-teia", "^0.2"),
9318            Dep::simple("caixa-teia", "^0.3"),
9319        ];
9320        let err = c.validate_deps().unwrap_err();
9321        // The diagnostic carries the offending caixa name; the
9322        // implementation surfaces on the *second* entry (the first
9323        // collision), so the test pins the `:nome` value.
9324        assert!(
9325            matches!(
9326                err,
9327                crate::dep::DepError::DuplicateNome { ref nome, list }
9328                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9329            ),
9330            "got {err:?}"
9331        );
9332    }
9333
9334    #[test]
9335    fn validate_deps_duplicate_in_deps_fires_before_duplicate_in_deps_dev() {
9336        // Cross-list precedence pin: when both lists carry duplicates,
9337        // the `:deps` diagnostic surfaces first — same author-mental-
9338        // model ordering the `validate_deps_runs_deps_before_deps_dev`
9339        // pin establishes for malformed `:versao` (runtime axis before
9340        // dev axis).
9341        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9342        c.deps = vec![
9343            Dep::simple("runtime-dep", "^0.1"),
9344            Dep::simple("runtime-dep", "^0.2"),
9345        ];
9346        c.deps_dev = vec![Dep::simple("dev-dep", "*"), Dep::simple("dev-dep", "^0.1")];
9347        let err = c.validate_deps().unwrap_err();
9348        assert!(
9349            matches!(
9350                err,
9351                crate::dep::DepError::DuplicateNome { ref nome, list }
9352                    if nome == "runtime-dep" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9353            ),
9354            "expected :deps duplicate to surface before :deps-dev duplicate, got {err:?}"
9355        );
9356    }
9357
9358    #[test]
9359    fn validate_deps_empty_lists_pass_duplicate_gate() {
9360        // Empty-set identity pin: the bare template (zero deps, zero
9361        // deps_dev) passes the duplicate gate as the gate's identity
9362        // element. A future tighten that conflates "empty" with
9363        // "missing" would regress this baseline.
9364        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9365        c.validate_deps().unwrap();
9366    }
9367
9368    #[test]
9369    fn validate_deps_duplicate_diagnostic_carries_list_tag() {
9370        // Diagnostic-shape pin: the `list:` field tags which list the
9371        // duplicate landed in (`:deps` vs `:deps-dev`) verbatim, so a
9372        // `feira lint` run can route the author to the right block in
9373        // their caixa.lisp without re-deriving the list from context.
9374        // Same self-locating shape every peer per-axis diagnostic
9375        // already exposes.
9376        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9377        c.deps_dev = vec![
9378            Dep::simple("dev-thing", "*"),
9379            Dep::simple("dev-thing", "^0.1"),
9380        ];
9381        let err = c.validate_deps().unwrap_err();
9382        let crate::dep::DepError::DuplicateNome { nome, list } = err else {
9383            panic!("expected DuplicateNome from :deps-dev walk");
9384        };
9385        assert_eq!(nome, "dev-thing");
9386        assert_eq!(list, crate::render::DEP_AUTHOR_KEY_DEPS_DEV);
9387    }
9388
9389    // ── validate_deps: per-entry :caracteristicas set-discipline gate ──
9390
9391    #[test]
9392    fn validate_deps_surfaces_caracteristicas_duplicate_in_deps_list() {
9393        // Thread-through pin on `:deps`: the per-entry
9394        // `Dep::validate_caracteristicas` gate fires inside
9395        // `Caixa::validate_deps`'s linear walk, so a malformed feature
9396        // list on any `:deps` entry surfaces as a `DepError` from
9397        // `validate_deps` — the same reachability shape every per-entry
9398        // `Dep::validate` arm threads through. Without this pin a future
9399        // shortcut that skips the per-entry `Dep::validate` call on the
9400        // cross-entry-uniqueness path would mask the within-entry
9401        // `:caracteristicas` gates.
9402        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9403        c.deps = vec![Dep {
9404            nome: "caixa-teia".into(),
9405            versao: "^0.1".into(),
9406            fonte: None,
9407            opcional: false,
9408            caracteristicas: vec!["http".into(), "http".into()],
9409        }];
9410        let err = c.validate_deps().unwrap_err();
9411        let crate::dep::DepError::CaracteristicaDuplicate {
9412            nome,
9413            caracteristica,
9414        } = err
9415        else {
9416            panic!("expected CaracteristicaDuplicate from :deps walk, got {err:?}");
9417        };
9418        assert_eq!(nome, "caixa-teia");
9419        assert_eq!(caracteristica, "http");
9420    }
9421
9422    #[test]
9423    fn validate_deps_surfaces_caracteristicas_empty_in_deps_dev_list() {
9424        // Peer thread-through pin on `:deps-dev`: same reachability as
9425        // the `:deps` arm above, on the dev-only authoring axis. Pins
9426        // that the `validate_deps` walk visits both lists' per-entry
9427        // gates uniformly. The empty-feature arm carries here so both
9428        // new `:caracteristicas` arms are surfaced via at least one
9429        // `validate_deps` thread-through.
9430        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9431        c.deps_dev = vec![Dep {
9432            nome: "caixa-teia".into(),
9433            versao: "^0.1".into(),
9434            fonte: None,
9435            opcional: false,
9436            caracteristicas: vec![String::new()],
9437        }];
9438        let err = c.validate_deps().unwrap_err();
9439        let crate::dep::DepError::CaracteristicaEmpty { nome } = err else {
9440            panic!("expected CaracteristicaEmpty from :deps-dev walk, got {err:?}");
9441        };
9442        assert_eq!(nome, "caixa-teia");
9443    }
9444
9445    #[test]
9446    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_list() {
9447        // Thread-through pin on `:deps`: the per-entry
9448        // `Dep::validate_caracteristicas` value-shape gate (lifted via
9449        // `crate::render::is_cargo_feature_name`) fires inside
9450        // `Caixa::validate_deps`'s linear walk on the `:deps` list, so
9451        // a structurally invalid feature name on any `:deps` entry
9452        // surfaces as `DepError::CaracteristicaInvalid` from
9453        // `validate_deps` — the same reachability shape every per-entry
9454        // `Dep::validate` arm threads through. Without this pin a
9455        // future shortcut that skips the per-entry `Dep::validate` call
9456        // on the cross-entry-uniqueness path would mask the within-
9457        // entry `:caracteristicas` value-shape gate.
9458        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9459        c.deps = vec![Dep {
9460            nome: "caixa-teia".into(),
9461            versao: "^0.1".into(),
9462            fonte: None,
9463            opcional: false,
9464            caracteristicas: vec!["+http".into()],
9465        }];
9466        let err = c.validate_deps().unwrap_err();
9467        let crate::dep::DepError::CaracteristicaInvalid {
9468            nome,
9469            caracteristica,
9470            ..
9471        } = err
9472        else {
9473            panic!("expected CaracteristicaInvalid from :deps walk, got {err:?}");
9474        };
9475        assert_eq!(nome, "caixa-teia");
9476        assert_eq!(caracteristica, "+http");
9477    }
9478
9479    #[test]
9480    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_dev_list() {
9481        // Peer thread-through pin on `:deps-dev`: same reachability as
9482        // the `:deps` arm above, on the dev-only authoring axis. The
9483        // `http/json` shape carries here so the segment-separator
9484        // diagnostic (the canonical Cargo `dep/feat` namespaced-dep
9485        // confusion footgun) is surfaced via the cross-entry walk too —
9486        // pinning that the `:deps-dev` list visits the same per-entry
9487        // value-shape gate as the `:deps` list.
9488        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9489        c.deps_dev = vec![Dep {
9490            nome: "caixa-teia".into(),
9491            versao: "^0.1".into(),
9492            fonte: None,
9493            opcional: false,
9494            caracteristicas: vec!["http/json".into()],
9495        }];
9496        let err = c.validate_deps().unwrap_err();
9497        let crate::dep::DepError::CaracteristicaInvalid {
9498            nome,
9499            caracteristica,
9500            ..
9501        } = err
9502        else {
9503            panic!("expected CaracteristicaInvalid from :deps-dev walk, got {err:?}");
9504        };
9505        assert_eq!(nome, "caixa-teia");
9506        assert_eq!(caracteristica, "http/json");
9507    }
9508
9509    #[test]
9510    fn to_lisp_preserves_deps() {
9511        let src = r#"
9512(defcaixa
9513  :nome "x"
9514  :versao "0.1.0"
9515  :kind Biblioteca
9516  :deps ((:nome "a" :versao "^0.1")
9517         (:nome "b" :versao "*" :fonte (:tipo git :repo "github:o/b" :tag "v1"))))
9518"#;
9519        let c1 = Caixa::from_lisp(src).unwrap();
9520        let emitted = c1.to_lisp();
9521        let c2 = Caixa::from_lisp(&emitted).expect("round trip");
9522        assert_eq!(c1.deps, c2.deps);
9523    }
9524
9525    // ── Caixa::validate_nome — top-level :nome value-shape gate ─────────
9526
9527    fn caixa_with_nome(nome: &str) -> Caixa {
9528        let mut c = Caixa::from_lisp(&Caixa::template("placeholder")).unwrap();
9529        c.nome = nome.to_string();
9530        c
9531    }
9532
9533    #[test]
9534    fn validate_nome_accepts_canonical_template() {
9535        // Positive control: the bare `feira init`-style template's
9536        // `:nome` ("demo") is a canonical DNS-1123 label; the gate must
9537        // not regress this baseline shape. A future tightening of the
9538        // accepted set surfaces here as a test failure first.
9539        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9540        c.validate_nome().unwrap();
9541    }
9542
9543    #[test]
9544    fn validate_nome_accepts_canonical_forms() {
9545        // Positive-set sweep: each realistic caixa-name shape the K8s
9546        // apiserver accepts as a `metadata.name` label must pass —
9547        // single-word, hyphen-joined, version-suffixed, single-char,
9548        // two-char, digit-start (DNS-1123 allows this; the stricter
9549        // DNS-1035 Service-name rule doesn't), version-suffix-bearing.
9550        // Mirrors `accepts_canonical_membro_caixa_forms` (3f9d7a0) on
9551        // the peer member-name axis.
9552        for nome in [
9553            "checkout",
9554            "cart-v2",
9555            "a",
9556            "db",
9557            "3rd-party-shim",
9558            "payment-retry",
9559            "0",
9560        ] {
9561            caixa_with_nome(nome)
9562                .validate_nome()
9563                .unwrap_or_else(|e| panic!("canonical :nome {nome:?} must validate, got {e:?}"));
9564        }
9565    }
9566
9567    #[test]
9568    fn validate_nome_rejects_empty() {
9569        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
9570        // an empty `:nome` (the derive macro stores the raw String);
9571        // the gate's empty arm names the offending axis with a narrower
9572        // diagnostic than the `NomeInvalid` parse arm would emit.
9573        let c = caixa_with_nome("");
9574        let err = c.validate_nome().unwrap_err();
9575        assert_eq!(err, ManifestError::NomeEmpty);
9576    }
9577
9578    #[test]
9579    fn validate_nome_rejects_uppercase() {
9580        // The canonical "I copied the TitleCase display name verbatim"
9581        // footgun. The K8s apiserver rejects `metadata.name: MyApp` at
9582        // admission on every derived artifact (Helm chart, ComputeUnit,
9583        // CNP, HTTPRoute, label values); the gate moves the diagnostic
9584        // to the source `caixa.lisp` and the reason suggests the
9585        // lowercased fix verbatim.
9586        let c = caixa_with_nome("MyApp");
9587        let err = c.validate_nome().unwrap_err();
9588        let ManifestError::NomeInvalid { nome, reason } = err else {
9589            panic!("expected NomeInvalid for uppercase :nome");
9590        };
9591        assert_eq!(nome, "MyApp");
9592        assert!(
9593            reason.contains("uppercase") && reason.contains("myapp"),
9594            "diagnostic must name the violation + the lowercased fix, got {reason:?}"
9595        );
9596    }
9597
9598    #[test]
9599    fn validate_nome_rejects_underscore() {
9600        // The Python-/Postgres-style `snake_case` leak. DNS-1123 forbids
9601        // `_`; the apiserver rejects on admission across every derived
9602        // artifact. Same fixture pinned for `:membros :caixa` (3f9d7a0)
9603        // and `:children :caixa` (31bfa43).
9604        let c = caixa_with_nome("my_app");
9605        let err = c.validate_nome().unwrap_err();
9606        assert!(
9607            matches!(
9608                err,
9609                ManifestError::NomeInvalid { ref nome, ref reason }
9610                    if nome == "my_app" && reason.contains('_')
9611            ),
9612            "got {err:?}"
9613        );
9614    }
9615
9616    #[test]
9617    fn validate_nome_rejects_dot() {
9618        // A `:nome` is a single DNS-1123 label, not a subdomain. The
9619        // "I want to namespace with `.`" footgun the gate redirects to
9620        // `-` via the shared predicate's reason wording.
9621        let c = caixa_with_nome("team.app");
9622        let err = c.validate_nome().unwrap_err();
9623        assert!(
9624            matches!(
9625                err,
9626                ManifestError::NomeInvalid { ref nome, ref reason }
9627                    if nome == "team.app" && reason.contains('.')
9628            ),
9629            "got {err:?}"
9630        );
9631    }
9632
9633    #[test]
9634    fn validate_nome_rejects_leading_hyphen() {
9635        // DNS-1123 boundary rule: the label must start with an ASCII
9636        // alphanumeric. Pin the leading-`-` arm explicitly.
9637        let c = caixa_with_nome("-app");
9638        let err = c.validate_nome().unwrap_err();
9639        assert!(
9640            matches!(
9641                err,
9642                ManifestError::NomeInvalid { ref nome, .. } if nome == "-app"
9643            ),
9644            "got {err:?}"
9645        );
9646    }
9647
9648    #[test]
9649    fn validate_nome_rejects_trailing_hyphen() {
9650        // Symmetric arm of the boundary rule, pinned separately so a
9651        // future relaxation that only checks the leading position
9652        // surfaces here. Mirrors `rejects_membro_caixa_with_trailing_hyphen`
9653        // and `_with_trailing_hyphen` on the supervisor / aplicacao
9654        // axes.
9655        let c = caixa_with_nome("app-");
9656        let err = c.validate_nome().unwrap_err();
9657        assert!(
9658            matches!(
9659                err,
9660                ManifestError::NomeInvalid { ref nome, .. } if nome == "app-"
9661            ),
9662            "got {err:?}"
9663        );
9664    }
9665
9666    #[test]
9667    fn validate_nome_rejects_unicode() {
9668        // IDN must be pre-encoded as Punycode (`xn--…`); raw Unicode
9669        // bytes are rejected by the K8s apiserver on every name axis.
9670        let c = caixa_with_nome("café");
9671        let err = c.validate_nome().unwrap_err();
9672        assert!(
9673            matches!(
9674                err,
9675                ManifestError::NomeInvalid { ref nome, .. } if nome == "café"
9676            ),
9677            "got {err:?}"
9678        );
9679    }
9680
9681    #[test]
9682    fn validate_nome_rejects_whitespace() {
9683        // The paste-from-sketch / paste-from-spec footgun. Internal
9684        // whitespace is rejected by every K8s name axis.
9685        let c = caixa_with_nome("my app");
9686        let err = c.validate_nome().unwrap_err();
9687        assert!(
9688            matches!(
9689                err,
9690                ManifestError::NomeInvalid { ref nome, .. } if nome == "my app"
9691            ),
9692            "got {err:?}"
9693        );
9694    }
9695
9696    #[test]
9697    fn validate_nome_rejects_too_long() {
9698        // 64-byte boundary pin: the K8s apiserver rejects any
9699        // `metadata.name` over 63 bytes at admission; the diagnostic
9700        // names both the 63-byte cap and the actual length so the
9701        // author can shorten in one edit. Mirrors `_too_long` on the
9702        // peer member-/cluster-/child-name axes.
9703        let over = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN + 1);
9704        let c = caixa_with_nome(&over);
9705        let err = c.validate_nome().unwrap_err();
9706        let ManifestError::NomeInvalid { nome, reason } = err else {
9707            panic!("expected NomeInvalid for over-cap :nome");
9708        };
9709        assert_eq!(nome.len(), crate::DNS_1123_LABEL_MAX_LEN + 1);
9710        assert!(
9711            reason.contains("63") && reason.contains("64"),
9712            "diagnostic must name the cap + actual length, got {reason:?}"
9713        );
9714    }
9715
9716    #[test]
9717    fn nome_max_length_validates() {
9718        // The 63-byte cap exactly — the boundary-accepting case pinned
9719        // alongside `validate_nome_rejects_too_long` so a future cap
9720        // shift surfaces both arms simultaneously. Mirrors
9721        // `membro_caixa_max_length_validates`,
9722        // `placement_cluster_max_length_validates`,
9723        // `child_caixa_max_length_validates`.
9724        let at_cap = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
9725        caixa_with_nome(&at_cap).validate_nome().unwrap();
9726    }
9727
9728    #[test]
9729    fn nome_empty_takes_precedence_over_invalid() {
9730        // Order pin: the empty arm fires before the predicate is
9731        // consulted. Empty < invalid in self-locating-ness — the
9732        // narrower `NomeEmpty` diagnostic doesn't carry a useless
9733        // `nome: ""` reference into the parser-shaped reason. Mirrors
9734        // `membro_caixa_empty_takes_precedence_over_invalid` on the
9735        // peer axis (3f9d7a0).
9736        let c = caixa_with_nome("");
9737        assert_eq!(c.validate_nome().unwrap_err(), ManifestError::NomeEmpty);
9738    }
9739
9740    #[test]
9741    fn nome_invalid_diagnostic_carries_offending_nome() {
9742        // Diagnostic-shape pin: the error names the offending `:nome`
9743        // verbatim with a non-empty parser-shaped reason, so a `feira
9744        // lint` run can render the diagnostic without re-parsing.
9745        // Mirrors `membro_caixa_invalid_diagnostic_carries_offending_caixa`.
9746        let c = caixa_with_nome("MyApp");
9747        let err = c.validate_nome().unwrap_err();
9748        let ManifestError::NomeInvalid { nome, reason } = err else {
9749            panic!("expected NomeInvalid variant");
9750        };
9751        assert_eq!(nome, "MyApp");
9752        assert!(
9753            !reason.is_empty(),
9754            "NomeInvalid `reason` must carry the predicate's wording verbatim"
9755        );
9756    }
9757
9758    // ── Caixa::validate_nome_chart_name_budget — joint-length on `:nome` ──
9759    //
9760    // The bare-`:nome` axis [`Caixa::validate_nome`] caps at 63 bytes
9761    // via DNS-1123; this second-axis gate caps the joint
9762    // `lareira-<nome>` chart name at the same 63-byte ceiling. The
9763    // canonical [`crate::lareira_chart_name`] helper's doc comment
9764    // (f7320d7, caixa-core/src/render.rs:3198) explicitly deferred:
9765    // "the M4 admission webhook will pin the joint-length invariant
9766    // when it lands". These tests pin it at the manifest-validate
9767    // layer instead, fail-before-pass-after on the 56-byte boundary.
9768
9769    #[test]
9770    fn validate_nome_chart_name_budget_accepts_canonical_template() {
9771        // Positive control: the bare `feira init`-style template's
9772        // `:nome` ("demo") sits far below the cap; the gate must not
9773        // regress this baseline. Same shape every peer
9774        // value-shape-gate baseline pin uses.
9775        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9776        c.validate_nome_chart_name_budget().unwrap();
9777    }
9778
9779    #[test]
9780    fn validate_nome_chart_name_budget_accepts_canonical_fixtures() {
9781        // Positive-set sweep across the canonical author surface every
9782        // in-tree fixture uses (`hello-rio`, `cart`, `checkout`,
9783        // `worker`, the `checkout-aplicacao` example members, the
9784        // `example-attest` caixa-tatara fixture). Every value sits
9785        // far below the 55-byte per-`:nome` budget. Same shape every
9786        // peer per-axis baseline pin uses.
9787        for nome in [
9788            "hello-rio",
9789            "cart",
9790            "checkout",
9791            "worker",
9792            "example-attest",
9793            "demo",
9794            "a",
9795        ] {
9796            caixa_with_nome(nome)
9797                .validate_nome_chart_name_budget()
9798                .unwrap_or_else(|e| {
9799                    panic!("canonical :nome {nome:?} must pass chart-name budget, got {e:?}")
9800                });
9801        }
9802    }
9803
9804    #[test]
9805    fn validate_nome_chart_name_budget_accepts_nome_at_cap() {
9806        // Boundary-accepting case at the 55-byte per-`:nome` budget —
9807        // the joint chart name is exactly 63 bytes, the DNS-1123 label
9808        // cap. Pinned alongside the rejecting-arm test so a future cap
9809        // shift surfaces both arms simultaneously. Mirrors
9810        // `nome_max_length_validates` on the peer bare-`:nome` axis.
9811        let at_cap = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN);
9812        caixa_with_nome(&at_cap)
9813            .validate_nome_chart_name_budget()
9814            .unwrap();
9815    }
9816
9817    #[test]
9818    fn validate_nome_chart_name_budget_rejects_nome_one_over_cap() {
9819        // Fail-before-pass-after pin on the 56-byte boundary: the
9820        // smallest `:nome` length that overflows the joint chart-name
9821        // cap. The inner [`is_dns_1123_label`] gate
9822        // (`Caixa::validate_nome`) accepts it (56 ≤ 63), so prior to
9823        // this gate it silently passed the manifest-validate cascade
9824        // and surfaced as a `helm lint` / apiserver rejection on the
9825        // rendered chart name far from the source `caixa.lisp`, with
9826        // no field naming the overflow. With this gate the diagnostic
9827        // names the offending `:nome` verbatim alongside the rendered
9828        // chart name and the budget, so the author can shorten in one
9829        // edit. Mirrors `validate_nome_rejects_too_long` on the peer
9830        // bare-`:nome` axis.
9831        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9832        let c = caixa_with_nome(&over);
9833        let err = c.validate_nome_chart_name_budget().unwrap_err();
9834        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
9835            panic!("expected NomeChartNameBudgetExceeded for over-budget :nome");
9836        };
9837        assert_eq!(nome.len(), crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9838        assert_eq!(nome, over);
9839        assert!(
9840            reason.contains("63") && reason.contains("64") && reason.contains("55"),
9841            "diagnostic must name the DNS-1123 cap (63), the actual chart-name length (64), \
9842             and the per-`:nome` budget (55), got {reason:?}"
9843        );
9844    }
9845
9846    #[test]
9847    fn validate_nome_chart_name_budget_rejects_nome_at_bare_dns_cap() {
9848        // The 63-byte `:nome` boundary — passes the bare-`:nome`
9849        // [`is_dns_1123_label`] cap exactly, but produces a 71-byte
9850        // joint chart name that overflows the DNS-1123 label cap
9851        // structurally. The most stringent fail-before-pass-after
9852        // surface: every `:nome` in the 56..=63-byte range passed the
9853        // prior cascade and broke at admission.
9854        let bare_max = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
9855        let c = caixa_with_nome(&bare_max);
9856        // The bare-`:nome` gate accepts the 63-byte length.
9857        c.validate_nome().unwrap();
9858        // The new joint-length gate rejects it.
9859        let err = c.validate_nome_chart_name_budget().unwrap_err();
9860        assert!(
9861            matches!(
9862                err,
9863                ManifestError::NomeChartNameBudgetExceeded { ref nome, .. }
9864                    if nome.len() == crate::DNS_1123_LABEL_MAX_LEN
9865            ),
9866            "got {err:?}"
9867        );
9868    }
9869
9870    #[test]
9871    fn validate_nome_chart_name_budget_diagnostic_carries_offending_chart_name() {
9872        // Diagnostic-shape pin: the rendered `lareira-<nome>` chart
9873        // name appears verbatim in the diagnostic so the author sees
9874        // exactly the string the apiserver / `helm lint` would have
9875        // rejected — no re-derivation required to grep the source.
9876        // Peer with `nome_invalid_diagnostic_carries_offending_nome`
9877        // on the bare-`:nome` axis.
9878        let over = "x".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 5);
9879        let c = caixa_with_nome(&over);
9880        let err = c.validate_nome_chart_name_budget().unwrap_err();
9881        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
9882            panic!("expected NomeChartNameBudgetExceeded variant");
9883        };
9884        assert_eq!(nome, over);
9885        let expected_chart = crate::lareira_chart_name(&over);
9886        assert!(
9887            reason.contains(&expected_chart),
9888            "diagnostic must carry the rendered chart name {expected_chart:?} verbatim, \
9889             got {reason:?}"
9890        );
9891        assert!(
9892            reason.contains("lareira-"),
9893            "diagnostic must name the canonical chart-name prefix verbatim, got {reason:?}"
9894        );
9895    }
9896
9897    #[test]
9898    fn validate_nome_chart_name_budget_runs_after_nome_shape_via_layout_verify() {
9899        // Order pin on the layout cascade: the narrower
9900        // `NomeInvalid` (bare-DNS-1123 shape) fires before the
9901        // joint-length budget. A structurally-malformed `:nome` (here:
9902        // uppercase) surfaces its specific shape error rather than
9903        // the chart-name-budget error, even when the joint length
9904        // would also overflow — the narrower diagnostic is more
9905        // self-locating. Mirrors the cascade-precedence pins peer
9906        // gates already use (e.g. `EntradaParaEmpty` before
9907        // `EntradaParaInvalid`).
9908        let over = "A".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9909        let c = caixa_with_nome(&over);
9910        // The bare-shape gate fires first.
9911        let err = c.validate_nome().unwrap_err();
9912        assert!(
9913            matches!(err, ManifestError::NomeInvalid { .. }),
9914            "bare-shape gate must fire before chart-name-budget gate; got {err:?}"
9915        );
9916        // And the layout verify cascade surfaces that diagnostic, not
9917        // the budget arm. Inject a path-exists oracle so the cascade
9918        // gets past the manifest-presence check and into the
9919        // value-shape gates.
9920        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
9921        let err = crate::LayoutInvariants::verify(
9922            &layout,
9923            &c,
9924            std::path::Path::new("/tmp/caixa-test-fake-root"),
9925        )
9926        .unwrap_err();
9927        let issue = err.to_string();
9928        assert!(
9929            issue.contains("DNS-1123") || issue.contains("uppercase"),
9930            "layout cascade must surface the bare-DNS-1123 diagnostic on a \
9931             structurally-malformed :nome, not the chart-name-budget diagnostic; got {issue:?}"
9932        );
9933    }
9934
9935    #[test]
9936    fn layout_verify_routes_chart_name_budget_through_nome_violation() {
9937        // Cross-axis envelope pin: the layout cascade wraps both
9938        // bare-`:nome` and joint-length-`:nome` failures through the
9939        // same [`LayoutError::NomeViolation`] envelope, since both
9940        // arms are on the `:nome` axis. The user's diagnostic stays
9941        // self-locating ("which axis"), and a future consumer that
9942        // dispatches on the layout-error variant (e.g. a `feira lint`
9943        // exit-code mapping) sees a single per-axis envelope. The
9944        // wrapped `issue:` carries the full inner diagnostic.
9945        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9946        let c = caixa_with_nome(&over);
9947        // The bare-shape gate accepts.
9948        c.validate_nome().unwrap();
9949        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
9950        let err = crate::LayoutInvariants::verify(
9951            &layout,
9952            &c,
9953            std::path::Path::new("/tmp/caixa-test-fake-root"),
9954        )
9955        .unwrap_err();
9956        let crate::LayoutError::NomeViolation { caixa, issue } = err else {
9957            panic!("expected LayoutError::NomeViolation, got {err:?}");
9958        };
9959        assert_eq!(caixa, over);
9960        assert!(
9961            issue.contains("lareira-") && issue.contains("63") && issue.contains("55"),
9962            "wrapped issue must carry the joint-length diagnostic verbatim, got {issue:?}"
9963        );
9964    }
9965
9966    // ── Caixa::validate_versao — top-level :versao value-shape gate ─────
9967
9968    fn caixa_with_versao(versao: &str) -> Caixa {
9969        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9970        c.versao = versao.to_string();
9971        c
9972    }
9973
9974    #[test]
9975    fn validate_versao_accepts_canonical_template() {
9976        // Positive control: the bare `feira init`-style template's
9977        // `:versao` ("0.1.0") is a canonical SemVer-2 literal; the gate
9978        // must not regress this baseline shape. A future tightening of
9979        // the accepted set surfaces here as a test failure first.
9980        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9981        c.validate_versao().unwrap();
9982    }
9983
9984    #[test]
9985    fn validate_versao_accepts_canonical_forms() {
9986        // Positive-set sweep: each realistic SemVer-2 shape the
9987        // substrate's downstream consumers accept must pass — bare
9988        // MAJOR.MINOR.PATCH, pre-release tags (`-rc.1`, `-alpha.0`),
9989        // build metadata (`+build.42`), the combined form, and the
9990        // `0.0.0` boundary case. Mirrors `accepts_canonical_forms` on
9991        // the peer `:nome` axis (6c992f8).
9992        for versao in [
9993            "0.1.0",
9994            "0.0.0",
9995            "1.0.0",
9996            "0.2.0-rc.1",
9997            "1.0.0-alpha.0",
9998            "1.0.0+build.42",
9999            "1.0.0-rc.1+build.42",
10000            "10.20.30",
10001        ] {
10002            caixa_with_versao(versao)
10003                .validate_versao()
10004                .unwrap_or_else(|e| {
10005                    panic!("canonical :versao {versao:?} must validate, got {e:?}")
10006                });
10007        }
10008    }
10009
10010    #[test]
10011    fn validate_versao_rejects_empty() {
10012        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
10013        // an empty `:versao` (the derive macro stores the raw String);
10014        // the gate's empty arm names the offending axis with a narrower
10015        // diagnostic than the `VersaoInvalid` parse arm would emit.
10016        // Mirrors `validate_nome_rejects_empty` (6c992f8).
10017        let c = caixa_with_versao("");
10018        let err = c.validate_versao().unwrap_err();
10019        assert_eq!(err, ManifestError::VersaoEmpty);
10020    }
10021
10022    #[test]
10023    fn validate_versao_rejects_git_tag_shape() {
10024        // The canonical "I copied the git tag verbatim" footgun —
10025        // `feira publish` *emits* `v<versao>` git tags, so a leaked
10026        // `v0.1.0` in `:versao` would render as `vv0.1.0` and silently
10027        // shift every downstream consumer's version axis. `semver`
10028        // rejects the leading `v` at parse time; the gate moves the
10029        // diagnostic to the source `caixa.lisp`.
10030        let c = caixa_with_versao("v0.1.0");
10031        let err = c.validate_versao().unwrap_err();
10032        let ManifestError::VersaoInvalid { versao, reason } = err else {
10033            panic!("expected VersaoInvalid for git-tag-shape :versao");
10034        };
10035        assert_eq!(versao, "v0.1.0");
10036        assert!(
10037            !reason.is_empty(),
10038            "VersaoInvalid `reason` must carry the parser's wording, got {reason:?}"
10039        );
10040    }
10041
10042    #[test]
10043    fn validate_versao_rejects_missing_patch() {
10044        // The canonical "I shortened it" footgun — SemVer-2 requires
10045        // three parts. Cargo's `version =` field accepts the shortened
10046        // form as a requirement, conflating the two leaks across the
10047        // typed `:deps :versao` vs top-level `:versao` axes; the gate
10048        // pins the top-level axis to the strict three-part shape.
10049        let c = caixa_with_versao("0.1");
10050        let err = c.validate_versao().unwrap_err();
10051        assert!(
10052            matches!(
10053                err,
10054                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1"
10055            ),
10056            "got {err:?}"
10057        );
10058    }
10059
10060    #[test]
10061    fn validate_versao_rejects_requirement_shape() {
10062        // The canonical "I leaked a requirement into a version" footgun —
10063        // the typed `:deps :versao` / `:membros :versao` axes accept
10064        // `^0.1` (a `VersionReq`); the top-level `:versao` requires a
10065        // concrete `Version`. Without this gate the two typed surfaces
10066        // would silently overlap, and a top-level `^0.1` would surface
10067        // at `helm install` time as a Chart.yaml version rejection far
10068        // from the source `caixa.lisp`.
10069        let c = caixa_with_versao("^0.1");
10070        let err = c.validate_versao().unwrap_err();
10071        assert!(
10072            matches!(
10073                err,
10074                ManifestError::VersaoInvalid { ref versao, .. } if versao == "^0.1"
10075            ),
10076            "got {err:?}"
10077        );
10078    }
10079
10080    #[test]
10081    fn validate_versao_rejects_docker_tag_shape() {
10082        // The "I confused it with a docker tag" footgun — `latest`,
10083        // `main`, `stable` parse as identifiers, not SemVer-2 versions.
10084        // SemVer rejects at parse time; the gate moves the diagnostic
10085        // to the source `caixa.lisp`.
10086        for bad in ["latest", "main", "stable"] {
10087            let c = caixa_with_versao(bad);
10088            let err = c.validate_versao().unwrap_err();
10089            assert!(
10090                matches!(
10091                    err,
10092                    ManifestError::VersaoInvalid { ref versao, .. } if versao == bad
10093                ),
10094                "got {err:?} for {bad:?}"
10095            );
10096        }
10097    }
10098
10099    #[test]
10100    fn validate_versao_rejects_four_part_form() {
10101        // The Java/Microsoft "MAJOR.MINOR.PATCH.BUILD" convention
10102        // SemVer-2 forbids. A leak from a non-SemVer ecosystem; the
10103        // semver crate rejects the extra `.0` at parse time.
10104        let c = caixa_with_versao("0.1.0.0");
10105        let err = c.validate_versao().unwrap_err();
10106        assert!(
10107            matches!(
10108                err,
10109                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1.0.0"
10110            ),
10111            "got {err:?}"
10112        );
10113    }
10114
10115    #[test]
10116    fn versao_empty_takes_precedence_over_invalid() {
10117        // Order pin: the empty arm fires before the parser is consulted.
10118        // Empty < invalid in self-locating-ness — the narrower
10119        // `VersaoEmpty` diagnostic doesn't carry a useless `versao: ""`
10120        // reference into the parser-shaped reason. Mirrors
10121        // `nome_empty_takes_precedence_over_invalid` (6c992f8) on the
10122        // peer axis.
10123        let c = caixa_with_versao("");
10124        assert_eq!(c.validate_versao().unwrap_err(), ManifestError::VersaoEmpty);
10125    }
10126
10127    #[test]
10128    fn versao_invalid_diagnostic_carries_offending_versao() {
10129        // Diagnostic-shape pin: the error names the offending `:versao`
10130        // verbatim with a non-empty parser-shaped reason, so a `feira
10131        // lint` run can render the diagnostic without re-parsing.
10132        // Mirrors `nome_invalid_diagnostic_carries_offending_nome`.
10133        let c = caixa_with_versao("v0.1.0");
10134        let err = c.validate_versao().unwrap_err();
10135        let ManifestError::VersaoInvalid { versao, reason } = err else {
10136            panic!("expected VersaoInvalid variant");
10137        };
10138        assert_eq!(versao, "v0.1.0");
10139        assert!(
10140            !reason.is_empty(),
10141            "VersaoInvalid `reason` must carry the parser's wording verbatim"
10142        );
10143    }
10144
10145    #[test]
10146    fn validate_versao_accepts_what_upgrade_from_from_accepts() {
10147        // Parity pin: every shape `UpgradeFromEntry::validate` accepts
10148        // for `:upgrade-from :from` must also pass `validate_versao` —
10149        // the two `:versao`-typed surfaces (top-level `:versao`,
10150        // `:upgrade-from :from`) consume the *same* `semver::Version`
10151        // parser, so they must agree on the accepted set. Without this
10152        // pin, a future tightening of one axis could silently diverge
10153        // from the other. Mirrors the `:versao` requirement-axis
10154        // parity (`:deps`/`:deps-dev`/`:membros`/`:children`) the prior
10155        // commits established.
10156        for versao in ["0.1.0", "0.2.0-rc.1", "1.0.0+build.42"] {
10157            // From the canonical UpgradeFromEntry round-trip fixture
10158            // (`upgrade::tests::round_trip_load_module` peers).
10159            let entry = crate::UpgradeFromEntry {
10160                from: versao.to_string(),
10161                instructions: Vec::new(),
10162            };
10163            entry
10164                .validate()
10165                .unwrap_or_else(|e| panic!(":from {versao:?} must validate, got {e:?}"));
10166            caixa_with_versao(versao)
10167                .validate_versao()
10168                .unwrap_or_else(|e| {
10169                    panic!(":versao {versao:?} must validate, got {e:?} — peer axis diverges")
10170                });
10171        }
10172    }
10173
10174    // ── Caixa::validate_restart_window — supervisor restart-window
10175    //    folds through the shared `supervisor::duration_codec` ────────
10176
10177    fn caixa_with_restart_window(window: Option<&str>) -> Caixa {
10178        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
10179        c.kind = CaixaKind::Supervisor;
10180        c.restart_window = window.map(str::to_string);
10181        c
10182    }
10183
10184    #[test]
10185    fn validate_restart_window_accepts_none() {
10186        // The canonical "omit the slot to express no reset" shape — a
10187        // `None` raw string is the absence of the typed
10188        // `:restart-window` slot, which is exactly the SupervisorSpec
10189        // "never reset" semantics. The gate must be a no-op here; a
10190        // future tightening that rejected `None` would force every
10191        // supervisor caixa to authoring-time pin a window even when
10192        // the OTP semantics call for none.
10193        caixa_with_restart_window(None)
10194            .validate_restart_window()
10195            .unwrap();
10196    }
10197
10198    #[test]
10199    fn validate_restart_window_accepts_canonical_forms() {
10200        // Positive-set sweep across the canonical authoring units the
10201        // shared `supervisor::duration_codec::parse` accepts —
10202        // matches the codec-side `parse_accepts_integer_canonical_units`
10203        // pin in supervisor::tests so a future codec-side tightening
10204        // surfaces simultaneously on both axes.
10205        for window in ["60s", "5m", "1h", "500ms", "30", "0s"] {
10206            caixa_with_restart_window(Some(window))
10207                .validate_restart_window()
10208                .unwrap_or_else(|e| {
10209                    panic!("canonical :restart-window {window:?} must validate, got {e:?}")
10210                });
10211        }
10212    }
10213
10214    #[test]
10215    fn validate_restart_window_rejects_fractional_seconds() {
10216        // Fail-before-pass-after pin: the `"1.5s"` drift class (parses
10217        // as f64 to 1.5 → renders back as `"1500ms"` on first
10218        // serialize). Prior to the fold + this gate, the inline
10219        // `parse_window_inline` accepted f64 magnitudes and silently
10220        // produced a `Duration::from_secs_f64(1.5)`, divergent from
10221        // the shared codec's integer-magnitude discipline on the
10222        // serde-routed siblings. The gate now surfaces a self-locating
10223        // diagnostic at the manifest layer.
10224        let err = caixa_with_restart_window(Some("1.5s"))
10225            .validate_restart_window()
10226            .unwrap_err();
10227        let ManifestError::RestartWindowMalformed {
10228            restart_window,
10229            reason,
10230        } = err
10231        else {
10232            panic!("expected RestartWindowMalformed for fractional seconds");
10233        };
10234        assert_eq!(restart_window, "1.5s");
10235        assert!(
10236            reason.contains("\"1.5\"") && reason.contains("not a non-negative integer"),
10237            "diagnostic must carry shared-codec wording, got {reason:?}"
10238        );
10239    }
10240
10241    #[test]
10242    fn validate_restart_window_rejects_decimal_shaped_integer() {
10243        // The `"1.0s"` class — numerically `1s` exactly, but the
10244        // canonical form is `"1s"` not `"1.0s"`. Decimal-shape leak
10245        // gets the same canonical-form diagnostic.
10246        let err = caixa_with_restart_window(Some("1.0s"))
10247            .validate_restart_window()
10248            .unwrap_err();
10249        assert!(
10250            matches!(
10251                err,
10252                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10253                    if restart_window == "1.0s"
10254            ),
10255            "got {err:?}"
10256        );
10257    }
10258
10259    #[test]
10260    fn validate_restart_window_rejects_half_unit_minute() {
10261        // `"0.5m"` is the unit-fraction footgun — author writes a
10262        // human-readable half-minute, the prior inline parser silently
10263        // produced `Duration::from_secs_f64(30.0)` and serde
10264        // re-emitted as `"30s"`, rewriting author intent. The gate
10265        // closes the loop at the manifest layer.
10266        let err = caixa_with_restart_window(Some("0.5m"))
10267            .validate_restart_window()
10268            .unwrap_err();
10269        let ManifestError::RestartWindowMalformed {
10270            restart_window,
10271            reason,
10272        } = err
10273        else {
10274            panic!("expected RestartWindowMalformed");
10275        };
10276        assert_eq!(restart_window, "0.5m");
10277        assert!(
10278            reason.contains("\"30s\""),
10279            "diagnostic must point at the canonical-form remediation, got {reason:?}"
10280        );
10281    }
10282
10283    #[test]
10284    fn validate_restart_window_rejects_leading_sign() {
10285        // `"+30s"` and `"-30s"` both round-tripped through f64 cleanly
10286        // on the prior parser (`+30` parses as `30.0`; `-30` parsed
10287        // and was caught by the `num < 0.0` arm which silently
10288        // returned `None`, dropping the author-supplied window). The
10289        // shared codec's digit-only gate rejects both with a unified
10290        // canonical-form diagnostic; the manifest-layer wrapper names
10291        // the offending value.
10292        for bad in ["+30s", "-30s"] {
10293            let err = caixa_with_restart_window(Some(bad))
10294                .validate_restart_window()
10295                .unwrap_err();
10296            assert!(
10297                matches!(
10298                    err,
10299                    ManifestError::RestartWindowMalformed { ref restart_window, .. }
10300                        if restart_window == bad
10301                ),
10302                "got {err:?} for {bad:?}"
10303            );
10304        }
10305    }
10306
10307    #[test]
10308    fn validate_restart_window_rejects_unknown_unit() {
10309        // `"30x"` — the typo / wrong-unit footgun. The shared codec's
10310        // unit dispatch surfaces an `unknown duration unit` reason;
10311        // the manifest-layer wrapper names the offending value.
10312        let err = caixa_with_restart_window(Some("30x"))
10313            .validate_restart_window()
10314            .unwrap_err();
10315        let ManifestError::RestartWindowMalformed {
10316            restart_window,
10317            reason,
10318        } = err
10319        else {
10320            panic!("expected RestartWindowMalformed for unknown unit");
10321        };
10322        assert_eq!(restart_window, "30x");
10323        assert!(
10324            reason.contains("unknown duration unit"),
10325            "diagnostic must carry shared-codec unit-rejection wording, got {reason:?}"
10326        );
10327    }
10328
10329    #[test]
10330    fn validate_restart_window_rejects_garbage() {
10331        // Pure non-numeric magnitude (`"abc"`) falls through to the
10332        // shared codec's narrower `"bad duration magnitude"` arm. Same
10333        // diagnostic shape as the codec-side
10334        // `parse_garbage_still_falls_through_to_bad_magnitude` pin.
10335        let err = caixa_with_restart_window(Some("abc"))
10336            .validate_restart_window()
10337            .unwrap_err();
10338        let ManifestError::RestartWindowMalformed {
10339            restart_window,
10340            reason,
10341        } = err
10342        else {
10343            panic!("expected RestartWindowMalformed for garbage");
10344        };
10345        assert_eq!(restart_window, "abc");
10346        assert!(
10347            reason.contains("bad duration magnitude"),
10348            "diagnostic must carry shared-codec garbage-rejection wording, got {reason:?}"
10349        );
10350    }
10351
10352    #[test]
10353    fn validate_restart_window_rejects_empty_string() {
10354        // The empty-after-trim edge case — distinct from the `None`
10355        // canonical "omit the slot" shape. The shared codec's
10356        // digit-only gate refuses an empty magnitude; the manifest
10357        // layer names the offending `""` so the author can grep for
10358        // the literal empty value in their `caixa.lisp` and either
10359        // remove the slot (the canonical "no reset" shape) or pin a
10360        // positive duration.
10361        let err = caixa_with_restart_window(Some(""))
10362            .validate_restart_window()
10363            .unwrap_err();
10364        assert!(
10365            matches!(
10366                err,
10367                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10368                    if restart_window.is_empty()
10369            ),
10370            "got {err:?}"
10371        );
10372    }
10373
10374    #[test]
10375    fn validate_restart_window_diagnostic_carries_offending_value() {
10376        // Diagnostic-shape pin (peer with
10377        // `nome_invalid_diagnostic_carries_offending_nome` /
10378        // `versao_invalid_diagnostic_carries_offending_versao`): the
10379        // error names the offending raw `:restart-window` verbatim
10380        // with a non-empty shared-codec-shaped reason, so a `feira
10381        // lint` run can render the diagnostic without re-parsing.
10382        let err = caixa_with_restart_window(Some("1.5s"))
10383            .validate_restart_window()
10384            .unwrap_err();
10385        let ManifestError::RestartWindowMalformed {
10386            restart_window,
10387            reason,
10388        } = err
10389        else {
10390            panic!("expected RestartWindowMalformed variant");
10391        };
10392        assert_eq!(restart_window, "1.5s");
10393        assert!(
10394            !reason.is_empty(),
10395            "RestartWindowMalformed `reason` must carry the codec's wording verbatim"
10396        );
10397    }
10398
10399    #[test]
10400    fn supervisor_view_folds_through_shared_codec_on_canonical_form() {
10401        // Behavioral parity pin after the fold (`parse_window_inline`
10402        // deletion): the canonical `"60s"` still produces
10403        // `Duration::from_secs(60)` on the typed view — the fold is
10404        // semantically equivalent to the prior inline parser on the
10405        // accepted set. Mirrors the pre-fold `supervisor_view_returns_typed_shape`
10406        // pin, narrowed to the parser-side contract.
10407        let c = caixa_with_restart_window(Some("60s"));
10408        let view = c.supervisor_view().expect("Supervisor kind has a view");
10409        assert_eq!(
10410            view.restart_window,
10411            Some(std::time::Duration::from_secs(60))
10412        );
10413    }
10414
10415    #[test]
10416    fn supervisor_view_soft_swallows_what_validate_rejects() {
10417        // Parity pin between the view-construction path and the
10418        // manifest-level validator: the same `"1.5s"` that surfaces
10419        // `RestartWindowMalformed` at `validate_restart_window` time
10420        // becomes `restart_window: None` on the typed view (the fold
10421        // preserves the existing best-effort shape of `supervisor_view`).
10422        // The contract is: a layout-verifier / `feira lint` flow that
10423        // cares about the malformed-window axis MUST consult
10424        // `validate_restart_window` — relying solely on the view's
10425        // `None` swallows the diagnostic silently. This pin makes the
10426        // expectation a typed invariant.
10427        let c = caixa_with_restart_window(Some("1.5s"));
10428        let view = c.supervisor_view().expect("Supervisor kind has a view");
10429        assert_eq!(
10430            view.restart_window, None,
10431            "view-construction path soft-swallows the parse error to None"
10432        );
10433        // And the manifest-level validator does NOT soft-swallow:
10434        assert!(
10435            matches!(
10436                c.validate_restart_window().unwrap_err(),
10437                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10438                    if restart_window == "1.5s"
10439            ),
10440            "validator must surface the offending value",
10441        );
10442    }
10443
10444    // ── validate_code_paths — per-entry shape on :bibliotecas / :exe / :servicos ──
10445
10446    fn caixa_with_code_paths(bibliotecas: Vec<&str>, exe: Vec<&str>, servicos: Vec<&str>) -> Caixa {
10447        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10448        c.bibliotecas = bibliotecas.into_iter().map(String::from).collect();
10449        c.exe = exe.into_iter().map(String::from).collect();
10450        c.servicos = servicos.into_iter().map(String::from).collect();
10451        c
10452    }
10453
10454    #[test]
10455    fn validate_code_paths_accepts_canonical_template() {
10456        // The bare `Caixa::template` shape is the gate's identity element
10457        // on the canonical authoring shape — `:bibliotecas
10458        // ("lib/demo.lisp")` + empty `:exe` + empty `:servicos`. Pins
10459        // that the gate is non-disruptive against every existing caixa.
10460        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10461        c.validate_code_paths().unwrap();
10462    }
10463
10464    #[test]
10465    fn validate_code_paths_accepts_explicit_relative_paths_on_every_slot() {
10466        // Positive control sweep: a canonical-shaped path on every slot
10467        // passes. Mirrors the peer
10468        // `behavior::validate_every_slot_relative_is_ok` pin.
10469        let c = caixa_with_code_paths(
10470            vec!["lib/demo.lisp", "lib/helpers.lisp"],
10471            vec!["exe/demo", "exe/tool"],
10472            vec!["servicos/demo.computeunit.yaml"],
10473        );
10474        c.validate_code_paths().unwrap();
10475    }
10476
10477    #[test]
10478    fn validate_code_paths_accepts_all_empty_lists() {
10479        // The empty-list identity element: every Caixa with no declared
10480        // code paths trivially passes (Supervisor / Aplicacao kinds rely
10481        // on this — the OwnCode gate already rejected them before the
10482        // path-shape gate runs in the layout, but the validator itself
10483        // must accept the empty shape).
10484        let c = caixa_with_code_paths(vec![], vec![], vec![]);
10485        c.validate_code_paths().unwrap();
10486    }
10487
10488    #[test]
10489    fn validate_code_paths_rejects_empty_bibliotecas_entry() {
10490        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
10491        let err = c.validate_code_paths().unwrap_err();
10492        assert!(
10493            matches!(
10494                err,
10495                ManifestError::CodePathEmpty {
10496                    slot: ":bibliotecas"
10497                }
10498            ),
10499            "got {err:?}",
10500        );
10501    }
10502
10503    #[test]
10504    fn validate_code_paths_rejects_empty_exe_entry() {
10505        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
10506        let err = c.validate_code_paths().unwrap_err();
10507        assert!(
10508            matches!(err, ManifestError::CodePathEmpty { slot: ":exe" }),
10509            "got {err:?}",
10510        );
10511    }
10512
10513    #[test]
10514    fn validate_code_paths_rejects_empty_servicos_entry() {
10515        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
10516        let err = c.validate_code_paths().unwrap_err();
10517        assert!(
10518            matches!(err, ManifestError::CodePathEmpty { slot: ":servicos" }),
10519            "got {err:?}",
10520        );
10521    }
10522
10523    #[test]
10524    fn validate_code_paths_rejects_absolute_bibliotecas_entry() {
10525        // `:bibliotecas` has no `starts_with(<dir>)` fence downstream,
10526        // so an absolute path that resolves on disk silently passes the
10527        // layout's existence check — the canonical sandbox-escape on
10528        // the biblioteca axis.
10529        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10530        let err = c.validate_code_paths().unwrap_err();
10531        let ManifestError::CodePathAbsolute { slot, path } = err else {
10532            panic!("expected CodePathAbsolute, got {err:?}");
10533        };
10534        assert_eq!(slot, ":bibliotecas");
10535        assert_eq!(path, PathBuf::from("/etc/passwd"));
10536    }
10537
10538    #[test]
10539    fn validate_code_paths_rejects_absolute_exe_entry() {
10540        let c = caixa_with_code_paths(vec![], vec!["/usr/bin/env"], vec![]);
10541        let err = c.validate_code_paths().unwrap_err();
10542        let ManifestError::CodePathAbsolute { slot, path } = err else {
10543            panic!("expected CodePathAbsolute, got {err:?}");
10544        };
10545        assert_eq!(slot, ":exe");
10546        assert_eq!(path, PathBuf::from("/usr/bin/env"));
10547    }
10548
10549    #[test]
10550    fn validate_code_paths_rejects_absolute_servicos_entry() {
10551        let c = caixa_with_code_paths(vec![], vec![], vec!["/var/servicos/x.yaml"]);
10552        let err = c.validate_code_paths().unwrap_err();
10553        let ManifestError::CodePathAbsolute { slot, path } = err else {
10554            panic!("expected CodePathAbsolute, got {err:?}");
10555        };
10556        assert_eq!(slot, ":servicos");
10557        assert_eq!(path, PathBuf::from("/var/servicos/x.yaml"));
10558    }
10559
10560    #[test]
10561    fn validate_code_paths_rejects_parent_escape_bibliotecas_leading() {
10562        // Canonical "I want a lib from a sibling caixa" footgun on the
10563        // biblioteca axis. `:bibliotecas` has no `starts_with` fence
10564        // downstream, so a leading `..` traverses to the parent of the
10565        // caixa root with no diagnostic at layout time if the resolved
10566        // target exists.
10567        let c = caixa_with_code_paths(vec!["../sibling/x.lisp"], vec![], vec![]);
10568        let err = c.validate_code_paths().unwrap_err();
10569        let ManifestError::CodePathParentEscape { slot, path } = err else {
10570            panic!("expected CodePathParentEscape, got {err:?}");
10571        };
10572        assert_eq!(slot, ":bibliotecas");
10573        assert_eq!(path, PathBuf::from("../sibling/x.lisp"));
10574    }
10575
10576    #[test]
10577    fn validate_code_paths_rejects_parent_escape_exe_mid_path() {
10578        // Mid-path `..` defeats the layout's component-aware
10579        // `starts_with(exe_dir)` fence — `root.join("exe/../../escape")`
10580        // `starts_with(<root>/exe)` is true, but the canonical resolution
10581        // lives outside the caixa root. Caught regardless of where the
10582        // `..` sits — mirrors the peer
10583        // `behavior::validate_rejects_parent_escape_mid_path` pin.
10584        let c = caixa_with_code_paths(vec![], vec!["exe/../../escape"], vec![]);
10585        let err = c.validate_code_paths().unwrap_err();
10586        let ManifestError::CodePathParentEscape { slot, path } = err else {
10587            panic!("expected CodePathParentEscape, got {err:?}");
10588        };
10589        assert_eq!(slot, ":exe");
10590        assert_eq!(path, PathBuf::from("exe/../../escape"));
10591    }
10592
10593    #[test]
10594    fn validate_code_paths_rejects_parent_escape_servicos_trailing() {
10595        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/foo/../../escape.yaml"]);
10596        let err = c.validate_code_paths().unwrap_err();
10597        let ManifestError::CodePathParentEscape { slot, path } = err else {
10598            panic!("expected CodePathParentEscape, got {err:?}");
10599        };
10600        assert_eq!(slot, ":servicos");
10601        assert_eq!(path, PathBuf::from("servicos/foo/../../escape.yaml"));
10602    }
10603
10604    #[test]
10605    fn validate_code_paths_cross_slot_precedence_bibliotecas_before_exe_before_servicos() {
10606        // Cross-slot precedence pin: `:bibliotecas` → `:exe` →
10607        // `:servicos`. A manifest with malformed entries on all three
10608        // surfaces surfaces the `:bibliotecas` defect first, mirroring
10609        // the canonical declaration order
10610        // `Caixa::declared_foreign_code_slots` already establishes for
10611        // the foreign-code-slot diagnostic.
10612        let c = caixa_with_code_paths(vec![""], vec![""], vec![""]);
10613        let err = c.validate_code_paths().unwrap_err();
10614        assert!(
10615            matches!(
10616                err,
10617                ManifestError::CodePathEmpty {
10618                    slot: ":bibliotecas"
10619                }
10620            ),
10621            "got {err:?}",
10622        );
10623    }
10624
10625    #[test]
10626    fn validate_code_paths_within_slot_precedence_empty_before_absolute_before_parent_escape() {
10627        // Within-slot precedence pin: empty → absolute → parent-escape,
10628        // matching the [`PathShapeViolation`] arm-ordering every peer
10629        // `is_sandboxed_relative_path` caller follows (b0c8389
10630        // BehaviorSpec, 26da2c7 UpgradeInstruction::StateChange). A
10631        // `:bibliotecas` list whose first entry is empty *and* whose
10632        // later entries are absolute/parent-escape surfaces the empty
10633        // arm first, on the lexicographically-earliest offending entry.
10634        let c = caixa_with_code_paths(vec!["", "/etc/passwd", "../escape.lisp"], vec![], vec![]);
10635        let err = c.validate_code_paths().unwrap_err();
10636        assert!(
10637            matches!(
10638                err,
10639                ManifestError::CodePathEmpty {
10640                    slot: ":bibliotecas"
10641                }
10642            ),
10643            "got {err:?}",
10644        );
10645    }
10646
10647    #[test]
10648    fn validate_code_paths_first_offender_per_slot_wins() {
10649        // Within a single slot, the first declaration-order offender
10650        // surfaces — pins that the gate is left-to-right deterministic
10651        // (peer of every `*_first_collision_*` pin on duplicate gates).
10652        let c = caixa_with_code_paths(
10653            vec!["lib/ok.lisp", "/etc/escape", "../also-escape"],
10654            vec![],
10655            vec![],
10656        );
10657        let err = c.validate_code_paths().unwrap_err();
10658        let ManifestError::CodePathAbsolute { slot, path } = err else {
10659            panic!("expected CodePathAbsolute, got {err:?}");
10660        };
10661        assert_eq!(slot, ":bibliotecas");
10662        assert_eq!(path, PathBuf::from("/etc/escape"));
10663    }
10664
10665    #[test]
10666    fn validate_code_paths_diagnostic_carries_offending_slot_and_path() {
10667        // Diagnostic-shape pin (peer with
10668        // `nome_invalid_diagnostic_carries_offending_nome` /
10669        // `versao_invalid_diagnostic_carries_offending_versao`): the
10670        // error's Display surfaces both the offending `:slot` tag and
10671        // the offending path verbatim, so a `feira lint` run can render
10672        // the diagnostic without re-parsing.
10673        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10674        let rendered = c.validate_code_paths().unwrap_err().to_string();
10675        assert!(
10676            rendered.contains(":bibliotecas"),
10677            "diagnostic must name the offending slot: {rendered}",
10678        );
10679        assert!(
10680            rendered.contains("/etc/passwd"),
10681            "diagnostic must quote the offending path: {rendered}",
10682        );
10683    }
10684
10685    #[test]
10686    fn validate_code_paths_rejects_duplicate_bibliotecas_entry() {
10687        // Canonical copy-paste-the-wrong-file footgun on the biblioteca
10688        // axis. Without the gate `feira build` re-parses the same lib
10689        // twice, wasting work and silently masking the author's intent
10690        // to declare a *second* biblioteca.
10691        let c = caixa_with_code_paths(vec!["lib/demo.lisp", "lib/demo.lisp"], vec![], vec![]);
10692        let err = c.validate_code_paths().unwrap_err();
10693        let ManifestError::CodePathDuplicate { slot, path } = err else {
10694            panic!("expected CodePathDuplicate, got {err:?}");
10695        };
10696        assert_eq!(slot, ":bibliotecas");
10697        assert_eq!(path, PathBuf::from("lib/demo.lisp"));
10698    }
10699
10700    #[test]
10701    fn validate_code_paths_rejects_duplicate_exe_entry() {
10702        // Same footgun on the Binario surface. The future `caixa-flake`
10703        // emitter that materializes each `:exe` entry as a flake
10704        // `packages.<name>` derivation would collide on the duplicate
10705        // package key — surfaced here at the typed-validate layer with a
10706        // self-locating diagnostic instead.
10707        let c = caixa_with_code_paths(vec![], vec!["exe/cli", "exe/cli"], vec![]);
10708        let err = c.validate_code_paths().unwrap_err();
10709        let ManifestError::CodePathDuplicate { slot, path } = err else {
10710            panic!("expected CodePathDuplicate, got {err:?}");
10711        };
10712        assert_eq!(slot, ":exe");
10713        assert_eq!(path, PathBuf::from("exe/cli"));
10714    }
10715
10716    #[test]
10717    fn validate_code_paths_rejects_duplicate_servicos_entry() {
10718        // Same footgun on the Servico surface. The peer caixa-helm /
10719        // caixa-flux renderers refuse `:servicos.len() != 1` with the
10720        // narrower `UnsupportedServicoCount` diagnostic, but that
10721        // diagnostic surfaces "too many servicos" without naming
10722        // "duplicate entry" — the typed self-locating framing only lands
10723        // at this gate.
10724        let c = caixa_with_code_paths(
10725            vec![],
10726            vec![],
10727            vec![
10728                "servicos/demo.computeunit.yaml",
10729                "servicos/demo.computeunit.yaml",
10730            ],
10731        );
10732        let err = c.validate_code_paths().unwrap_err();
10733        let ManifestError::CodePathDuplicate { slot, path } = err else {
10734            panic!("expected CodePathDuplicate, got {err:?}");
10735        };
10736        assert_eq!(slot, ":servicos");
10737        assert_eq!(path, PathBuf::from("servicos/demo.computeunit.yaml"));
10738    }
10739
10740    #[test]
10741    fn validate_code_paths_accepts_same_path_across_slots() {
10742        // Per-list scope pin: a `:bibliotecas` entry that happens to
10743        // collide with an `:exe` or `:servicos` entry as a *string* is
10744        // not a duplicate by this gate (each list gets its own HashSet),
10745        // mirroring the peer `:deps` ↔ `:deps-dev` per-list scope
10746        // (a `:nome` present in both lists is a legitimate dev-vs-runtime
10747        // shape on the dep axis). The structural `starts_with(<exe |
10748        // servicos>_dir)` fence at layout time prevents the realistic
10749        // cross-slot collision case from existing on disk, but the gate's
10750        // per-list scope is correct independent of that downstream fence.
10751        let c = caixa_with_code_paths(
10752            vec!["lib/x.lisp"],
10753            vec!["exe/x"],
10754            vec!["servicos/x.computeunit.yaml"],
10755        );
10756        c.validate_code_paths().unwrap();
10757    }
10758
10759    #[test]
10760    fn validate_code_paths_duplicate_fires_after_structural_checks_on_same_slot() {
10761        // Within-slot ordering pin: structural defects (empty / absolute
10762        // / parent-escape) fire before the duplicate gate on the same
10763        // slot. A `:bibliotecas ("" "lib/x.lisp" "lib/x.lisp")` shape
10764        // surfaces the narrower `CodePathEmpty` for the empty entry
10765        // first, not the duplicate on the later pair — same arm-ordering
10766        // every peer per-list duplicate gate uses (`:etiquetas` 360a499,
10767        // `:autores` 86c769b, `:deps` 359fba5).
10768        let c = caixa_with_code_paths(vec!["", "lib/x.lisp", "lib/x.lisp"], vec![], vec![]);
10769        let err = c.validate_code_paths().unwrap_err();
10770        assert!(
10771            matches!(
10772                err,
10773                ManifestError::CodePathEmpty {
10774                    slot: ":bibliotecas"
10775                }
10776            ),
10777            "got {err:?}",
10778        );
10779    }
10780
10781    #[test]
10782    fn validate_code_paths_duplicate_in_bibliotecas_fires_before_duplicate_in_exe() {
10783        // Cross-slot ordering pin on the duplicate arm: `:bibliotecas`
10784        // duplicates surface before `:exe` duplicates, matching the
10785        // canonical `:bibliotecas` → `:exe` → `:servicos` declaration
10786        // order every peer per-slot diagnostic on this surface follows.
10787        let c = caixa_with_code_paths(
10788            vec!["lib/x.lisp", "lib/x.lisp"],
10789            vec!["exe/y", "exe/y"],
10790            vec![],
10791        );
10792        let err = c.validate_code_paths().unwrap_err();
10793        let ManifestError::CodePathDuplicate { slot, path } = err else {
10794            panic!("expected CodePathDuplicate, got {err:?}");
10795        };
10796        assert_eq!(slot, ":bibliotecas");
10797        assert_eq!(path, PathBuf::from("lib/x.lisp"));
10798    }
10799
10800    #[test]
10801    fn validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path() {
10802        // Diagnostic-shape pin (peer with
10803        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
10804        // on the structural arm): the duplicate-arm Display surfaces both
10805        // the offending `:slot` tag and the offending path verbatim, so a
10806        // `feira lint` run can render the diagnostic without re-parsing.
10807        let c = caixa_with_code_paths(
10808            vec![],
10809            vec![],
10810            vec![
10811                "servicos/demo.computeunit.yaml",
10812                "servicos/demo.computeunit.yaml",
10813            ],
10814        );
10815        let rendered = c.validate_code_paths().unwrap_err().to_string();
10816        assert!(
10817            rendered.contains(":servicos"),
10818            "diagnostic must name the offending slot: {rendered}",
10819        );
10820        assert!(
10821            rendered.contains("servicos/demo.computeunit.yaml"),
10822            "diagnostic must quote the offending path: {rendered}",
10823        );
10824    }
10825
10826    // ── validate_code_paths — `.lisp` extension gate on :bibliotecas ──
10827    //
10828    // The lifted [`crate::render::is_lisp_extension`] predicate (33cc830)
10829    // now gates `:bibliotecas` entries on the tatara-lisp-source file-type
10830    // contract. The `feira build` loop (`caixa-feira/src/cmd/build.rs:33`)
10831    // reads every declared `:bibliotecas` entry through `tatara_lisp::read`
10832    // at parse time — the same downstream consumer the peer `:behavior
10833    // :on-*` (c97815a, [`crate::BehaviorError::NonLispExtension`]) and
10834    // `:upgrade-from :state-change :script` (33cc830,
10835    // [`crate::UpgradeError::NonLispExtensionScript`]) axes route through.
10836    // `:exe` and `:servicos` are deliberately excluded — `:exe` is the
10837    // nix-built executable surface (`"exe/<name>"` shape per the canonical
10838    // [`crate::LayoutError::ExeOutsideDir`] error message and every
10839    // in-tree `caixa_with_code_paths` positive control), and `:servicos`
10840    // is the `.computeunit.yaml` ComputeUnit-CR axis.
10841
10842    #[test]
10843    fn validate_code_paths_rejects_no_extension_bibliotecas_entry() {
10844        // Canonical "I dragged the wrong file from the workspace tree"
10845        // footgun on the biblioteca axis. Without the gate `feira build`
10846        // hands the extensionless path to `tatara_lisp::read` and fails
10847        // with a parser-shaped diagnostic far from the source caixa.lisp,
10848        // with no field naming the offending `:bibliotecas` entry.
10849        for relpath in ["lib/demo", "demo", "lib/handlers/inner"] {
10850            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10851            let err = c.validate_code_paths().unwrap_err();
10852            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10853                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10854            };
10855            assert_eq!(slot, ":bibliotecas");
10856            assert_eq!(path, PathBuf::from(relpath));
10857        }
10858    }
10859
10860    #[test]
10861    fn validate_code_paths_rejects_wrong_extension_bibliotecas_entry() {
10862        // Wrong-extension sweep across common authoring footguns. Same
10863        // sweep posture as the peer
10864        // `behavior::validate_rejects_wrong_extension` (c97815a) and
10865        // `upgrade::tests::state_change_rejects_wrong_extension_script`
10866        // (33cc830) cases.
10867        for relpath in [
10868            "lib/demo.rs",
10869            "lib/demo.txt",
10870            "lib/demo.md",
10871            "lib/demo.json",
10872            "lib/demo.yaml",
10873            "lib/demo.toml",
10874            "lib/demo.lisp.bak",
10875            "lib/demo.lispx",
10876            "lib/demo.lis",
10877        ] {
10878            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10879            let err = c.validate_code_paths().unwrap_err();
10880            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10881                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10882            };
10883            assert_eq!(slot, ":bibliotecas");
10884            assert_eq!(path, PathBuf::from(relpath));
10885        }
10886    }
10887
10888    #[test]
10889    fn validate_code_paths_rejects_case_folded_extension_bibliotecas_entry() {
10890        // Case-sensitivity sweep — pins the strict lowercase `.lisp`
10891        // contract. An uppercase `.LISP` shape that the layout's existence
10892        // check would (case-insensitively, on case-insensitive volumes)
10893        // match the on-disk file still mismatches the canonical form the
10894        // codec emits, breaking the THEORY.md §V.2.7 render-determinism
10895        // contract. Mirrors the peer
10896        // `behavior::validate_rejects_case_folded_extension` (c97815a) and
10897        // `upgrade::tests::state_change_rejects_case_folded_extension_script`
10898        // (33cc830) sweeps.
10899        for relpath in [
10900            "lib/demo.LISP",
10901            "lib/demo.Lisp",
10902            "lib/demo.LiSp",
10903            "lib/demo.lISP",
10904        ] {
10905            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10906            let err = c.validate_code_paths().unwrap_err();
10907            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10908                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10909            };
10910            assert_eq!(slot, ":bibliotecas");
10911            assert_eq!(path, PathBuf::from(relpath));
10912        }
10913    }
10914
10915    #[test]
10916    fn validate_code_paths_accepts_canonical_lisp_shapes() {
10917        // Positive-control sweep through every canonical authoring shape
10918        // every in-tree fixture and the `Caixa::template` scaffold use.
10919        // Mirrors the peer `behavior::validate_accepts_canonical_lisp_paths`
10920        // (c97815a) and the lifted predicate's own
10921        // `is_lisp_extension_accepts_canonical_shapes` sweep in render.rs
10922        // (33cc830).
10923        for relpath in [
10924            "lib/demo.lisp",
10925            "lib/handlers.lisp",
10926            "lib/migrations/v01-to-v02.lisp",
10927            "demo.lisp",
10928            "a.lisp",
10929            "./lib/demo.lisp",
10930            "lib/./handlers.lisp",
10931            "lib/migrations/v.0.1.lisp",
10932        ] {
10933            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10934            c.validate_code_paths()
10935                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
10936        }
10937    }
10938
10939    #[test]
10940    fn validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos() {
10941        // The file-type gate is per-slot — only `:bibliotecas` carries the
10942        // tatara-lisp-source contract. An extensionless `:exe` entry
10943        // (`exe/demo`) and a `.computeunit.yaml` `:servicos` entry are the
10944        // canonical shapes every in-tree fixture uses, and must continue
10945        // to pass validate. Pins that a future tightening that broadens
10946        // the `.lisp` gate to either axis surfaces as a test failure
10947        // rather than as a silent breaking change to existing valid
10948        // manifests.
10949        let c = caixa_with_code_paths(
10950            vec![],
10951            vec!["exe/demo", "exe/tool"],
10952            vec!["servicos/demo.computeunit.yaml"],
10953        );
10954        c.validate_code_paths().unwrap();
10955    }
10956
10957    #[test]
10958    fn validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension() {
10959        // Cross-arm precedence pin: a `:bibliotecas` entry that is *both*
10960        // sandbox-escaping and non-`.lisp` surfaces the more fundamental
10961        // sandbox-shape diagnostic first (the `.lisp` remediation would
10962        // be misleading when the offending path can never resolve under
10963        // the caixa root anyway). Mirrors the peer
10964        // `EmptyPath` → `AbsolutePath` → `ParentEscape` → `NonLispExtension`
10965        // ordering on `:behavior :on-*` (c97815a) and `EmptyScript` →
10966        // `AbsoluteScript` → `ParentEscapeScript` → `NonLispExtensionScript`
10967        // on `:upgrade-from :state-change :script` (33cc830).
10968        //
10969        // Empty wins (the strictly-smaller-scope structural arm).
10970        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
10971        assert!(
10972            matches!(
10973                c.validate_code_paths().unwrap_err(),
10974                ManifestError::CodePathEmpty {
10975                    slot: ":bibliotecas"
10976                }
10977            ),
10978            "empty must win over non-lisp-extension",
10979        );
10980        // Absolute wins (the path can't resolve under the caixa root).
10981        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10982        let err = c.validate_code_paths().unwrap_err();
10983        let ManifestError::CodePathAbsolute { slot, .. } = err else {
10984            panic!("absolute must win over non-lisp-extension, got {err:?}");
10985        };
10986        assert_eq!(slot, ":bibliotecas");
10987        // ParentEscape wins (the path escapes the caixa root).
10988        let c = caixa_with_code_paths(vec!["../sibling/x.txt"], vec![], vec![]);
10989        let err = c.validate_code_paths().unwrap_err();
10990        let ManifestError::CodePathParentEscape { slot, .. } = err else {
10991            panic!("parent-escape must win over non-lisp-extension, got {err:?}");
10992        };
10993        assert_eq!(slot, ":bibliotecas");
10994    }
10995
10996    #[test]
10997    fn validate_code_paths_non_lisp_extension_precedes_duplicate() {
10998        // Within-slot precedence pin: the per-entry file-type shape gate
10999        // fires before the cross-entry duplicate gate, so the narrower
11000        // structural defect dominates the uniqueness diagnostic. A
11001        // `("lib/x.txt" "lib/x.txt")` shape surfaces
11002        // `CodePathNonLispExtension` on the first entry rather than
11003        // `CodePathDuplicate` on the pair — same posture every per-entry
11004        // shape-gate-precedes-duplicate cascade follows on this surface
11005        // (the empty / absolute / parent-escape arms already precede the
11006        // duplicate arm; the lifted file-type arm joins that set).
11007        let c = caixa_with_code_paths(vec!["lib/x.txt", "lib/x.txt"], vec![], vec![]);
11008        let err = c.validate_code_paths().unwrap_err();
11009        let ManifestError::CodePathNonLispExtension { slot, path } = err else {
11010            panic!("expected CodePathNonLispExtension, got {err:?}");
11011        };
11012        assert_eq!(slot, ":bibliotecas");
11013        assert_eq!(path, PathBuf::from("lib/x.txt"));
11014    }
11015
11016    #[test]
11017    fn validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path() {
11018        // Diagnostic-shape pin (peer with
11019        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
11020        // on the sandbox-shape arms and
11021        // `validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path`
11022        // on the duplicate arm): the file-type-arm Display surfaces both
11023        // the offending `:slot` tag, the offending path verbatim, and the
11024        // expected `.lisp` extension named in the remediation text, so a
11025        // `feira lint` run can render the diagnostic without re-parsing.
11026        let c = caixa_with_code_paths(vec!["lib/demo.rs"], vec![], vec![]);
11027        let rendered = c.validate_code_paths().unwrap_err().to_string();
11028        assert!(
11029            rendered.contains(":bibliotecas"),
11030            "diagnostic must name the offending slot: {rendered}",
11031        );
11032        assert!(
11033            rendered.contains("lib/demo.rs"),
11034            "diagnostic must quote the offending path: {rendered}",
11035        );
11036        assert!(
11037            rendered.contains(".lisp"),
11038            "diagnostic must name the expected extension: {rendered}",
11039        );
11040    }
11041
11042    // ── validate_code_paths — `.computeunit.yaml` compound-suffix gate on :servicos ──
11043    //
11044    // The lifted [`crate::render::is_computeunit_yaml_extension`] predicate
11045    // now gates `:servicos` entries on the ComputeUnit-CR YAML file-type
11046    // contract. The peer caixa-helm / caixa-flux renderers consume each
11047    // `:servicos` entry through `serde_yaml::from_str` as a typed
11048    // `ComputeUnit` CR — same downstream-consumer-shape lift as the peer
11049    // `:bibliotecas` `.lisp` gate (64772a9), here on the compound-suffix
11050    // axis `Path::extension` can't express on its own.
11051
11052    #[test]
11053    fn validate_code_paths_rejects_no_extension_servicos_entry() {
11054        // Canonical "I dragged the wrong file from the workspace tree"
11055        // footgun on the Servico axis. Without the gate the peer
11056        // caixa-helm / caixa-flux renderers hand the extensionless path
11057        // to `serde_yaml::from_str` and fail with a parser-shaped
11058        // diagnostic far from the source caixa.lisp, with no field
11059        // naming the offending `:servicos` entry.
11060        for relpath in ["servicos/demo", "demo", "servicos/sub/nested"] {
11061            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11062            let err = c.validate_code_paths().unwrap_err();
11063            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11064                panic!(
11065                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11066                     got {err:?}"
11067                );
11068            };
11069            assert_eq!(slot, ":servicos");
11070            assert_eq!(path, PathBuf::from(relpath));
11071        }
11072    }
11073
11074    #[test]
11075    fn validate_code_paths_rejects_wrong_extension_servicos_entry() {
11076        // Wrong-extension sweep across common authoring footguns on the
11077        // Servico axis. Bare `.yaml` is the canonical "I forgot the
11078        // `.computeunit` segment" typo; the off-by-one-segment shapes
11079        // (`.computeunit-yaml` / `.computeunit_yaml`) silently pass the
11080        // bare `Path::extension` view but mismatch the typed compound
11081        // suffix the renderers' `serde_yaml::from_str` consumer demands.
11082        // Same sweep-posture as the peer
11083        // `validate_code_paths_rejects_wrong_extension_bibliotecas_entry`
11084        // (64772a9) on the sibling tatara-lisp-source axis.
11085        for relpath in [
11086            "servicos/demo.yaml",
11087            "servicos/demo.yml",
11088            "servicos/demo.json",
11089            "servicos/demo.toml",
11090            "servicos/demo.txt",
11091            "servicos/demo.computeunit.yaml.bak",
11092            "servicos/demo.computeunit.yam",
11093            "servicos/demo.computeunit",
11094            "servicos/demo-computeunit.yaml",
11095            "servicos/demo_computeunit.yaml",
11096        ] {
11097            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11098            let err = c.validate_code_paths().unwrap_err();
11099            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11100                panic!(
11101                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11102                     got {err:?}"
11103                );
11104            };
11105            assert_eq!(slot, ":servicos");
11106            assert_eq!(path, PathBuf::from(relpath));
11107        }
11108    }
11109
11110    #[test]
11111    fn validate_code_paths_rejects_case_folded_extension_servicos_entry() {
11112        // Case-sensitivity sweep — pins the strict lowercase
11113        // `.computeunit.yaml` contract. A case-folded shape that the
11114        // layout's existence check would (case-insensitively, on
11115        // case-insensitive volumes) match the on-disk file still
11116        // mismatches the canonical form the codec emits, breaking the
11117        // THEORY.md §V.2.7 render-determinism contract. Mirrors the peer
11118        // `validate_code_paths_rejects_case_folded_extension_bibliotecas_entry`
11119        // (64772a9) sweep on the sibling tatara-lisp-source axis.
11120        for relpath in [
11121            "servicos/demo.ComputeUnit.yaml",
11122            "servicos/demo.COMPUTEUNIT.yaml",
11123            "servicos/demo.computeunit.YAML",
11124            "servicos/demo.computeunit.Yaml",
11125            "servicos/demo.COMPUTEUNIT.YAML",
11126        ] {
11127            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11128            let err = c.validate_code_paths().unwrap_err();
11129            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11130                panic!(
11131                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11132                     got {err:?}"
11133                );
11134            };
11135            assert_eq!(slot, ":servicos");
11136            assert_eq!(path, PathBuf::from(relpath));
11137        }
11138    }
11139
11140    #[test]
11141    fn validate_code_paths_rejects_empty_stem_servicos_entry() {
11142        // Degenerate hidden-file shape: a file name exactly equal to the
11143        // suffix (`.computeunit.yaml` — no stem preceding the suffix) is
11144        // the structural "Servico declared with no identity" footgun.
11145        // The substrate identifies each ComputeUnit by the file-stem
11146        // segment that precedes `.computeunit.yaml` (the rendered
11147        // `lareira-<stem>` Helm chart, the per-Servico `metadata.name`,
11148        // the M3 `:contratos` membership lookup), so an empty stem
11149        // leaves the Servico unidentifiable. Pinned at the typed-axis
11150        // level so a future regression that drops the `name.len() >
11151        // SUFFIX.len()` bound at the predicate surfaces here, not
11152        // piecemeal as a `lareira-` chart-name collision at render time.
11153        for relpath in ["servicos/.computeunit.yaml"] {
11154            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11155            let err = c.validate_code_paths().unwrap_err();
11156            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11157                panic!(
11158                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11159                     got {err:?}"
11160                );
11161            };
11162            assert_eq!(slot, ":servicos");
11163            assert_eq!(path, PathBuf::from(relpath));
11164        }
11165    }
11166
11167    #[test]
11168    fn validate_code_paths_accepts_canonical_computeunit_yaml_shapes() {
11169        // Positive-control sweep through every canonical authoring shape
11170        // every in-tree fixture and the `Caixa::template` scaffold use.
11171        // Mirrors the peer
11172        // `validate_code_paths_accepts_canonical_lisp_shapes` (64772a9)
11173        // and the lifted predicate's own
11174        // `computeunit_yaml_extension_accepts_canonical_shapes` sweep in
11175        // render.rs.
11176        for relpath in [
11177            "servicos/demo.computeunit.yaml",
11178            "servicos/hello-rio.computeunit.yaml",
11179            "servicos/my-service.computeunit.yaml",
11180            "servicos/a.computeunit.yaml",
11181            "./servicos/demo.computeunit.yaml",
11182            "servicos/./demo.computeunit.yaml",
11183            "servicos/sub/nested.computeunit.yaml",
11184            "servicos/v0.1.computeunit.yaml",
11185        ] {
11186            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11187            c.validate_code_paths()
11188                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
11189        }
11190    }
11191
11192    #[test]
11193    fn validate_code_paths_non_computeunit_yaml_extension_does_not_fire_on_bibliotecas_or_exe() {
11194        // The file-type gate is per-slot — only `:servicos` carries the
11195        // ComputeUnit-CR YAML contract. A canonical `.lisp` `:bibliotecas`
11196        // entry and an extensionless `:exe` entry are the canonical
11197        // shapes every in-tree fixture uses, and must continue to pass
11198        // validate. Peer of
11199        // `validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos`
11200        // (64772a9) — together pin that the typed
11201        // [`CodePathFileType`] dispatch is exhaustively per-slot, with no
11202        // cross-axis leakage in either direction.
11203        let c = caixa_with_code_paths(
11204            vec!["lib/demo.lisp"],
11205            vec!["exe/demo", "exe/tool"],
11206            vec!["servicos/demo.computeunit.yaml"],
11207        );
11208        c.validate_code_paths().unwrap();
11209    }
11210
11211    #[test]
11212    fn validate_code_paths_sandbox_shape_arms_precede_non_computeunit_yaml_extension() {
11213        // Cross-arm precedence pin: a `:servicos` entry that is *both*
11214        // sandbox-escaping and wrong-extension surfaces the more
11215        // fundamental sandbox-shape diagnostic first (the
11216        // `.computeunit.yaml` remediation would be misleading when the
11217        // offending path can never resolve under the caixa root
11218        // anyway). Mirrors the peer
11219        // `validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension`
11220        // (64772a9) ordering on the sibling `:bibliotecas` axis and the
11221        // peer `EmptyPath` → `AbsolutePath` → `ParentEscape` →
11222        // `NonComputeUnitYamlExtension` arm-ordering the dispatch
11223        // table establishes.
11224        //
11225        // Empty wins (the strictly-smaller-scope structural arm).
11226        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
11227        assert!(
11228            matches!(
11229                c.validate_code_paths().unwrap_err(),
11230                ManifestError::CodePathEmpty { slot: ":servicos" }
11231            ),
11232            "empty must win over non-computeunit-yaml-extension",
11233        );
11234        // Absolute wins (the path can't resolve under the caixa root).
11235        let c = caixa_with_code_paths(vec![], vec![], vec!["/etc/foo.yaml"]);
11236        let err = c.validate_code_paths().unwrap_err();
11237        let ManifestError::CodePathAbsolute { slot, .. } = err else {
11238            panic!("absolute must win over non-computeunit-yaml-extension, got {err:?}");
11239        };
11240        assert_eq!(slot, ":servicos");
11241        // ParentEscape wins (the path escapes the caixa root).
11242        let c = caixa_with_code_paths(vec![], vec![], vec!["../sibling/x.yaml"]);
11243        let err = c.validate_code_paths().unwrap_err();
11244        let ManifestError::CodePathParentEscape { slot, .. } = err else {
11245            panic!("parent-escape must win over non-computeunit-yaml-extension, got {err:?}");
11246        };
11247        assert_eq!(slot, ":servicos");
11248    }
11249
11250    #[test]
11251    fn validate_code_paths_non_computeunit_yaml_extension_precedes_duplicate() {
11252        // Within-slot precedence pin: the per-entry file-type shape gate
11253        // fires before the cross-entry duplicate gate, so the narrower
11254        // structural defect dominates the uniqueness diagnostic. A
11255        // `("servicos/x.yaml" "servicos/x.yaml")` shape surfaces
11256        // `CodePathNonComputeUnitYamlExtension` on the first entry
11257        // rather than `CodePathDuplicate` on the pair — same posture
11258        // every per-entry shape-gate-precedes-duplicate cascade follows
11259        // on this surface, peer of the 64772a9 `:bibliotecas`
11260        // `("lib/x.txt" "lib/x.txt")` ordering.
11261        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/x.yaml", "servicos/x.yaml"]);
11262        let err = c.validate_code_paths().unwrap_err();
11263        let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11264            panic!("expected CodePathNonComputeUnitYamlExtension, got {err:?}");
11265        };
11266        assert_eq!(slot, ":servicos");
11267        assert_eq!(path, PathBuf::from("servicos/x.yaml"));
11268    }
11269
11270    #[test]
11271    fn validate_code_paths_non_computeunit_yaml_extension_diagnostic_carries_offending_slot_and_path()
11272     {
11273        // Diagnostic-shape pin (peer with
11274        // `validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path`
11275        // on the sibling tatara-lisp-source axis): the file-type-arm
11276        // Display surfaces both the offending `:slot` tag, the
11277        // offending path verbatim, and the expected
11278        // `.computeunit.yaml` compound suffix named in the remediation
11279        // text, so a `feira lint` run can render the diagnostic without
11280        // re-parsing.
11281        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.yaml"]);
11282        let rendered = c.validate_code_paths().unwrap_err().to_string();
11283        assert!(
11284            rendered.contains(":servicos"),
11285            "diagnostic must name the offending slot: {rendered}",
11286        );
11287        assert!(
11288            rendered.contains("servicos/demo.yaml"),
11289            "diagnostic must quote the offending path: {rendered}",
11290        );
11291        assert!(
11292            rendered.contains(".computeunit.yaml"),
11293            "diagnostic must name the expected compound suffix: {rendered}",
11294        );
11295    }
11296
11297    // ── validate_etiquetas — universal-axis registry-search-tag shape ──
11298
11299    fn caixa_with_etiquetas(etiquetas: Vec<&str>) -> Caixa {
11300        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11301        c.etiquetas = etiquetas.into_iter().map(String::from).collect();
11302        c
11303    }
11304
11305    #[test]
11306    fn validate_etiquetas_accepts_empty_list() {
11307        // The empty-list identity: every caixa with no declared tags
11308        // trivially passes — `Caixa::template` emits `:etiquetas ()`,
11309        // so the gate is non-disruptive against every existing manifest.
11310        let c = caixa_with_etiquetas(vec![]);
11311        c.validate_etiquetas().unwrap();
11312    }
11313
11314    #[test]
11315    fn validate_etiquetas_accepts_canonical_forms() {
11316        // Positive control sweep: a canonical-shaped non-empty distinct
11317        // tag list passes, mirroring the example checkout-aplicacao
11318        // (`:etiquetas ("example" "aplicacao" "mesh" "ecommerce" "demo")`)
11319        // and the hello-rio fixture (`("hello-world" "wasm" "rust")`).
11320        let c = caixa_with_etiquetas(vec!["example", "aplicacao", "mesh", "ecommerce", "demo"]);
11321        c.validate_etiquetas().unwrap();
11322    }
11323
11324    #[test]
11325    fn validate_etiquetas_rejects_empty_entry() {
11326        // Canonical paste-from-blank-doc footgun. Without the gate the
11327        // empty entry rendered as `keywords: [""]` in `Chart.yaml`, a
11328        // no-op tag indexing nothing in the future caixa-registry.
11329        let c = caixa_with_etiquetas(vec![""]);
11330        let err = c.validate_etiquetas().unwrap_err();
11331        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11332    }
11333
11334    #[test]
11335    fn validate_etiquetas_rejects_duplicate_entry() {
11336        // Canonical copy-paste-the-wrong-tag footgun. Without the gate
11337        // the duplicate was silently dedup'd by caixa-helm's BTreeSet
11338        // collect at chart render — a "second wins / one silently
11339        // disappears" shape divergent from every peer typed-graph set
11340        // gate. The duplicate-arm names the offending tag verbatim.
11341        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
11342        let err = c.validate_etiquetas().unwrap_err();
11343        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
11344            panic!("expected EtiquetaDuplicate, got {err:?}");
11345        };
11346        assert_eq!(etiqueta, "demo");
11347    }
11348
11349    #[test]
11350    fn validate_etiquetas_empty_takes_precedence_over_duplicate() {
11351        // Empty-first cascade pin: `("" "demo" "demo")` surfaces
11352        // `EtiquetaEmpty` not `EtiquetaDuplicate` — the narrower
11353        // structural "this entry has no value" defect dominates the
11354        // cross-entry uniqueness diagnostic. Mirrors the peer
11355        // empty-before-duplicate cascades on `:caracteristicas`
11356        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
11357        // fc3b4d5) and `:membros :caixa` (`MembroCaixaEmpty` before
11358        // `MembroDuplicate`).
11359        let c = caixa_with_etiquetas(vec!["", "demo", "demo"]);
11360        let err = c.validate_etiquetas().unwrap_err();
11361        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11362    }
11363
11364    #[test]
11365    fn validate_etiquetas_duplicate_reports_first_collision() {
11366        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
11367        // duplicate (the lexicographically-earliest offending position
11368        // — the second `"a"` at index 2 collides with the first `"a"`
11369        // at index 0), not the later `"b"` collision at index 3,
11370        // peer with every other first-collision diagnostic posture on
11371        // this surface (`validate_load_singularity_reports_first_collision`,
11372        // `validate_cleanup_singularity_reports_first_collision`).
11373        let c = caixa_with_etiquetas(vec!["a", "b", "a", "b"]);
11374        let err = c.validate_etiquetas().unwrap_err();
11375        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
11376            panic!("expected EtiquetaDuplicate, got {err:?}");
11377        };
11378        assert_eq!(etiqueta, "a");
11379    }
11380
11381    #[test]
11382    fn validate_etiquetas_case_sensitive() {
11383        // Case-sensitivity pin: `("Foo" "foo")` is two distinct entries,
11384        // mirroring the peer `:membros :caixa` / `:children :caixa`
11385        // exact-string-match discipline. The shape gate this routine
11386        // landed (`is_chart_keyword_shape`, Cargo crates.io keyword
11387        // grammar) accepts mixed case — crates.io's keyword rule is
11388        // "case-insensitive" at the index layer but admits mixed case
11389        // at the entry layer (the canonical Helm chart `keywords:`
11390        // shape is lowercase by convention, but the grammar admits
11391        // uppercase). Case-sensitivity at the duplicate-set layer
11392        // remains structural — two distinct strings are two distinct
11393        // entries.
11394        let c = caixa_with_etiquetas(vec!["Foo", "foo"]);
11395        c.validate_etiquetas().unwrap();
11396    }
11397
11398    #[test]
11399    fn validate_etiquetas_diagnostic_carries_offending_tag() {
11400        // Diagnostic-shape pin (peer with
11401        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`):
11402        // the error's Display surfaces the offending tag verbatim, so a
11403        // `feira lint` run can render the diagnostic without re-parsing
11404        // and the author can grep their caixa.lisp for the offending
11405        // value.
11406        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
11407        let rendered = c.validate_etiquetas().unwrap_err().to_string();
11408        assert!(
11409            rendered.contains(":etiquetas"),
11410            "diagnostic must name the offending slot: {rendered}",
11411        );
11412        assert!(
11413            rendered.contains("demo"),
11414            "diagnostic must quote the offending tag: {rendered}",
11415        );
11416    }
11417
11418    #[test]
11419    fn validate_etiquetas_rejects_leading_whitespace_entry() {
11420        // Canonical paste-from-aligned-doc footgun. Without the shape
11421        // gate `" mesh"` silently passed validate and landed as a
11422        // YAML plain-style scalar with leading whitespace in the
11423        // rendered Chart.yaml `keywords:` array — every YAML 1.2
11424        // dumper trims leading whitespace from plain-style scalars,
11425        // so the authored space round-tripped inconsistently back
11426        // through `caixa.lisp`. Mirrors the peer
11427        // `validate_autores_rejects_leading_whitespace_entry`.
11428        let c = caixa_with_etiquetas(vec![" mesh"]);
11429        let err = c.validate_etiquetas().unwrap_err();
11430        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11431            panic!("expected EtiquetaInvalid, got {err:?}");
11432        };
11433        assert_eq!(etiqueta, " mesh");
11434        assert!(reason.contains("whitespace"), "got: {reason}");
11435    }
11436
11437    #[test]
11438    fn validate_etiquetas_rejects_embedded_newline_entry() {
11439        // Canonical paste-from-multiline-doc footgun — the author
11440        // pasted a multi-tag block into one `:etiquetas` entry
11441        // instead of splitting into one entry per tag. Without the
11442        // shape gate `"mesh\nhttp"` silently passed validate and
11443        // landed as a YAML-illegal multi-line scalar in the rendered
11444        // Chart.yaml `keywords:` array.
11445        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
11446        let err = c.validate_etiquetas().unwrap_err();
11447        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11448            panic!("expected EtiquetaInvalid, got {err:?}");
11449        };
11450        assert_eq!(etiqueta, "mesh\nhttp");
11451        assert!(reason.contains("newline"), "got: {reason}");
11452    }
11453
11454    #[test]
11455    fn validate_etiquetas_rejects_embedded_comma_entry() {
11456        // Canonical CSV-list-separator-confusion footgun: the author
11457        // confused the CSV-style separator convention with the
11458        // `:etiquetas` list grammar. Without the shape gate
11459        // `"mesh,http,grpc"` silently passed validate and landed as a
11460        // single malformed search tag in the rendered Chart.yaml
11461        // `keywords:` array — Artifact Hub's keyword index would
11462        // either silently drop the tag or index it as
11463        // `mesh,http,grpc` instead of three separate tags.
11464        let c = caixa_with_etiquetas(vec!["mesh,http,grpc"]);
11465        let err = c.validate_etiquetas().unwrap_err();
11466        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11467            panic!("expected EtiquetaInvalid, got {err:?}");
11468        };
11469        assert_eq!(etiqueta, "mesh,http,grpc");
11470        assert!(reason.contains('`'), "got: {reason}");
11471        assert!(reason.contains(','), "got: {reason}");
11472    }
11473
11474    #[test]
11475    fn validate_etiquetas_rejects_embedded_slash_entry() {
11476        // Canonical path-separator-confusion footgun: the author
11477        // confused namespace-path notation with the keyword grammar.
11478        let c = caixa_with_etiquetas(vec!["caixa/servico"]);
11479        let err = c.validate_etiquetas().unwrap_err();
11480        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11481            panic!("expected EtiquetaInvalid, got {err:?}");
11482        };
11483        assert_eq!(etiqueta, "caixa/servico");
11484        assert!(reason.contains('/'), "got: {reason}");
11485    }
11486
11487    #[test]
11488    fn validate_etiquetas_rejects_leading_digit_entry() {
11489        // Canonical paste-from-numbered-list footgun: the author
11490        // copied `1. mesh` from a numbered doc and the `1` leaked
11491        // into the tag.
11492        let c = caixa_with_etiquetas(vec!["1mesh"]);
11493        let err = c.validate_etiquetas().unwrap_err();
11494        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11495            panic!("expected EtiquetaInvalid, got {err:?}");
11496        };
11497        assert_eq!(etiqueta, "1mesh");
11498        assert!(reason.contains("digit"), "got: {reason}");
11499    }
11500
11501    #[test]
11502    fn validate_etiquetas_rejects_leading_hyphen_entry() {
11503        // Canonical kebab-leak footgun.
11504        let c = caixa_with_etiquetas(vec!["-foo"]);
11505        let err = c.validate_etiquetas().unwrap_err();
11506        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11507            panic!("expected EtiquetaInvalid, got {err:?}");
11508        };
11509        assert_eq!(etiqueta, "-foo");
11510        assert!(reason.contains('-'), "got: {reason}");
11511    }
11512
11513    #[test]
11514    fn validate_etiquetas_rejects_non_ascii_entry() {
11515        // Canonical paste-from-Unicode-doc footgun. Every legitimate
11516        // search tag is strict ASCII; raw non-ASCII silently
11517        // round-trips inconsistently across NFC/NFD normalization on
11518        // APFS / case-folding filesystems and breaks the Artifact Hub
11519        // keyword search index lookup.
11520        let c = caixa_with_etiquetas(vec!["café"]);
11521        let err = c.validate_etiquetas().unwrap_err();
11522        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11523            panic!("expected EtiquetaInvalid, got {err:?}");
11524        };
11525        assert_eq!(etiqueta, "café");
11526        assert!(reason.contains("non-ASCII"), "got: {reason}");
11527    }
11528
11529    #[test]
11530    fn validate_etiquetas_rejects_period_entry() {
11531        // Canonical namespace-confusion / version-suffix footgun
11532        // (`"http.1"` / `"v1.0"`): Cargo's crates.io keyword grammar
11533        // excludes `.` from the continuation set even though the
11534        // sibling `:caracteristicas` axis (Cargo's feature-name
11535        // grammar) admits it. Tighter than the sibling axis, peer
11536        // with Cargo's own crates.io keyword shape.
11537        let c = caixa_with_etiquetas(vec!["http.1"]);
11538        let err = c.validate_etiquetas().unwrap_err();
11539        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11540            panic!("expected EtiquetaInvalid, got {err:?}");
11541        };
11542        assert_eq!(etiqueta, "http.1");
11543        assert!(reason.contains('.'), "got: {reason}");
11544    }
11545
11546    #[test]
11547    fn validate_etiquetas_empty_takes_precedence_over_shape() {
11548        // Per-entry empty-first cascade pin: an entry that is both
11549        // empty *and* shape-invalid surfaces `EtiquetaEmpty` (the
11550        // narrower "this entry has no value" structural defect
11551        // dominates the broader shape-predicate diagnostic). The
11552        // empty arm fires before the shape predicate is consulted,
11553        // mirroring the peer `validate_autores_empty_takes_precedence_over_shape`
11554        // cascade established on the sibling universal-axis Vec<String>
11555        // surface.
11556        let c = caixa_with_etiquetas(vec![""]);
11557        let err = c.validate_etiquetas().unwrap_err();
11558        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11559    }
11560
11561    #[test]
11562    fn validate_etiquetas_shape_takes_precedence_over_duplicate() {
11563        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
11564        // entry that is malformed surfaces `EtiquetaInvalid` even when
11565        // a later entry would have collided on duplicate. The
11566        // per-entry shape arm fires inside the same loop iteration as
11567        // the empty arm, before the seen-set insert at end-of-iteration
11568        // — structural per-entry defects dominate the cross-entry
11569        // uniqueness diagnostic. Mirrors the peer
11570        // `validate_autores_shape_takes_precedence_over_duplicate`.
11571        let c = caixa_with_etiquetas(vec!["mesh\nhttp", "mesh\nhttp"]);
11572        let err = c.validate_etiquetas().unwrap_err();
11573        assert!(
11574            matches!(err, ManifestError::EtiquetaInvalid { .. }),
11575            "got {err:?}",
11576        );
11577    }
11578
11579    #[test]
11580    fn validate_etiquetas_invalid_diagnostic_names_offending_slot_and_value() {
11581        // Diagnostic-shape pin on the new shape arm (peer with
11582        // `validate_autores_invalid_diagnostic_names_offending_slot_and_value`):
11583        // the rendered Display surfaces both the offending slot name
11584        // and the offending value verbatim, so a `feira lint` run
11585        // points the author at the exact `:etiquetas` entry to fix.
11586        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
11587        let rendered = c.validate_etiquetas().unwrap_err().to_string();
11588        assert!(
11589            rendered.contains(":etiquetas"),
11590            "diagnostic must name the offending slot: {rendered}",
11591        );
11592        assert!(
11593            rendered.contains("mesh\\nhttp"),
11594            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11595        );
11596    }
11597
11598    #[test]
11599    fn validate_etiquetas_rejects_at_21_byte_boundary() {
11600        // The 20-byte cap pin — boundary-exceeding case rejected,
11601        // boundary-accepting case passes. Mirrors the peer
11602        // `chart_keyword_shape_rejects_at_21_byte_boundary` substrate-
11603        // side pin, surfaced at the per-axis caller so the cap
11604        // propagates through validate end-to-end. Constructed as a
11605        // single all-`a` token so only the cap arm fires.
11606        let max_ok = "a".repeat(20);
11607        let c = caixa_with_etiquetas(vec![max_ok.as_str()]);
11608        c.validate_etiquetas().unwrap();
11609        let too_long = "a".repeat(21);
11610        let c = caixa_with_etiquetas(vec![too_long.as_str()]);
11611        let err = c.validate_etiquetas().unwrap_err();
11612        let ManifestError::EtiquetaInvalid { reason, .. } = err else {
11613            panic!("expected EtiquetaInvalid, got {err:?}");
11614        };
11615        assert!(reason.contains("20"), "got: {reason}");
11616        assert!(reason.contains("21"), "got: {reason}");
11617    }
11618
11619    #[test]
11620    fn validate_etiquetas_accepts_canonical_shaped_forms() {
11621        // Positive control sweep: every canonical-shaped tag from the
11622        // hello-rio / checkout-aplicacao / pangea-tatara-akeyless
11623        // example fixtures plus the substrate-fixed tags caixa-helm
11624        // unions in at chart render. Drift between this list and the
11625        // substrate-side `chart_keyword_shape_accepts_canonical_forms`
11626        // sweep surfaces here — one source of truth for the rule.
11627        let c = caixa_with_etiquetas(vec![
11628            "example",
11629            "aplicacao",
11630            "mesh",
11631            "ecommerce",
11632            "demo",
11633            "infrastructure",
11634            "aws",
11635            "akeyless",
11636            "pangea-native",
11637            "hello-world",
11638            "wasm",
11639            "rust",
11640            "tatara-lisp",
11641            "caixa-servico",
11642            "lareira",
11643        ]);
11644        c.validate_etiquetas().unwrap();
11645    }
11646
11647    // ── validate_autores — universal-axis maintainer shape ────────────
11648
11649    fn caixa_with_autores(autores: Vec<&str>) -> Caixa {
11650        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11651        c.autores = autores.into_iter().map(String::from).collect();
11652        c
11653    }
11654
11655    #[test]
11656    fn validate_autores_accepts_empty_list() {
11657        // The empty-list identity: `Caixa::template` emits `:autores ()`,
11658        // so the gate is non-disruptive against every existing manifest.
11659        let c = caixa_with_autores(vec![]);
11660        c.validate_autores().unwrap();
11661    }
11662
11663    #[test]
11664    fn validate_autores_accepts_canonical_forms() {
11665        // Positive control sweep: every canonical-shaped non-empty
11666        // distinct maintainer list passes — the hello-rio / checkout-
11667        // aplicacao fixtures' `:autores ("pleme-io")` shape, plus the
11668        // multi-author shape downstream packaging surfaces emit.
11669        let c = caixa_with_autores(vec!["pleme-io"]);
11670        c.validate_autores().unwrap();
11671        let c = caixa_with_autores(vec!["alice <alice@example.com>", "bob <bob@example.com>"]);
11672        c.validate_autores().unwrap();
11673    }
11674
11675    #[test]
11676    fn validate_autores_rejects_empty_entry() {
11677        // Canonical paste-from-blank-doc footgun. Without the gate the
11678        // empty entry rendered as `maintainers: [{name: "", email: null}]`
11679        // in `Chart.yaml`, a no-op maintainer the substrate cannot route
11680        // to.
11681        let c = caixa_with_autores(vec![""]);
11682        let err = c.validate_autores().unwrap_err();
11683        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11684    }
11685
11686    #[test]
11687    fn validate_autores_rejects_duplicate_entry() {
11688        // Canonical copy-paste-the-wrong-author footgun. Unlike the
11689        // `:etiquetas` peer (caixa-helm's `BTreeSet` collect silently
11690        // dedups the rendered `keywords:` array), the `maintainers:`
11691        // rendering has *no* dedup — duplicates stack verbatim. The
11692        // duplicate-arm names the offending author verbatim.
11693        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
11694        let err = c.validate_autores().unwrap_err();
11695        let ManifestError::AutorDuplicate { autor } = err else {
11696            panic!("expected AutorDuplicate, got {err:?}");
11697        };
11698        assert_eq!(autor, "pleme-io");
11699    }
11700
11701    #[test]
11702    fn validate_autores_empty_takes_precedence_over_duplicate() {
11703        // Empty-first cascade pin: `("" "pleme-io" "pleme-io")` surfaces
11704        // `AutorEmpty` not `AutorDuplicate` — the narrower structural
11705        // "this entry has no value" defect dominates the cross-entry
11706        // uniqueness diagnostic. Mirrors the peer empty-before-duplicate
11707        // cascades on `:etiquetas` (`EtiquetaEmpty` before
11708        // `EtiquetaDuplicate`, 360a499), `:caracteristicas`
11709        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
11710        // fc3b4d5), and `:membros :caixa` (`MembroCaixaEmpty` before
11711        // `MembroDuplicate`).
11712        let c = caixa_with_autores(vec!["", "pleme-io", "pleme-io"]);
11713        let err = c.validate_autores().unwrap_err();
11714        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11715    }
11716
11717    #[test]
11718    fn validate_autores_duplicate_reports_first_collision() {
11719        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
11720        // duplicate (the lexicographically-earliest offending position
11721        // — the second `"a"` at index 2 collides with the first `"a"`
11722        // at index 0), not the later `"b"` collision at index 3,
11723        // peer with every other first-collision diagnostic posture on
11724        // this surface.
11725        let c = caixa_with_autores(vec!["a", "b", "a", "b"]);
11726        let err = c.validate_autores().unwrap_err();
11727        let ManifestError::AutorDuplicate { autor } = err else {
11728            panic!("expected AutorDuplicate, got {err:?}");
11729        };
11730        assert_eq!(autor, "a");
11731    }
11732
11733    #[test]
11734    fn validate_autores_case_sensitive() {
11735        // Case-sensitivity pin: `("Pleme-io" "pleme-io")` is two distinct
11736        // entries, mirroring the peer `:etiquetas` / `:membros :caixa`
11737        // / `:children :caixa` exact-string-match discipline.
11738        let c = caixa_with_autores(vec!["Pleme-io", "pleme-io"]);
11739        c.validate_autores().unwrap();
11740    }
11741
11742    #[test]
11743    fn validate_autores_diagnostic_carries_offending_author() {
11744        // Diagnostic-shape pin (peer with
11745        // `validate_etiquetas_diagnostic_carries_offending_tag`): the
11746        // error's Display surfaces the offending author verbatim, so a
11747        // `feira lint` run can render the diagnostic without re-parsing
11748        // and the author can grep their caixa.lisp for the offending
11749        // value.
11750        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
11751        let rendered = c.validate_autores().unwrap_err().to_string();
11752        assert!(
11753            rendered.contains(":autores"),
11754            "diagnostic must name the offending slot: {rendered}",
11755        );
11756        assert!(
11757            rendered.contains("pleme-io"),
11758            "diagnostic must quote the offending author: {rendered}",
11759        );
11760    }
11761
11762    #[test]
11763    fn validate_autores_rejects_leading_whitespace_entry() {
11764        // Canonical paste-from-aligned-doc footgun. Without the shape
11765        // gate `" pleme-io"` silently passed validate and landed as a
11766        // YAML plain-style scalar with leading whitespace in the
11767        // rendered Chart.yaml `maintainers:` array — every YAML 1.2
11768        // dumper trims leading whitespace from plain-style scalars, so
11769        // the authored space round-tripped inconsistently back through
11770        // `caixa.lisp`. Mirrors the peer
11771        // `validate_descricao_rejects_leading_whitespace`.
11772        let c = caixa_with_autores(vec![" pleme-io"]);
11773        let err = c.validate_autores().unwrap_err();
11774        let ManifestError::AutorInvalid { autor, reason } = err else {
11775            panic!("expected AutorInvalid, got {err:?}");
11776        };
11777        assert_eq!(autor, " pleme-io");
11778        assert!(reason.contains("whitespace"), "got: {reason}");
11779    }
11780
11781    #[test]
11782    fn validate_autores_rejects_trailing_whitespace_entry() {
11783        // Canonical paste-from-doc footgun.
11784        let c = caixa_with_autores(vec!["pleme-io "]);
11785        let err = c.validate_autores().unwrap_err();
11786        let ManifestError::AutorInvalid { autor, reason } = err else {
11787            panic!("expected AutorInvalid, got {err:?}");
11788        };
11789        assert_eq!(autor, "pleme-io ");
11790        assert!(reason.contains("whitespace"), "got: {reason}");
11791    }
11792
11793    #[test]
11794    fn validate_autores_rejects_embedded_newline_entry() {
11795        // Canonical paste-from-multiline-doc footgun — the author
11796        // pasted a multi-line block of author records into one
11797        // `:autores` entry instead of splitting into one entry per
11798        // author. Without the shape gate `"alice\nbob"` silently
11799        // passed validate and landed as a YAML-illegal multi-line
11800        // scalar in the rendered Chart.yaml `maintainers:` array.
11801        let c = caixa_with_autores(vec!["alice\nbob"]);
11802        let err = c.validate_autores().unwrap_err();
11803        let ManifestError::AutorInvalid { autor, reason } = err else {
11804            panic!("expected AutorInvalid, got {err:?}");
11805        };
11806        assert_eq!(autor, "alice\nbob");
11807        assert!(reason.contains("newline"), "got: {reason}");
11808    }
11809
11810    #[test]
11811    fn validate_autores_rejects_embedded_carriage_return_entry() {
11812        // Canonical paste-from-Windows-CRLF-doc footgun.
11813        let c = caixa_with_autores(vec!["alice\rbob"]);
11814        let err = c.validate_autores().unwrap_err();
11815        let ManifestError::AutorInvalid { autor, reason } = err else {
11816            panic!("expected AutorInvalid, got {err:?}");
11817        };
11818        assert_eq!(autor, "alice\rbob");
11819        assert!(reason.contains("carriage return"), "got: {reason}");
11820    }
11821
11822    #[test]
11823    fn validate_autores_rejects_embedded_tab_entry() {
11824        // Canonical tab-from-aligned-doc footgun.
11825        let c = caixa_with_autores(vec!["Pleme\tContributors"]);
11826        let err = c.validate_autores().unwrap_err();
11827        let ManifestError::AutorInvalid { autor, reason } = err else {
11828            panic!("expected AutorInvalid, got {err:?}");
11829        };
11830        assert_eq!(autor, "Pleme\tContributors");
11831        assert!(reason.contains("tab"), "got: {reason}");
11832    }
11833
11834    #[test]
11835    fn validate_autores_rejects_embedded_control_bytes_entry() {
11836        // Paste-from-binary-blob footguns: NUL, BEL, ESC, DEL all
11837        // surface the same control-byte arm.
11838        for entry in [
11839            "alice\x00bob",
11840            "alice\x07bob",
11841            "alice\x1bbob",
11842            "alice\x7fbob",
11843        ] {
11844            let c = caixa_with_autores(vec![entry]);
11845            let err = c.validate_autores().unwrap_err();
11846            let ManifestError::AutorInvalid { autor, reason } = err else {
11847                panic!("expected AutorInvalid for {entry:?}, got {err:?}");
11848            };
11849            assert_eq!(autor, entry);
11850            assert!(
11851                reason.contains("control character"),
11852                "{entry:?} reason: {reason}",
11853            );
11854        }
11855    }
11856
11857    #[test]
11858    fn validate_autores_accepts_unicode_entry() {
11859        // Unicode positive control: realistic maintainer names carry
11860        // Unicode (`François`, `日本語`, `naïve`). The predicate must
11861        // round-trip Unicode losslessly, peer with the
11862        // `chart_maintainer_name_shape_accepts_unicode` substrate-side
11863        // sweep.
11864        let c = caixa_with_autores(vec![
11865            "François Dupont",
11866            "日本語の名前",
11867            "naïve <naive@example.com>",
11868        ]);
11869        c.validate_autores().unwrap();
11870    }
11871
11872    #[test]
11873    fn validate_autores_empty_takes_precedence_over_shape() {
11874        // Per-entry empty-first cascade pin: an entry that is both
11875        // empty *and* shape-invalid surfaces `AutorEmpty` (the narrower
11876        // "this entry has no value" structural defect dominates the
11877        // broader shape-predicate diagnostic). The empty arm fires
11878        // before the shape predicate is consulted, mirroring the peer
11879        // `validate_repositorio_empty_takes_precedence_over_shape`
11880        // cascade on the universal `Option<String>` siblings — and now
11881        // established on the Vec<String> per-entry surface.
11882        let c = caixa_with_autores(vec![""]);
11883        let err = c.validate_autores().unwrap_err();
11884        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11885    }
11886
11887    #[test]
11888    fn validate_autores_shape_takes_precedence_over_duplicate() {
11889        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
11890        // entry that is malformed surfaces `AutorInvalid` even when a
11891        // later entry would have collided on duplicate. The per-entry
11892        // shape arm fires inside the same loop iteration as the empty
11893        // arm, before the seen-set insert at end-of-iteration —
11894        // structural per-entry defects dominate the cross-entry
11895        // uniqueness diagnostic.
11896        let c = caixa_with_autores(vec!["alice\nbob", "alice\nbob"]);
11897        let err = c.validate_autores().unwrap_err();
11898        assert!(
11899            matches!(err, ManifestError::AutorInvalid { .. }),
11900            "got {err:?}",
11901        );
11902    }
11903
11904    #[test]
11905    fn validate_autores_invalid_diagnostic_names_offending_slot_and_value() {
11906        // Diagnostic-shape pin on the new shape arm (peer with
11907        // `validate_descricao_invalid_diagnostic_carries_offending_value`):
11908        // the rendered Display surfaces both the offending slot name
11909        // and the offending value verbatim, so a `feira lint` run
11910        // points the author at the exact `:autores` entry to fix.
11911        let c = caixa_with_autores(vec!["alice\nbob"]);
11912        let rendered = c.validate_autores().unwrap_err().to_string();
11913        assert!(
11914            rendered.contains(":autores"),
11915            "diagnostic must name the offending slot: {rendered}",
11916        );
11917        assert!(
11918            rendered.contains("alice\\nbob"),
11919            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11920        );
11921    }
11922
11923    #[test]
11924    fn validate_autores_rejects_at_129_byte_boundary() {
11925        // The 128-byte cap pin — boundary-exceeding case rejected,
11926        // boundary-accepting case passes. Mirrors the peer
11927        // `chart_maintainer_name_shape_rejects_at_129_byte_boundary`
11928        // substrate-side pin, surfaced at the per-axis caller so the
11929        // cap propagates through validate end-to-end. Constructed as
11930        // a single all-`a` token so only the cap arm fires.
11931        let max_ok = "a".repeat(128);
11932        let c = caixa_with_autores(vec![max_ok.as_str()]);
11933        c.validate_autores().unwrap();
11934        let too_long = "a".repeat(129);
11935        let c = caixa_with_autores(vec![too_long.as_str()]);
11936        let err = c.validate_autores().unwrap_err();
11937        let ManifestError::AutorInvalid { reason, .. } = err else {
11938            panic!("expected AutorInvalid, got {err:?}");
11939        };
11940        assert!(reason.contains("128"), "got: {reason}");
11941        assert!(reason.contains("129"), "got: {reason}");
11942    }
11943
11944    // ── validate_repositorio — universal-axis git-repo-URL shape ──────
11945
11946    fn caixa_with_repositorio(repositorio: Option<&str>) -> Caixa {
11947        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11948        c.repositorio = repositorio.map(String::from);
11949        c
11950    }
11951
11952    #[test]
11953    fn validate_repositorio_accepts_none() {
11954        // The omit-the-slot identity: `:repositorio` is optional. The
11955        // gate is a no-op when the author didn't declare a value —
11956        // every caixa without a `:repositorio` line trivially passes,
11957        // and the substrate-side renderers fall back to their
11958        // documented placeholder (`caixa-helm`'s `home: None`,
11959        // `caixa-flux`'s `https://github.com/pleme-io/<nome>` derived
11960        // URL). Mirrors the peer `validate_restart_window_accepts_none`
11961        // posture on the other `Option<String>` Caixa slot.
11962        let c = caixa_with_repositorio(None);
11963        c.validate_repositorio().unwrap();
11964    }
11965
11966    #[test]
11967    fn validate_repositorio_accepts_canonical_forms() {
11968        // Positive control sweep across every documented `:repositorio`
11969        // authoring shape — the same union the shared
11970        // `crate::render::is_git_repo_url` predicate accepts and the
11971        // peer `:deps :fonte :repo` axis already routes through.
11972        // Covers the `github:` shorthand (the canonical pleme-io
11973        // convention used in the `:repositorio` field of every
11974        // manifest fixture across `caixa-helm` / `caixa-mesh` and the
11975        // `examples/`), the `https://…` URL the README quickstart uses,
11976        // the `ssh://`, `git://`, `git@host:path` scp-style SSH, and
11977        // `file://` URL schemes the shared predicate documents.
11978        for repo in [
11979            "github:pleme-io/hello-rio",
11980            "github:pleme-io/checkout",
11981            "https://github.com/pleme-io/hello-rio",
11982            "ssh://git@github.com/pleme-io/hello-rio.git",
11983            "git://github.com/pleme-io/hello-rio.git",
11984            "git@github.com:pleme-io/hello-rio.git",
11985            "file:///srv/pleme/hello-rio",
11986        ] {
11987            let c = caixa_with_repositorio(Some(repo));
11988            c.validate_repositorio()
11989                .unwrap_or_else(|err| panic!("canonical {repo:?} must pass: {err:?}"));
11990        }
11991    }
11992
11993    #[test]
11994    fn validate_repositorio_rejects_empty_some() {
11995        // Canonical paste-from-blank-doc footgun. The narrower
11996        // [`ManifestError::RepositorioEmpty`] arm fires before the
11997        // shape predicate is consulted, mirroring the empty-first
11998        // cascade every peer per-axis identity gate uses
11999        // (`NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
12000        // `FonteRepoEmpty` → `FonteRepoInvalid`). Without this gate
12001        // the empty `Some("")` silently passed the renderer's
12002        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
12003        // on `None`) and landed as `home: ""` in `Chart.yaml` /
12004        // `url: ""` in the FluxCD `GitRepository`.
12005        let c = caixa_with_repositorio(Some(""));
12006        let err = c.validate_repositorio().unwrap_err();
12007        assert!(
12008            matches!(err, ManifestError::RepositorioEmpty),
12009            "got {err:?}",
12010        );
12011    }
12012
12013    #[test]
12014    fn validate_repositorio_rejects_whitespace() {
12015        // Paste-from-doc whitespace footgun. The shared
12016        // `is_git_repo_url` predicate refuses any whitespace byte; a
12017        // trailing space in a `:repositorio` value silently broke
12018        // `git clone '<value> '` at clone time. The diagnostic names
12019        // the offending value verbatim.
12020        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio "));
12021        let err = c.validate_repositorio().unwrap_err();
12022        let ManifestError::RepositorioInvalid { repositorio, .. } = err else {
12023            panic!("expected RepositorioInvalid, got {err:?}");
12024        };
12025        assert_eq!(repositorio, "github:pleme-io/hello-rio ");
12026    }
12027
12028    #[test]
12029    fn validate_repositorio_rejects_control_char() {
12030        // Paste-from-multiline-doc CRLF footgun — control characters
12031        // at the URL boundary are a class of subprocess-arg injection
12032        // and break git's URL parser at every porcelain entry point.
12033        let c = caixa_with_repositorio(Some("https://example.com/repo\n"));
12034        let err = c.validate_repositorio().unwrap_err();
12035        assert!(
12036            matches!(err, ManifestError::RepositorioInvalid { .. }),
12037            "got {err:?}",
12038        );
12039    }
12040
12041    #[test]
12042    fn validate_repositorio_rejects_leading_dash() {
12043        // Canonical CLI-argument-injection footgun: `git clone <repo>`
12044        // interprets a leading `-` as a CLI flag, so a
12045        // `-upload-pack=…` value escapes the subprocess argument
12046        // boundary. The shared predicate refuses every leading-`-`
12047        // shape at validate time.
12048        let c = caixa_with_repositorio(Some("-upload-pack=evil"));
12049        let err = c.validate_repositorio().unwrap_err();
12050        assert!(
12051            matches!(err, ManifestError::RepositorioInvalid { .. }),
12052            "got {err:?}",
12053        );
12054    }
12055
12056    #[test]
12057    fn validate_repositorio_rejects_missing_colon_separator() {
12058        // The bare `org/repo` ambiguity footgun — `git clone` reads
12059        // a no-`:` form as a relative filesystem path rather than the
12060        // GitHub-shorthand expansion the author probably intended.
12061        // The shared predicate refuses every shape without a `:`
12062        // separator.
12063        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
12064        let err = c.validate_repositorio().unwrap_err();
12065        assert!(
12066            matches!(err, ManifestError::RepositorioInvalid { .. }),
12067            "got {err:?}",
12068        );
12069    }
12070
12071    #[test]
12072    fn validate_repositorio_rejects_fragment_anchor() {
12073        // Paste-from-browser-address-bar footgun on the
12074        // `:repositorio` axis — an author copies a GitHub permalink
12075        // to a README section / line-permalink and forgets to trim
12076        // the `#fragment` tail. The shared `is_git_repo_url`
12077        // predicate refuses the byte at the URL-grammar layer
12078        // (libcurl strips the fragment before opening the
12079        // transport, so the byte rides verbatim into the rendered
12080        // `Chart.yaml` `home:` and FluxCD `GitRepository` `url:`
12081        // fields but is silently dropped on the wire — two
12082        // manifest variants whose values differ only in their
12083        // fragment anchor lock to two distinct rendered artifacts
12084        // for the byte-identical clone, defeating the THEORY.md
12085        // §V.2 render-determinism contract on the `:repositorio`
12086        // axis the peer `:fonte :repo` axis already closes).
12087        let c = caixa_with_repositorio(Some("https://github.com/pleme-io/hello-rio#readme"));
12088        let err = c.validate_repositorio().unwrap_err();
12089        let ManifestError::RepositorioInvalid {
12090            repositorio,
12091            reason,
12092        } = err
12093        else {
12094            panic!("expected RepositorioInvalid, got {err:?}");
12095        };
12096        assert_eq!(repositorio, "https://github.com/pleme-io/hello-rio#readme");
12097        assert!(
12098            reason.contains("must not contain `#`"),
12099            "reason must surface the fragment-`#` arm, got {reason:?}"
12100        );
12101    }
12102
12103    #[test]
12104    fn validate_repositorio_rejects_query_string() {
12105        // Paste-from-browser-address-bar footgun on the
12106        // `:repositorio` axis (peer with the a68f818 fragment-`#`
12107        // arm on the same axis). An author copies a GitHub tab
12108        // deep-link out of the address bar and forgets to trim
12109        // the `?tab=…` query tail. The shared `is_git_repo_url`
12110        // predicate refuses the byte at the URL-grammar layer
12111        // (GitHub / GitLab / Bitbucket silently ignore the
12112        // `?query` tail and serve the same repo regardless, so
12113        // the byte rides verbatim into the rendered `Chart.yaml`
12114        // `home:` and FluxCD `GitRepository` `url:` fields but
12115        // is silently masked at the wire — two manifest variants
12116        // whose values differ only in their query tail lock to
12117        // two distinct rendered artifacts for the byte-identical
12118        // clone, defeating the THEORY.md §V.2 render-determinism
12119        // contract on the `:repositorio` axis the peer `:fonte
12120        // :repo` axis already closes).
12121        let c = caixa_with_repositorio(Some(
12122            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file",
12123        ));
12124        let err = c.validate_repositorio().unwrap_err();
12125        let ManifestError::RepositorioInvalid {
12126            repositorio,
12127            reason,
12128        } = err
12129        else {
12130            panic!("expected RepositorioInvalid, got {err:?}");
12131        };
12132        assert_eq!(
12133            repositorio,
12134            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file"
12135        );
12136        assert!(
12137            reason.contains("must not contain `?`"),
12138            "reason must surface the query-`?` arm, got {reason:?}"
12139        );
12140    }
12141
12142    #[test]
12143    fn validate_repositorio_rejects_embedded_backslash() {
12144        // Windows-file-path-confusion footgun on the `:repositorio`
12145        // axis (peer with the prior fragment-`#` / query-`?` arms on
12146        // the same axis, and peer with the new dep-level `:fonte :repo`
12147        // backslash arm on the URL-grammar trajectory). An author
12148        // pastes a Windows Explorer address-bar `file:///C:\Users\me\
12149        // hello-rio` into the `:repositorio` slot, expecting the
12150        // `lareira-<nome>` chart's `home:` field and the FluxCD
12151        // `GitRepository` `url:` field to render the canonical local
12152        // file-URI. The shared `is_git_repo_url` predicate refuses
12153        // the byte at the URL-grammar layer (libcurl silently
12154        // translates `\` → `/` on some platforms and refuses it on
12155        // others, so the byte rides verbatim into the rendered
12156        // artifacts but is silently rewritten or rejected at the wire
12157        // — two manifest variants whose values differ only in
12158        // backslash-vs-forward-slash lock to two distinct rendered
12159        // artifacts for the byte-identical clone, defeating the
12160        // THEORY.md §V.2 render-determinism contract on the
12161        // `:repositorio` axis the peer `:fonte :repo` axis already
12162        // closes).
12163        let c = caixa_with_repositorio(Some("file:///C:\\Users\\me\\hello-rio"));
12164        let err = c.validate_repositorio().unwrap_err();
12165        let ManifestError::RepositorioInvalid {
12166            repositorio,
12167            reason,
12168        } = err
12169        else {
12170            panic!("expected RepositorioInvalid, got {err:?}");
12171        };
12172        assert_eq!(repositorio, "file:///C:\\Users\\me\\hello-rio");
12173        assert!(
12174            reason.contains("must not contain `\\`"),
12175            "reason must surface the backslash-`\\` arm, got {reason:?}"
12176        );
12177    }
12178
12179    #[test]
12180    fn validate_repositorio_rejects_uri_template_placeholder() {
12181        // URI Template (RFC 6570) placeholder footgun on the
12182        // `:repositorio` axis (peer with the prior fragment-`#` /
12183        // query-`?` / backslash-`\` arms on the same axis, and peer
12184        // with the new dep-level `:fonte :repo` `{` / `}` arm on the
12185        // URL-grammar trajectory). An author pastes a quick-start
12186        // README snippet / OpenAPI `servers:` URL / Helm chart
12187        // `home:` template carrying unresolved `{org}` / `{repo}`
12188        // placeholders into the `:repositorio` slot, expecting the
12189        // substrate to resolve the placeholder downstream. The
12190        // shared `is_git_repo_url` predicate refuses the byte at the
12191        // URL-grammar layer (libcurl percent-encodes `{` / `}` to
12192        // `%7B` / `%7D` on the wire, so the byte round-trips
12193        // inconsistently between the rendered `Chart.yaml home:` /
12194        // FluxCD `GitRepository url:` and the resolver's `git clone`
12195        // invocation, defeating the THEORY.md §V.2 render-
12196        // determinism contract on the `:repositorio` axis the peer
12197        // `:fonte :repo` axis already closes; every git porcelain
12198        // entry-point additionally fetches a nonexistent literal-
12199        // `{placeholder}`-named path far from the source caixa.lisp).
12200        let c = caixa_with_repositorio(Some("https://github.com/{org}/hello-rio"));
12201        let err = c.validate_repositorio().unwrap_err();
12202        let ManifestError::RepositorioInvalid {
12203            repositorio,
12204            reason,
12205        } = err
12206        else {
12207            panic!("expected RepositorioInvalid, got {err:?}");
12208        };
12209        assert_eq!(repositorio, "https://github.com/{org}/hello-rio");
12210        assert!(
12211            reason.contains("must not contain `{`"),
12212            "reason must surface the open-brace `{{` arm, got {reason:?}"
12213        );
12214        assert!(
12215            reason.contains("URI Template") || reason.contains("RFC 6570"),
12216            "reason must name the RFC 6570 URI Template grammar, got {reason:?}"
12217        );
12218    }
12219
12220    #[test]
12221    fn validate_repositorio_empty_takes_precedence_over_shape() {
12222        // Empty-first cascade pin: the empty `Some("")` surfaces the
12223        // narrower `RepositorioEmpty` not the shape-predicate-wrapped
12224        // `RepositorioInvalid`, mirroring the peer
12225        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
12226        // `FonteRepoEmpty` → `FonteRepoInvalid` cascades. The shared
12227        // `is_git_repo_url` predicate also rejects the empty input
12228        // (defensively, with its own `"must not be empty"` reason),
12229        // but the manifest-layer empty arm runs first to surface the
12230        // narrower diagnostic verbatim.
12231        let c = caixa_with_repositorio(Some(""));
12232        let err = c.validate_repositorio().unwrap_err();
12233        assert!(
12234            matches!(err, ManifestError::RepositorioEmpty),
12235            "got {err:?}",
12236        );
12237    }
12238
12239    #[test]
12240    fn validate_repositorio_diagnostic_carries_offending_value() {
12241        // Diagnostic-shape pin (peer with
12242        // `validate_autores_diagnostic_carries_offending_author`): the
12243        // error's Display surfaces the offending value + slot name
12244        // verbatim, so a `feira lint` run can render the diagnostic
12245        // without re-parsing and the author can grep their caixa.lisp
12246        // for the offending `:repositorio` value.
12247        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
12248        let rendered = c.validate_repositorio().unwrap_err().to_string();
12249        assert!(
12250            rendered.contains(":repositorio"),
12251            "diagnostic must name the offending slot: {rendered}",
12252        );
12253        assert!(
12254            rendered.contains("pleme-io/hello-rio"),
12255            "diagnostic must quote the offending value: {rendered}",
12256        );
12257    }
12258
12259    // ── validate_descricao — universal-axis Chart.yaml description shape ──
12260
12261    fn caixa_with_descricao(descricao: Option<&str>) -> Caixa {
12262        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12263        c.descricao = descricao.map(String::from);
12264        c
12265    }
12266
12267    #[test]
12268    fn validate_descricao_accepts_none() {
12269        // The omit-the-slot identity: `:descricao` is optional. The
12270        // gate is a no-op when the author didn't declare a value —
12271        // every caixa without a `:descricao` line trivially passes,
12272        // and the substrate-side renderers fall back to their
12273        // documented `caixa.nome`-derived placeholder. Mirrors the
12274        // peer `validate_repositorio_accepts_none` posture on the
12275        // sibling `Option<String>` Caixa slot.
12276        let c = caixa_with_descricao(None);
12277        c.validate_descricao().unwrap();
12278    }
12279
12280    #[test]
12281    fn validate_descricao_accepts_canonical_summary() {
12282        // Positive control: the canonical pleme-io descricao shape —
12283        // a short free-form prose summary — passes the gate. Covers
12284        // the fixture shapes the `caixa-helm` / `caixa-flux` /
12285        // `caixa-mesh` test fixtures use (`"Canonical Rust→wasm32-
12286        // wasip2 caixa Servico."`, `"Checkout flow."`).
12287        for desc in [
12288            "Canonical Rust→wasm32-wasip2 caixa Servico.",
12289            "Checkout flow.",
12290            "AWS provider caixa for tatara-lisp",
12291            "FIXME — describe this caixa",
12292            "x",
12293        ] {
12294            let c = caixa_with_descricao(Some(desc));
12295            c.validate_descricao()
12296                .unwrap_or_else(|err| panic!("canonical {desc:?} must pass: {err:?}"));
12297        }
12298    }
12299
12300    #[test]
12301    fn validate_descricao_rejects_empty_some() {
12302        // Canonical paste-from-blank-doc footgun. Without this gate
12303        // the empty `Some("")` silently passed the renderer's
12304        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
12305        // on `None`) and landed as `description: ""` in `Chart.yaml`
12306        // and a blank `README.md` header. Mirrors the peer
12307        // [`ManifestError::RepositorioEmpty`] empty-arm on the
12308        // sibling `Option<String>` Caixa slot.
12309        let c = caixa_with_descricao(Some(""));
12310        let err = c.validate_descricao().unwrap_err();
12311        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
12312    }
12313
12314    #[test]
12315    fn validate_descricao_rejects_leading_whitespace() {
12316        // Paste-from-aligned-doc footgun: a leading ASCII space the
12317        // bare empty-arm gate accepted, the shape predicate now
12318        // refuses. The diagnostic carries the offending value
12319        // verbatim (with the leading space preserved) so the author
12320        // can grep their caixa.lisp for the exact `:descricao` line
12321        // and fix the round-trip-inconsistent leading whitespace.
12322        // Mirrors the peer
12323        // `validate_licenca_rejects_leading_whitespace` arm on the
12324        // sibling `:licenca` axis.
12325        let c = caixa_with_descricao(Some(" Checkout flow."));
12326        let err = c.validate_descricao().unwrap_err();
12327        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
12328            panic!("expected DescricaoInvalid, got {err:?}");
12329        };
12330        assert_eq!(descricao, " Checkout flow.");
12331        assert!(reason.contains("whitespace"), "got: {reason:?}");
12332    }
12333
12334    #[test]
12335    fn validate_descricao_rejects_trailing_whitespace() {
12336        // Paste-from-doc footgun: a trailing ASCII space the bare
12337        // empty-arm gate accepted, the shape predicate now refuses.
12338        let c = caixa_with_descricao(Some("Checkout flow. "));
12339        let err = c.validate_descricao().unwrap_err();
12340        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
12341            panic!("expected DescricaoInvalid, got {err:?}");
12342        };
12343        assert_eq!(descricao, "Checkout flow. ");
12344        assert!(reason.contains("whitespace"), "got: {reason:?}");
12345    }
12346
12347    #[test]
12348    fn validate_descricao_rejects_embedded_newline() {
12349        // Paste-from-multiline-doc footgun: an embedded LF the bare
12350        // empty-arm gate accepted, the shape predicate now refuses.
12351        // Without this gate the embedded newline silently landed in
12352        // the rendered Chart.yaml as a multi-line YAML block scalar,
12353        // and every chart-aware UI (`helm list`, `helm search`,
12354        // Artifact Hub) renders the description in a single-line
12355        // column so the embedded newline is silently dropped at
12356        // every downstream consumer.
12357        let c = caixa_with_descricao(Some("Checkout\nflow."));
12358        let err = c.validate_descricao().unwrap_err();
12359        assert!(
12360            matches!(err, ManifestError::DescricaoInvalid { .. }),
12361            "got {err:?}",
12362        );
12363        assert!(err.to_string().contains("newline"), "got {err}");
12364    }
12365
12366    #[test]
12367    fn validate_descricao_rejects_embedded_carriage_return() {
12368        // Paste-from-Windows-CRLF-doc footgun.
12369        let c = caixa_with_descricao(Some("Checkout\rflow."));
12370        let err = c.validate_descricao().unwrap_err();
12371        assert!(
12372            matches!(err, ManifestError::DescricaoInvalid { .. }),
12373            "got {err:?}",
12374        );
12375        assert!(err.to_string().contains("carriage return"), "got {err}");
12376    }
12377
12378    #[test]
12379    fn validate_descricao_rejects_embedded_tab() {
12380        // Tab-from-aligned-doc footgun.
12381        let c = caixa_with_descricao(Some("Checkout\tflow."));
12382        let err = c.validate_descricao().unwrap_err();
12383        assert!(
12384            matches!(err, ManifestError::DescricaoInvalid { .. }),
12385            "got {err:?}",
12386        );
12387        assert!(err.to_string().contains("tab"), "got {err}");
12388    }
12389
12390    #[test]
12391    fn validate_descricao_rejects_embedded_control_bytes() {
12392        // Paste-from-binary-blob footgun: every other control byte
12393        // (NUL, BEL, ESC, DEL) is refused at validate time. Mirrors
12394        // the peer SPDX-expression control-byte arm.
12395        for s in [
12396            "Checkout\x00flow.",
12397            "Checkout\x07flow.",
12398            "Checkout\x1bflow.",
12399            "Checkout\x7fflow.",
12400        ] {
12401            let c = caixa_with_descricao(Some(s));
12402            let err = c.validate_descricao().unwrap_err();
12403            assert!(
12404                matches!(err, ManifestError::DescricaoInvalid { .. }),
12405                "{s:?} got {err:?}",
12406            );
12407            assert!(
12408                err.to_string().contains("control character"),
12409                "{s:?} got {err}",
12410            );
12411        }
12412    }
12413
12414    #[test]
12415    fn validate_descricao_accepts_unicode_prose() {
12416        // Positive control: Unicode prose is accepted — the
12417        // canonical fixtures carry `→` (U+2192) and `—` (U+2014),
12418        // and `Caixa::template`'s `"FIXME — describe this caixa"`
12419        // scaffold every `feira init` emits must continue to pass.
12420        for s in [
12421            "Canonical Rust→wasm32-wasip2 caixa Servico.",
12422            "FIXME — describe this caixa",
12423            "Caixa pour le projet tâche",
12424            "日本語の説明",
12425        ] {
12426            let c = caixa_with_descricao(Some(s));
12427            c.validate_descricao()
12428                .unwrap_or_else(|err| panic!("Unicode {s:?} must pass: {err:?}"));
12429        }
12430    }
12431
12432    #[test]
12433    fn validate_descricao_empty_takes_precedence_over_shape() {
12434        // Cascade pin: a `Some("")` surfaces the narrower
12435        // `DescricaoEmpty` arm, not the broader `DescricaoInvalid`
12436        // shape-predicate arm. Mirrors the peer
12437        // `validate_licenca_empty_takes_precedence_over_shape` pin
12438        // on the sibling `:licenca` axis.
12439        let c = caixa_with_descricao(Some(""));
12440        let err = c.validate_descricao().unwrap_err();
12441        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
12442    }
12443
12444    #[test]
12445    fn validate_descricao_invalid_diagnostic_carries_offending_value_and_slot() {
12446        // Diagnostic-shape pin: the error's Display surfaces both
12447        // the `:descricao` slot name and the offending value
12448        // verbatim, so a `feira lint` run can render the diagnostic
12449        // without re-parsing and the author can grep their caixa.lisp
12450        // for the offending `:descricao` line. Mirrors the peer
12451        // `validate_licenca_invalid_diagnostic_carries_offending_value_and_slot`
12452        // pin (ee2e888) on the sibling `:licenca` axis.
12453        // The `{descricao:?}` Debug format escapes embedded control
12454        // bytes; the quoted offending value surfaces as
12455        // `"Checkout\nflow."` (literal backslash-n) in the rendered
12456        // diagnostic. The author can grep their caixa.lisp for the
12457        // literal `Checkout` summary prefix.
12458        let c = caixa_with_descricao(Some("Checkout\nflow."));
12459        let rendered = c.validate_descricao().unwrap_err().to_string();
12460        assert!(
12461            rendered.contains(":descricao"),
12462            "diagnostic must name the offending slot: {rendered}",
12463        );
12464        assert!(
12465            rendered.contains("Checkout\\nflow."),
12466            "diagnostic must quote the offending value (debug-escaped): {rendered}",
12467        );
12468    }
12469
12470    #[test]
12471    fn validate_descricao_template_passes() {
12472        // Round-trip pin: the bare `Caixa::template` shape carries
12473        // `:descricao "FIXME — describe this caixa"` (a non-empty
12474        // sentinel), so the template-derived Caixa passes the gate by
12475        // construction. A future template-shape change that omits or
12476        // empties `:descricao` would surface here as a regression.
12477        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12478        c.validate_descricao().unwrap();
12479    }
12480
12481    #[test]
12482    fn validate_descricao_diagnostic_names_offending_slot() {
12483        // Diagnostic-shape pin (peer with
12484        // `validate_repositorio_diagnostic_carries_offending_value`):
12485        // the error's Display surfaces the `:descricao` slot name
12486        // verbatim, so a `feira lint` run can render the diagnostic
12487        // without re-parsing and the author can grep their caixa.lisp
12488        // for the offending `:descricao` line.
12489        let c = caixa_with_descricao(Some(""));
12490        let rendered = c.validate_descricao().unwrap_err().to_string();
12491        assert!(
12492            rendered.contains(":descricao"),
12493            "diagnostic must name the offending slot: {rendered}",
12494        );
12495    }
12496
12497    // ── validate_licenca — universal-axis chart README license shape ──
12498
12499    fn caixa_with_licenca(licenca: Option<&str>) -> Caixa {
12500        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12501        c.licenca = licenca.map(String::from);
12502        c
12503    }
12504
12505    #[test]
12506    fn validate_licenca_accepts_none() {
12507        // The omit-the-slot identity: `:licenca` is optional. The
12508        // gate is a no-op when the author didn't declare a value —
12509        // every caixa without a `:licenca` line trivially passes,
12510        // and the substrate-side `caixa-helm` renderer falls back to
12511        // the documented `"MIT"` placeholder. Mirrors the peer
12512        // `validate_descricao_accepts_none` posture on the sibling
12513        // `Option<String>` Caixa slot.
12514        let c = caixa_with_licenca(None);
12515        c.validate_licenca().unwrap();
12516    }
12517
12518    #[test]
12519    fn validate_licenca_accepts_canonical_expressions() {
12520        // Positive control: every canonical SPDX expression shape
12521        // pleme-io carries in its existing fixtures + the canonical
12522        // SPDX dual-license / with-exception / `+`-suffix / grouped /
12523        // user-defined-reference shapes all pass the gate. Covers
12524        // the single-license, `OR`-compound, `AND`-compound,
12525        // `WITH`-exception, parenthesis-grouped, `+`-suffix, and
12526        // `LicenseRef-` / `DocumentRef-:LicenseRef-` shapes — every
12527        // production the SPDX 2.1 expression grammar admits that
12528        // sits within the alphabet floor the
12529        // `is_spdx_expression_shape` predicate enforces.
12530        for lic in [
12531            "MIT",
12532            "Apache-2.0",
12533            "Apache-2.0 OR MIT",
12534            "Apache-2.0 AND MIT",
12535            "BSD-3-Clause",
12536            "MPL-2.0",
12537            "GPL-3.0-or-later",
12538            "GPL-2.0+",
12539            "Apache-2.0 WITH LLVM-exception",
12540            "(MIT OR Apache-2.0) AND BSD-3-Clause",
12541            "(MIT OR Apache-2.0) AND BSD-3-Clause AND ISC",
12542            "LicenseRef-MyLicense",
12543            "DocumentRef-spdx-tool:LicenseRef-MIT-Style",
12544            "x",
12545        ] {
12546            let c = caixa_with_licenca(Some(lic));
12547            c.validate_licenca()
12548                .unwrap_or_else(|err| panic!("canonical {lic:?} must pass: {err:?}"));
12549        }
12550    }
12551
12552    #[test]
12553    fn validate_licenca_rejects_trailing_whitespace() {
12554        // Paste-from-doc whitespace footgun. A trailing space in the
12555        // `:licenca` value would silently break a downstream SPDX
12556        // parser that splits on exact `AND` / `OR` / `WITH` keyword
12557        // boundaries. The shape predicate refuses every trailing
12558        // whitespace byte by construction. Peer with
12559        // `validate_repositorio_rejects_whitespace` and
12560        // `validate_edicao_rejects_trailing_whitespace`.
12561        let c = caixa_with_licenca(Some("MIT "));
12562        let err = c.validate_licenca().unwrap_err();
12563        let ManifestError::LicencaInvalid { licenca, .. } = err else {
12564            panic!("expected LicencaInvalid, got {err:?}");
12565        };
12566        assert_eq!(licenca, "MIT ");
12567    }
12568
12569    #[test]
12570    fn validate_licenca_rejects_leading_whitespace() {
12571        // Symmetric paste-from-doc whitespace footgun on the leading
12572        // boundary — the gate refuses every shape that starts with a
12573        // space byte by construction. Peer with
12574        // `validate_edicao_rejects_leading_whitespace`.
12575        let c = caixa_with_licenca(Some(" MIT"));
12576        let err = c.validate_licenca().unwrap_err();
12577        assert!(
12578            matches!(err, ManifestError::LicencaInvalid { .. }),
12579            "got {err:?}",
12580        );
12581    }
12582
12583    #[test]
12584    fn validate_licenca_rejects_control_char() {
12585        // Paste-from-multiline-doc CRLF footgun — control characters
12586        // at the value boundary land as a malformed line in the
12587        // rendered chart `README.md` `## License` section. Peer with
12588        // `validate_repositorio_rejects_control_char` and
12589        // `validate_edicao_rejects_control_char`.
12590        for lic in ["MIT\n", "MIT\r\n", "MIT\rApache-2.0"] {
12591            let c = caixa_with_licenca(Some(lic));
12592            let err = c.validate_licenca().unwrap_err();
12593            assert!(
12594                matches!(err, ManifestError::LicencaInvalid { .. }),
12595                "expected LicencaInvalid on {lic:?}, got {err:?}",
12596            );
12597        }
12598    }
12599
12600    #[test]
12601    fn validate_licenca_rejects_tab() {
12602        // Tab-from-aligned-doc footgun — SPDX expressions use a
12603        // single ASCII space between tokens; a tab breaks every
12604        // downstream SPDX parser that splits on exact `" "`
12605        // boundaries.
12606        let c = caixa_with_licenca(Some("MIT\tOR Apache-2.0"));
12607        let err = c.validate_licenca().unwrap_err();
12608        assert!(
12609            matches!(err, ManifestError::LicencaInvalid { .. }),
12610            "got {err:?}",
12611        );
12612    }
12613
12614    #[test]
12615    fn validate_licenca_rejects_non_ascii() {
12616        // Smart-quote / non-ASCII paste footgun — SPDX identifiers
12617        // are ASCII per the `idstring = 1*(ALPHA / DIGIT / "-" /
12618        // ".")` production. The shape predicate refuses every
12619        // non-ASCII byte by construction; peer with
12620        // `validate_edicao_rejects_non_ascii_lookalike`.
12621        for lic in ["MIT\u{a0}OR Apache-2.0", "MIT\u{2013}1.0", "Café-1.0"] {
12622            let c = caixa_with_licenca(Some(lic));
12623            let err = c.validate_licenca().unwrap_err();
12624            assert!(
12625                matches!(err, ManifestError::LicencaInvalid { .. }),
12626                "expected LicencaInvalid on {lic:?}, got {err:?}",
12627            );
12628        }
12629    }
12630
12631    #[test]
12632    fn validate_licenca_rejects_underscore() {
12633        // Underscore-instead-of-hyphen typo footgun — `Apache_2.0` /
12634        // `MIT_Style` / `BSD_3_Clause` are familiar shapes from
12635        // snake-case identifier conventions that don't apply to the
12636        // SPDX `idstring` grammar (which admits only `ALPHA / DIGIT /
12637        // "-" / "."`). The shape predicate refuses every underscore
12638        // byte by construction.
12639        for lic in ["Apache_2.0", "MIT_Style", "BSD_3_Clause"] {
12640            let c = caixa_with_licenca(Some(lic));
12641            let err = c.validate_licenca().unwrap_err();
12642            assert!(
12643                matches!(err, ManifestError::LicencaInvalid { .. }),
12644                "expected LicencaInvalid on {lic:?}, got {err:?}",
12645            );
12646        }
12647    }
12648
12649    #[test]
12650    fn validate_licenca_rejects_comma_separator() {
12651        // Comma-instead-of-`OR`-keyword colloquial idiom footgun —
12652        // SPDX expressions compose multiple licenses via `AND` / `OR`
12653        // keywords, not the comma separator. The shape predicate
12654        // refuses every comma byte by construction.
12655        for lic in ["MIT, Apache-2.0", "MIT,Apache-2.0"] {
12656            let c = caixa_with_licenca(Some(lic));
12657            let err = c.validate_licenca().unwrap_err();
12658            assert!(
12659                matches!(err, ManifestError::LicencaInvalid { .. }),
12660                "expected LicencaInvalid on {lic:?}, got {err:?}",
12661            );
12662        }
12663    }
12664
12665    #[test]
12666    fn validate_licenca_rejects_slash_dual_license() {
12667        // Slash-dual-license colloquial idiom footgun — the
12668        // `MIT/Apache-2.0` shape is common in Cargo's pre-SPDX
12669        // `package.license` field but non-SPDX; the SPDX equivalent
12670        // is `MIT OR Apache-2.0`. The shape predicate refuses every
12671        // forward-slash byte by construction.
12672        for lic in ["MIT/Apache-2.0", "MIT/BSD-3-Clause"] {
12673            let c = caixa_with_licenca(Some(lic));
12674            let err = c.validate_licenca().unwrap_err();
12675            assert!(
12676                matches!(err, ManifestError::LicencaInvalid { .. }),
12677                "expected LicencaInvalid on {lic:?}, got {err:?}",
12678            );
12679        }
12680    }
12681
12682    #[test]
12683    fn validate_licenca_rejects_semicolon_separator() {
12684        // Semicolon-list-separator confusion footgun — adjacent to
12685        // the comma-separator idiom, every list-separator-belongs-
12686        // to-list-grammar confusion lands here.
12687        let c = caixa_with_licenca(Some("MIT; Apache-2.0"));
12688        let err = c.validate_licenca().unwrap_err();
12689        assert!(
12690            matches!(err, ManifestError::LicencaInvalid { .. }),
12691            "got {err:?}",
12692        );
12693    }
12694
12695    #[test]
12696    fn validate_licenca_empty_takes_precedence_over_shape() {
12697        // Empty-first cascade pin: the empty `Some("")` surfaces the
12698        // narrower `LicencaEmpty` not the shape-predicate-wrapped
12699        // `LicencaInvalid`, mirroring the peer
12700        // `validate_edicao_empty_takes_precedence_over_shape` and
12701        // `validate_repositorio_empty_takes_precedence_over_shape`
12702        // (`RepositorioEmpty` → `RepositorioInvalid`), `NomeEmpty` →
12703        // `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid` cascades.
12704        // The shape predicate also refuses the empty input
12705        // (defensively — `"must not be empty"`), but the manifest-
12706        // layer empty arm runs first to surface the narrower
12707        // diagnostic verbatim.
12708        let c = caixa_with_licenca(Some(""));
12709        let err = c.validate_licenca().unwrap_err();
12710        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
12711    }
12712
12713    #[test]
12714    fn validate_licenca_invalid_diagnostic_carries_offending_value() {
12715        // Diagnostic-shape pin on the shape-predicate arm (peer with
12716        // `validate_edicao_invalid_diagnostic_carries_offending_value`
12717        // and `validate_repositorio_diagnostic_carries_offending_value`):
12718        // the error's Display surfaces the offending value + slot
12719        // name verbatim, so a `feira lint` run can render the
12720        // diagnostic without re-parsing and the author can grep
12721        // their caixa.lisp for the offending `:licenca` value.
12722        let c = caixa_with_licenca(Some("Apache_2.0"));
12723        let rendered = c.validate_licenca().unwrap_err().to_string();
12724        assert!(
12725            rendered.contains(":licenca"),
12726            "diagnostic must name the offending slot: {rendered}",
12727        );
12728        assert!(
12729            rendered.contains("Apache_2.0"),
12730            "diagnostic must quote the offending value: {rendered}",
12731        );
12732    }
12733
12734    #[test]
12735    fn validate_licenca_rejects_empty_some() {
12736        // Canonical paste-from-blank-doc footgun. Without this gate
12737        // the empty `Some("")` silently passed the renderer's
12738        // `Option::unwrap_or_else(|| "MIT".into())` (which only
12739        // fires on `None`) and landed as a bare trailing period in
12740        // the rendered chart `README.md` `## License` section.
12741        // Mirrors the peer [`ManifestError::DescricaoEmpty`] empty-
12742        // arm on the sibling `Option<String>` Caixa slot.
12743        let c = caixa_with_licenca(Some(""));
12744        let err = c.validate_licenca().unwrap_err();
12745        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
12746    }
12747
12748    #[test]
12749    fn validate_licenca_template_passes() {
12750        // Round-trip pin: the bare `Caixa::template` shape (whether
12751        // it carries `:licenca` or omits it) passes the gate by
12752        // construction. A future template-shape change that
12753        // introduced `(:licenca "")` would surface here as a
12754        // regression. Mirrors the peer
12755        // `validate_descricao_template_passes` pin.
12756        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12757        c.validate_licenca().unwrap();
12758    }
12759
12760    #[test]
12761    fn validate_licenca_diagnostic_names_offending_slot() {
12762        // Diagnostic-shape pin (peer with
12763        // `validate_descricao_diagnostic_names_offending_slot`):
12764        // the error's Display surfaces the `:licenca` slot name
12765        // verbatim, so a `feira lint` run can render the diagnostic
12766        // without re-parsing and the author can grep their caixa.lisp
12767        // for the offending `:licenca` line.
12768        let c = caixa_with_licenca(Some(""));
12769        let rendered = c.validate_licenca().unwrap_err().to_string();
12770        assert!(
12771            rendered.contains(":licenca"),
12772            "diagnostic must name the offending slot: {rendered}",
12773        );
12774    }
12775
12776    // ── Caixa::licenca — outer top-level Option<&str> scalar accessor ──
12777
12778    #[test]
12779    fn licenca_returns_licenca_byte_string_verbatim_across_permutations() {
12780        // The canonical per-`Caixa` `:licenca` SPDX-expression scalar
12781        // pin: [`Caixa::licenca`] must return the `:licenca` typed
12782        // byte-string verbatim as an `Option<&str>`, byte-equal to the
12783        // raw `self.licenca.as_deref()` access across every
12784        // representative value in the accept-set — `None` (the "omit
12785        // the slot to defer to the caixa-helm renderer's `MIT`
12786        // fallback" arm every existing fixture without a `:licenca`
12787        // line carries), `Some("")` (a past-the-guard sentinel that
12788        // pins the accessor doesn't perform a silent
12789        // `Some("") → None` collapse on the empty arm — validate
12790        // rejects `Some("")` through `LicencaEmpty` but the accessor
12791        // must ship the raw slot verbatim so a validate-time gate
12792        // regression surfaces at the caixa-helm emit boundary rather
12793        // than being silently absorbed into the fallback), `Some("MIT")`
12794        // (the canonical single-license shape every `feira init`
12795        // template scaffolds), `Some("Apache-2.0 OR MIT")` (the
12796        // canonical `OR`-compound shape the peer
12797        // `validate_licenca_accepts_canonical_expressions` positive
12798        // sweep exercises), `Some("(MIT OR Apache-2.0) AND
12799        // BSD-3-Clause")` (the canonical parenthesis-grouped shape),
12800        // `Some("MIT ")` / `Some(" MIT")` / `Some("MIT\n")` /
12801        // `Some("Apache_2.0")` / `Some("MIT,Apache-2.0")` (past-the-
12802        // guard sentinels — validate rejects each through
12803        // `LicencaInvalid` but the accessor must ship the raw slot
12804        // verbatim).
12805        //
12806        // First outer top-level [`Caixa`] `Option<&str>`-return scalar
12807        // accessor pin on the substrate primitive — opens the "outer
12808        // [`Caixa`] `Option<&str>` scalar" projection pattern the
12809        // sibling per-`Caixa` `:descricao` / `:repositorio` / `:edicao`
12810        // future lifts fold on. Sibling in shape to the peer per-`:placement`
12811        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12812        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12813        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12814        // axes, extended onto the outer top-level [`Caixa`] universal-
12815        // axis surface. Pins against a future silent detour that
12816        // returned an owned `Option<String>` (which would type-check
12817        // but silently allocate on every accessor call, breaking the
12818        // zero-cost projection every peer sibling accessor carries), a
12819        // `Some("") → None` collapse (which would silently absorb the
12820        // `LicencaEmpty` refusal case at the accessor boundary and the
12821        // caixa-helm emit path would silently fall back to `"MIT"` on
12822        // a struct-literal `Caixa { licenca: Some(""), .. }`), or a
12823        // `None → Some("MIT")` collapse (which would silently reify
12824        // the caixa-helm renderer's `"MIT"` fallback at the accessor
12825        // boundary and every downstream consumer keying off the
12826        // `Option::is_none()` discriminator would lose the "author
12827        // omitted the slot" signal).
12828        for licenca in [
12829            None,
12830            Some(""),
12831            Some("MIT"),
12832            Some("Apache-2.0 OR MIT"),
12833            Some("(MIT OR Apache-2.0) AND BSD-3-Clause"),
12834            Some("MIT "),
12835            Some(" MIT"),
12836            Some("MIT\n"),
12837            Some("Apache_2.0"),
12838            Some("MIT,Apache-2.0"),
12839        ] {
12840            let c = caixa_with_licenca(licenca);
12841            assert_eq!(
12842                c.licenca(),
12843                licenca,
12844                "Caixa::licenca must return :licenca verbatim (got {:?}, \
12845                 expected {licenca:?})",
12846                c.licenca(),
12847            );
12848            assert_eq!(
12849                c.licenca(),
12850                c.licenca.as_deref(),
12851                "Caixa::licenca must byte-equal the raw \
12852                 `self.licenca.as_deref()` field access across every \
12853                 value in the Option<&str> accept-set",
12854            );
12855        }
12856    }
12857
12858    #[test]
12859    fn validate_licenca_empty_arm_routes_through_accessor() {
12860        // Composition pin: [`Caixa::validate_licenca`]'s empty-arm gate
12861        // must key off [`Caixa::licenca`], not the raw
12862        // `self.licenca.as_deref()` field access. Structurally: a
12863        // `Caixa { licenca: Some(""), .. }` must surface the
12864        // `LicencaEmpty` refusal exactly, and a
12865        // `Caixa { licenca: Some("MIT"), .. }` (the canonical
12866        // single-license form) must pass validate. The pair jointly
12867        // pins the accessor + validate-gate composition: any future
12868        // silent detour that had the accessor return `None` on the
12869        // empty arm (a `.filter(|s| !s.is_empty())` collapse) would
12870        // silently absorb the `LicencaEmpty` refusal at the accessor
12871        // boundary and the validate gate would accept a struct-literal
12872        // `Caixa { licenca: Some(""), .. }` — the composition pin
12873        // catches that at caixa-core build time.
12874        //
12875        // Peer of the per-`:politicas :circuit-breaker`
12876        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
12877        // accessor-composition pin
12878        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
12879        // on the sibling per-M3-mesh-slot required-`u32` axis — same
12880        // "the validate / shape-gate predicate must route through the
12881        // substrate-primitive typed dispatch" discipline extended onto
12882        // the outer top-level [`Caixa`] universal-axis
12883        // `Option<&str>`-composition surface.
12884        let c = caixa_with_licenca(Some(""));
12885        assert!(
12886            matches!(c.validate_licenca(), Err(ManifestError::LicencaEmpty)),
12887            "validate_licenca must reject licenca == Some(\"\") with \
12888             LicencaEmpty — the accessor and the validate gate must \
12889             route through the same substrate-primitive typed dispatch \
12890             on the :licenca empty arm",
12891        );
12892        let c = caixa_with_licenca(Some("MIT"));
12893        assert!(
12894            c.validate_licenca().is_ok(),
12895            "validate_licenca must accept licenca == Some(\"MIT\") \
12896             (the canonical single-license SPDX shape)",
12897        );
12898    }
12899
12900    #[test]
12901    fn licenca_projects_option_str_by_borrow() {
12902        // The by-borrow pin: [`Caixa::licenca`] returns
12903        // `Option<&str>` by borrow — the `&str` borrows the underlying
12904        // `String` storage of the `Option<String>` slot and the
12905        // accessor must not allocate a fresh `String` on every call.
12906        // Peer of the per-`:placement`
12907        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
12908        // borrow pin on the peer per-M3-mesh-slot
12909        // `Option<&str>`-return axis, extended onto the outer top-
12910        // level [`Caixa`] universal-axis `Option<&str>` shape — the
12911        // accessor's returned `&str` must borrow from `&self` (the
12912        // returned reference's lifetime is tied to `&self`), and
12913        // calling the accessor twice on the same [`Caixa`] must yield
12914        // the same `Option<&str>` verbatim (idempotent, no side
12915        // effects on `&self`).
12916        //
12917        // Pins against a future silent detour that returned an owned
12918        // `Option<String>` (which would type-check but silently
12919        // allocate on every call, breaking the zero-cost projection
12920        // every peer sibling accessor carries), or a one-arm-only
12921        // accessor that returned a saturating value on some sentinel
12922        // input (breaking the pass-through invariant the sibling
12923        // required-scalar accessors carry).
12924        for licenca in [None, Some(""), Some("MIT"), Some("Apache-2.0 OR MIT")] {
12925            let c = caixa_with_licenca(licenca);
12926            let first = c.licenca();
12927            let second = c.licenca();
12928            assert_eq!(
12929                first, second,
12930                "Caixa::licenca must be idempotent — two successive \
12931                 calls on the same &self must return the same \
12932                 Option<&str>",
12933            );
12934            assert_eq!(
12935                first, licenca,
12936                "Caixa::licenca must return :licenca verbatim by \
12937                 borrow — got {first:?}, expected {licenca:?}",
12938            );
12939        }
12940    }
12941
12942    // ── Caixa::repositorio — outer top-level Option<&str> scalar accessor ──
12943
12944    #[test]
12945    fn repositorio_returns_repositorio_byte_string_verbatim_across_permutations() {
12946        // The canonical per-`Caixa` `:repositorio` git-repo-URL scalar
12947        // pin: [`Caixa::repositorio`] must return the `:repositorio`
12948        // typed byte-string verbatim as an `Option<&str>`, byte-equal
12949        // to the raw `self.repositorio.as_deref()` access across every
12950        // representative value in the accept-set — `None` (the "omit
12951        // the slot to defer to the per-renderer placeholder" arm every
12952        // existing fixture without a `:repositorio` line carries),
12953        // `Some("")` (a past-the-guard sentinel that pins the accessor
12954        // doesn't perform a silent `Some("") → None` collapse on the
12955        // empty arm — validate rejects `Some("")` through
12956        // `RepositorioEmpty` but the accessor must ship the raw slot
12957        // verbatim so a validate-time gate regression surfaces at the
12958        // caixa-helm / caixa-flux emit boundary rather than being
12959        // silently absorbed into the per-renderer fallback),
12960        // `Some("github:pleme-io/hello-rio")` (the canonical `github:`
12961        // shorthand every existing manifest fixture across
12962        // `caixa-helm` / `caixa-mesh` and the `examples/` uses),
12963        // `Some("https://github.com/pleme-io/checkout")` (the canonical
12964        // `https://` URL the README quickstart uses),
12965        // `Some("ssh://git@github.com/pleme-io/checkout.git")` /
12966        // `Some("git://github.com/pleme-io/checkout.git")` /
12967        // `Some("git@github.com:pleme-io/checkout.git")` /
12968        // `Some("file:///opt/mirrors/pleme-io/checkout")` (every non-
12969        // github scheme the shared `is_git_repo_url` predicate
12970        // documents), and five past-the-guard sentinels for the
12971        // `RepositorioInvalid` refusal cases (`Some("pleme-io/checkout")`
12972        // missing-colon, `Some("-upload-pack=evil")` leading-dash, /
12973        // `Some("github:pleme-io/checkout?ref=main")` query-string, /
12974        // `Some("github:pleme-io/checkout#main")` fragment-anchor, /
12975        // `Some("github:pleme-io/{tpl}")` URI-template-placeholder — the
12976        // sentinels pin the accessor doesn't silently absorb the
12977        // refusal cases into a fallback).
12978        //
12979        // Second outer top-level [`Caixa`] `Option<&str>`-return scalar
12980        // accessor pin on the substrate primitive — sibling of the peer
12981        // [`Caixa::licenca`] (6d5bc28) pin
12982        // (`licenca_returns_licenca_byte_string_verbatim_across_permutations`)
12983        // that opened the "outer [`Caixa`] `Option<&str>` scalar"
12984        // projection pin pattern this pin folds on. Sibling in shape to
12985        // the peer per-`:placement`
12986        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12987        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12988        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12989        // axes, extended onto the outer top-level [`Caixa`] universal-
12990        // axis surface. Pins against a future silent detour that
12991        // returned an owned `Option<String>` (which would type-check
12992        // but silently allocate on every accessor call, breaking the
12993        // zero-cost projection every peer sibling accessor carries), a
12994        // `Some("") → None` collapse (which would silently absorb the
12995        // `RepositorioEmpty` refusal case at the accessor boundary and
12996        // the caixa-helm `Chart.yaml` `home:` fold would silently
12997        // render a `home: null` / omitted field on a struct-literal
12998        // `Caixa { repositorio: Some(""), .. }`), or a
12999        // `None → Some(<default>)` collapse (which would silently reify
13000        // the per-renderer fallback at the accessor boundary and every
13001        // downstream consumer keying off the `Option::is_none()`
13002        // discriminator would lose the "author omitted the slot"
13003        // signal).
13004        for repositorio in [
13005            None,
13006            Some(""),
13007            Some("github:pleme-io/hello-rio"),
13008            Some("https://github.com/pleme-io/checkout"),
13009            Some("ssh://git@github.com/pleme-io/checkout.git"),
13010            Some("git://github.com/pleme-io/checkout.git"),
13011            Some("git@github.com:pleme-io/checkout.git"),
13012            Some("file:///opt/mirrors/pleme-io/checkout"),
13013            Some("pleme-io/checkout"),
13014            Some("-upload-pack=evil"),
13015            Some("github:pleme-io/checkout?ref=main"),
13016            Some("github:pleme-io/checkout#main"),
13017            Some("github:pleme-io/{tpl}"),
13018        ] {
13019            let c = caixa_with_repositorio(repositorio);
13020            assert_eq!(
13021                c.repositorio(),
13022                repositorio,
13023                "Caixa::repositorio must return :repositorio verbatim \
13024                 (got {:?}, expected {repositorio:?})",
13025                c.repositorio(),
13026            );
13027            assert_eq!(
13028                c.repositorio(),
13029                c.repositorio.as_deref(),
13030                "Caixa::repositorio must byte-equal the raw \
13031                 `self.repositorio.as_deref()` field access across every \
13032                 value in the Option<&str> accept-set",
13033            );
13034        }
13035    }
13036
13037    #[test]
13038    fn validate_repositorio_empty_arm_routes_through_accessor() {
13039        // Composition pin: [`Caixa::validate_repositorio`]'s empty-arm
13040        // gate must key off [`Caixa::repositorio`], not the raw
13041        // `self.repositorio.as_deref()` field access. Structurally: a
13042        // `Caixa { repositorio: Some(""), .. }` must surface the
13043        // `RepositorioEmpty` refusal exactly, and a
13044        // `Caixa { repositorio: Some("github:pleme-io/hello-rio"), .. }`
13045        // (the canonical `github:` shorthand form) must pass validate.
13046        // The pair jointly pins the accessor + validate-gate
13047        // composition: any future silent detour that had the accessor
13048        // return `None` on the empty arm (a `.filter(|s| !s.is_empty())`
13049        // collapse) would silently absorb the `RepositorioEmpty` refusal
13050        // at the accessor boundary and the validate gate would accept a
13051        // struct-literal `Caixa { repositorio: Some(""), .. }` — the
13052        // composition pin catches that at caixa-core build time.
13053        //
13054        // Peer of the [`Caixa::licenca`] (6d5bc28)
13055        // `validate_licenca_empty_arm_routes_through_accessor`
13056        // composition pin on the sibling outer top-level [`Caixa`]
13057        // `Option<&str>` universal-axis surface — same "the validate /
13058        // shape-gate predicate must route through the substrate-
13059        // primitive typed dispatch" discipline extended onto the second
13060        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
13061        // composition surface.
13062        let c = caixa_with_repositorio(Some(""));
13063        assert!(
13064            matches!(
13065                c.validate_repositorio(),
13066                Err(ManifestError::RepositorioEmpty),
13067            ),
13068            "validate_repositorio must reject repositorio == Some(\"\") \
13069             with RepositorioEmpty — the accessor and the validate gate \
13070             must route through the same substrate-primitive typed \
13071             dispatch on the :repositorio empty arm",
13072        );
13073        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio"));
13074        assert!(
13075            c.validate_repositorio().is_ok(),
13076            "validate_repositorio must accept repositorio == \
13077             Some(\"github:pleme-io/hello-rio\") (the canonical \
13078             `github:` shorthand git-repo-URL shape)",
13079        );
13080    }
13081
13082    #[test]
13083    fn repositorio_projects_option_str_by_borrow() {
13084        // The by-borrow pin: [`Caixa::repositorio`] returns
13085        // `Option<&str>` by borrow — the `&str` borrows the underlying
13086        // `String` storage of the `Option<String>` slot and the
13087        // accessor must not allocate a fresh `String` on every call.
13088        // Peer of the per-`:placement`
13089        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) and the
13090        // [`Caixa::licenca`] (6d5bc28) by-borrow pins on the peer
13091        // `Option<&str>`-return axes, extended onto the second outer
13092        // top-level [`Caixa`] universal-axis `Option<&str>` shape —
13093        // the accessor's returned `&str` must borrow from `&self` (the
13094        // returned reference's lifetime is tied to `&self`), and
13095        // calling the accessor twice on the same [`Caixa`] must yield
13096        // the same `Option<&str>` verbatim (idempotent, no side effects
13097        // on `&self`).
13098        //
13099        // Pins against a future silent detour that returned an owned
13100        // `Option<String>` (which would type-check but silently
13101        // allocate on every call, breaking the zero-cost projection
13102        // every peer sibling accessor carries), or a one-arm-only
13103        // accessor that returned a saturating value on some sentinel
13104        // input (breaking the pass-through invariant the sibling
13105        // required-scalar accessors carry).
13106        for repositorio in [
13107            None,
13108            Some(""),
13109            Some("github:pleme-io/hello-rio"),
13110            Some("https://github.com/pleme-io/checkout"),
13111        ] {
13112            let c = caixa_with_repositorio(repositorio);
13113            let first = c.repositorio();
13114            let second = c.repositorio();
13115            assert_eq!(
13116                first, second,
13117                "Caixa::repositorio must be idempotent — two successive \
13118                 calls on the same &self must return the same \
13119                 Option<&str>",
13120            );
13121            assert_eq!(
13122                first, repositorio,
13123                "Caixa::repositorio must return :repositorio verbatim by \
13124                 borrow — got {first:?}, expected {repositorio:?}",
13125            );
13126        }
13127    }
13128
13129    // ── Caixa::canonical_git_url — resolved-git-URL composer ──────────
13130
13131    #[test]
13132    fn canonical_git_url_returns_repositorio_verbatim_on_some_arm() {
13133        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] must
13134        // return the author-declared `:repositorio` byte-string verbatim
13135        // on the `Some` arm — no scheme rewrite, no trailing-slash
13136        // canonicalization, no `github:` → `https://github.com/`
13137        // desugaring. The resolved-URL composer is the projection of
13138        // the raw [`Caixa::repositorio`] `Option<&str>` accessor onto
13139        // the `String`-return arity every substrate-side field-fill
13140        // consumer keys off; on the `Some` arm the projection is
13141        // `str::to_owned` verbatim, so every accept-set value the
13142        // sibling `repositorio_returns_repositorio_byte_string_verbatim_
13143        // across_permutations` pin covers (`https://…`, `github:…`,
13144        // `ssh://…`, `git://…`, `git@…`, `file://…`, and the past-the-
13145        // guard sentinel `pleme-io/…`) must survive the accessor
13146        // byte-equal. Pins against a future silent detour that rewrote
13147        // the `github:` shorthand to the `https://github.com/` full URL
13148        // at the accessor boundary (which would silently split the
13149        // resolved-URL surface from the raw [`Caixa::repositorio`]
13150        // accessor's documented pass-through invariant), or a trailing-
13151        // slash normalization (which would silently break the
13152        // FluxCD `GitRepository` `spec.url` byte-exact match every
13153        // downstream consumer keys the source-controller reconcile off).
13154        for repositorio in [
13155            "github:pleme-io/hello-rio",
13156            "https://github.com/pleme-io/checkout",
13157            "ssh://git@github.com/pleme-io/checkout.git",
13158            "git://github.com/pleme-io/checkout.git",
13159            "git@github.com:pleme-io/checkout.git",
13160            "file:///opt/mirrors/pleme-io/checkout",
13161        ] {
13162            let c = caixa_with_repositorio(Some(repositorio));
13163            assert_eq!(
13164                c.canonical_git_url(),
13165                repositorio,
13166                "Caixa::canonical_git_url on the Some arm must return \
13167                 :repositorio verbatim (got {:?}, expected {repositorio:?})",
13168                c.canonical_git_url(),
13169            );
13170        }
13171    }
13172
13173    #[test]
13174    fn canonical_git_url_falls_back_to_pleme_org_url_on_none_arm() {
13175        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] on the
13176        // `None` arm must emit the substrate's canonical pleme-org github
13177        // URL derived from `caixa.nome()` — `https://github.com/<org>/
13178        // <nome>` with `<org>` bound to [`crate::DEFAULT_PLEME_GIT_ORG`]
13179        // and `<nome>` bound to the typed [`Caixa::nome`] accessor. This
13180        // is the exact byte-image of the prior inline
13181        // [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url`
13182        // composer at caixa-flux/src/lib.rs:2080 that every prior caller
13183        // re-derived open-coded. Pins against a future silent detour
13184        // that migrated the `<org>` segment to a different constant (a
13185        // fork rebranding that split off a new
13186        // `DEFAULT_PLEME_GIT_ORG_MIRROR` const the accessor would need
13187        // to migrate onto), a scheme change (`https://` → `git://` or
13188        // `ssh://`), or a per-`Caixa` `.canonical_git_url_prefix`
13189        // override (which would break the substrate-wide single-source-
13190        // of-truth guarantee this method encodes).
13191        let c = caixa_with_repositorio(None);
13192        let expected = format!(
13193            "https://github.com/{org}/{nome}",
13194            org = crate::DEFAULT_PLEME_GIT_ORG,
13195            nome = c.nome(),
13196        );
13197        assert_eq!(
13198            c.canonical_git_url(),
13199            expected,
13200            "Caixa::canonical_git_url on the None arm must fold through \
13201             the substrate's canonical pleme-org github URL fallback \
13202             `https://github.com/<DEFAULT_PLEME_GIT_ORG>/<nome>` — got \
13203             {:?}, expected {expected:?}",
13204            c.canonical_git_url(),
13205        );
13206    }
13207
13208    #[test]
13209    fn canonical_git_url_byte_matches_manual_composition() {
13210        // Byte-parity pin: [`Caixa::canonical_git_url`] must render
13211        // byte-identically to the manual open-coded
13212        // `caixa.repositorio().map(str::to_owned).unwrap_or_else(||
13213        //  format!("https://github.com/{org}/{nome}", ...))` composition
13214        // every prior substrate-side caller re-derived. Guards the
13215        // paired-site convergence just applied at caixa-flux's
13216        // [`ClusterBundleOpts::for_caixa`] `git_url` composer (which
13217        // now routes through this accessor): a future implementation of
13218        // this method that reordered the format arguments, swapped the
13219        // `<org>` constant for a different one, or interposed a
13220        // canonicalization pass on the `Some` arm surfaces here as a
13221        // caixa-core build-time test failure rather than as a downstream
13222        // FluxCD `GitRepository` reconcile mismatch far from this
13223        // method's source.
13224        for repositorio in [
13225            None,
13226            Some("github:pleme-io/hello-rio"),
13227            Some("https://github.com/pleme-io/checkout"),
13228            Some("ssh://git@github.com/pleme-io/checkout.git"),
13229        ] {
13230            let c = caixa_with_repositorio(repositorio);
13231            let manual = c.repositorio().map_or_else(
13232                || {
13233                    format!(
13234                        "https://github.com/{org}/{nome}",
13235                        org = crate::DEFAULT_PLEME_GIT_ORG,
13236                        nome = c.nome(),
13237                    )
13238                },
13239                str::to_owned,
13240            );
13241            assert_eq!(
13242                c.canonical_git_url(),
13243                manual,
13244                "Caixa::canonical_git_url must byte-equal the manual \
13245                 open-coded `repositorio().map(str::to_owned)\
13246                 .unwrap_or_else(|| format!(...))` composition across \
13247                 every representative :repositorio input — got {:?}, \
13248                 expected {manual:?}",
13249                c.canonical_git_url(),
13250            );
13251        }
13252    }
13253
13254    // ── Caixa::publish_tag — resolved-publish-tag composer ───────────
13255
13256    #[test]
13257    fn publish_tag_composes_prefix_and_versao_on_all_shapes() {
13258        // Fail-before-pass-after pin: [`Caixa::publish_tag`] must compose
13259        // [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] against the caixa's typed
13260        // [`Caixa::versao`] byte-string across every SemVer-2 shape the
13261        // sibling [`validate_versao_accepts_canonical_forms`] positive-set
13262        // sweep documents — bare MAJOR.MINOR.PATCH, pre-release tags
13263        // (`-rc.1`), build metadata (`+build.42`), the combined form, and
13264        // the `0.0.0` boundary case. Every accept-set value the peer
13265        // validate gate lets through must survive the resolved-tag
13266        // projection byte-equal.
13267        for versao in [
13268            "0.1.0",
13269            "0.0.0",
13270            "1.0.0",
13271            "1.2.3-rc.1",
13272            "1.2.3+build.42",
13273            "1.2.3-rc.1+build.42",
13274        ] {
13275            let c = caixa_with_versao(versao);
13276            let expected = format!(
13277                "{prefix}{versao}",
13278                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13279            );
13280            assert_eq!(
13281                c.publish_tag(),
13282                expected,
13283                "Caixa::publish_tag must compose \
13284                 DEFAULT_PUBLISH_TAG_PREFIX ({prefix:?}) against \
13285                 :versao ({versao:?}) verbatim — got {got:?}, \
13286                 expected {expected:?}",
13287                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13288                got = c.publish_tag(),
13289            );
13290        }
13291    }
13292
13293    #[test]
13294    fn publish_tag_starts_with_default_publish_tag_prefix() {
13295        // Prefix-shape pin: every [`Caixa::publish_tag`] emission must
13296        // begin with the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
13297        // byte-string on every input, guarding a hypothetical future
13298        // implementation that migrated the prefix segment to an inline
13299        // literal (`"v"`) that would silently drift from any rebrand of
13300        // the lifted constant. Peer to the sibling caixa-flux
13301        // `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`
13302        // test which pins the same prefix invariant at the reader-side
13303        // `GitRefSpec::Tag` emit site.
13304        for versao in ["0.0.0", "0.1.0", "1.2.3-rc.1", "9.9.9+build.1"] {
13305            let c = caixa_with_versao(versao);
13306            let tag = c.publish_tag();
13307            assert!(
13308                tag.starts_with(crate::DEFAULT_PUBLISH_TAG_PREFIX),
13309                "Caixa::publish_tag emission {tag:?} must start with \
13310                 the lifted crate::DEFAULT_PUBLISH_TAG_PREFIX \
13311                 ({prefix:?})",
13312                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13313            );
13314        }
13315    }
13316
13317    #[test]
13318    fn publish_tag_byte_matches_manual_composition() {
13319        // Byte-parity pin: [`Caixa::publish_tag`] must render byte-
13320        // identically to the manual open-coded
13321        // `format!("{prefix}{versao}", prefix =
13322        //  caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao =
13323        //  caixa.versao())` composition every prior substrate-side
13324        // caller re-derived. Guards the paired-site convergence just
13325        // applied at caixa-flux's [`ClusterBundleOpts::for_caixa`]
13326        // `git_ref` composer (which now routes through this accessor):
13327        // a future implementation of this method that reordered the
13328        // format arguments, swapped the `<prefix>` constant for a
13329        // different one, or interposed a canonicalization pass on the
13330        // `:versao` axis surfaces here as a caixa-core build-time test
13331        // failure rather than as a downstream FluxCD `GitRepository`
13332        // reconcile mismatch far from this method's source.
13333        for versao in [
13334            "0.1.0",
13335            "0.0.0",
13336            "1.2.3-rc.1",
13337            "1.2.3+build.42",
13338            "1.2.3-rc.1+build.42",
13339        ] {
13340            let c = caixa_with_versao(versao);
13341            let manual = format!(
13342                "{prefix}{versao}",
13343                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13344                versao = c.versao(),
13345            );
13346            assert_eq!(
13347                c.publish_tag(),
13348                manual,
13349                "Caixa::publish_tag must byte-equal the manual \
13350                 open-coded `format!(\"{{prefix}}{{versao}}\", ...)` \
13351                 composition across every representative :versao input \
13352                 — got {got:?}, expected {manual:?}",
13353                got = c.publish_tag(),
13354            );
13355        }
13356    }
13357
13358    // ── Caixa::lareira_chart_name — resolved-chart-name composer ─────
13359
13360    #[test]
13361    fn lareira_chart_name_composes_prefix_and_nome_on_all_shapes() {
13362        // Fail-before-pass-after pin: [`Caixa::lareira_chart_name`] must
13363        // compose [`crate::LAREIRA_CHART_NAME_PREFIX`] against the caixa's
13364        // typed [`Caixa::nome`] byte-string across every DNS-1123 shape
13365        // the sibling [`validate_nome_accepts_canonical_forms`] positive-
13366        // set sweep documents — single-word, hyphen-joined, version-
13367        // suffixed, single-char, two-char, digit-start, retry-suffixed.
13368        // Every accept-set value the peer validate gate lets through must
13369        // survive the resolved-chart-name projection byte-equal.
13370        for nome in [
13371            "checkout",
13372            "cart-v2",
13373            "a",
13374            "db",
13375            "3rd-party-shim",
13376            "payment-retry",
13377            "0",
13378        ] {
13379            let c = caixa_with_nome(nome);
13380            let expected = format!("{prefix}{nome}", prefix = crate::LAREIRA_CHART_NAME_PREFIX);
13381            assert_eq!(
13382                c.lareira_chart_name(),
13383                expected,
13384                "Caixa::lareira_chart_name must compose \
13385                 LAREIRA_CHART_NAME_PREFIX ({prefix:?}) against \
13386                 :nome ({nome:?}) verbatim — got {got:?}, \
13387                 expected {expected:?}",
13388                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
13389                got = c.lareira_chart_name(),
13390            );
13391        }
13392    }
13393
13394    #[test]
13395    fn lareira_chart_name_starts_with_lifted_prefix() {
13396        // Prefix-shape pin: every [`Caixa::lareira_chart_name`] emission
13397        // must begin with the canonical
13398        // [`crate::LAREIRA_CHART_NAME_PREFIX`] byte-string on every
13399        // input, guarding a hypothetical future implementation that
13400        // migrated the prefix segment to an inline literal (`"lareira-"`)
13401        // that would silently drift from any rebrand of the lifted
13402        // constant. Peer to the sibling
13403        // [`publish_tag_starts_with_default_publish_tag_prefix`] pin on
13404        // the co-resident resolved-publish-tag composer's prefix axis.
13405        for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
13406            let c = caixa_with_nome(nome);
13407            let chart = c.lareira_chart_name();
13408            assert!(
13409                chart.starts_with(crate::LAREIRA_CHART_NAME_PREFIX),
13410                "Caixa::lareira_chart_name emission {chart:?} must start \
13411                 with the lifted crate::LAREIRA_CHART_NAME_PREFIX \
13412                 ({prefix:?})",
13413                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
13414            );
13415        }
13416    }
13417
13418    #[test]
13419    fn lareira_chart_name_byte_matches_canonical_helper_composition() {
13420        // Byte-parity pin: [`Caixa::lareira_chart_name`] must render
13421        // byte-identically to the manual open-coded
13422        // `caixa_core::lareira_chart_name(caixa.nome())` two-step
13423        // composition every prior substrate-side caller re-derived.
13424        // Guards the paired-site convergence just applied at caixa-helm's
13425        // [`render_chart_for_servico_with`] `ChartDir.name` composer,
13426        // caixa-flux's [`cluster_bundle`] per-CR `chart_name` binding,
13427        // and caixa-tatara's [`process_for_aplicacao`] `release_name`
13428        // composer (all of which now route through this accessor): a
13429        // future implementation of this method that reordered the
13430        // composition arguments, swapped the `<prefix>` constant for a
13431        // different one, or interposed a canonicalization pass on the
13432        // `:nome` axis surfaces here as a caixa-core build-time test
13433        // failure rather than as a downstream Helm chart-render / FluxCD
13434        // reconcile / tatara Process-CR mismatch far from this method's
13435        // source.
13436        for nome in [
13437            "checkout",
13438            "cart-v2",
13439            "a",
13440            "db",
13441            "3rd-party-shim",
13442            "payment-retry",
13443        ] {
13444            let c = caixa_with_nome(nome);
13445            let manual = crate::lareira_chart_name(c.nome());
13446            assert_eq!(
13447                c.lareira_chart_name(),
13448                manual,
13449                "Caixa::lareira_chart_name must byte-equal the manual \
13450                 open-coded `caixa_core::lareira_chart_name(caixa.nome())` \
13451                 composition across every representative :nome input — \
13452                 got {got:?}, expected {manual:?}",
13453                got = c.lareira_chart_name(),
13454            );
13455        }
13456    }
13457
13458    // ── Caixa::oci_chart_ref — resolved-OCI-chart-ref composer ────────
13459
13460    #[test]
13461    fn oci_chart_ref_composes_scheme_and_lareira_chart_name_on_all_shapes() {
13462        // Fail-before-pass-after pin: [`Caixa::oci_chart_ref`] must
13463        // compose [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied
13464        // `registry` + [`crate::lareira_chart_name`]-of-[`Caixa::nome`]
13465        // across the full paired `(registry, :nome)` accept-set — every
13466        // representative registry the substrate-side emitters carry
13467        // (`ghcr.io/pleme-io/charts`, the canonical CAIXA-SDLC §II
13468        // ArtifactHub-tier registry; `ghcr.io/pleme-io`, the bare-org
13469        // arm the sibling `oci_chart_ref_pins_byte_shape_against_prior_
13470        // inline_format` render-side pin exercises; `registry.example.
13471        // com`, an off-org shape; `localhost:5000`, the local-dev shape
13472        // every `feira chart` iteration path lands under) × every DNS-
13473        // 1123 `:nome` shape the peer `validate_nome_accepts_canonical_
13474        // forms` positive-set sweep documents (single-word, hyphen-
13475        // joined, single-char, two-char, digit-start, retry-suffixed).
13476        // Every accept-set pair the peer validate gates let through must
13477        // survive the resolved-OCI-ref projection byte-equal.
13478        for registry in [
13479            "ghcr.io/pleme-io/charts",
13480            "ghcr.io/pleme-io",
13481            "registry.example.com",
13482            "localhost:5000",
13483        ] {
13484            for nome in [
13485                "checkout",
13486                "cart-v2",
13487                "a",
13488                "db",
13489                "3rd-party-shim",
13490                "payment-retry",
13491                "0",
13492            ] {
13493                let c = caixa_with_nome(nome);
13494                let expected = format!(
13495                    "{scheme}{registry}/{chart}",
13496                    scheme = crate::OCI_SCHEME_PREFIX,
13497                    chart = crate::lareira_chart_name(nome),
13498                );
13499                assert_eq!(
13500                    c.oci_chart_ref(registry),
13501                    expected,
13502                    "Caixa::oci_chart_ref must compose \
13503                     OCI_SCHEME_PREFIX ({scheme:?}) + registry ({registry:?}) + \
13504                     lareira_chart_name(:nome ({nome:?})) verbatim — got {got:?}, \
13505                     expected {expected:?}",
13506                    scheme = crate::OCI_SCHEME_PREFIX,
13507                    got = c.oci_chart_ref(registry),
13508                );
13509            }
13510        }
13511    }
13512
13513    #[test]
13514    fn oci_chart_ref_starts_with_lifted_scheme_prefix() {
13515        // Scheme-prefix-shape pin: every [`Caixa::oci_chart_ref`]
13516        // emission must begin with the canonical
13517        // [`crate::OCI_SCHEME_PREFIX`] byte-string on every input, guarding
13518        // a hypothetical future implementation that migrated the scheme
13519        // segment to an inline literal (`"oci://"`) that would silently
13520        // drift from any rebrand of the lifted constant. Peer to the
13521        // sibling [`publish_tag_starts_with_default_publish_tag_prefix`]
13522        // + [`lareira_chart_name_starts_with_lifted_prefix`] pins on the
13523        // co-resident resolved-publish-tag / resolved-chart-name
13524        // composers' prefix axes.
13525        for registry in [
13526            "ghcr.io/pleme-io/charts",
13527            "ghcr.io/pleme-io",
13528            "localhost:5000",
13529        ] {
13530            for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
13531                let c = caixa_with_nome(nome);
13532                let ref_ = c.oci_chart_ref(registry);
13533                assert!(
13534                    ref_.starts_with(crate::OCI_SCHEME_PREFIX),
13535                    "Caixa::oci_chart_ref emission {ref_:?} must start \
13536                     with the lifted crate::OCI_SCHEME_PREFIX ({scheme:?}) \
13537                     — registry ({registry:?}), :nome ({nome:?})",
13538                    scheme = crate::OCI_SCHEME_PREFIX,
13539                );
13540            }
13541        }
13542    }
13543
13544    #[test]
13545    fn oci_chart_ref_byte_matches_canonical_helper_composition() {
13546        // Byte-parity pin: [`Caixa::oci_chart_ref`] must render byte-
13547        // identically to the manual open-coded
13548        // `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step
13549        // composition every prior substrate-side caller re-derived.
13550        // Guards the paired-site convergence just applied at caixa-
13551        // tatara's [`derive_chart_ref`] helper (which now routes through
13552        // this accessor): a future implementation of this method that
13553        // reordered the composition arguments, swapped the `<scheme>`
13554        // constant for a different one, migrated the `<chart>` segment
13555        // off the paired [`crate::lareira_chart_name`] composer, or
13556        // interposed a canonicalization pass on either input axis
13557        // surfaces here as a caixa-core build-time test failure rather
13558        // than as a downstream `helm install` / FluxCD OCI-source
13559        // reconcile / tatara `Process`-CR mismatch far from this
13560        // method's source. Sibling to the peer
13561        // [`lareira_chart_name_byte_matches_canonical_helper_composition`]
13562        // / [`publish_tag_byte_matches_manual_composition`] /
13563        // [`canonical_git_url_byte_matches_manual_composition`] byte-
13564        // parity pins that carry the same discipline on the co-resident
13565        // resolved-chart-name / resolved-publish-tag / resolved-git-URL
13566        // composers.
13567        for registry in [
13568            "ghcr.io/pleme-io/charts",
13569            "ghcr.io/pleme-io",
13570            "registry.example.com",
13571            "localhost:5000",
13572        ] {
13573            for nome in [
13574                "checkout",
13575                "cart-v2",
13576                "a",
13577                "db",
13578                "3rd-party-shim",
13579                "payment-retry",
13580            ] {
13581                let c = caixa_with_nome(nome);
13582                let manual = crate::oci_chart_ref(registry, c.nome());
13583                assert_eq!(
13584                    c.oci_chart_ref(registry),
13585                    manual,
13586                    "Caixa::oci_chart_ref must byte-equal the manual \
13587                     open-coded `caixa_core::oci_chart_ref(registry, \
13588                     caixa.nome())` composition across every representative \
13589                     (registry, :nome) pair — registry ({registry:?}), \
13590                     :nome ({nome:?}), got {got:?}, expected {manual:?}",
13591                    got = c.oci_chart_ref(registry),
13592                );
13593            }
13594        }
13595    }
13596
13597    // ── Caixa::descricao — outer top-level Option<&str> scalar accessor ──
13598
13599    #[test]
13600    fn descricao_returns_descricao_byte_string_verbatim_across_permutations() {
13601        // The canonical per-`Caixa` `:descricao` free-form-prose scalar
13602        // pin: [`Caixa::descricao`] must return the `:descricao` typed
13603        // byte-string verbatim as an `Option<&str>`, byte-equal to the
13604        // raw `self.descricao.as_deref()` access across every
13605        // representative value in the accept-set — `None` (the "omit
13606        // the slot to defer to the per-renderer `caixa.nome`-derived
13607        // fallback" arm every existing fixture without a `:descricao`
13608        // line carries), `Some("")` (a past-the-guard sentinel that
13609        // pins the accessor doesn't perform a silent `Some("") → None`
13610        // collapse on the empty arm — validate rejects `Some("")`
13611        // through `DescricaoEmpty` but the accessor must ship the raw
13612        // slot verbatim so a validate-time gate regression surfaces at
13613        // the caixa-helm / caixa-feira emit boundary rather than being
13614        // silently absorbed into the per-renderer `caixa.nome`-derived
13615        // fallback), `Some("Checkout flow.")` (the canonical one-line
13616        // prose descriptor the peer
13617        // `validate_descricao_accepts_canonical_value` positive sweep
13618        // exercises), `Some("Canonical Rust→wasm32-wasip2 caixa
13619        // Servico.")` (the multi-byte Unicode continuation-byte shape
13620        // the `hello-rio` fixture carries), `Some("→ — · ✓")` (a
13621        // multi-glyph Unicode shape the peer
13622        // `is_chart_description_shape` predicate accepts), and five
13623        // past-the-guard sentinels for the `DescricaoInvalid` refusal
13624        // cases (`Some(" Checkout flow.")` leading-whitespace,
13625        // `Some("Checkout flow. ")` trailing-whitespace,
13626        // `Some("Checkout\nflow.")` embedded-LF,
13627        // `Some("Checkout\tflow.")` embedded-TAB, and
13628        // `Some("Checkout\x00flow.")` embedded-NUL — the sentinels pin
13629        // the accessor doesn't silently absorb the refusal cases into
13630        // a fallback).
13631        //
13632        // Third outer top-level [`Caixa`] `Option<&str>`-return scalar
13633        // accessor pin on the substrate primitive — sibling of the peer
13634        // [`Caixa::licenca`] (6d5bc28) and [`Caixa::repositorio`]
13635        // (cc7332d) pins that opened the "outer [`Caixa`]
13636        // `Option<&str>` scalar" projection pin pattern this pin folds
13637        // on. Sibling in shape to the peer per-`:placement`
13638        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
13639        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
13640        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
13641        // axes, extended onto the outer top-level [`Caixa`] universal-
13642        // axis surface. Pins against a future silent detour that
13643        // returned an owned `Option<String>` (which would type-check
13644        // but silently allocate on every accessor call, breaking the
13645        // zero-cost projection every peer sibling accessor carries), a
13646        // `Some("") → None` collapse (which would silently absorb the
13647        // `DescricaoEmpty` refusal case at the accessor boundary and
13648        // the caixa-helm `Chart.yaml` `description:` fold would
13649        // silently render a `caixa.nome`-derived fallback on a
13650        // struct-literal `Caixa { descricao: Some(""), .. }`), or a
13651        // `None → Some(<default>)` collapse (which would silently
13652        // reify the per-renderer `caixa.nome`-derived fallback at the
13653        // accessor boundary and every downstream consumer keying off
13654        // the `Option::is_none()` discriminator would lose the "author
13655        // omitted the slot" signal).
13656        for descricao in [
13657            None,
13658            Some(""),
13659            Some("Checkout flow."),
13660            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
13661            Some("→ — · ✓"),
13662            Some(" Checkout flow."),
13663            Some("Checkout flow. "),
13664            Some("Checkout\nflow."),
13665            Some("Checkout\tflow."),
13666            Some("Checkout\x00flow."),
13667        ] {
13668            let c = caixa_with_descricao(descricao);
13669            assert_eq!(
13670                c.descricao(),
13671                descricao,
13672                "Caixa::descricao must return :descricao verbatim (got \
13673                 {:?}, expected {descricao:?})",
13674                c.descricao(),
13675            );
13676            assert_eq!(
13677                c.descricao(),
13678                c.descricao.as_deref(),
13679                "Caixa::descricao must byte-equal the raw \
13680                 `self.descricao.as_deref()` field access across every \
13681                 value in the Option<&str> accept-set",
13682            );
13683        }
13684    }
13685
13686    #[test]
13687    fn validate_descricao_empty_arm_routes_through_accessor() {
13688        // Composition pin: [`Caixa::validate_descricao`]'s empty-arm
13689        // gate must key off [`Caixa::descricao`], not the raw
13690        // `self.descricao.as_deref()` field access. Structurally: a
13691        // `Caixa { descricao: Some(""), .. }` must surface the
13692        // `DescricaoEmpty` refusal exactly, and a
13693        // `Caixa { descricao: Some("Checkout flow."), .. }` (the
13694        // canonical one-line-prose form) must pass validate. The pair
13695        // jointly pins the accessor + validate-gate composition: any
13696        // future silent detour that had the accessor return `None` on
13697        // the empty arm (a `.filter(|s| !s.is_empty())` collapse) would
13698        // silently absorb the `DescricaoEmpty` refusal at the accessor
13699        // boundary and the validate gate would accept a struct-literal
13700        // `Caixa { descricao: Some(""), .. }` — the composition pin
13701        // catches that at caixa-core build time.
13702        //
13703        // Peer of the [`Caixa::licenca`] (6d5bc28)
13704        // `validate_licenca_empty_arm_routes_through_accessor` and
13705        // [`Caixa::repositorio`] (cc7332d)
13706        // `validate_repositorio_empty_arm_routes_through_accessor`
13707        // composition pins on the sibling outer top-level [`Caixa`]
13708        // `Option<&str>` universal-axis surface — same "the validate /
13709        // shape-gate predicate must route through the substrate-
13710        // primitive typed dispatch" discipline extended onto the third
13711        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
13712        // composition surface.
13713        let c = caixa_with_descricao(Some(""));
13714        assert!(
13715            matches!(c.validate_descricao(), Err(ManifestError::DescricaoEmpty),),
13716            "validate_descricao must reject descricao == Some(\"\") \
13717             with DescricaoEmpty — the accessor and the validate gate \
13718             must route through the same substrate-primitive typed \
13719             dispatch on the :descricao empty arm",
13720        );
13721        let c = caixa_with_descricao(Some("Checkout flow."));
13722        assert!(
13723            c.validate_descricao().is_ok(),
13724            "validate_descricao must accept descricao == \
13725             Some(\"Checkout flow.\") (the canonical one-line-prose \
13726             chart-description shape)",
13727        );
13728    }
13729
13730    #[test]
13731    fn descricao_projects_option_str_by_borrow() {
13732        // The by-borrow pin: [`Caixa::descricao`] returns
13733        // `Option<&str>` by borrow — the `&str` borrows the underlying
13734        // `String` storage of the `Option<String>` slot and the
13735        // accessor must not allocate a fresh `String` on every call.
13736        // Peer of the [`Caixa::licenca`] (6d5bc28) and
13737        // [`Caixa::repositorio`] (cc7332d) by-borrow pins on the peer
13738        // outer top-level [`Caixa`] `Option<&str>`-return axes, and of
13739        // the per-`:placement`
13740        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
13741        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
13742        // return axis, extended onto the third outer top-level
13743        // [`Caixa`] universal-axis `Option<&str>` shape — the
13744        // accessor's returned `&str` must borrow from `&self` (the
13745        // returned reference's lifetime is tied to `&self`), and
13746        // calling the accessor twice on the same [`Caixa`] must yield
13747        // the same `Option<&str>` verbatim (idempotent, no side
13748        // effects on `&self`).
13749        //
13750        // Pins against a future silent detour that returned an owned
13751        // `Option<String>` (which would type-check but silently
13752        // allocate on every call, breaking the zero-cost projection
13753        // every peer sibling accessor carries), or a one-arm-only
13754        // accessor that returned a saturating value on some sentinel
13755        // input (breaking the pass-through invariant the sibling
13756        // required-scalar accessors carry).
13757        for descricao in [
13758            None,
13759            Some(""),
13760            Some("Checkout flow."),
13761            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
13762        ] {
13763            let c = caixa_with_descricao(descricao);
13764            let first = c.descricao();
13765            let second = c.descricao();
13766            assert_eq!(
13767                first, second,
13768                "Caixa::descricao must be idempotent — two successive \
13769                 calls on the same &self must return the same \
13770                 Option<&str>",
13771            );
13772            assert_eq!(
13773                first, descricao,
13774                "Caixa::descricao must return :descricao verbatim by \
13775                 borrow — got {first:?}, expected {descricao:?}",
13776            );
13777        }
13778    }
13779
13780    // ── validate_edicao — universal-axis language-edition shape ──
13781
13782    fn caixa_with_edicao(edicao: Option<&str>) -> Caixa {
13783        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13784        c.edicao = edicao.map(String::from);
13785        c
13786    }
13787
13788    #[test]
13789    fn validate_edicao_accepts_none() {
13790        // The omit-the-slot identity: `:edicao` is optional. The
13791        // gate is a no-op when the author didn't declare a value —
13792        // every caixa without an `:edicao` line trivially passes,
13793        // and the substrate-side build pipeline falls back to the
13794        // documented default edition. Mirrors the peer
13795        // `validate_licenca_accepts_none` posture on the sibling
13796        // `Option<String>` Caixa slot.
13797        let c = caixa_with_edicao(None);
13798        c.validate_edicao().unwrap();
13799    }
13800
13801    #[test]
13802    fn validate_edicao_accepts_canonical_value() {
13803        // Positive control: the canonical `"2026"` edition every
13804        // existing renderer-side fixture (`caixa-helm`, `caixa-flux`,
13805        // `caixa-mesh`) carries by construction passes the gate.
13806        // Future-introduced sibling editions (`"2027"`, `"2030"`,
13807        // `"2049"`) that match the same 4-digit ASCII decimal year
13808        // shape must also trivially pass — the structural shape
13809        // predicate accepts every well-formed year regardless of
13810        // whether the substrate yet understands the specific value
13811        // (a future known-edition allowlist tightens that).
13812        for ed in ["2026", "2027", "2030", "2049"] {
13813            let c = caixa_with_edicao(Some(ed));
13814            c.validate_edicao()
13815                .unwrap_or_else(|err| panic!("canonical {ed:?} must pass: {err:?}"));
13816        }
13817    }
13818
13819    #[test]
13820    fn validate_edicao_rejects_empty_some() {
13821        // Canonical paste-from-blank-doc footgun. Without this gate
13822        // the empty `Some("")` silently lands as `(:edicao "")` in
13823        // the rendered caixa.lisp and a future renderer-side
13824        // consumer's `Option::unwrap_or_else` (which only fires on
13825        // `None`) skips its fallback. Mirrors the peer
13826        // [`ManifestError::LicencaEmpty`] empty-arm on the sibling
13827        // `Option<String>` Caixa slot.
13828        let c = caixa_with_edicao(Some(""));
13829        let err = c.validate_edicao().unwrap_err();
13830        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
13831    }
13832
13833    #[test]
13834    fn validate_edicao_rejects_free_form_non_year() {
13835        // Free-form non-year footgun: the bare `"x"` / `"latest"` /
13836        // `"nightly"` shapes carry no operational meaning on the
13837        // substrate's build-time edition selector. Until this gate
13838        // landed the bare empty-arm check let every such value
13839        // through and broke far from the source caixa.lisp. Peer
13840        // with the shape-predicate cascade
13841        // `validate_repositorio_rejects_missing_colon_separator`
13842        // establishes past its own empty arm.
13843        for ed in ["x", "latest", "nightly", "stable"] {
13844            let c = caixa_with_edicao(Some(ed));
13845            let err = c.validate_edicao().unwrap_err();
13846            assert!(
13847                matches!(err, ManifestError::EdicaoInvalid { .. }),
13848                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13849            );
13850        }
13851    }
13852
13853    #[test]
13854    fn validate_edicao_rejects_trailing_whitespace() {
13855        // Paste-from-doc whitespace footgun. A trailing space in
13856        // the `:edicao` value would silently break the substrate's
13857        // build-time edition match-table lookup at the rendered
13858        // artifact's edition-selector consumer. The shape predicate
13859        // refuses every whitespace byte by construction (any byte
13860        // outside `0-9` fails `is_ascii_digit`). Peer with
13861        // `validate_repositorio_rejects_whitespace`.
13862        let c = caixa_with_edicao(Some("2026 "));
13863        let err = c.validate_edicao().unwrap_err();
13864        let ManifestError::EdicaoInvalid { edicao, .. } = err else {
13865            panic!("expected EdicaoInvalid, got {err:?}");
13866        };
13867        assert_eq!(edicao, "2026 ");
13868    }
13869
13870    #[test]
13871    fn validate_edicao_rejects_leading_whitespace() {
13872        // Symmetric paste-from-doc whitespace footgun on the leading
13873        // boundary — the gate refuses every shape with a non-digit
13874        // byte by construction.
13875        let c = caixa_with_edicao(Some(" 2026"));
13876        let err = c.validate_edicao().unwrap_err();
13877        assert!(
13878            matches!(err, ManifestError::EdicaoInvalid { .. }),
13879            "got {err:?}",
13880        );
13881    }
13882
13883    #[test]
13884    fn validate_edicao_rejects_control_char() {
13885        // Paste-from-multiline-doc CRLF footgun — control characters
13886        // at the value boundary break the substrate's build-time
13887        // edition-selector parser. Peer with
13888        // `validate_repositorio_rejects_control_char`.
13889        let c = caixa_with_edicao(Some("2026\n"));
13890        let err = c.validate_edicao().unwrap_err();
13891        assert!(
13892            matches!(err, ManifestError::EdicaoInvalid { .. }),
13893            "got {err:?}",
13894        );
13895    }
13896
13897    #[test]
13898    fn validate_edicao_rejects_non_ascii_lookalike() {
13899        // Fullwidth-keyboard look-alike footgun — `"2026"` is
13900        // the U+FF12 U+FF10 U+FF12 U+FF16 sequence (CJK fullwidth
13901        // digits), 4 codepoints but 12 UTF-8 bytes; the substrate's
13902        // edition selector wants an ASCII year, and the gate
13903        // refuses every non-ASCII shape by construction (length in
13904        // bytes is 12 ≠ 4, *and* every byte falls outside
13905        // `is_ascii_digit`'s `0-9` range).
13906        let c = caixa_with_edicao(Some("2026"));
13907        let err = c.validate_edicao().unwrap_err();
13908        assert!(
13909            matches!(err, ManifestError::EdicaoInvalid { .. }),
13910            "got {err:?}",
13911        );
13912    }
13913
13914    #[test]
13915    fn validate_edicao_rejects_version_tag_prefix() {
13916        // Common version-tag idiom footgun — `"v2026"` / `"e2026"`
13917        // / `"r2026"` are familiar shapes from git-tag / Rust
13918        // edition / release-tag conventions that don't apply to
13919        // the year-shaped edition axis. The shape predicate refuses
13920        // every leading non-digit prefix.
13921        for ed in ["v2026", "e2026", "r2026"] {
13922            let c = caixa_with_edicao(Some(ed));
13923            let err = c.validate_edicao().unwrap_err();
13924            assert!(
13925                matches!(err, ManifestError::EdicaoInvalid { .. }),
13926                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13927            );
13928        }
13929    }
13930
13931    #[test]
13932    fn validate_edicao_rejects_decimal_shape() {
13933        // Decimal-shaped pseudo-version footgun — `"2026.1"` /
13934        // `"2026.0"` are familiar shapes from semver / float
13935        // conventions that don't apply to the year-shaped edition
13936        // axis. The shape predicate refuses every non-digit byte
13937        // (`.` falls outside `is_ascii_digit`).
13938        for ed in ["2026.1", "2026.0", "2026.0.1"] {
13939            let c = caixa_with_edicao(Some(ed));
13940            let err = c.validate_edicao().unwrap_err();
13941            assert!(
13942                matches!(err, ManifestError::EdicaoInvalid { .. }),
13943                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13944            );
13945        }
13946    }
13947
13948    #[test]
13949    fn validate_edicao_rejects_wrong_length_numeric() {
13950        // Wrong-length numeric footgun — `"26"` (truncated) /
13951        // `"202"` (truncated) / `"20260"` (extra digit) / `"00026"`
13952        // (zero-padded too wide) all parse as integers but don't
13953        // name a 4-digit year. The shape predicate refuses every
13954        // value whose length isn't exactly 4 bytes.
13955        for ed in ["26", "202", "20260", "00026", "9"] {
13956            let c = caixa_with_edicao(Some(ed));
13957            let err = c.validate_edicao().unwrap_err();
13958            assert!(
13959                matches!(err, ManifestError::EdicaoInvalid { .. }),
13960                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13961            );
13962        }
13963    }
13964
13965    #[test]
13966    fn validate_edicao_empty_takes_precedence_over_shape() {
13967        // Empty-first cascade pin: the empty `Some("")` surfaces
13968        // the narrower `EdicaoEmpty` not the shape-predicate-
13969        // wrapped `EdicaoInvalid`, mirroring the peer
13970        // `validate_repositorio_empty_takes_precedence_over_shape`
13971        // (`RepositorioEmpty` → `RepositorioInvalid`),
13972        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` →
13973        // `VersaoInvalid`, `FonteRepoEmpty` → `FonteRepoInvalid`
13974        // cascades. The shape predicate also refuses the empty
13975        // input (defensively — `s.len() != 4`), but the
13976        // manifest-layer empty arm runs first to surface the
13977        // narrower diagnostic verbatim.
13978        let c = caixa_with_edicao(Some(""));
13979        let err = c.validate_edicao().unwrap_err();
13980        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
13981    }
13982
13983    #[test]
13984    fn validate_edicao_template_passes() {
13985        // Round-trip pin: the bare `Caixa::template` shape (which
13986        // carries `:edicao "2026"` verbatim) passes the gate by
13987        // construction. A future template-shape change that
13988        // introduced `(:edicao "")` or a non-year value would
13989        // surface here as a regression. Mirrors the peer
13990        // `validate_licenca_template_passes` pin.
13991        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13992        c.validate_edicao().unwrap();
13993    }
13994
13995    #[test]
13996    fn validate_edicao_diagnostic_names_offending_slot() {
13997        // Diagnostic-shape pin (peer with
13998        // `validate_licenca_diagnostic_names_offending_slot`): the
13999        // error's Display surfaces the `:edicao` slot name verbatim,
14000        // so a `feira lint` run can render the diagnostic without
14001        // re-parsing and the author can grep their caixa.lisp for
14002        // the offending `:edicao` line.
14003        let c = caixa_with_edicao(Some(""));
14004        let rendered = c.validate_edicao().unwrap_err().to_string();
14005        assert!(
14006            rendered.contains(":edicao"),
14007            "diagnostic must name the offending slot: {rendered}",
14008        );
14009    }
14010
14011    #[test]
14012    fn validate_edicao_invalid_diagnostic_carries_offending_value() {
14013        // Diagnostic-shape pin on the shape-predicate arm (peer
14014        // with `validate_repositorio_diagnostic_carries_offending_value`):
14015        // the error's Display surfaces the offending value + slot
14016        // name verbatim, so a `feira lint` run can render the
14017        // diagnostic without re-parsing and the author can grep
14018        // their caixa.lisp for the offending `:edicao` value.
14019        let c = caixa_with_edicao(Some("v2026"));
14020        let rendered = c.validate_edicao().unwrap_err().to_string();
14021        assert!(
14022            rendered.contains(":edicao"),
14023            "diagnostic must name the offending slot: {rendered}",
14024        );
14025        assert!(
14026            rendered.contains("v2026"),
14027            "diagnostic must quote the offending value: {rendered}",
14028        );
14029    }
14030
14031    // ── Caixa::edicao — outer top-level Option<&str> scalar accessor ──
14032
14033    #[test]
14034    fn edicao_returns_edicao_byte_string_verbatim_across_permutations() {
14035        // The canonical per-`Caixa` `:edicao` language-edition scalar
14036        // pin: [`Caixa::edicao`] must return the `:edicao` typed
14037        // byte-string verbatim as an `Option<&str>`, byte-equal to the
14038        // raw `self.edicao.as_deref()` access across every representative
14039        // value in the accept-set — `None` (the "omit the slot to defer
14040        // to the substrate's default edition" arm every existing
14041        // [`caixa-resolver`] fixture without an `:edicao` line carries),
14042        // `Some("")` (a past-the-guard sentinel that pins the accessor
14043        // doesn't perform a silent `Some("") → None` collapse on the
14044        // empty arm — validate rejects `Some("")` through `EdicaoEmpty`
14045        // but the accessor must ship the raw slot verbatim so a
14046        // validate-time gate regression surfaces at any future edition-
14047        // aware consumer's boundary rather than being silently absorbed
14048        // into the substrate's default edition), `Some("2026")` (the
14049        // canonical 4-digit-ASCII-decimal-year shape every `feira init`
14050        // template scaffolds via [`Caixa::template`] and every
14051        // renderer-side fixture at `caixa-helm/src/lib.rs:978` /
14052        // `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208`
14053        // carries by construction), `Some("2018")` / `Some("2021")` /
14054        // `Some("2024")` (canonical 4-digit-ASCII-decimal-year shapes
14055        // peer with Cargo's `[package] edition` grammar every future-
14056        // introduced sibling to `"2026"` will follow), and eight
14057        // past-the-guard sentinels for the `EdicaoInvalid` refusal cases
14058        // (`Some("2026 ")` trailing-whitespace, `Some(" 2026")` leading-
14059        // whitespace, `Some("2026\n")` embedded-LF, `Some("2026")`
14060        // fullwidth-non-ASCII-lookalike, `Some("v2026")` version-tag-
14061        // prefix, `Some("2026.1")` decimal-shape, `Some("26")` wrong-
14062        // length-numeric, `Some("latest")` free-form-non-year — the
14063        // sentinels pin the accessor doesn't silently absorb the
14064        // refusal cases into a substrate-default-edition fallback).
14065        //
14066        // Fourth and final outer top-level [`Caixa`] `Option<&str>`-
14067        // return scalar accessor pin on the substrate primitive —
14068        // sibling of the peer [`Caixa::licenca`] (6d5bc28),
14069        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
14070        // (3f16e2f) pins that opened the "outer [`Caixa`]
14071        // `Option<&str>` scalar" projection pin pattern this pin folds
14072        // on. Sibling in shape to the peer per-`:placement`
14073        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
14074        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
14075        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
14076        // axes, extended onto the outer top-level [`Caixa`] universal-
14077        // axis surface's last unlifted `Option<String>` slot. Pins
14078        // against a future silent detour that returned an owned
14079        // `Option<String>` (which would type-check but silently
14080        // allocate on every accessor call, breaking the zero-cost
14081        // projection every peer sibling accessor carries), a
14082        // `Some("") → None` collapse (which would silently absorb the
14083        // `EdicaoEmpty` refusal case at the accessor boundary and any
14084        // future edition-aware consumer would silently fall back to
14085        // the substrate's default edition on a struct-literal
14086        // `Caixa { edicao: Some(""), .. }`), or a
14087        // `None → Some("2026")` collapse (which would silently reify
14088        // the substrate's default edition at the accessor boundary
14089        // and every downstream consumer keying off the
14090        // `Option::is_none()` discriminator would lose the "author
14091        // omitted the slot" signal).
14092        for edicao in [
14093            None,
14094            Some(""),
14095            Some("2026"),
14096            Some("2018"),
14097            Some("2021"),
14098            Some("2024"),
14099            Some("2026 "),
14100            Some(" 2026"),
14101            Some("2026\n"),
14102            Some("2026"),
14103            Some("v2026"),
14104            Some("2026.1"),
14105            Some("26"),
14106            Some("latest"),
14107        ] {
14108            let c = caixa_with_edicao(edicao);
14109            assert_eq!(
14110                c.edicao(),
14111                edicao,
14112                "Caixa::edicao must return :edicao verbatim (got {:?}, \
14113                 expected {edicao:?})",
14114                c.edicao(),
14115            );
14116            assert_eq!(
14117                c.edicao(),
14118                c.edicao.as_deref(),
14119                "Caixa::edicao must byte-equal the raw \
14120                 `self.edicao.as_deref()` field access across every \
14121                 value in the Option<&str> accept-set",
14122            );
14123        }
14124    }
14125
14126    #[test]
14127    fn validate_edicao_empty_arm_routes_through_accessor() {
14128        // Composition pin: [`Caixa::validate_edicao`]'s empty-arm gate
14129        // must key off [`Caixa::edicao`], not the raw
14130        // `self.edicao.as_deref()` field access. Structurally: a
14131        // `Caixa { edicao: Some(""), .. }` must surface the
14132        // `EdicaoEmpty` refusal exactly, and a
14133        // `Caixa { edicao: Some("2026"), .. }` (the canonical
14134        // 4-digit-ASCII-decimal-year form) must pass validate. The
14135        // pair jointly pins the accessor + validate-gate composition:
14136        // any future silent detour that had the accessor return `None`
14137        // on the empty arm (a `.filter(|s| !s.is_empty())` collapse)
14138        // would silently absorb the `EdicaoEmpty` refusal at the
14139        // accessor boundary and the validate gate would accept a
14140        // struct-literal `Caixa { edicao: Some(""), .. }` — the
14141        // composition pin catches that at caixa-core build time.
14142        //
14143        // Peer of the [`Caixa::licenca`] (6d5bc28)
14144        // `validate_licenca_empty_arm_routes_through_accessor`,
14145        // [`Caixa::repositorio`] (cc7332d)
14146        // `validate_repositorio_empty_arm_routes_through_accessor`,
14147        // and [`Caixa::descricao`] (3f16e2f)
14148        // `validate_descricao_empty_arm_routes_through_accessor`
14149        // composition pins on the sibling outer top-level [`Caixa`]
14150        // `Option<&str>` universal-axis surface — same "the validate /
14151        // shape-gate predicate must route through the substrate-
14152        // primitive typed dispatch" discipline extended onto the
14153        // fourth and final outer top-level [`Caixa`] universal-axis
14154        // `Option<&str>`-composition surface, closing the accessor-
14155        // composition family.
14156        let c = caixa_with_edicao(Some(""));
14157        assert!(
14158            matches!(c.validate_edicao(), Err(ManifestError::EdicaoEmpty)),
14159            "validate_edicao must reject edicao == Some(\"\") with \
14160             EdicaoEmpty — the accessor and the validate gate must \
14161             route through the same substrate-primitive typed dispatch \
14162             on the :edicao empty arm",
14163        );
14164        let c = caixa_with_edicao(Some("2026"));
14165        assert!(
14166            c.validate_edicao().is_ok(),
14167            "validate_edicao must accept edicao == Some(\"2026\") \
14168             (the canonical 4-digit-ASCII-decimal-year shape)",
14169        );
14170    }
14171
14172    #[test]
14173    fn edicao_projects_option_str_by_borrow() {
14174        // The by-borrow pin: [`Caixa::edicao`] returns
14175        // `Option<&str>` by borrow — the `&str` borrows the underlying
14176        // `String` storage of the `Option<String>` slot and the
14177        // accessor must not allocate a fresh `String` on every call.
14178        // Peer of the [`Caixa::licenca`] (6d5bc28),
14179        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
14180        // (3f16e2f) by-borrow pins on the peer outer top-level
14181        // [`Caixa`] `Option<&str>`-return axes, and of the
14182        // per-`:placement`
14183        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
14184        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
14185        // return axis, extended onto the fourth and final outer top-
14186        // level [`Caixa`] universal-axis `Option<&str>` shape — the
14187        // accessor's returned `&str` must borrow from `&self` (the
14188        // returned reference's lifetime is tied to `&self`), and
14189        // calling the accessor twice on the same [`Caixa`] must yield
14190        // the same `Option<&str>` verbatim (idempotent, no side
14191        // effects on `&self`).
14192        //
14193        // Pins against a future silent detour that returned an owned
14194        // `Option<String>` (which would type-check but silently
14195        // allocate on every call, breaking the zero-cost projection
14196        // every peer sibling accessor carries), or a one-arm-only
14197        // accessor that returned a saturating value on some sentinel
14198        // input (breaking the pass-through invariant the sibling
14199        // required-scalar accessors carry).
14200        for edicao in [None, Some(""), Some("2026"), Some("2018")] {
14201            let c = caixa_with_edicao(edicao);
14202            let first = c.edicao();
14203            let second = c.edicao();
14204            assert_eq!(
14205                first, second,
14206                "Caixa::edicao must be idempotent — two successive \
14207                 calls on the same &self must return the same \
14208                 Option<&str>",
14209            );
14210            assert_eq!(
14211                first, edicao,
14212                "Caixa::edicao must return :edicao verbatim by \
14213                 borrow — got {first:?}, expected {edicao:?}",
14214            );
14215        }
14216    }
14217
14218    #[test]
14219    fn nome_returns_nome_byte_string_verbatim_across_permutations() {
14220        // The canonical per-`Caixa` `:nome` universal-axis DNS-1123-
14221        // label caixa-identity scalar pin: [`Caixa::nome`] must return
14222        // the `:nome` typed `String` verbatim as `&str`, byte-equal to
14223        // the raw field access across every representative value in
14224        // the accept-set — the canonical `"demo"` template baseline
14225        // (the same `feira init`-scaffolded default the sibling
14226        // `validate_nome_accepts_canonical_template` positive-control
14227        // gate pins), plus every sibling per-typed-slot atom accessor's
14228        // canonical positive-arm byte-string (`"catalog"` per
14229        // [`crate::aplicacao::Membro::nome`], `"cart"` per the peer
14230        // per-`:contratos` `:de`, `"hello-rio"` per the canonical
14231        // `caixa-helm`/`caixa-flux` cross-crate integration-test
14232        // fixture, `"checkout"` per the M3 mesh-slot Aplicacao
14233        // canonical example), plus every past-the-guard sentinel for
14234        // the `NomeEmpty` / `NomeInvalid` / `NomeChartNameBudgetExceeded`
14235        // refusal cases (`""`, `"Bad_Name"`, `"a"` × 56 — 56 bytes fits
14236        // the bare DNS-1123 63-byte cap but overflows the joint
14237        // `lareira-<nome>` chart-name budget the sibling
14238        // [`Caixa::validate_nome_chart_name_budget`] gate closes on).
14239        //
14240        // The past-the-guard sentinels pin the accessor doesn't
14241        // silently absorb the refusal cases into a template-derived
14242        // fallback (a future `.nome().is_empty().then(|| "demo")`
14243        // collapse would silently absorb the `NomeEmpty` refusal at
14244        // the accessor boundary and the validate gate would accept a
14245        // struct-literal `Caixa { nome: "".into(), .. }` — the pin
14246        // catches that at caixa-core build time).
14247        //
14248        // First outer top-level [`Caixa`] `&str`-return required-
14249        // scalar accessor pin — opens the "outer [`Caixa`] `&str`
14250        // required-scalar" projection pattern the sibling per-`Caixa`
14251        // `:versao` future lift folds on. Sibling in shape to the peer
14252        // per-`:membros` [`crate::aplicacao::Membro::nome`] (4a32abf)
14253        // required-`String`-carry accessor pin on the sibling per-
14254        // sub-struct required-axis, extended onto the outer top-level
14255        // [`Caixa`] universal-axis required-`String`-carry axis.
14256        for nome in [
14257            "demo",
14258            "catalog",
14259            "cart",
14260            "hello-rio",
14261            "checkout",
14262            "",
14263            "Bad_Name",
14264            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14265        ] {
14266            let c = caixa_with_nome(nome);
14267            assert_eq!(
14268                c.nome(),
14269                nome,
14270                "Caixa::nome must return :nome verbatim (got {}, \
14271                 expected {nome})",
14272                c.nome(),
14273            );
14274            assert_eq!(
14275                c.nome(),
14276                c.nome.as_str(),
14277                "Caixa::nome must byte-equal the raw .nome field \
14278                 access across every value in the String accept-set",
14279            );
14280        }
14281    }
14282
14283    #[test]
14284    fn validate_nome_empty_arm_routes_through_accessor() {
14285        // Composition pin: [`Caixa::validate_nome`]'s empty-arm must
14286        // key off [`Caixa::nome`], not the raw `.nome` field access.
14287        // Structurally: a `Caixa { nome: "".into(), .. }` must surface
14288        // the `NomeEmpty` refusal exactly, and the canonical `"demo"`
14289        // template baseline (the peer positive-arm the sibling
14290        // `validate_nome_accepts_canonical_template` gate carves out)
14291        // must pass validate. The pair jointly pins the accessor +
14292        // validate-gate composition: any future silent detour that
14293        // had the accessor return a fresh `"demo"` on the empty arm
14294        // (a `.nome().is_empty().then(|| "demo")` fallback collapse)
14295        // would silently absorb the `NomeEmpty` refusal at the
14296        // accessor boundary and the validate gate would accept a
14297        // struct-literal `Caixa { nome: "".into(), .. }` — the
14298        // composition pin catches that at caixa-core build time.
14299        //
14300        // Peer of the sibling per-`Caixa`
14301        // `validate_licenca_empty_arm_routes_through_accessor` (6d5bc28)
14302        // / `validate_repositorio_empty_arm_routes_through_accessor`
14303        // (cc7332d) / `validate_descricao_empty_arm_routes_through_accessor`
14304        // (3f16e2f) / `validate_edicao_empty_arm_routes_through_accessor`
14305        // (2641cbd) composition pins on the sibling outer top-level
14306        // [`Caixa`] `Option<&str>` axes — same "the validate /
14307        // shape-gate predicate must route through the substrate-
14308        // primitive typed dispatch" discipline extended onto the peer
14309        // outer top-level [`Caixa`] required-`&str` composition axis.
14310        let c = caixa_with_nome("");
14311        assert!(
14312            matches!(c.validate_nome(), Err(ManifestError::NomeEmpty)),
14313            "validate_nome must reject nome == \"\" with NomeEmpty — \
14314             the accessor and the validate gate must route through the \
14315             same substrate-primitive typed dispatch on the :nome \
14316             empty-arm",
14317        );
14318        let c = caixa_with_nome("demo");
14319        assert!(
14320            c.validate_nome().is_ok(),
14321            "validate_nome must accept nome == \"demo\" (the canonical \
14322             DNS-1123-label template baseline)",
14323        );
14324    }
14325
14326    #[test]
14327    fn nome_projects_str_by_borrow() {
14328        // The by-borrow pin: [`Caixa::nome`] returns `&str` by borrow
14329        // — the `&str` borrows the underlying `String` storage of the
14330        // required `nome` slot and the accessor must not allocate a
14331        // fresh `String` on every call. Peer of the [`Caixa::licenca`]
14332        // (6d5bc28) / [`Caixa::repositorio`] (cc7332d) /
14333        // [`Caixa::descricao`] (3f16e2f) / [`Caixa::edicao`] (2641cbd)
14334        // by-borrow pins on the peer outer top-level [`Caixa`]
14335        // `Option<&str>`-return axes, extended onto the first outer
14336        // top-level [`Caixa`] required-`&str`-return axis — the
14337        // accessor's returned `&str` must borrow from `&self` (the
14338        // returned reference's lifetime is tied to `&self`), and
14339        // calling the accessor twice on the same [`Caixa`] must yield
14340        // the same `&str` verbatim (idempotent, no side effects on
14341        // `&self`).
14342        //
14343        // Pins against a future silent detour that returned an owned
14344        // `String` (which would type-check but silently allocate on
14345        // every call, breaking the zero-cost projection every peer
14346        // sibling accessor carries), an accidental
14347        // `.nome.to_lowercase()` detour that returned a fresh
14348        // allocation through an already-DNS-1123-lowercase-only
14349        // string (breaking a future `const fn` regression), or a
14350        // one-arm-only accessor that returned a canonicalized value
14351        // on some sentinel input (breaking the pass-through invariant
14352        // the sibling required-scalar accessors carry).
14353        for nome in ["demo", "catalog", "hello-rio", "checkout"] {
14354            let c = caixa_with_nome(nome);
14355            let first = c.nome();
14356            let second = c.nome();
14357            assert_eq!(
14358                first, second,
14359                "Caixa::nome must be idempotent — two successive calls \
14360                 on the same &self must return the same &str",
14361            );
14362            assert_eq!(
14363                first, nome,
14364                "Caixa::nome must return :nome verbatim by borrow — \
14365                 got {first}, expected {nome}",
14366            );
14367        }
14368    }
14369
14370    #[test]
14371    fn versao_returns_versao_byte_string_verbatim_across_permutations() {
14372        // The canonical per-`Caixa` `:versao` universal-axis SemVer-2
14373        // pinned-version scalar pin: [`Caixa::versao`] must return the
14374        // `:versao` typed `String` verbatim as `&str`, byte-equal to the
14375        // raw `.versao` field access across every representative value
14376        // in the accept-set — the canonical `"0.1.0"` template baseline
14377        // (the same `feira init`-scaffolded default the sibling
14378        // `validate_versao_accepts_canonical_template` positive-control
14379        // gate pins), plus every canonical SemVer-2 shape the sibling
14380        // `validate_versao_accepts_canonical_forms` positive-arm sweep
14381        // covers (`"0.0.0"`, `"1.0.0"`, `"0.2.0-rc.1"`,
14382        // `"1.0.0-alpha.0"`, `"1.0.0+build.42"`, `"1.0.0-rc.1+build.42"`,
14383        // `"10.20.30"`), plus every past-the-guard sentinel for the
14384        // `VersaoEmpty` / `VersaoInvalid` refusal cases (`""` the empty
14385        // arm, `"v0.1.0"` the git-tag-shape-leak footgun, `"0.1"` the
14386        // missing-patch footgun, `"^0.1"` the requirement-shape-leak
14387        // footgun, `"0.1.0.0"` the four-part-Java-convention footgun,
14388        // `"latest"` the docker-tag-shape footgun — the sentinels pin
14389        // the accessor doesn't silently absorb the refusal cases into a
14390        // template-derived fallback like `"0.1.0"`).
14391        //
14392        // The past-the-guard sentinels pin the accessor doesn't silently
14393        // absorb the refusal cases into a template-derived fallback (a
14394        // future `.versao().is_empty().then(|| "0.1.0")` collapse would
14395        // silently absorb the `VersaoEmpty` refusal at the accessor
14396        // boundary and the validate gate would accept a struct-literal
14397        // `Caixa { versao: "".into(), .. }` — the pin catches that at
14398        // caixa-core build time).
14399        //
14400        // Second outer top-level [`Caixa`] `&str`-return required-scalar
14401        // accessor pin — folds on the "outer [`Caixa`] `&str` required-
14402        // scalar" projection pattern the sibling per-`Caixa`
14403        // [`Caixa::nome`] (e6b7d97) opened. Sibling in shape to the peer
14404        // per-`:membros` [`crate::aplicacao::Membro::versao_requirement`]
14405        // (4127bb6) / per-`:children`
14406        // [`crate::supervisor::ChildSpec::versao_requirement`] (2c053c8)
14407        // / per-`:upgrade-from`
14408        // [`crate::UpgradeFromEntry::prior_versao`] (75d27a8) per-sub-
14409        // struct `:versao`-shaped `&str`-return accessor pins on the
14410        // sibling per-typed-slot version-carrier axes, extended onto the
14411        // second outer top-level [`Caixa`] universal-axis required-
14412        // `String`-carry axis so the two universal-axis identity-
14413        // carrying scalars every `defcaixa` form supplies (`:nome` +
14414        // `:versao`) share the same "one typed dispatch per axis" pin
14415        // discipline.
14416        for versao in [
14417            "0.1.0",
14418            "0.0.0",
14419            "1.0.0",
14420            "0.2.0-rc.1",
14421            "1.0.0-alpha.0",
14422            "1.0.0+build.42",
14423            "1.0.0-rc.1+build.42",
14424            "10.20.30",
14425            "",
14426            "v0.1.0",
14427            "0.1",
14428            "^0.1",
14429            "0.1.0.0",
14430            "latest",
14431        ] {
14432            let c = caixa_with_versao(versao);
14433            assert_eq!(
14434                c.versao(),
14435                versao,
14436                "Caixa::versao must return :versao verbatim (got {}, \
14437                 expected {versao})",
14438                c.versao(),
14439            );
14440            assert_eq!(
14441                c.versao(),
14442                c.versao.as_str(),
14443                "Caixa::versao must byte-equal the raw .versao field \
14444                 access across every value in the String accept-set",
14445            );
14446        }
14447    }
14448
14449    #[test]
14450    fn validate_versao_empty_arm_routes_through_accessor() {
14451        // Composition pin: [`Caixa::validate_versao`]'s empty-arm gate
14452        // must key off [`Caixa::versao`], not the raw `.versao` field
14453        // access. Structurally: a `Caixa { versao: "".into(), .. }` must
14454        // surface the `VersaoEmpty` refusal exactly, and the canonical
14455        // `"0.1.0"` template baseline (the peer positive-arm the sibling
14456        // `validate_versao_accepts_canonical_template` gate carves out)
14457        // must pass validate. The pair jointly pins the accessor +
14458        // validate-gate composition: any future silent detour that had
14459        // the accessor return a fresh `"0.1.0"` on the empty arm
14460        // (a `.versao().is_empty().then(|| "0.1.0")` fallback collapse)
14461        // would silently absorb the `VersaoEmpty` refusal at the
14462        // accessor boundary and the validate gate would accept a
14463        // struct-literal `Caixa { versao: "".into(), .. }` — the
14464        // composition pin catches that at caixa-core build time.
14465        //
14466        // Peer of the sibling per-`Caixa`
14467        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97)
14468        // composition pin on the sibling outer top-level [`Caixa`]
14469        // required-`&str` universal-axis surface — same "the validate /
14470        // shape-gate predicate must route through the substrate-
14471        // primitive typed dispatch" discipline extended onto the peer
14472        // outer top-level [`Caixa`] required-`&str` universal-axis
14473        // pinned-version composition axis, closing the second
14474        // coordinate of the "one canonical typed dispatch per per-Caixa
14475        // required-`&str` universal-axis" discipline.
14476        let c = caixa_with_versao("");
14477        assert!(
14478            matches!(c.validate_versao(), Err(ManifestError::VersaoEmpty)),
14479            "validate_versao must reject versao == \"\" with VersaoEmpty — \
14480             the accessor and the validate gate must route through the \
14481             same substrate-primitive typed dispatch on the :versao \
14482             empty-arm",
14483        );
14484        let c = caixa_with_versao("0.1.0");
14485        assert!(
14486            c.validate_versao().is_ok(),
14487            "validate_versao must accept versao == \"0.1.0\" (the \
14488             canonical SemVer-2 template baseline)",
14489        );
14490    }
14491
14492    #[test]
14493    fn versao_projects_str_by_borrow() {
14494        // The by-borrow pin: [`Caixa::versao`] returns `&str` by borrow
14495        // — the `&str` borrows the underlying `String` storage of the
14496        // required `versao` slot and the accessor must not allocate a
14497        // fresh `String` on every call. Peer of the [`Caixa::nome`]
14498        // (e6b7d97) by-borrow pin on the sibling outer top-level
14499        // [`Caixa`] required-`&str`-return axis, extended onto the
14500        // second outer top-level [`Caixa`] required-`&str`-return
14501        // universal-axis pinned-version surface — the accessor's
14502        // returned `&str` must borrow from `&self` (the returned
14503        // reference's lifetime is tied to `&self`), and calling the
14504        // accessor twice on the same [`Caixa`] must yield the same
14505        // `&str` verbatim (idempotent, no side effects on `&self`).
14506        //
14507        // Pins against a future silent detour that returned an owned
14508        // `String` (which would type-check but silently allocate on
14509        // every call, breaking the zero-cost projection every peer
14510        // sibling accessor carries), an accidental
14511        // `semver::Version::parse(&self.versao).unwrap().to_string()`
14512        // detour that returned a canonicalized fresh allocation through
14513        // an already-canonical byte-string (breaking a future `const fn`
14514        // regression and silently absorbing the `VersaoInvalid` refusal
14515        // at the accessor boundary), or a one-arm-only accessor that
14516        // returned a canonicalized value on some sentinel input
14517        // (breaking the pass-through invariant the sibling required-
14518        // scalar accessors carry).
14519        for versao in ["0.1.0", "1.0.0", "0.2.0-rc.1", "1.0.0+build.42"] {
14520            let c = caixa_with_versao(versao);
14521            let first = c.versao();
14522            let second = c.versao();
14523            assert_eq!(
14524                first, second,
14525                "Caixa::versao must be idempotent — two successive \
14526                 calls on the same &self must return the same &str",
14527            );
14528            assert_eq!(
14529                first, versao,
14530                "Caixa::versao must return :versao verbatim by borrow \
14531                 — got {first}, expected {versao}",
14532            );
14533        }
14534    }
14535
14536    fn caixa_with_kind(kind: CaixaKind) -> Caixa {
14537        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14538        c.kind = kind;
14539        c
14540    }
14541
14542    #[test]
14543    fn kind_returns_kind_variant_verbatim_across_permutations() {
14544        // The canonical per-`Caixa` `:kind` universal-axis closed-set-
14545        // enum discriminant pin: [`Caixa::kind`] must return the `:kind`
14546        // typed [`CaixaKind`] variant verbatim by `Copy`, byte-equal to
14547        // the raw `.kind` field access across every variant in the
14548        // closed accept-set (`Biblioteca` — the library kind that
14549        // exports lisp forms; `Binario` — the nix-built executable kind
14550        // under `exe/`; `Servico` — the wasm-component daemon kind
14551        // under `servicos/`; `Supervisor` — the OTP-shaped hierarchical
14552        // reconciliation kind; `Aplicacao` — the M3 typed-mesh
14553        // composition kind).
14554        //
14555        // Pins against a future silent detour that re-derived the kind
14556        // from a peer axis (an accidental fallback to
14557        // `if !servicos.is_empty() { Servico } else if
14558        // !membros.is_empty() { Aplicacao } else { Biblioteca }`
14559        // collapse that read the code-surface / mesh-slot columns into
14560        // the kind discriminator), a variant remap the operator
14561        // authors on one consumer without the other, or a stale-derive
14562        // detour that substituted [`CaixaKind::Biblioteca`] as the
14563        // default when the field held any other variant (which would
14564        // silently collapse the distinction between "author explicitly
14565        // declared `:kind Servico`" and "author declared any other
14566        // kind" every downstream renderer-dispatch site depends on).
14567        //
14568        // First outer top-level [`Caixa`] `Copy`-return required-enum-
14569        // discriminant accessor pin — opens the "outer [`Caixa`]
14570        // `Copy`-return required-discriminant" projection pattern.
14571        // Sibling in shape to the peer per-`:supervisor`
14572        // [`crate::supervisor::SupervisorSpec::estrategia`] (eafb619),
14573        // per-`:placement` [`crate::aplicacao::Placement::estrategia`]
14574        // (921fe1b), and per-`:children`
14575        // [`crate::supervisor::ChildSpec::restart`] (dfb4a81)
14576        // `Copy`-return closed-set-enum discriminant accessor pins on
14577        // the sibling nested-spec typed-slot discriminator axes,
14578        // extended here to the outer top-level [`Caixa`] universal-
14579        // axis surface.
14580        for kind in [
14581            CaixaKind::Biblioteca,
14582            CaixaKind::Binario,
14583            CaixaKind::Servico,
14584            CaixaKind::Supervisor,
14585            CaixaKind::Aplicacao,
14586        ] {
14587            let c = caixa_with_kind(kind);
14588            assert_eq!(
14589                c.kind(),
14590                kind,
14591                "Caixa::kind must return :kind verbatim (got {:?}, \
14592                 expected {kind:?})",
14593                c.kind(),
14594            );
14595            assert_eq!(
14596                c.kind(),
14597                c.kind,
14598                "Caixa::kind accessor and .kind field access must \
14599                 byte-equal — the accessor is the substrate-primitive \
14600                 typed dispatch every downstream kind-gate consumer \
14601                 must route through",
14602            );
14603        }
14604    }
14605
14606    #[test]
14607    fn require_kind_reads_through_lifted_kind_accessor() {
14608        // Two-consumer coherence pin: the [`crate::render::require_kind`]
14609        // entry-gate predicate (the canonical two-line
14610        // `require_kind(caixa, Servico)?` prelude every per-Servico /
14611        // per-Aplicacao renderer runs at its entry-point) and the
14612        // sibling [`crate::render::KindMismatch`] error carrier's
14613        // `actual:` field (which names the offending caixa's variant
14614        // in the diagnostic) must both key off the lifted accessor, so
14615        // any future rebrand on the typed slot's reader shape lands at
14616        // exactly one place. Pins the two-site coherence by exercising
14617        // every off-diagonal `(actual, expected)` pair across the
14618        // closed accept-set — the `KindMismatch { actual, expected }`
14619        // surfaced on the mismatch arm must byte-equal the pair the
14620        // accessor returns for each side.
14621        //
14622        // Peer of the sibling per-`:placement`
14623        // `validate_placement_reads_through_lifted_estrategia_accessor`
14624        // (921fe1b) two-arm consumer-coherence pin on the M3 mesh-slot
14625        // `Copy`-return discriminant axis — same "the entry-gate
14626        // predicate and the error carrier's `actual:` field must route
14627        // through the substrate-primitive typed dispatch" discipline
14628        // extended onto the outer top-level [`Caixa`] universal-axis
14629        // discriminant surface.
14630        for expected in [
14631            CaixaKind::Biblioteca,
14632            CaixaKind::Binario,
14633            CaixaKind::Servico,
14634            CaixaKind::Supervisor,
14635            CaixaKind::Aplicacao,
14636        ] {
14637            for actual in [
14638                CaixaKind::Biblioteca,
14639                CaixaKind::Binario,
14640                CaixaKind::Servico,
14641                CaixaKind::Supervisor,
14642                CaixaKind::Aplicacao,
14643            ] {
14644                let c = caixa_with_kind(actual);
14645                let result = crate::render::require_kind(&c, expected);
14646                if expected == actual {
14647                    assert!(
14648                        result.is_ok(),
14649                        "require_kind must accept when actual == expected \
14650                         (actual={actual:?}, expected={expected:?})",
14651                    );
14652                } else {
14653                    let err = result.expect_err("require_kind must reject when actual != expected");
14654                    assert_eq!(
14655                        err.actual,
14656                        c.kind(),
14657                        "KindMismatch.actual must byte-equal Caixa::kind() \
14658                         — the error carrier's `actual:` field reads \
14659                         through the lifted accessor",
14660                    );
14661                    assert_eq!(
14662                        err.expected, expected,
14663                        "KindMismatch.expected must byte-equal the \
14664                         expected variant passed to require_kind",
14665                    );
14666                }
14667            }
14668        }
14669    }
14670
14671    #[test]
14672    fn aplicacao_view_kind_gate_routes_through_accessor() {
14673        // Composition pin: [`Caixa::aplicacao_view`]'s kind-gate arm
14674        // must key off [`Caixa::kind`], not the raw `.kind` field
14675        // access. Structurally: a `Caixa { kind: X, .. }` for any
14676        // non-`Aplicacao` variant must fold to `None` on the
14677        // `aplicacao_view` composer (the "kind mismatch → no typed
14678        // view" contract every downstream Aplicacao consumer keys off
14679        // via `?`), and a `Caixa { kind: Aplicacao, .. }` must fold to
14680        // `Some(_)`. The pair jointly pins the accessor + view-gate
14681        // composition: any future silent detour that had the accessor
14682        // return a fresh [`CaixaKind::Aplicacao`] on some sentinel
14683        // input would silently absorb the kind-mismatch case at the
14684        // accessor boundary and every per-Aplicacao renderer would
14685        // silently render a non-Aplicacao caixa's mesh slots — the
14686        // composition pin catches that at caixa-core build time.
14687        //
14688        // Peer of the sibling per-`Caixa`
14689        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97) /
14690        // `validate_versao_empty_arm_routes_through_accessor` (20c0539)
14691        // composition pins on the sibling outer top-level [`Caixa`]
14692        // required-`&str` universal-axis surfaces — same "the
14693        // composer / validate gate must route through the substrate-
14694        // primitive typed dispatch" discipline extended onto the
14695        // outer top-level [`Caixa`] `Copy`-return required-
14696        // discriminant composition axis.
14697        for kind in [
14698            CaixaKind::Biblioteca,
14699            CaixaKind::Binario,
14700            CaixaKind::Servico,
14701            CaixaKind::Supervisor,
14702        ] {
14703            let c = caixa_with_kind(kind);
14704            assert!(
14705                c.aplicacao_view().is_none(),
14706                "aplicacao_view must return None on non-Aplicacao \
14707                 kind {kind:?} — the composer's kind-gate must route \
14708                 through Caixa::kind()",
14709            );
14710        }
14711        let c = caixa_with_kind(CaixaKind::Aplicacao);
14712        assert!(
14713            c.aplicacao_view().is_some(),
14714            "aplicacao_view must return Some on kind Aplicacao — \
14715             the composer's kind-gate must accept the matching arm \
14716             through Caixa::kind()",
14717        );
14718    }
14719
14720    #[test]
14721    fn supervisor_view_kind_gate_routes_through_accessor() {
14722        // Composition pin (mirror of the sibling
14723        // `aplicacao_view_kind_gate_routes_through_accessor` on the
14724        // second `_view` composer): [`Caixa::supervisor_view`]'s kind-
14725        // gate arm must key off [`Caixa::kind`], not the raw `.kind`
14726        // field access. A `Caixa { kind: X, .. }` for any non-
14727        // `Supervisor` variant must fold to `None` on the
14728        // `supervisor_view` composer, and a `Caixa { kind:
14729        // Supervisor, .. }` must fold to `Some(_)`. Same peer
14730        // composition pin discipline on the second `_view` composer
14731        // axis.
14732        for kind in [
14733            CaixaKind::Biblioteca,
14734            CaixaKind::Binario,
14735            CaixaKind::Servico,
14736            CaixaKind::Aplicacao,
14737        ] {
14738            let c = caixa_with_kind(kind);
14739            assert!(
14740                c.supervisor_view().is_none(),
14741                "supervisor_view must return None on non-Supervisor \
14742                 kind {kind:?} — the composer's kind-gate must route \
14743                 through Caixa::kind()",
14744            );
14745        }
14746        let mut c = caixa_with_kind(CaixaKind::Supervisor);
14747        // A Supervisor caixa needs a strategy + at least one child to
14748        // fold to a Some(_) that also validates; the composer itself
14749        // requires only the kind arm, so bare kind flip is enough to
14750        // pin the `Some(_)` return, but we populate the minimum
14751        // supervisor shape so a future strengthening of the composer
14752        // to reject an empty spec doesn't false-positive this pin.
14753        c.estrategia = Some(crate::supervisor::RestartStrategy::OneForOne);
14754        c.children = vec![crate::supervisor::ChildSpec {
14755            caixa: "child".into(),
14756            versao: "^0.1".into(),
14757            restart: crate::supervisor::RestartPolicy::Permanent,
14758        }];
14759        assert!(
14760            c.supervisor_view().is_some(),
14761            "supervisor_view must return Some on kind Supervisor — \
14762             the composer's kind-gate must accept the matching arm \
14763             through Caixa::kind()",
14764        );
14765    }
14766
14767    #[test]
14768    fn kind_projects_by_copy() {
14769        // The by-`Copy` pin: [`Caixa::kind`] returns a fresh
14770        // [`CaixaKind`] by `Copy` — the accessor must not borrow from
14771        // `&self` (the returned value is owned, `Copy`-projected from
14772        // the underlying [`CaixaKind`] storage; two calls on the same
14773        // [`Caixa`] must yield byte-equal values). Peer of the peer
14774        // per-`:placement` `Placement::estrategia` / per-`:supervisor`
14775        // `SupervisorSpec::estrategia` / per-`:children`
14776        // `ChildSpec::restart` `Copy`-return discriminant accessor
14777        // pins on the sibling nested-spec typed-slot discriminator
14778        // axes, extended onto the first outer top-level [`Caixa`]
14779        // required-`Copy`-return axis — pins against a future silent
14780        // detour that returned `&CaixaKind` (which would type-check
14781        // but silently constrain every consumer's callsite to a
14782        // borrow-shaped dispatch, breaking the zero-cost `Copy`
14783        // projection every peer sibling accessor carries).
14784        for kind in [
14785            CaixaKind::Biblioteca,
14786            CaixaKind::Binario,
14787            CaixaKind::Servico,
14788            CaixaKind::Supervisor,
14789            CaixaKind::Aplicacao,
14790        ] {
14791            let c = caixa_with_kind(kind);
14792            let first: CaixaKind = c.kind();
14793            let second: CaixaKind = c.kind();
14794            assert_eq!(
14795                first, second,
14796                "Caixa::kind must be idempotent — two successive \
14797                 calls on the same &self must return the same \
14798                 CaixaKind variant",
14799            );
14800            assert_eq!(
14801                first, kind,
14802                "Caixa::kind must return :kind verbatim by Copy — \
14803                 got {first:?}, expected {kind:?}",
14804            );
14805        }
14806    }
14807
14808    // ── Caixa::autores — outer top-level &[T] slice accessor ──────────
14809
14810    #[test]
14811    fn autores_returns_autores_slice_verbatim_across_permutations() {
14812        // The canonical per-`Caixa` `:autores` universal-axis maintainer-
14813        // name-list slice pin: [`Caixa::autores`] must return the
14814        // `:autores` typed [`Vec<String>`] list verbatim as a
14815        // `&[String]`, byte-equal to the raw `self.autores.as_slice()`
14816        // access across every representative value in the accept-set —
14817        // `[]` (the "no maintainers declared" arm every existing
14818        // fixture without an `:autores` line carries), `[""]` (a past-
14819        // the-guard sentinel that pins the accessor doesn't perform a
14820        // silent `[""] → []` collapse on the empty-entry arm — validate
14821        // rejects `[""]` through `AutorEmpty` but the accessor must
14822        // ship the raw slot verbatim so a validate-time gate regression
14823        // surfaces at the caixa-helm emit boundary rather than being
14824        // silently absorbed into a maintainer-drop), `["pleme-io"]` (the
14825        // canonical single-maintainer form every `feira init` template
14826        // scaffolds), `["alice", "bob"]` (a canonical multi-maintainer
14827        // form), `["alice <alice@example.com>", "bob <bob@example.com>"]`
14828        // (the canonical RFC-5322 `<name> <email>` form the
14829        // `is_chart_maintainer_name_shape` predicate accepts), and
14830        // `["pleme-io", "pleme-io"]` (a past-the-guard duplicate
14831        // sentinel — validate rejects through `AutorDuplicate` but the
14832        // accessor must ship the raw slot verbatim).
14833        //
14834        // First outer top-level [`Caixa`] `&[T]`-return slice accessor
14835        // pin on the substrate primitive — opens the "outer [`Caixa`]
14836        // `&[T]` slice" projection pattern the sibling per-`Caixa`
14837        // `:etiquetas` / `:deps` / `:deps-dev` / `:exe` / `:bibliotecas`
14838        // / `:servicos` / `:upgrade-from` / `:children` future lifts
14839        // fold on. Sibling in shape to the peer per-`:supervisor`
14840        // [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
14841        // per-`:placement` [`crate::aplicacao::Placement::clusters`]
14842        // (a6e18d7), per-`:membros`
14843        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
14844        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
14845        // (0dcc926), and per-`:upgrade-from :instructions`
14846        // [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
14847        // `&[T]`-return slice accessor pins on the sibling per-M2 /
14848        // per-M3 typed-slot list axes, extended onto the outer top-
14849        // level [`Caixa`] universal-axis surface. Pins against a future
14850        // silent detour that returned an owned `Vec<String>` (which
14851        // would type-check but silently clone on every accessor call,
14852        // breaking the zero-cost projection every peer sibling slice
14853        // accessor carries), a `[""] → []` collapse (which would
14854        // silently absorb the `AutorEmpty` refusal case at the accessor
14855        // boundary), or a `["a", "a"] → ["a"]` dedup collapse (which
14856        // would silently absorb the `AutorDuplicate` refusal case at
14857        // the accessor boundary and the caixa-helm `maintainers:` fold
14858        // would silently render a dedupped list on a struct-literal
14859        // `Caixa { autores: vec!["a".into(), "a".into()], .. }`).
14860        for autores in [
14861            vec![],
14862            vec![""],
14863            vec!["pleme-io"],
14864            vec!["alice", "bob"],
14865            vec!["alice <alice@example.com>", "bob <bob@example.com>"],
14866            vec!["pleme-io", "pleme-io"],
14867        ] {
14868            let c = caixa_with_autores(autores.clone());
14869            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
14870            assert_eq!(
14871                c.autores(),
14872                expected.as_slice(),
14873                "Caixa::autores must return :autores verbatim (got {:?}, \
14874                 expected {expected:?})",
14875                c.autores(),
14876            );
14877            assert_eq!(
14878                c.autores(),
14879                c.autores.as_slice(),
14880                "Caixa::autores must byte-equal the raw \
14881                 `self.autores.as_slice()` field access across every \
14882                 value in the Vec<String> accept-set",
14883            );
14884        }
14885    }
14886
14887    #[test]
14888    fn validate_autores_empty_entry_arm_routes_through_accessor() {
14889        // Composition pin: [`Caixa::validate_autores`]'s per-entry
14890        // empty-arm gate must key off [`Caixa::autores`], not the raw
14891        // `&self.autores` field-borrow walk. Structurally: a
14892        // `Caixa { autores: vec!["".into()], .. }` must surface the
14893        // `AutorEmpty` refusal exactly, and a
14894        // `Caixa { autores: vec!["pleme-io".into()], .. }` (the
14895        // canonical single-maintainer form) must pass validate. The
14896        // pair jointly pins the accessor + validate-gate composition:
14897        // any future silent detour that had the accessor return an
14898        // empty slice on the `[""]` arm (a
14899        // `.iter().filter(|s| !s.is_empty()).collect()` collapse)
14900        // would silently absorb the `AutorEmpty` refusal at the
14901        // accessor boundary and the validate gate would accept a
14902        // struct-literal `Caixa { autores: vec!["".into()], .. }` —
14903        // the composition pin catches that at caixa-core build time.
14904        //
14905        // Peer of the per-`Caixa` [`Caixa::validate_licenca`] (6d5bc28)
14906        // accessor-composition pin
14907        // (`validate_licenca_empty_arm_routes_through_accessor`) on the
14908        // sibling `Option<&str>`-composition axis and the
14909        // per-`:politicas :circuit-breaker`
14910        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
14911        // accessor-composition pin
14912        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
14913        // on the sibling required-`u32`-composition axis — same "the
14914        // validate / shape-gate predicate must route through the
14915        // substrate-primitive typed dispatch" discipline extended onto
14916        // the outer top-level [`Caixa`] universal-axis `&[T]`-
14917        // composition surface.
14918        let c = caixa_with_autores(vec![""]);
14919        assert!(
14920            matches!(c.validate_autores(), Err(ManifestError::AutorEmpty)),
14921            "validate_autores must reject autores == vec![\"\"] with \
14922             AutorEmpty — the accessor and the validate gate must \
14923             route through the same substrate-primitive typed dispatch \
14924             on the :autores per-entry empty arm",
14925        );
14926        let c = caixa_with_autores(vec!["pleme-io"]);
14927        assert!(
14928            c.validate_autores().is_ok(),
14929            "validate_autores must accept autores == vec![\"pleme-io\"] \
14930             (the canonical single-maintainer shape every `feira init` \
14931             template scaffolds)",
14932        );
14933    }
14934
14935    #[test]
14936    fn autores_projects_slice_by_borrow() {
14937        // The by-borrow pin: [`Caixa::autores`] returns `&[String]` by
14938        // borrow — the returned slice borrows the underlying
14939        // `Vec<String>` storage of the `:autores` slot and the
14940        // accessor must not clone the backing `Vec` on every call.
14941        // Peer of the per-`:membros`
14942        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36) /
14943        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
14944        // (0dcc926) / per-`:placement`
14945        // [`crate::aplicacao::Placement::clusters`] (a6e18d7) /
14946        // per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
14947        // (bc92bce) by-borrow pins on the sibling per-M2 / per-M3
14948        // typed-slot `&[T]`-return axes, extended onto the outer top-
14949        // level [`Caixa`] universal-axis `&[String]` shape — the
14950        // accessor's returned slice must borrow from `&self` (the
14951        // returned reference's lifetime is tied to `&self`), and
14952        // calling the accessor twice on the same [`Caixa`] must yield
14953        // slices that are pointer-equal (the underlying byte-buffer is
14954        // the storage `Vec`'s allocation, not a fresh copy) as well as
14955        // value-equal (idempotent, no side effects on `&self`).
14956        //
14957        // Pins against a future silent detour that returned an owned
14958        // `Vec<String>` (which would type-check but silently clone on
14959        // every call, breaking the zero-cost projection every peer
14960        // sibling slice accessor carries), a `&Vec<String>` return
14961        // (which would leak the backing `Vec`'s grow/push/reserve
14962        // surface no downstream consumer reaches for), or a one-arm-
14963        // only accessor that returned a saturating value on some
14964        // sentinel input (breaking the pass-through invariant the
14965        // sibling slice accessors carry).
14966        for autores in [
14967            vec![],
14968            vec!["pleme-io"],
14969            vec!["alice", "bob"],
14970            vec!["pleme-io", "pleme-io"],
14971        ] {
14972            let c = caixa_with_autores(autores.clone());
14973            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
14974            let first = c.autores();
14975            let second = c.autores();
14976            assert_eq!(
14977                first, second,
14978                "Caixa::autores must be idempotent — two successive \
14979                 calls on the same &self must return the same \
14980                 &[String]",
14981            );
14982            assert_eq!(
14983                first.as_ptr(),
14984                second.as_ptr(),
14985                "Caixa::autores must borrow the underlying Vec<String> \
14986                 storage — two successive calls must return slices \
14987                 with the same backing pointer (a fresh Vec<String> \
14988                 clone would change the pointer on every call)",
14989            );
14990            assert_eq!(
14991                first,
14992                expected.as_slice(),
14993                "Caixa::autores must return :autores verbatim by \
14994                 borrow — got {first:?}, expected {expected:?}",
14995            );
14996        }
14997    }
14998
14999    // ── Caixa::etiquetas — outer top-level &[T] slice accessor ────────
15000
15001    #[test]
15002    fn etiquetas_returns_etiquetas_slice_verbatim_across_permutations() {
15003        // The canonical per-`Caixa` `:etiquetas` universal-axis
15004        // registry-search-tag-list slice pin: [`Caixa::etiquetas`] must
15005        // return the `:etiquetas` typed [`Vec<String>`] list verbatim
15006        // as a `&[String]`, byte-equal to the raw
15007        // `self.etiquetas.as_slice()` access across every representative
15008        // value in the accept-set — `[]` (the "no tags declared" arm
15009        // every existing fixture without an `:etiquetas` line carries),
15010        // `[""]` (a past-the-guard sentinel that pins the accessor
15011        // doesn't perform a silent `[""] → []` collapse on the empty-
15012        // entry arm — validate rejects `[""]` through `EtiquetaEmpty`
15013        // but the accessor must ship the raw slot verbatim so a
15014        // validate-time gate regression surfaces at the caixa-helm emit
15015        // boundary rather than being silently absorbed into a keyword-
15016        // drop), `["demo"]` (the canonical single-tag form every
15017        // `feira init` template scaffolds), `["example", "aplicacao",
15018        // "mesh", "ecommerce", "demo"]` (the canonical multi-tag form
15019        // the checkout-aplicacao fixture emits), and `["demo", "demo"]`
15020        // (a past-the-guard duplicate sentinel — validate rejects
15021        // through `EtiquetaDuplicate` but the accessor must ship the
15022        // raw slot verbatim so the caixa-helm `BTreeSet::collect` dedup
15023        // at chart-render time isn't silently promoted into the
15024        // accessor boundary and struct-literal
15025        // `Caixa { etiquetas: vec!["demo".into(), "demo".into()], .. }`
15026        // fixtures continue to expose the duplicate at the accessor).
15027        //
15028        // Second outer top-level [`Caixa`] `&[T]`-return slice accessor
15029        // pin on the substrate primitive — folds on the "outer
15030        // [`Caixa`] `&[T]` slice" projection pattern
15031        // `autores_returns_autores_slice_verbatim_across_permutations`
15032        // (b5d813f) opened, sibling in shape and idiom. Pins against a
15033        // future silent detour that returned an owned `Vec<String>`
15034        // (which would type-check but silently clone on every accessor
15035        // call, breaking the zero-cost projection every peer sibling
15036        // slice accessor carries), a `[""] → []` collapse (which would
15037        // silently absorb the `EtiquetaEmpty` refusal case at the
15038        // accessor boundary), or a `["a", "a"] → ["a"]` dedup collapse
15039        // (which would silently absorb the `EtiquetaDuplicate` refusal
15040        // case at the accessor boundary — the caixa-helm chart-render
15041        // `BTreeSet::collect` dedup is downstream of the accessor and
15042        // must not be silently promoted into it).
15043        for etiquetas in [
15044            vec![],
15045            vec![""],
15046            vec!["demo"],
15047            vec!["example", "aplicacao", "mesh", "ecommerce", "demo"],
15048            vec!["demo", "demo"],
15049        ] {
15050            let c = caixa_with_etiquetas(etiquetas.clone());
15051            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
15052            assert_eq!(
15053                c.etiquetas(),
15054                expected.as_slice(),
15055                "Caixa::etiquetas must return :etiquetas verbatim (got \
15056                 {:?}, expected {expected:?})",
15057                c.etiquetas(),
15058            );
15059            assert_eq!(
15060                c.etiquetas(),
15061                c.etiquetas.as_slice(),
15062                "Caixa::etiquetas must byte-equal the raw \
15063                 `self.etiquetas.as_slice()` field access across every \
15064                 value in the Vec<String> accept-set",
15065            );
15066        }
15067    }
15068
15069    #[test]
15070    fn validate_etiquetas_empty_entry_arm_routes_through_accessor() {
15071        // Composition pin: [`Caixa::validate_etiquetas`]'s per-entry
15072        // empty-arm gate must key off [`Caixa::etiquetas`], not the raw
15073        // `&self.etiquetas` field-borrow walk. Structurally: a
15074        // `Caixa { etiquetas: vec!["".into()], .. }` must surface the
15075        // `EtiquetaEmpty` refusal exactly, and a
15076        // `Caixa { etiquetas: vec!["demo".into()], .. }` (the canonical
15077        // single-tag form) must pass validate. The pair jointly pins
15078        // the accessor + validate-gate composition: any future silent
15079        // detour that had the accessor return an empty slice on the
15080        // `[""]` arm (a
15081        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
15082        // silently absorb the `EtiquetaEmpty` refusal at the accessor
15083        // boundary and the validate gate would accept a struct-literal
15084        // `Caixa { etiquetas: vec!["".into()], .. }` — the composition
15085        // pin catches that at caixa-core build time.
15086        //
15087        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
15088        // through_accessor` (b5d813f) accessor-composition pin on the
15089        // sibling `&[T]`-composition axis — same "the validate / shape-
15090        // gate predicate must route through the substrate-primitive
15091        // typed dispatch" discipline extended onto the sibling outer
15092        // top-level [`Caixa`] `&[T]`-composition surface.
15093        let c = caixa_with_etiquetas(vec![""]);
15094        assert!(
15095            matches!(c.validate_etiquetas(), Err(ManifestError::EtiquetaEmpty)),
15096            "validate_etiquetas must reject etiquetas == vec![\"\"] \
15097             with EtiquetaEmpty — the accessor and the validate gate \
15098             must route through the same substrate-primitive typed \
15099             dispatch on the :etiquetas per-entry empty arm",
15100        );
15101        let c = caixa_with_etiquetas(vec!["demo"]);
15102        assert!(
15103            c.validate_etiquetas().is_ok(),
15104            "validate_etiquetas must accept etiquetas == vec![\"demo\"] \
15105             (the canonical single-tag shape every `feira init` \
15106             template scaffolds)",
15107        );
15108    }
15109
15110    #[test]
15111    fn etiquetas_projects_slice_by_borrow() {
15112        // The by-borrow pin: [`Caixa::etiquetas`] returns `&[String]`
15113        // by borrow — the returned slice borrows the underlying
15114        // `Vec<String>` storage of the `:etiquetas` slot and the
15115        // accessor must not clone the backing `Vec` on every call.
15116        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15117        // (b5d813f) by-borrow pin on the sibling outer top-level
15118        // [`Caixa`] `&[String]`-return axis — the accessor's returned
15119        // slice must borrow from `&self` (the returned reference's
15120        // lifetime is tied to `&self`), and calling the accessor twice
15121        // on the same [`Caixa`] must yield slices that are pointer-
15122        // equal (the underlying byte-buffer is the storage `Vec`'s
15123        // allocation, not a fresh copy) as well as value-equal
15124        // (idempotent, no side effects on `&self`).
15125        //
15126        // Pins against a future silent detour that returned an owned
15127        // `Vec<String>` (which would type-check but silently clone on
15128        // every call, breaking the zero-cost projection every peer
15129        // sibling slice accessor carries), a `&Vec<String>` return
15130        // (which would leak the backing `Vec`'s grow/push/reserve
15131        // surface no downstream consumer reaches for), or a one-arm-
15132        // only accessor that returned a saturating value on some
15133        // sentinel input (breaking the pass-through invariant the
15134        // sibling slice accessors carry).
15135        for etiquetas in [
15136            vec![],
15137            vec!["demo"],
15138            vec!["example", "aplicacao", "mesh"],
15139            vec!["demo", "demo"],
15140        ] {
15141            let c = caixa_with_etiquetas(etiquetas.clone());
15142            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
15143            let first = c.etiquetas();
15144            let second = c.etiquetas();
15145            assert_eq!(
15146                first, second,
15147                "Caixa::etiquetas must be idempotent — two successive \
15148                 calls on the same &self must return the same \
15149                 &[String]",
15150            );
15151            assert_eq!(
15152                first.as_ptr(),
15153                second.as_ptr(),
15154                "Caixa::etiquetas must borrow the underlying \
15155                 Vec<String> storage — two successive calls must \
15156                 return slices with the same backing pointer (a fresh \
15157                 Vec<String> clone would change the pointer on every \
15158                 call)",
15159            );
15160            assert_eq!(
15161                first,
15162                expected.as_slice(),
15163                "Caixa::etiquetas must return :etiquetas verbatim by \
15164                 borrow — got {first:?}, expected {expected:?}",
15165            );
15166        }
15167    }
15168
15169    // ── Caixa::bibliotecas — outer top-level &[T] slice accessor ──────
15170
15171    #[test]
15172    fn bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations() {
15173        // The canonical per-`Caixa` `:bibliotecas` universal-axis
15174        // library-source-path-list slice pin: [`Caixa::bibliotecas`]
15175        // must return the `:bibliotecas` typed [`Vec<String>`] list
15176        // verbatim as a `&[String]`, byte-equal to the raw
15177        // `self.bibliotecas.as_slice()` access across every
15178        // representative value in the accept-set — `[]` (the "no
15179        // libraries declared" arm every `:kind` other than `Biblioteca`
15180        // + every `Biblioteca` relying on the canonical
15181        // `lib/<nome>.lisp` implicit-default path carries; the
15182        // layout's [`crate::LayoutInvariants`] `MissingLib` arm-gate
15183        // fires exactly on this empty-slot + `Biblioteca`-kind
15184        // combination), `[""]` (a past-the-guard sentinel that pins
15185        // the accessor doesn't perform a silent `[""] → []` collapse
15186        // on the empty-entry arm — validate rejects `[""]` through
15187        // `CodePathEmpty { slot: ":bibliotecas" }` but the accessor
15188        // must ship the raw slot verbatim so a validate-time gate
15189        // regression surfaces at the `feira build` phase-1 parse
15190        // boundary rather than being silently absorbed into a
15191        // library-drop), `["lib/demo.lisp"]` (the canonical single-
15192        // entry form `Caixa::template` scaffolds and every `feira init`
15193        // template emits), `["lib/demo.lisp", "lib/helpers.lisp"]`
15194        // (the canonical multi-library form the
15195        // `validate_code_paths_accepts_explicit_relative_paths_on_
15196        // every_slot` fixture emits), and `["lib/foo.lisp",
15197        // "lib/foo.lisp"]` (a past-the-guard duplicate sentinel —
15198        // validate rejects through `CodePathDuplicate { slot:
15199        // ":bibliotecas" }` per the per-slot set-not-multiset gate,
15200        // but the accessor must ship the raw slot verbatim so the
15201        // `feira build` `for entry in caixa.bibliotecas()` parse walk
15202        // sees the duplicate at the accessor boundary and struct-
15203        // literal `Caixa { bibliotecas: vec!["lib/foo.lisp".into(),
15204        // "lib/foo.lisp".into()], .. }` fixtures continue to expose
15205        // the duplicate at the accessor).
15206        //
15207        // Third outer top-level [`Caixa`] `&[T]`-return slice accessor
15208        // pin on the substrate primitive — folds on the "outer
15209        // [`Caixa`] `&[T]` slice" projection pattern
15210        // `autores_returns_autores_slice_verbatim_across_permutations`
15211        // (b5d813f) opened and
15212        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15213        // (78c7d3c) folded on, sibling in shape and idiom. Pins
15214        // against a future silent detour that returned an owned
15215        // `Vec<String>` (which would type-check but silently clone on
15216        // every accessor call, breaking the zero-cost projection
15217        // every peer sibling slice accessor carries), a `[""] → []`
15218        // collapse (which would silently absorb the `CodePathEmpty`
15219        // refusal case at the accessor boundary), or a `["lib/foo.lisp",
15220        // "lib/foo.lisp"] → ["lib/foo.lisp"]` dedup collapse (which
15221        // would silently absorb the `CodePathDuplicate` refusal case
15222        // at the accessor boundary — the per-slot set-not-multiset
15223        // gate is downstream of the accessor and must not be silently
15224        // promoted into it).
15225        for bibliotecas in [
15226            vec![],
15227            vec![""],
15228            vec!["lib/demo.lisp"],
15229            vec!["lib/demo.lisp", "lib/helpers.lisp"],
15230            vec!["lib/foo.lisp", "lib/foo.lisp"],
15231        ] {
15232            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
15233            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
15234            assert_eq!(
15235                c.bibliotecas(),
15236                expected.as_slice(),
15237                "Caixa::bibliotecas must return :bibliotecas verbatim \
15238                 (got {:?}, expected {expected:?})",
15239                c.bibliotecas(),
15240            );
15241            assert_eq!(
15242                c.bibliotecas(),
15243                c.bibliotecas.as_slice(),
15244                "Caixa::bibliotecas must byte-equal the raw \
15245                 `self.bibliotecas.as_slice()` field access across \
15246                 every value in the Vec<String> accept-set",
15247            );
15248        }
15249    }
15250
15251    #[test]
15252    fn validate_code_paths_bibliotecas_empty_arm_routes_through_accessor() {
15253        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15254        // empty-arm gate on the `:bibliotecas` slot must key off
15255        // [`Caixa::bibliotecas`], not a divergent raw
15256        // `&self.bibliotecas` field-borrow walk. Structurally: a
15257        // `Caixa { bibliotecas: vec!["".into()], .. }` must surface
15258        // the `CodePathEmpty { slot: ":bibliotecas" }` refusal
15259        // exactly, and a `Caixa { bibliotecas: vec!["lib/demo.lisp".
15260        // into()], .. }` (the canonical single-library form
15261        // `Caixa::template` scaffolds) must pass validate. The pair
15262        // jointly pins the accessor + validate-gate composition: any
15263        // future silent detour that had the accessor return an empty
15264        // slice on the `[""]` arm (a `.iter().filter(|s|
15265        // !s.is_empty()).collect()` collapse) would silently absorb
15266        // the `CodePathEmpty` refusal at the accessor boundary and
15267        // the validate gate would accept a struct-literal
15268        // `Caixa { bibliotecas: vec!["".into()], .. }` — the
15269        // composition pin catches that at caixa-core build time.
15270        //
15271        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
15272        // through_accessor` (b5d813f) and
15273        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15274        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15275        // composition axes — same "the validate / shape-gate
15276        // predicate must route through the substrate-primitive typed
15277        // dispatch" discipline extended onto the sibling outer top-
15278        // level [`Caixa`] `&[T]`-composition surface. Nominally the
15279        // in-tree `validate_code_paths` production body still keys
15280        // off the internal `[(":bibliotecas", &self.bibliotecas,
15281        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15282        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15283        // (the tuple's homogeneous slice-typed shape blocks a per-
15284        // element accessor swap in isolation — a future companion
15285        // lift for `:exe` and `:servicos` on the same outer-`Caixa`
15286        // `&[T]` slice-accessor axis closes that tuple onto the
15287        // triple of typed dispatches as a unit); the composition pin
15288        // catches any future accessor-side silent filter drop against
15289        // that eventual tuple-closure regardless of whether the
15290        // `:bibliotecas` slot is threaded through the accessor or the
15291        // raw field access at the tuple's construction site.
15292        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
15293        assert!(
15294            matches!(
15295                c.validate_code_paths(),
15296                Err(ManifestError::CodePathEmpty {
15297                    slot: ":bibliotecas"
15298                })
15299            ),
15300            "validate_code_paths must reject bibliotecas == vec![\"\"] \
15301             with CodePathEmpty {{ slot: \":bibliotecas\" }} — the \
15302             accessor and the validate gate must route through the \
15303             same substrate-primitive typed dispatch on the \
15304             :bibliotecas per-entry empty arm",
15305        );
15306        let c = caixa_with_code_paths(vec!["lib/demo.lisp"], vec![], vec![]);
15307        assert!(
15308            c.validate_code_paths().is_ok(),
15309            "validate_code_paths must accept bibliotecas == \
15310             vec![\"lib/demo.lisp\"] (the canonical single-library \
15311             shape every `feira init` template scaffolds)",
15312        );
15313    }
15314
15315    #[test]
15316    fn bibliotecas_projects_slice_by_borrow() {
15317        // The by-borrow pin: [`Caixa::bibliotecas`] returns
15318        // `&[String]` by borrow — the returned slice borrows the
15319        // underlying `Vec<String>` storage of the `:bibliotecas` slot
15320        // and the accessor must not clone the backing `Vec` on every
15321        // call. Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15322        // (b5d813f) and `etiquetas_projects_slice_by_borrow` (78c7d3c)
15323        // by-borrow pins on the sibling outer top-level [`Caixa`]
15324        // `&[String]`-return axes — the accessor's returned slice
15325        // must borrow from `&self` (the returned reference's lifetime
15326        // is tied to `&self`), and calling the accessor twice on the
15327        // same [`Caixa`] must yield slices that are pointer-equal
15328        // (the underlying byte-buffer is the storage `Vec`'s
15329        // allocation, not a fresh copy) as well as value-equal
15330        // (idempotent, no side effects on `&self`).
15331        //
15332        // Pins against a future silent detour that returned an owned
15333        // `Vec<String>` (which would type-check but silently clone on
15334        // every call, breaking the zero-cost projection every peer
15335        // sibling slice accessor carries), a `&Vec<String>` return
15336        // (which would leak the backing `Vec`'s grow/push/reserve
15337        // surface no downstream consumer reaches for), or a one-arm-
15338        // only accessor that returned a saturating value on some
15339        // sentinel input (breaking the pass-through invariant the
15340        // sibling slice accessors carry).
15341        for bibliotecas in [
15342            vec![],
15343            vec!["lib/demo.lisp"],
15344            vec!["lib/demo.lisp", "lib/helpers.lisp"],
15345            vec!["lib/foo.lisp", "lib/foo.lisp"],
15346        ] {
15347            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
15348            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
15349            let first = c.bibliotecas();
15350            let second = c.bibliotecas();
15351            assert_eq!(
15352                first, second,
15353                "Caixa::bibliotecas must be idempotent — two \
15354                 successive calls on the same &self must return the \
15355                 same &[String]",
15356            );
15357            assert_eq!(
15358                first.as_ptr(),
15359                second.as_ptr(),
15360                "Caixa::bibliotecas must borrow the underlying \
15361                 Vec<String> storage — two successive calls must \
15362                 return slices with the same backing pointer (a \
15363                 fresh Vec<String> clone would change the pointer on \
15364                 every call)",
15365            );
15366            assert_eq!(
15367                first,
15368                expected.as_slice(),
15369                "Caixa::bibliotecas must return :bibliotecas verbatim \
15370                 by borrow — got {first:?}, expected {expected:?}",
15371            );
15372        }
15373    }
15374
15375    // ── Caixa::exe — outer top-level &[T] slice accessor ──────────────
15376
15377    #[test]
15378    fn exe_returns_exe_slice_verbatim_across_permutations() {
15379        // The canonical per-`Caixa` `:exe` universal-axis
15380        // nix-built-executable-entry-path-list slice pin: [`Caixa::exe`]
15381        // must return the `:exe` typed [`Vec<String>`] list verbatim as
15382        // a `&[String]`, byte-equal to the raw `self.exe.as_slice()`
15383        // access across every representative value in the accept-set —
15384        // `[]` (the "no executable declared" arm every `:kind` other
15385        // than `Binario` carries; the layout's [`crate::LayoutInvariants`]
15386        // `BinarioWithoutExe` arm-gate fires exactly on this empty-slot
15387        // + `Binario`-kind combination), `[""]` (a past-the-guard
15388        // sentinel that pins the accessor doesn't perform a silent
15389        // `[""] → []` collapse on the empty-entry arm — validate rejects
15390        // `[""]` through `CodePathEmpty { slot: ":exe" }` but the
15391        // accessor must ship the raw slot verbatim so a validate-time
15392        // gate regression surfaces at the layout / `feira nix` boundary
15393        // rather than being silently absorbed into an executable-drop),
15394        // `["exe/cli"]` (the canonical single-entry Binario form every
15395        // in-tree `caixa_with_code_paths` positive control uses),
15396        // `["exe/cli", "exe/serve"]` (the canonical multi-executable
15397        // form the `validate_code_paths_accepts_explicit_relative_paths_
15398        // on_every_slot` fixture emits), and `["exe/cli", "exe/cli"]`
15399        // (a past-the-guard duplicate sentinel — validate rejects
15400        // through `CodePathDuplicate { slot: ":exe" }` per the per-slot
15401        // set-not-multiset gate, but the accessor must ship the raw
15402        // slot verbatim so struct-literal `Caixa { exe: vec!["exe/cli".
15403        // into(), "exe/cli".into()], .. }` fixtures continue to expose
15404        // the duplicate at the accessor).
15405        //
15406        // Fourth outer top-level [`Caixa`] `&[T]`-return slice accessor
15407        // pin on the substrate primitive — folds on the "outer
15408        // [`Caixa`] `&[T]` slice" projection pattern
15409        // `autores_returns_autores_slice_verbatim_across_permutations`
15410        // (b5d813f) opened,
15411        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15412        // (78c7d3c) folded on, and
15413        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15414        // (8a36c23) closed the universal-axis text-tag family of.
15415        // Opens the outer-`Caixa` foreign-code-slot `&[T]` sub-family
15416        // the sibling `:servicos` future lift closes onto. Pins against
15417        // a future silent detour that returned an owned `Vec<String>`
15418        // (which would type-check but silently clone on every accessor
15419        // call, breaking the zero-cost projection every peer sibling
15420        // slice accessor carries), a `[""] → []` collapse (which would
15421        // silently absorb the `CodePathEmpty` refusal case at the
15422        // accessor boundary), or an `["exe/cli", "exe/cli"] →
15423        // ["exe/cli"]` dedup collapse (which would silently absorb the
15424        // `CodePathDuplicate` refusal case at the accessor boundary —
15425        // the per-slot set-not-multiset gate is downstream of the
15426        // accessor and must not be silently promoted into it).
15427        for exe in [
15428            vec![],
15429            vec![""],
15430            vec!["exe/cli"],
15431            vec!["exe/cli", "exe/serve"],
15432            vec!["exe/cli", "exe/cli"],
15433        ] {
15434            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
15435            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
15436            assert_eq!(
15437                c.exe(),
15438                expected.as_slice(),
15439                "Caixa::exe must return :exe verbatim (got {:?}, \
15440                 expected {expected:?})",
15441                c.exe(),
15442            );
15443            assert_eq!(
15444                c.exe(),
15445                c.exe.as_slice(),
15446                "Caixa::exe must byte-equal the raw \
15447                 `self.exe.as_slice()` field access across every value \
15448                 in the Vec<String> accept-set",
15449            );
15450        }
15451    }
15452
15453    #[test]
15454    fn validate_code_paths_exe_empty_arm_routes_through_accessor() {
15455        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15456        // empty-arm gate on the `:exe` slot must key off
15457        // [`Caixa::exe`], not a divergent raw `&self.exe` field-borrow
15458        // walk. Structurally: a `Caixa { exe: vec!["".into()], .. }`
15459        // must surface the `CodePathEmpty { slot: ":exe" }` refusal
15460        // exactly, and a `Caixa { exe: vec!["exe/cli".into()], .. }`
15461        // (the canonical single-executable form every in-tree
15462        // `caixa_with_code_paths` positive control uses) must pass
15463        // validate. The pair jointly pins the accessor + validate-gate
15464        // composition: any future silent detour that had the accessor
15465        // return an empty slice on the `[""]` arm (a
15466        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
15467        // silently absorb the `CodePathEmpty` refusal at the accessor
15468        // boundary and the validate gate would accept a struct-literal
15469        // `Caixa { exe: vec!["".into()], .. }` — the composition pin
15470        // catches that at caixa-core build time.
15471        //
15472        // Peer of the per-`Caixa`
15473        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15474        // (8a36c23), `validate_autores_empty_arm_routes_through_accessor`
15475        // (b5d813f), and
15476        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15477        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15478        // composition axes — same "the validate / shape-gate predicate
15479        // must route through the substrate-primitive typed dispatch"
15480        // discipline extended onto the sibling outer top-level [`Caixa`]
15481        // `&[T]`-composition surface. Nominally the in-tree
15482        // `validate_code_paths` production body still keys off the
15483        // internal `[(":bibliotecas", &self.bibliotecas,
15484        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15485        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15486        // (the tuple's homogeneous slice-typed shape blocks a per-
15487        // element accessor swap in isolation — a future companion lift
15488        // for `:servicos` on the same outer-`Caixa` `&[T]` slice-
15489        // accessor axis closes that tuple onto the triple of typed
15490        // dispatches as a unit); the composition pin catches any future
15491        // accessor-side silent filter drop against that eventual tuple-
15492        // closure regardless of whether the `:exe` slot is threaded
15493        // through the accessor or the raw field access at the tuple's
15494        // construction site.
15495        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
15496        assert!(
15497            matches!(
15498                c.validate_code_paths(),
15499                Err(ManifestError::CodePathEmpty { slot: ":exe" })
15500            ),
15501            "validate_code_paths must reject exe == vec![\"\"] \
15502             with CodePathEmpty {{ slot: \":exe\" }} — the \
15503             accessor and the validate gate must route through the \
15504             same substrate-primitive typed dispatch on the \
15505             :exe per-entry empty arm",
15506        );
15507        let c = caixa_with_code_paths(vec![], vec!["exe/cli"], vec![]);
15508        assert!(
15509            c.validate_code_paths().is_ok(),
15510            "validate_code_paths must accept exe == vec![\"exe/cli\"] \
15511             (the canonical single-executable shape every in-tree \
15512             `caixa_with_code_paths` positive control uses)",
15513        );
15514    }
15515
15516    #[test]
15517    fn exe_projects_slice_by_borrow() {
15518        // The by-borrow pin: [`Caixa::exe`] returns `&[String]` by
15519        // borrow — the returned slice borrows the underlying
15520        // `Vec<String>` storage of the `:exe` slot and the accessor
15521        // must not clone the backing `Vec` on every call. Peer of the
15522        // per-`Caixa` `autores_projects_slice_by_borrow` (b5d813f),
15523        // `etiquetas_projects_slice_by_borrow` (78c7d3c), and
15524        // `bibliotecas_projects_slice_by_borrow` (8a36c23) by-borrow
15525        // pins on the sibling outer top-level [`Caixa`] `&[String]`-
15526        // return axes — the accessor's returned slice must borrow from
15527        // `&self` (the returned reference's lifetime is tied to
15528        // `&self`), and calling the accessor twice on the same
15529        // [`Caixa`] must yield slices that are pointer-equal (the
15530        // underlying byte-buffer is the storage `Vec`'s allocation,
15531        // not a fresh copy) as well as value-equal (idempotent, no
15532        // side effects on `&self`).
15533        //
15534        // Pins against a future silent detour that returned an owned
15535        // `Vec<String>` (which would type-check but silently clone on
15536        // every call, breaking the zero-cost projection every peer
15537        // sibling slice accessor carries), a `&Vec<String>` return
15538        // (which would leak the backing `Vec`'s grow/push/reserve
15539        // surface no downstream consumer reaches for), or a one-arm-
15540        // only accessor that returned a saturating value on some
15541        // sentinel input (breaking the pass-through invariant the
15542        // sibling slice accessors carry).
15543        for exe in [
15544            vec![],
15545            vec!["exe/cli"],
15546            vec!["exe/cli", "exe/serve"],
15547            vec!["exe/cli", "exe/cli"],
15548        ] {
15549            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
15550            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
15551            let first = c.exe();
15552            let second = c.exe();
15553            assert_eq!(
15554                first, second,
15555                "Caixa::exe must be idempotent — two successive calls \
15556                 on the same &self must return the same &[String]",
15557            );
15558            assert_eq!(
15559                first.as_ptr(),
15560                second.as_ptr(),
15561                "Caixa::exe must borrow the underlying Vec<String> \
15562                 storage — two successive calls must return slices \
15563                 with the same backing pointer (a fresh Vec<String> \
15564                 clone would change the pointer on every call)",
15565            );
15566            assert_eq!(
15567                first,
15568                expected.as_slice(),
15569                "Caixa::exe must return :exe verbatim by borrow — \
15570                 got {first:?}, expected {expected:?}",
15571            );
15572        }
15573    }
15574
15575    // ── Caixa::servicos — outer top-level &[T] slice accessor ─────────
15576
15577    #[test]
15578    fn servicos_returns_servicos_slice_verbatim_across_permutations() {
15579        // The canonical per-`Caixa` `:servicos` universal-axis
15580        // ComputeUnit-CR-YAML-entry-path-list slice pin:
15581        // [`Caixa::servicos`] must return the `:servicos` typed
15582        // [`Vec<String>`] list verbatim as a `&[String]`, byte-equal to
15583        // the raw `self.servicos.as_slice()` access across every
15584        // representative value in the accept-set — `[]` (the "no
15585        // ComputeUnit-CR declared" arm every `:kind` other than
15586        // `Servico` carries; the layout's [`crate::LayoutInvariants`]
15587        // `ServicoWithoutServicos` arm-gate fires exactly on this
15588        // empty-slot + `Servico`-kind combination), `[""]` (a past-the-
15589        // guard sentinel that pins the accessor doesn't perform a
15590        // silent `[""] → []` collapse on the empty-entry arm — validate
15591        // rejects `[""]` through `CodePathEmpty { slot: ":servicos" }`
15592        // but the accessor must ship the raw slot verbatim so a
15593        // validate-time gate regression surfaces at the layout /
15594        // per-Servico renderer boundary rather than being silently
15595        // absorbed into a component-drop),
15596        // `["servicos/demo.computeunit.yaml"]` (the canonical
15597        // singleton V0-shape every in-tree `caixa_with_code_paths`
15598        // positive control uses; the same shape
15599        // [`crate::require_single_servico`] admits),
15600        // `["servicos/a.computeunit.yaml", "servicos/b.computeunit.
15601        // yaml"]` (a past-the-guard `len != 1` sentinel — the V0
15602        // singularity gate rejects through `ServicoCountMismatch
15603        // { count: 2 }` but the accessor must ship the raw slot
15604        // verbatim so struct-literal `Caixa { servicos: vec![...,
15605        // ...], .. }` fixtures continue to expose the count at the
15606        // accessor), and `["servicos/a.computeunit.yaml",
15607        // "servicos/a.computeunit.yaml"]` (a past-the-guard duplicate
15608        // sentinel — validate rejects through
15609        // `CodePathDuplicate { slot: ":servicos" }` per the per-slot
15610        // set-not-multiset gate, but the accessor must ship the raw
15611        // slot verbatim so struct-literal fixtures continue to expose
15612        // the duplicate at the accessor).
15613        //
15614        // Fifth and final outer top-level [`Caixa`] `&[T]`-return
15615        // slice accessor pin on the substrate primitive — folds on the
15616        // "outer [`Caixa`] `&[T]` slice" projection pattern
15617        // `autores_returns_autores_slice_verbatim_across_permutations`
15618        // (b5d813f) opened,
15619        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15620        // (78c7d3c) folded on,
15621        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15622        // (8a36c23) closed the universal-axis text-tag family of, and
15623        // `exe_returns_exe_slice_verbatim_across_permutations`
15624        // (65d9527) opened the foreign-code-slot sub-family of. Closes
15625        // the outer-`Caixa` foreign-code-slot `&[T]` sub-family — the
15626        // trio of code-surface list slots (`:bibliotecas` + `:exe` +
15627        // `:servicos`) now each carries a substrate-canonical slice
15628        // accessor. Pins against a future silent detour that returned
15629        // an owned `Vec<String>` (which would type-check but silently
15630        // clone on every accessor call, breaking the zero-cost
15631        // projection every peer sibling slice accessor carries), a
15632        // `[""] → []` collapse (which would silently absorb the
15633        // `CodePathEmpty` refusal case at the accessor boundary), an
15634        // `[a, a] → [a]` dedup collapse (which would silently absorb
15635        // the `CodePathDuplicate` refusal case at the accessor
15636        // boundary — the per-slot set-not-multiset gate is downstream
15637        // of the accessor and must not be silently promoted into it),
15638        // or a `[a, b] → [a]` singleton collapse (which would silently
15639        // absorb the V0 `ServicoCountMismatch` refusal case at the
15640        // accessor boundary — the V0 singularity gate is downstream of
15641        // the accessor and must not be silently promoted into it).
15642        for servicos in [
15643            vec![],
15644            vec![""],
15645            vec!["servicos/demo.computeunit.yaml"],
15646            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
15647            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
15648        ] {
15649            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
15650            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
15651            assert_eq!(
15652                c.servicos(),
15653                expected.as_slice(),
15654                "Caixa::servicos must return :servicos verbatim (got \
15655                 {:?}, expected {expected:?})",
15656                c.servicos(),
15657            );
15658            assert_eq!(
15659                c.servicos(),
15660                c.servicos.as_slice(),
15661                "Caixa::servicos must byte-equal the raw \
15662                 `self.servicos.as_slice()` field access across every \
15663                 value in the Vec<String> accept-set",
15664            );
15665        }
15666    }
15667
15668    #[test]
15669    fn validate_code_paths_servicos_empty_arm_routes_through_accessor() {
15670        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15671        // empty-arm gate on the `:servicos` slot must key off
15672        // [`Caixa::servicos`], not a divergent raw `&self.servicos`
15673        // field-borrow walk. Structurally: a `Caixa { servicos:
15674        // vec!["".into()], .. }` must surface the `CodePathEmpty
15675        // { slot: ":servicos" }` refusal exactly, and a `Caixa
15676        // { servicos: vec!["servicos/demo.computeunit.yaml".into()],
15677        // .. }` (the canonical singleton V0-shape every in-tree
15678        // `caixa_with_code_paths` positive control uses) must pass
15679        // validate. The pair jointly pins the accessor + validate-gate
15680        // composition: any future silent detour that had the accessor
15681        // return an empty slice on the `[""]` arm (a `.iter().filter
15682        // (|s| !s.is_empty()).collect()` collapse) would silently
15683        // absorb the `CodePathEmpty` refusal at the accessor boundary
15684        // and the validate gate would accept a struct-literal
15685        // `Caixa { servicos: vec!["".into()], .. }` — the composition
15686        // pin catches that at caixa-core build time.
15687        //
15688        // Peer of the per-`Caixa`
15689        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15690        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
15691        // (65d9527), `validate_autores_empty_arm_routes_through_accessor`
15692        // (b5d813f), and
15693        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15694        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15695        // composition axes — same "the validate / shape-gate predicate
15696        // must route through the substrate-primitive typed dispatch"
15697        // discipline extended onto the sibling outer top-level
15698        // [`Caixa`] `&[T]`-composition surface, closing the trio of
15699        // code-surface accessor-composition pins on the same axis.
15700        // Nominally the in-tree `validate_code_paths` production body
15701        // still keys off the internal
15702        // `[(":bibliotecas", &self.bibliotecas,
15703        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15704        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15705        // (the tuple's homogeneous `&Vec<String>`-typed shape blocks a
15706        // per-element accessor swap in isolation — a future companion
15707        // lift promotes the tuple's element type to `&[String]` and
15708        // threads the triple of typed dispatches through as a unit);
15709        // the composition pin catches any future accessor-side silent
15710        // filter drop against that eventual tuple-closure regardless
15711        // of whether the `:servicos` slot is threaded through the
15712        // accessor or the raw field access at the tuple's construction
15713        // site.
15714        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
15715        assert!(
15716            matches!(
15717                c.validate_code_paths(),
15718                Err(ManifestError::CodePathEmpty { slot: ":servicos" })
15719            ),
15720            "validate_code_paths must reject servicos == vec![\"\"] \
15721             with CodePathEmpty {{ slot: \":servicos\" }} — the \
15722             accessor and the validate gate must route through the \
15723             same substrate-primitive typed dispatch on the \
15724             :servicos per-entry empty arm",
15725        );
15726        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.computeunit.yaml"]);
15727        assert!(
15728            c.validate_code_paths().is_ok(),
15729            "validate_code_paths must accept servicos == \
15730             vec![\"servicos/demo.computeunit.yaml\"] (the canonical \
15731             singleton V0-shape every in-tree `caixa_with_code_paths` \
15732             positive control uses)",
15733        );
15734    }
15735
15736    #[test]
15737    fn servicos_projects_slice_by_borrow() {
15738        // The by-borrow pin: [`Caixa::servicos`] returns `&[String]` by
15739        // borrow — the returned slice borrows the underlying
15740        // `Vec<String>` storage of the `:servicos` slot and the
15741        // accessor must not clone the backing `Vec` on every call.
15742        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15743        // (b5d813f), `etiquetas_projects_slice_by_borrow` (78c7d3c),
15744        // `bibliotecas_projects_slice_by_borrow` (8a36c23), and
15745        // `exe_projects_slice_by_borrow` (65d9527) by-borrow pins on
15746        // the sibling outer top-level [`Caixa`] `&[String]`-return
15747        // axes — the accessor's returned slice must borrow from
15748        // `&self` (the returned reference's lifetime is tied to
15749        // `&self`), and calling the accessor twice on the same
15750        // [`Caixa`] must yield slices that are pointer-equal (the
15751        // underlying byte-buffer is the storage `Vec`'s allocation,
15752        // not a fresh copy) as well as value-equal (idempotent, no
15753        // side effects on `&self`).
15754        //
15755        // Pins against a future silent detour that returned an owned
15756        // `Vec<String>` (which would type-check but silently clone on
15757        // every call, breaking the zero-cost projection every peer
15758        // sibling slice accessor carries), a `&Vec<String>` return
15759        // (which would leak the backing `Vec`'s grow/push/reserve
15760        // surface no downstream consumer reaches for), or a one-arm-
15761        // only accessor that returned a saturating value on some
15762        // sentinel input (breaking the pass-through invariant the
15763        // sibling slice accessors carry).
15764        for servicos in [
15765            vec![],
15766            vec!["servicos/demo.computeunit.yaml"],
15767            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
15768            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
15769        ] {
15770            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
15771            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
15772            let first = c.servicos();
15773            let second = c.servicos();
15774            assert_eq!(
15775                first, second,
15776                "Caixa::servicos must be idempotent — two successive \
15777                 calls on the same &self must return the same &[String]",
15778            );
15779            assert_eq!(
15780                first.as_ptr(),
15781                second.as_ptr(),
15782                "Caixa::servicos must borrow the underlying \
15783                 Vec<String> storage — two successive calls must \
15784                 return slices with the same backing pointer (a fresh \
15785                 Vec<String> clone would change the pointer on every \
15786                 call)",
15787            );
15788            assert_eq!(
15789                first,
15790                expected.as_slice(),
15791                "Caixa::servicos must return :servicos verbatim by \
15792                 borrow — got {first:?}, expected {expected:?}",
15793            );
15794        }
15795    }
15796
15797    // ── Caixa::deps — outer top-level &[Dep] slice accessor ───────────
15798
15799    fn caixa_with_deps(deps: Vec<Dep>) -> Caixa {
15800        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15801        c.deps = deps;
15802        c
15803    }
15804
15805    #[test]
15806    fn deps_returns_deps_slice_verbatim_across_permutations() {
15807        // The canonical per-`Caixa` `:deps` universal-axis runtime-
15808        // dependency-declaration-list slice pin: [`Caixa::deps`] must
15809        // return the `:deps` typed [`Vec<Dep>`] list verbatim as a
15810        // `&[Dep]`, element-equal to the raw `self.deps.as_slice()`
15811        // access across every representative value in the accept-set —
15812        // `[]` (the "no runtime deps declared" arm every existing
15813        // fixture without a `:deps` line carries; the
15814        // [`Caixa::template`] scaffold emits `:deps ()`), a canonical
15815        // single-entry list (the shape most consumer caixas carry), a
15816        // canonical two-entry list (the multi-dep runtime closure), and
15817        // two past-the-guard sentinels — a `[""]`-`:nome` entry
15818        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
15819        // `NomeInvalid` but the accessor must ship the raw slot
15820        // verbatim) and a `[a, a]` duplicate (validate rejects through
15821        // `DuplicateNome { list: ":deps" }` but the accessor must ship
15822        // the raw slot verbatim so struct-literal fixtures continue to
15823        // expose the duplicate at the accessor).
15824        //
15825        // First outer top-level [`Caixa`] `&[Dep]`-return slice accessor
15826        // pin on the substrate primitive — opens the outer-`Caixa`
15827        // dependency-slot `&[Dep]` sub-family the sibling `:deps-dev`
15828        // future lift closes on. Peer of the closed outer-`Caixa`
15829        // foreign-code-slot `&[String]` sub-family
15830        // (`bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15831        // 8a36c23, `exe_returns_exe_slice_verbatim_across_permutations`
15832        // 65d9527, `servicos_returns_servicos_slice_verbatim_across_permutations`
15833        // 611f78b) and the outer-`Caixa` universal-axis text-tag family
15834        // (`autores_returns_autores_slice_verbatim_across_permutations`
15835        // b5d813f, `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15836        // 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice"
15837        // projection pattern onto a novel element-type axis (`Dep`
15838        // composite vs the prior sibling family's `String` scalar).
15839        // Pins against a future silent detour that returned an owned
15840        // `Vec<Dep>` (which would type-check but silently clone on every
15841        // accessor call, breaking the zero-cost projection every peer
15842        // sibling slice accessor carries), a `[""] → []` collapse (which
15843        // would silently absorb the `NomeEmpty` refusal case at the
15844        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
15845        // would silently absorb the `DuplicateNome` refusal case at the
15846        // accessor boundary).
15847        for deps in [
15848            vec![],
15849            vec![Dep::simple("", "^0.1")],
15850            vec![Dep::simple("caixa-teia", "^0.1")],
15851            vec![
15852                Dep::simple("caixa-teia", "^0.1"),
15853                Dep::simple("caixa-core", "^0.1"),
15854            ],
15855            vec![
15856                Dep::simple("caixa-teia", "^0.1"),
15857                Dep::simple("caixa-teia", "^0.2"),
15858            ],
15859        ] {
15860            let c = caixa_with_deps(deps.clone());
15861            assert_eq!(
15862                c.deps(),
15863                deps.as_slice(),
15864                "Caixa::deps must return :deps verbatim (got {:?}, \
15865                 expected {deps:?})",
15866                c.deps(),
15867            );
15868            assert_eq!(
15869                c.deps(),
15870                c.deps.as_slice(),
15871                "Caixa::deps must element-equal the raw \
15872                 `self.deps.as_slice()` field access across every \
15873                 value in the Vec<Dep> accept-set",
15874            );
15875        }
15876    }
15877
15878    #[test]
15879    fn validate_deps_duplicate_arm_routes_through_accessor() {
15880        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps`
15881        // duplicate-`:nome` gate must key off [`Caixa::deps`], not the
15882        // raw `&self.deps` field-borrow walk. Structurally: a `Caixa
15883        // { deps: vec![Dep::simple("d", "^0.1"), Dep::simple("d",
15884        // "^0.2")], .. }` must surface the `DuplicateNome { list:
15885        // ":deps" }` refusal exactly, and a `Caixa { deps: vec![
15886        // Dep::simple("d", "^0.1")], .. }` (the canonical single-entry
15887        // form) must pass validate. The pair jointly pins the accessor +
15888        // validate-gate composition: any future silent detour that had
15889        // the accessor return a dedupped slice on the `[a, a]` arm (a
15890        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
15891        // would silently absorb the `DuplicateNome` refusal at the
15892        // accessor boundary and the validate gate would accept a
15893        // struct-literal `Caixa` carrying the drift — the composition
15894        // pin catches that at caixa-core build time.
15895        //
15896        // Peer of the per-`Caixa`
15897        // `validate_autores_empty_entry_arm_routes_through_accessor`
15898        // (b5d813f), `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15899        // (78c7d3c), `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15900        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
15901        // (65d9527), and `validate_code_paths_servicos_empty_arm_routes_through_accessor`
15902        // (611f78b) accessor-composition pins on the sibling `&[T]`-
15903        // composition axes — same "the validate gate must route through
15904        // the substrate-primitive typed dispatch" discipline extended
15905        // onto the sibling outer top-level [`Caixa`] `&[Dep]`-
15906        // composition surface, opening the outer-`Caixa` dependency-slot
15907        // arm of the composition-pin family.
15908        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
15909        let err = c.validate_deps().unwrap_err();
15910        assert!(
15911            matches!(
15912                err,
15913                DepError::DuplicateNome { ref nome, list } if nome == "d"
15914                    && list == crate::render::DEP_AUTHOR_KEY_DEPS
15915            ),
15916            "validate_deps must reject deps == \
15917             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
15918             DuplicateNome {{ nome: \"d\", list: \":deps\" }} — the \
15919             accessor and the validate gate must route through the \
15920             same substrate-primitive typed dispatch on the :deps \
15921             within-list duplicate arm (got {err:?})",
15922        );
15923        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1")]);
15924        assert!(
15925            c.validate_deps().is_ok(),
15926            "validate_deps must accept deps == vec![Dep(\"d\",\"^0.1\")] \
15927             (the canonical single-entry form)",
15928        );
15929    }
15930
15931    #[test]
15932    fn deps_projects_slice_by_borrow() {
15933        // The by-borrow pin: [`Caixa::deps`] returns `&[Dep]` by borrow
15934        // — the returned slice borrows the underlying `Vec<Dep>` storage
15935        // of the `:deps` slot and the accessor must not clone the
15936        // backing `Vec` on every call. Peer of the per-`Caixa`
15937        // `autores_projects_slice_by_borrow` (b5d813f),
15938        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
15939        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
15940        // `exe_projects_slice_by_borrow` (65d9527), and
15941        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
15942        // on the sibling outer top-level [`Caixa`] `&[String]`-return
15943        // axes — the accessor's returned slice must borrow from `&self`
15944        // (the returned reference's lifetime is tied to `&self`), and
15945        // calling the accessor twice on the same [`Caixa`] must yield
15946        // slices that are pointer-equal (the underlying byte-buffer is
15947        // the storage `Vec`'s allocation, not a fresh copy) as well as
15948        // value-equal (idempotent, no side effects on `&self`).
15949        //
15950        // Pins against a future silent detour that returned an owned
15951        // `Vec<Dep>` (which would type-check but silently clone on
15952        // every call), a `&Vec<Dep>` return (which would leak the
15953        // backing `Vec`'s grow/push/reserve surface no downstream
15954        // consumer reaches for), or a one-arm-only accessor that
15955        // returned a saturating value on some sentinel input.
15956        for deps in [
15957            vec![],
15958            vec![Dep::simple("caixa-teia", "^0.1")],
15959            vec![
15960                Dep::simple("caixa-teia", "^0.1"),
15961                Dep::simple("caixa-core", "^0.1"),
15962            ],
15963        ] {
15964            let c = caixa_with_deps(deps.clone());
15965            let first = c.deps();
15966            let second = c.deps();
15967            assert_eq!(
15968                first, second,
15969                "Caixa::deps must be idempotent — two successive calls \
15970                 on the same &self must return the same &[Dep]",
15971            );
15972            assert_eq!(
15973                first.as_ptr(),
15974                second.as_ptr(),
15975                "Caixa::deps must borrow the underlying Vec<Dep> \
15976                 storage — two successive calls must return slices \
15977                 with the same backing pointer (a fresh Vec<Dep> clone \
15978                 would change the pointer on every call)",
15979            );
15980            assert_eq!(
15981                first,
15982                deps.as_slice(),
15983                "Caixa::deps must return :deps verbatim by borrow — \
15984                 got {first:?}, expected {deps:?}",
15985            );
15986        }
15987    }
15988
15989    // ── Caixa::deps_dev — outer top-level &[Dep] slice accessor ──────
15990
15991    fn caixa_with_deps_dev(deps_dev: Vec<Dep>) -> Caixa {
15992        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15993        c.deps_dev = deps_dev;
15994        c
15995    }
15996
15997    #[test]
15998    fn deps_dev_returns_deps_dev_slice_verbatim_across_permutations() {
15999        // The canonical per-`Caixa` `:deps-dev` universal-axis dev-only-
16000        // dependency-declaration-list slice pin: [`Caixa::deps_dev`]
16001        // must return the `:deps-dev` typed [`Vec<Dep>`] list verbatim as
16002        // a `&[Dep]`, element-equal to the raw `self.deps_dev.as_slice()`
16003        // access across every representative value in the accept-set —
16004        // `[]` (the "no dev deps declared" arm every existing fixture
16005        // without a `:deps-dev` line carries; the [`Caixa::template`]
16006        // scaffold emits `:deps-dev ()`), a canonical single-entry list
16007        // (the shape most consumer caixas carry — a `tatara-check` dev
16008        // pin), a canonical two-entry list (the multi-dev-dep closure),
16009        // and two past-the-guard sentinels — a `[""]`-`:nome` entry
16010        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
16011        // `NomeInvalid` but the accessor must ship the raw slot
16012        // verbatim) and a `[a, a]` duplicate (validate rejects through
16013        // `DuplicateNome { list: ":deps-dev" }` but the accessor must
16014        // ship the raw slot verbatim so struct-literal fixtures continue
16015        // to expose the duplicate at the accessor).
16016        //
16017        // Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor
16018        // pin on the substrate primitive — closes the outer-`Caixa`
16019        // dependency-slot `&[Dep]` sub-family the sibling
16020        // `deps_returns_deps_slice_verbatim_across_permutations`
16021        // (ad34b4e) opened on. Folds the "outer [`Caixa`] `&[Dep]`
16022        // slice" projection pattern onto the sibling dev-dep axis —
16023        // pins against a future silent detour that returned an owned
16024        // `Vec<Dep>` (which would type-check but silently clone on every
16025        // accessor call, breaking the zero-cost projection every peer
16026        // sibling slice accessor carries), a `[""] → []` collapse (which
16027        // would silently absorb the `NomeEmpty` refusal case at the
16028        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
16029        // would silently absorb the `DuplicateNome` refusal case at the
16030        // accessor boundary).
16031        for deps_dev in [
16032            vec![],
16033            vec![Dep::simple("", "^0.1")],
16034            vec![Dep::simple("tatara-check", "^0.1")],
16035            vec![
16036                Dep::simple("tatara-check", "^0.1"),
16037                Dep::simple("caixa-lint", "^0.1"),
16038            ],
16039            vec![
16040                Dep::simple("tatara-check", "^0.1"),
16041                Dep::simple("tatara-check", "^0.2"),
16042            ],
16043        ] {
16044            let c = caixa_with_deps_dev(deps_dev.clone());
16045            assert_eq!(
16046                c.deps_dev(),
16047                deps_dev.as_slice(),
16048                "Caixa::deps_dev must return :deps-dev verbatim (got \
16049                 {:?}, expected {deps_dev:?})",
16050                c.deps_dev(),
16051            );
16052            assert_eq!(
16053                c.deps_dev(),
16054                c.deps_dev.as_slice(),
16055                "Caixa::deps_dev must element-equal the raw \
16056                 `self.deps_dev.as_slice()` field access across every \
16057                 value in the Vec<Dep> accept-set",
16058            );
16059        }
16060    }
16061
16062    #[test]
16063    fn validate_deps_duplicate_deps_dev_arm_routes_through_accessor() {
16064        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps-dev`
16065        // duplicate-`:nome` gate must key off [`Caixa::deps_dev`], not
16066        // the raw `&self.deps_dev` field-borrow walk. Structurally: a
16067        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1"),
16068        // Dep::simple("d", "^0.2")], .. }` must surface the
16069        // `DuplicateNome { list: ":deps-dev" }` refusal exactly, and a
16070        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1")], .. }` (the
16071        // canonical single-entry form) must pass validate. The pair
16072        // jointly pins the accessor + validate-gate composition: any
16073        // future silent detour that had the accessor return a dedupped
16074        // slice on the `[a, a]` arm (a
16075        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
16076        // would silently absorb the `DuplicateNome` refusal at the
16077        // accessor boundary and the validate gate would accept a
16078        // struct-literal `Caixa` carrying the drift — the composition
16079        // pin catches that at caixa-core build time.
16080        //
16081        // Peer of `validate_deps_duplicate_arm_routes_through_accessor`
16082        // (ad34b4e) on the sibling `:deps` axis — same "the validate
16083        // gate must route through the substrate-primitive typed
16084        // dispatch" discipline folded onto the sibling `:deps-dev`
16085        // axis, closing the two-list dep-graph composition-pin family.
16086        // The `:deps-dev` diagnostic must carry the
16087        // `DEP_AUTHOR_KEY_DEPS_DEV` list-tag (not
16088        // `DEP_AUTHOR_KEY_DEPS`) so the emitted error names the
16089        // offending list unambiguously.
16090        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
16091        let err = c.validate_deps().unwrap_err();
16092        assert!(
16093            matches!(
16094                err,
16095                DepError::DuplicateNome { ref nome, list } if nome == "d"
16096                    && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
16097            ),
16098            "validate_deps must reject deps_dev == \
16099             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
16100             DuplicateNome {{ nome: \"d\", list: \":deps-dev\" }} — the \
16101             accessor and the validate gate must route through the \
16102             same substrate-primitive typed dispatch on the :deps-dev \
16103             within-list duplicate arm (got {err:?})",
16104        );
16105        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1")]);
16106        assert!(
16107            c.validate_deps().is_ok(),
16108            "validate_deps must accept deps_dev == \
16109             vec![Dep(\"d\",\"^0.1\")] (the canonical single-entry form)",
16110        );
16111    }
16112
16113    #[test]
16114    fn deps_dev_projects_slice_by_borrow() {
16115        // The by-borrow pin: [`Caixa::deps_dev`] returns `&[Dep]` by
16116        // borrow — the returned slice borrows the underlying `Vec<Dep>`
16117        // storage of the `:deps-dev` slot and the accessor must not
16118        // clone the backing `Vec` on every call. Peer of
16119        // `deps_projects_slice_by_borrow` (ad34b4e) on the sibling
16120        // `:deps` axis, and of the per-`Caixa`
16121        // `autores_projects_slice_by_borrow` (b5d813f),
16122        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
16123        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
16124        // `exe_projects_slice_by_borrow` (65d9527), and
16125        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
16126        // on the sibling outer top-level [`Caixa`] `&[String]`-return
16127        // axes — the accessor's returned slice must borrow from `&self`
16128        // (the returned reference's lifetime is tied to `&self`), and
16129        // calling the accessor twice on the same [`Caixa`] must yield
16130        // slices that are pointer-equal (the underlying byte-buffer is
16131        // the storage `Vec`'s allocation, not a fresh copy) as well as
16132        // value-equal (idempotent, no side effects on `&self`).
16133        //
16134        // Pins against a future silent detour that returned an owned
16135        // `Vec<Dep>` (which would type-check but silently clone on
16136        // every call), a `&Vec<Dep>` return (which would leak the
16137        // backing `Vec`'s grow/push/reserve surface no downstream
16138        // consumer reaches for), or a one-arm-only accessor that
16139        // returned a saturating value on some sentinel input.
16140        for deps_dev in [
16141            vec![],
16142            vec![Dep::simple("tatara-check", "^0.1")],
16143            vec![
16144                Dep::simple("tatara-check", "^0.1"),
16145                Dep::simple("caixa-lint", "^0.1"),
16146            ],
16147        ] {
16148            let c = caixa_with_deps_dev(deps_dev.clone());
16149            let first = c.deps_dev();
16150            let second = c.deps_dev();
16151            assert_eq!(
16152                first, second,
16153                "Caixa::deps_dev must be idempotent — two successive \
16154                 calls on the same &self must return the same &[Dep]",
16155            );
16156            assert_eq!(
16157                first.as_ptr(),
16158                second.as_ptr(),
16159                "Caixa::deps_dev must borrow the underlying Vec<Dep> \
16160                 storage — two successive calls must return slices \
16161                 with the same backing pointer (a fresh Vec<Dep> clone \
16162                 would change the pointer on every call)",
16163            );
16164            assert_eq!(
16165                first,
16166                deps_dev.as_slice(),
16167                "Caixa::deps_dev must return :deps-dev verbatim by \
16168                 borrow — got {first:?}, expected {deps_dev:?}",
16169            );
16170        }
16171    }
16172
16173    // ── Caixa::limits — outer top-level Option<&LimitsSpec> composite-reference accessor ──
16174
16175    fn caixa_with_limits(limits: Option<crate::LimitsSpec>) -> Caixa {
16176        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16177        c.limits = limits;
16178        c
16179    }
16180
16181    #[test]
16182    fn limits_returns_limits_option_ref_verbatim_across_permutations() {
16183        // The canonical per-`Caixa` `:limits` M2 typed-slot outer-
16184        // composite optional-composite-reference-shape pin:
16185        // [`Caixa::limits`] must return the `:limits` typed
16186        // `Option<LimitsSpec>` verbatim as an `Option<&LimitsSpec>`
16187        // reference over the same backing storage the raw
16188        // `self.limits.as_ref()` field access borrows from, byte-equal
16189        // across every representative fixture in the accept-set — the
16190        // author-omitted `None` shape (the "engine-default applies"
16191        // partition every downstream Servico M2 overlay emitter treats
16192        // as "emit nothing"), the empty-composite `Some(LimitsSpec {
16193        // .. default })` shape ([`LimitsSpec::is_empty`] holds — every
16194        // per-axis cap is `None`, so the peer M2 overlay emitter's
16195        // `.is_empty()`-gated projection still emits nothing but the
16196        // outer presence-bit is `Some`, so [`Caixa::declared_servico_slots`]
16197        // still pushes the `M2_AUTHOR_KEY_LIMITS` label), a single-axis
16198        // fixture (only `:memory` set — the canonical shape most
16199        // memory-heavy Servicos carry), and a fully-populated composite
16200        // (every per-axis cap set — the canonical shape a
16201        // sandboxed-by-default Servico carries).
16202        //
16203        // Pins against a future silent detour that returned a fresh-
16204        // cloned [`LimitsSpec`] copy (which would type-check via the
16205        // `Clone` impl but silently break every downstream caller that
16206        // relied on the reference sharing the composite's backing
16207        // identity), a reference to an operator-resolved overlay (the
16208        // future per-cluster `:limits-overrides` slot — its resolution
16209        // must land at exactly this accessor body, not silently divert
16210        // the raw slot away from a second consumer), a
16211        // `None` → `Some(LimitsSpec::default)` cluster-default
16212        // projection (which would collapse the load-bearing
16213        // "author-omitted `:limits` ⇒ engine-default applies" partition
16214        // the peer [`crate::render::servico_m2_overlay`] emitter and
16215        // the peer [`Caixa::declared_servico_slots`] enumerator both
16216        // read), or an axis-shuffled projection (a future detour that
16217        // swapped `memory` and `fuel` through the accessor would
16218        // silently split the paired [`crate::StandardLayout::verify`]
16219        // per-`:limits` shape gate's traversal input from the peer
16220        // `servico_m2_overlay` emitter's projection input).
16221        //
16222        // First outer top-level [`Caixa`] `Option<&Composite>`-return
16223        // composite-reference accessor pin on the substrate primitive
16224        // — opens the outer-`Caixa` `Option<&Composite>` composite-
16225        // reference projection pattern the sibling `:behavior`
16226        // [`crate::BehaviorSpec`] / `:politicas`
16227        // [`crate::aplicacao::MeshPolicy`] / `:placement`
16228        // [`crate::aplicacao::Placement`] / `:entrada`
16229        // [`crate::aplicacao::Entrada`] future outer-composite lifts
16230        // fold on. Peer of the closed M3 outer-composite family the
16231        // sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
16232        // [`crate::AplicacaoSpec::placement`] (9abb8f0) /
16233        // [`crate::AplicacaoSpec::entrada`] (d32111c) composite-
16234        // reference accessor pins already carry on the outer
16235        // [`crate::AplicacaoSpec`] altitude — extends the outer-
16236        // accessor byte-equal-projection discipline onto the outer
16237        // top-level [`Caixa`] M2 Servico-runtime slot altitude.
16238        use crate::LimitsSpec;
16239        use std::time::Duration;
16240        let fixtures: Vec<Option<LimitsSpec>> = vec![
16241            None,
16242            Some(LimitsSpec::default()),
16243            Some(LimitsSpec {
16244                memory: Some(64 * 1024 * 1024),
16245                ..Default::default()
16246            }),
16247            Some(LimitsSpec {
16248                memory: Some(64 * 1024 * 1024),
16249                fuel: Some(1_000_000),
16250                wall_clock: Some(Duration::from_secs(30)),
16251                cpu: Some(500),
16252            }),
16253        ];
16254        for limits in fixtures {
16255            let c = caixa_with_limits(limits.clone());
16256            assert_eq!(
16257                c.limits(),
16258                limits.as_ref(),
16259                "Caixa::limits must return :limits verbatim (got {:?}, \
16260                 expected {:?})",
16261                c.limits(),
16262                limits.as_ref(),
16263            );
16264            match (c.limits(), c.limits.as_ref()) {
16265                (Some(a), Some(b)) => assert!(
16266                    std::ptr::eq(a, b),
16267                    "Caixa::limits accessor and self.limits.as_ref() \
16268                     field access must borrow the same backing storage \
16269                     — the accessor is the substrate-primitive typed \
16270                     dispatch every downstream Servico-M2-overlay \
16271                     composite consumer must route through, and a \
16272                     reference-identity split would silently break \
16273                     every consumer that relied on the borrow sharing \
16274                     the composite's storage",
16275                ),
16276                (None, None) => {}
16277                _ => panic!(
16278                    "Caixa::limits presence bit must byte-equal \
16279                     self.limits.is_some() — a presence-bit drift would \
16280                     silently split the paired StandardLayout::verify \
16281                     per-`:limits` shape gate's traversal head from \
16282                     the peer render::servico_m2_overlay M2 overlay \
16283                     emitter's traversal head from the peer \
16284                     Caixa::declared_servico_slots M2 declared-slot \
16285                     enumerator's presence probe",
16286                ),
16287            }
16288            assert_eq!(
16289                c.limits().is_some(),
16290                c.limits.is_some(),
16291                "Caixa::limits().is_some() must byte-equal \
16292                 self.limits.is_some() — a presence-bit drift would \
16293                 silently split every downstream Option<&LimitsSpec> \
16294                 consumer's partition on the engine-default arm",
16295            );
16296        }
16297    }
16298
16299    #[test]
16300    fn declared_servico_slots_limits_arm_routes_through_accessor() {
16301        // Composition pin: [`Caixa::declared_servico_slots`]'s
16302        // `:limits` presence-probe arm must key off [`Caixa::limits`],
16303        // not the raw `self.limits.is_some()` field-probe. Structurally:
16304        // a `Caixa { limits: Some(LimitsSpec::default()), .. }` must
16305        // still push `M2_AUTHOR_KEY_LIMITS` onto the declared-slot list
16306        // (the presence bit is `Some`, so the M2 kind-coherence gate
16307        // must surface the slot as "declared" even when every per-axis
16308        // cap is unset), and a `Caixa { limits: None, .. }` must NOT
16309        // push the label (the "author omitted the slot entirely"
16310        // partition). The pair jointly pins the accessor + declared-
16311        // slot enumerator composition: any future silent detour that
16312        // had the accessor collapse `Some(LimitsSpec::default())` to
16313        // `None` (a `.filter(|l| !l.is_empty())` projection) would
16314        // silently absorb the "declared but empty" arm at the
16315        // accessor boundary and the [`crate::LayoutError::ServicoSlotsOnNonServico`]
16316        // kind-coherence gate would silently accept a
16317        // struct-literal `Caixa` carrying the drift.
16318        //
16319        // Peer of the sibling per-`Caixa`
16320        // `validate_deps_duplicate_arm_routes_through_accessor` (ad34b4e)
16321        // and `validate_deps_duplicate_deps_dev_arm_routes_through_accessor`
16322        // (f7fd81e) accessor-composition pins on the sibling `:deps` /
16323        // `:deps-dev` outer-`&[Dep]`-composition axes — same "the
16324        // enumerator gate must route through the substrate-primitive
16325        // typed dispatch" discipline extended onto the outer top-level
16326        // [`Caixa`] `Option<&LimitsSpec>`-composition surface, opening
16327        // the outer-`Caixa` M2 Servico-runtime-slot arm of the
16328        // composition-pin family.
16329        use crate::LimitsSpec;
16330        let c = caixa_with_limits(Some(LimitsSpec::default()));
16331        let slots = c.declared_servico_slots();
16332        assert!(
16333            slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
16334            "declared_servico_slots must push M2_AUTHOR_KEY_LIMITS \
16335             when `:limits` is Some (even for LimitsSpec::default()) \
16336             — the accessor and the enumerator gate must route through \
16337             the same substrate-primitive typed dispatch on the outer \
16338             :limits presence bit (got slots={slots:?})",
16339        );
16340        let c = caixa_with_limits(None);
16341        let slots = c.declared_servico_slots();
16342        assert!(
16343            !slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
16344            "declared_servico_slots must NOT push M2_AUTHOR_KEY_LIMITS \
16345             when `:limits` is None — the author-omitted arm must \
16346             route through the accessor's None-return unchanged (got \
16347             slots={slots:?})",
16348        );
16349    }
16350
16351    #[test]
16352    fn servico_m2_overlay_limits_arm_routes_through_accessor() {
16353        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16354        // per-`:limits` M2 overlay emit arm must key off
16355        // [`Caixa::limits`], not the raw `&caixa.limits` field-borrow.
16356        // Structurally: a `Caixa { limits: Some(LimitsSpec { memory:
16357        // Some(64 MiB), .. default }), .. }` must surface the
16358        // `M2_KEY_LIMITS` key with the per-axis
16359        // `memory: "64MiB"` sub-mapping in the overlay, a `Caixa {
16360        // limits: Some(LimitsSpec::default()), .. }` must omit the
16361        // key entirely (the `.is_empty()`-gated inner arm elides an
16362        // empty composite even when the outer presence bit is `Some`),
16363        // and a `Caixa { limits: None, .. }` must also omit the key
16364        // (the "author omitted the slot entirely" partition). The
16365        // three-fixture family jointly pins the accessor + M2 overlay
16366        // emitter composition: any future silent detour that had the
16367        // accessor return a fresh-cloned copy on the `Some` arm (a
16368        // `LimitsSpec::clone()` projection) would silently break the
16369        // reference-identity pin the peer per-axis
16370        // `serde_yaml::to_value(limits)` projection reads from.
16371        use crate::LimitsSpec;
16372        use crate::render::{M2_KEY_LIMITS, servico_m2_overlay};
16373        let c = caixa_with_limits(Some(LimitsSpec {
16374            memory: Some(64 * 1024 * 1024),
16375            ..Default::default()
16376        }));
16377        let overlay = servico_m2_overlay(&c).unwrap();
16378        assert!(
16379            overlay.contains_key(M2_KEY_LIMITS),
16380            "servico_m2_overlay must surface M2_KEY_LIMITS when \
16381             `:limits` carries a non-empty composite — the accessor \
16382             and the M2 overlay emitter must route through the same \
16383             substrate-primitive typed dispatch on the outer :limits \
16384             composite (got overlay={overlay:?})",
16385        );
16386        let c = caixa_with_limits(Some(LimitsSpec::default()));
16387        let overlay = servico_m2_overlay(&c).unwrap();
16388        assert!(
16389            !overlay.contains_key(M2_KEY_LIMITS),
16390            "servico_m2_overlay must omit M2_KEY_LIMITS when \
16391             `:limits` is Some(LimitsSpec::default()) — the empty \
16392             composite's `.is_empty()`-gated inner arm must elide \
16393             the key regardless of the outer presence bit (got \
16394             overlay={overlay:?})",
16395        );
16396        let c = caixa_with_limits(None);
16397        let overlay = servico_m2_overlay(&c).unwrap();
16398        assert!(
16399            !overlay.contains_key(M2_KEY_LIMITS),
16400            "servico_m2_overlay must omit M2_KEY_LIMITS when \
16401             `:limits` is None — the author-omitted arm must route \
16402             through the accessor's None-return unchanged (got \
16403             overlay={overlay:?})",
16404        );
16405    }
16406
16407    #[test]
16408    fn limits_projects_option_ref_by_borrow() {
16409        // The by-borrow pin: [`Caixa::limits`] returns
16410        // `Option<&LimitsSpec>` by borrow — the returned reference
16411        // borrows the underlying `Option<LimitsSpec>` storage of the
16412        // `:limits` slot and the accessor must not clone the backing
16413        // composite on every call. Peer of the sibling
16414        // `deps_projects_slice_by_borrow` (ad34b4e) /
16415        // `deps_dev_projects_slice_by_borrow` (f7fd81e) by-borrow pins
16416        // on the outer top-level [`Caixa`] `&[Dep]`-return axes —
16417        // extended here to the outer [`Caixa`] `Option<&Composite>`-
16418        // return axis: the accessor's returned reference must borrow
16419        // from `&self` (the returned reference's lifetime is tied to
16420        // `&self`), and calling the accessor twice on the same
16421        // [`Caixa`] must yield references that are pointer-equal (the
16422        // underlying byte-buffer is the storage `LimitsSpec`'s
16423        // allocation, not a fresh copy) as well as value-equal
16424        // (idempotent, no side effects on `&self`).
16425        //
16426        // Pins against a future silent detour that returned an owned
16427        // `LimitsSpec` (which would type-check via the `Clone` impl
16428        // but silently clone on every call), a `&LimitsSpec` panic-
16429        // return on the `None` arm (which would collapse the load-
16430        // bearing `Option` presence-bit into a runtime panic), or a
16431        // one-arm-only accessor that returned a saturating composite
16432        // on some sentinel input.
16433        use crate::LimitsSpec;
16434        use std::time::Duration;
16435        for limits in [
16436            Some(LimitsSpec::default()),
16437            Some(LimitsSpec {
16438                memory: Some(64 * 1024 * 1024),
16439                fuel: Some(1_000_000),
16440                wall_clock: Some(Duration::from_secs(30)),
16441                cpu: Some(500),
16442            }),
16443        ] {
16444            let c = caixa_with_limits(limits.clone());
16445            let first = c.limits().unwrap();
16446            let second = c.limits().unwrap();
16447            assert_eq!(
16448                first, second,
16449                "Caixa::limits must be idempotent — two successive \
16450                 calls on the same &self must return the same \
16451                 &LimitsSpec",
16452            );
16453            assert!(
16454                std::ptr::eq(first, second),
16455                "Caixa::limits must borrow the underlying \
16456                 Option<LimitsSpec> storage — two successive calls \
16457                 must return references with the same backing pointer \
16458                 (a fresh LimitsSpec clone would change the pointer \
16459                 on every call)",
16460            );
16461            assert_eq!(
16462                Some(first),
16463                limits.as_ref(),
16464                "Caixa::limits must return :limits verbatim by borrow \
16465                 — got {first:?}, expected {:?}",
16466                limits.as_ref(),
16467            );
16468        }
16469        let c = caixa_with_limits(None);
16470        assert!(
16471            c.limits().is_none(),
16472            "Caixa::limits must return None when :limits is absent — \
16473             the author-omitted arm must project through the \
16474             accessor's Option::None unchanged",
16475        );
16476    }
16477
16478    // ── Caixa::behavior — outer top-level Option<&BehaviorSpec> composite-reference accessor ──
16479
16480    fn caixa_with_behavior(behavior: Option<crate::BehaviorSpec>) -> Caixa {
16481        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16482        c.behavior = behavior;
16483        c
16484    }
16485
16486    #[test]
16487    fn behavior_returns_behavior_option_ref_verbatim_across_permutations() {
16488        // The canonical per-`Caixa` `:behavior` M2 typed-slot outer-
16489        // composite optional-composite-reference-shape pin:
16490        // [`Caixa::behavior`] must return the `:behavior` typed
16491        // `Option<BehaviorSpec>` verbatim as an `Option<&BehaviorSpec>`
16492        // reference over the same backing storage the raw
16493        // `self.behavior.as_ref()` field access borrows from, byte-equal
16494        // across every representative fixture in the accept-set — the
16495        // author-omitted `None` shape (the "runtime-default applies"
16496        // partition every downstream Servico M2 overlay emitter treats
16497        // as "emit nothing"), the empty-composite `Some(BehaviorSpec {
16498        // .. default })` shape ([`BehaviorSpec::is_empty`] holds —
16499        // every per-callback path is `None`, so the peer M2 overlay
16500        // emitter's `.is_empty()`-gated projection still emits nothing
16501        // but the outer presence-bit is `Some`, so
16502        // [`Caixa::declared_servico_slots`] still pushes the
16503        // `M2_AUTHOR_KEY_BEHAVIOR` label), a single-callback fixture
16504        // (only `:on-state-change` set — the canonical shape a caixa
16505        // that only wires the hot-upgrade migration path carries), and
16506        // a fully-populated composite (every per-callback path set —
16507        // the canonical shape a fully-instrumented gen_server-shaped
16508        // Servico carries).
16509        //
16510        // Peer of the sibling
16511        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16512        // (b2bd9d7) opening fixture-family + reference-identity +
16513        // presence-bit tetrad pin on the outer top-level [`Caixa`]
16514        // `Option<&Composite>`-return sub-family — extended here to the
16515        // second axis of that sub-family so both of the currently-lifted
16516        // M2 Servico-runtime `Option<&Composite>` slots (`:limits` /
16517        // `:behavior`) carry the same "byte-equal, borrow-shared,
16518        // presence-bit-preserved" outer-accessor discipline.
16519        //
16520        // Pins against a future silent detour that returned a fresh-
16521        // cloned [`crate::BehaviorSpec`] copy (which would type-check
16522        // via the `Clone` impl but silently break every downstream
16523        // caller that relied on the reference sharing the composite's
16524        // backing identity), a reference to an operator-resolved
16525        // overlay (a future per-cluster `:behavior-overrides` slot —
16526        // its resolution must land at exactly this accessor body, not
16527        // silently divert the raw slot away from a second consumer), a
16528        // `None` → `Some(BehaviorSpec::default)` cluster-default
16529        // projection (which would collapse the load-bearing
16530        // "author-omitted `:behavior` ⇒ runtime-default applies"
16531        // partition the peer [`crate::render::servico_m2_overlay`]
16532        // emitter, the peer [`Caixa::declared_servico_slots`]
16533        // enumerator, and the cross-slot
16534        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
16535        // gate all read), or a callback-shuffled projection (a future
16536        // detour that swapped `on_init` and `on_terminate` through the
16537        // accessor would silently split the paired
16538        // [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
16539        // traversal input from the peer `servico_m2_overlay` emitter's
16540        // projection input from the cross-slot `:state-change`
16541        // composition gate's traversal input).
16542        use crate::BehaviorSpec;
16543        use std::path::PathBuf;
16544        let fixtures: Vec<Option<BehaviorSpec>> = vec![
16545            None,
16546            Some(BehaviorSpec::default()),
16547            Some(BehaviorSpec {
16548                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16549                ..Default::default()
16550            }),
16551            Some(BehaviorSpec {
16552                on_init: Some(PathBuf::from("lib/init.lisp")),
16553                on_call: Some(PathBuf::from("lib/handlers.lisp")),
16554                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
16555                on_info: Some(PathBuf::from("lib/handlers.lisp")),
16556                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16557                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
16558            }),
16559        ];
16560        for behavior in fixtures {
16561            let c = caixa_with_behavior(behavior.clone());
16562            assert_eq!(
16563                c.behavior(),
16564                behavior.as_ref(),
16565                "Caixa::behavior must return :behavior verbatim (got \
16566                 {:?}, expected {:?})",
16567                c.behavior(),
16568                behavior.as_ref(),
16569            );
16570            match (c.behavior(), c.behavior.as_ref()) {
16571                (Some(a), Some(b)) => assert!(
16572                    std::ptr::eq(a, b),
16573                    "Caixa::behavior accessor and self.behavior.as_ref() \
16574                     field access must borrow the same backing storage \
16575                     — the accessor is the substrate-primitive typed \
16576                     dispatch every downstream Servico-M2-overlay \
16577                     composite consumer must route through, and a \
16578                     reference-identity split would silently break \
16579                     every consumer that relied on the borrow sharing \
16580                     the composite's storage",
16581                ),
16582                (None, None) => {}
16583                _ => panic!(
16584                    "Caixa::behavior presence bit must byte-equal \
16585                     self.behavior.is_some() — a presence-bit drift \
16586                     would silently split the paired \
16587                     StandardLayout::verify per-`:behavior` shape \
16588                     gate's traversal head from the peer \
16589                     render::servico_m2_overlay M2 overlay emitter's \
16590                     traversal head from the cross-slot \
16591                     validate_upgrade_from_against_behavior \
16592                     composition gate's traversal head from the peer \
16593                     Caixa::declared_servico_slots M2 declared-slot \
16594                     enumerator's presence probe",
16595                ),
16596            }
16597            assert_eq!(
16598                c.behavior().is_some(),
16599                c.behavior.is_some(),
16600                "Caixa::behavior().is_some() must byte-equal \
16601                 self.behavior.is_some() — a presence-bit drift would \
16602                 silently split every downstream Option<&BehaviorSpec> \
16603                 consumer's partition on the runtime-default arm",
16604            );
16605        }
16606    }
16607
16608    #[test]
16609    fn declared_servico_slots_behavior_arm_routes_through_accessor() {
16610        // Composition pin: [`Caixa::declared_servico_slots`]'s
16611        // `:behavior` presence-probe arm must key off
16612        // [`Caixa::behavior`], not the raw `self.behavior.is_some()`
16613        // field-probe. Structurally: a `Caixa { behavior:
16614        // Some(BehaviorSpec::default()), .. }` must still push
16615        // `M2_AUTHOR_KEY_BEHAVIOR` onto the declared-slot list (the
16616        // presence bit is `Some`, so the M2 kind-coherence gate must
16617        // surface the slot as "declared" even when every per-callback
16618        // path is unset), and a `Caixa { behavior: None, .. }` must
16619        // NOT push the label (the "author omitted the slot entirely"
16620        // partition). The pair jointly pins the accessor + declared-
16621        // slot enumerator composition: any future silent detour that
16622        // had the accessor collapse `Some(BehaviorSpec::default())`
16623        // to `None` (a `.filter(|b| !b.is_empty())` projection) would
16624        // silently absorb the "declared but empty" arm at the
16625        // accessor boundary and the
16626        // [`crate::LayoutError::ServicoSlotsOnNonServico`]
16627        // kind-coherence gate would silently accept a struct-literal
16628        // `Caixa` carrying the drift.
16629        //
16630        // Peer of the sibling
16631        // `declared_servico_slots_limits_arm_routes_through_accessor`
16632        // (b2bd9d7) composition pin on the sibling `:limits` outer-
16633        // `Option<&LimitsSpec>` arm of the same
16634        // [`Caixa::declared_servico_slots`] M2 declared-slot
16635        // enumerator's traversal — same "the enumerator gate must
16636        // route through the substrate-primitive typed dispatch"
16637        // discipline extended onto the outer top-level [`Caixa`]
16638        // `Option<&BehaviorSpec>`-composition surface.
16639        use crate::BehaviorSpec;
16640        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
16641        let slots = c.declared_servico_slots();
16642        assert!(
16643            slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
16644            "declared_servico_slots must push M2_AUTHOR_KEY_BEHAVIOR \
16645             when `:behavior` is Some (even for BehaviorSpec::default()) \
16646             — the accessor and the enumerator gate must route through \
16647             the same substrate-primitive typed dispatch on the outer \
16648             :behavior presence bit (got slots={slots:?})",
16649        );
16650        let c = caixa_with_behavior(None);
16651        let slots = c.declared_servico_slots();
16652        assert!(
16653            !slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
16654            "declared_servico_slots must NOT push M2_AUTHOR_KEY_BEHAVIOR \
16655             when `:behavior` is None — the author-omitted arm must \
16656             route through the accessor's None-return unchanged (got \
16657             slots={slots:?})",
16658        );
16659    }
16660
16661    #[test]
16662    fn servico_m2_overlay_behavior_arm_routes_through_accessor() {
16663        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16664        // per-`:behavior` M2 overlay emit arm must key off
16665        // [`Caixa::behavior`], not the raw `&caixa.behavior`
16666        // field-borrow. Structurally: a `Caixa { behavior:
16667        // Some(BehaviorSpec { on_state_change: Some(...), .. default
16668        // }), .. }` must surface the `M2_KEY_BEHAVIOR` key with the
16669        // per-callback `onStateChange` sub-mapping in the overlay, a
16670        // `Caixa { behavior: Some(BehaviorSpec::default()), .. }`
16671        // must omit the key entirely (the `.is_empty()`-gated inner
16672        // arm elides an empty composite even when the outer presence
16673        // bit is `Some`), and a `Caixa { behavior: None, .. }` must
16674        // also omit the key (the "author omitted the slot entirely"
16675        // partition). The three-fixture family jointly pins the
16676        // accessor + M2 overlay emitter composition: any future
16677        // silent detour that had the accessor return a fresh-cloned
16678        // copy on the `Some` arm (a `BehaviorSpec::clone()`
16679        // projection) would silently break the reference-identity
16680        // pin the peer per-callback `serde_yaml::to_value(behavior)`
16681        // projection reads from.
16682        //
16683        // Peer of the sibling
16684        // `servico_m2_overlay_limits_arm_routes_through_accessor`
16685        // (b2bd9d7) composition pin on the sibling `:limits` outer-
16686        // `Option<&LimitsSpec>` arm of the same
16687        // [`crate::render::servico_m2_overlay`] M2 overlay emitter's
16688        // traversal — same "the emitter must route through the
16689        // substrate-primitive typed dispatch on the outer composite"
16690        // discipline extended onto the outer top-level [`Caixa`]
16691        // `Option<&BehaviorSpec>`-composition surface.
16692        use crate::BehaviorSpec;
16693        use crate::render::{M2_KEY_BEHAVIOR, servico_m2_overlay};
16694        use std::path::PathBuf;
16695        let c = caixa_with_behavior(Some(BehaviorSpec {
16696            on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16697            ..Default::default()
16698        }));
16699        let overlay = servico_m2_overlay(&c).unwrap();
16700        assert!(
16701            overlay.contains_key(M2_KEY_BEHAVIOR),
16702            "servico_m2_overlay must surface M2_KEY_BEHAVIOR when \
16703             `:behavior` carries a non-empty composite — the accessor \
16704             and the M2 overlay emitter must route through the same \
16705             substrate-primitive typed dispatch on the outer :behavior \
16706             composite (got overlay={overlay:?})",
16707        );
16708        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
16709        let overlay = servico_m2_overlay(&c).unwrap();
16710        assert!(
16711            !overlay.contains_key(M2_KEY_BEHAVIOR),
16712            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
16713             `:behavior` is Some(BehaviorSpec::default()) — the empty \
16714             composite's `.is_empty()`-gated inner arm must elide the \
16715             key regardless of the outer presence bit (got \
16716             overlay={overlay:?})",
16717        );
16718        let c = caixa_with_behavior(None);
16719        let overlay = servico_m2_overlay(&c).unwrap();
16720        assert!(
16721            !overlay.contains_key(M2_KEY_BEHAVIOR),
16722            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
16723             `:behavior` is None — the author-omitted arm must route \
16724             through the accessor's None-return unchanged (got \
16725             overlay={overlay:?})",
16726        );
16727    }
16728
16729    #[test]
16730    fn behavior_projects_option_ref_by_borrow() {
16731        // The by-borrow pin: [`Caixa::behavior`] returns
16732        // `Option<&BehaviorSpec>` by borrow — the returned reference
16733        // borrows the underlying `Option<BehaviorSpec>` storage of the
16734        // `:behavior` slot and the accessor must not clone the backing
16735        // composite on every call. Peer of the sibling
16736        // `limits_projects_option_ref_by_borrow` (b2bd9d7) by-borrow
16737        // pin on the outer top-level [`Caixa`] `Option<&Composite>`-
16738        // return sub-family — extended here to the second axis of the
16739        // same sub-family: the accessor's returned reference must
16740        // borrow from `&self` (the returned reference's lifetime is
16741        // tied to `&self`), and calling the accessor twice on the same
16742        // [`Caixa`] must yield references that are pointer-equal (the
16743        // underlying byte-buffer is the storage `BehaviorSpec`'s
16744        // allocation, not a fresh copy) as well as value-equal
16745        // (idempotent, no side effects on `&self`).
16746        //
16747        // Pins against a future silent detour that returned an owned
16748        // `BehaviorSpec` (which would type-check via the `Clone` impl
16749        // but silently clone on every call), a `&BehaviorSpec` panic-
16750        // return on the `None` arm (which would collapse the load-
16751        // bearing `Option` presence-bit into a runtime panic), or a
16752        // one-arm-only accessor that returned a saturating composite
16753        // on some sentinel input.
16754        use crate::BehaviorSpec;
16755        use std::path::PathBuf;
16756        for behavior in [
16757            Some(BehaviorSpec::default()),
16758            Some(BehaviorSpec {
16759                on_init: Some(PathBuf::from("lib/init.lisp")),
16760                on_call: Some(PathBuf::from("lib/handlers.lisp")),
16761                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
16762                on_info: Some(PathBuf::from("lib/handlers.lisp")),
16763                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16764                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
16765            }),
16766        ] {
16767            let c = caixa_with_behavior(behavior.clone());
16768            let first = c.behavior().unwrap();
16769            let second = c.behavior().unwrap();
16770            assert_eq!(
16771                first, second,
16772                "Caixa::behavior must be idempotent — two successive \
16773                 calls on the same &self must return the same \
16774                 &BehaviorSpec",
16775            );
16776            assert!(
16777                std::ptr::eq(first, second),
16778                "Caixa::behavior must borrow the underlying \
16779                 Option<BehaviorSpec> storage — two successive calls \
16780                 must return references with the same backing pointer \
16781                 (a fresh BehaviorSpec clone would change the pointer \
16782                 on every call)",
16783            );
16784            assert_eq!(
16785                Some(first),
16786                behavior.as_ref(),
16787                "Caixa::behavior must return :behavior verbatim by \
16788                 borrow — got {first:?}, expected {:?}",
16789                behavior.as_ref(),
16790            );
16791        }
16792        let c = caixa_with_behavior(None);
16793        assert!(
16794            c.behavior().is_none(),
16795            "Caixa::behavior must return None when :behavior is absent \
16796             — the author-omitted arm must project through the \
16797             accessor's Option::None unchanged",
16798        );
16799    }
16800
16801    // ── Caixa::politicas — outer top-level Option<&MeshPolicy> composite-reference accessor ──
16802
16803    fn caixa_aplicacao_with_politicas(politicas: Option<crate::aplicacao::MeshPolicy>) -> Caixa {
16804        use crate::aplicacao::{Membro, WitContract};
16805        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16806        c.kind = CaixaKind::Aplicacao;
16807        c.membros = vec![Membro {
16808            caixa: "a".into(),
16809            versao: "^0.1".into(),
16810        }];
16811        c.contratos = vec![WitContract {
16812            de: "a".into(),
16813            para: "a".into(),
16814            wit: "wasi:http/proxy".into(),
16815            endpoint: Some("/x".into()),
16816            subject: None,
16817            slot: None,
16818        }];
16819        c.politicas = politicas;
16820        c
16821    }
16822
16823    #[test]
16824    fn politicas_returns_politicas_option_ref_verbatim_across_permutations() {
16825        // The canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
16826        // composite optional-composite-reference-shape pin:
16827        // [`Caixa::politicas`] must return the `:politicas` typed
16828        // `Option<MeshPolicy>` verbatim as an `Option<&MeshPolicy>`
16829        // reference over the same backing storage the raw
16830        // `self.politicas.as_ref()` field access borrows from,
16831        // byte-equal across every representative fixture in the
16832        // accept-set — the author-omitted `None` shape (the "cluster-
16833        // default applies" partition every downstream mesh-artifact
16834        // emitter treats as "emit no `:politicas` overlay"), the
16835        // empty-composite `Some(MeshPolicy { .. default })` shape
16836        // ([`crate::aplicacao::MeshPolicy::is_empty`] holds — every
16837        // per-axis mesh-policy scalar is `None`, so the peer inner
16838        // [`crate::AplicacaoSpec::politicas`] `.is_empty()`-gated
16839        // caixa-mesh overlay elides every per-axis emit but the outer
16840        // presence-bit is `Some`, so [`Caixa::declared_mesh_slots`]
16841        // still pushes the `M3_AUTHOR_KEY_POLITICAS` label), a
16842        // single-axis fixture (only `:timeout` set — the canonical
16843        // shape a latency-sensitive Aplicacao carries), and a
16844        // fully-populated composite (every per-axis mesh-policy
16845        // scalar set — the canonical shape a fully-governed
16846        // Aplicacao carries).
16847        //
16848        // Pins against a future silent detour that returned a fresh-
16849        // cloned [`crate::aplicacao::MeshPolicy`] copy (which would
16850        // type-check via the `Clone` impl but silently break every
16851        // downstream caller that relied on the reference sharing the
16852        // composite's backing identity), a reference to an operator-
16853        // resolved overlay (the future per-cluster
16854        // `:politicas-overrides` slot — its resolution must land at
16855        // exactly this accessor body, not silently divert the raw
16856        // slot away from the peer [`Caixa::declared_mesh_slots`]
16857        // enumerator's presence probe), a
16858        // `None` → `Some(MeshPolicy::default)` cluster-default
16859        // projection (which would collapse the load-bearing
16860        // "author-omitted `:politicas` ⇒ cluster-default applies"
16861        // partition the peer [`Caixa::declared_mesh_slots`]
16862        // enumerator and the peer [`Caixa::aplicacao_view`]
16863        // Aplicacao-composition seed both read), or an axis-shuffled
16864        // projection (a future detour that swapped `timeout` and
16865        // `retries` through the accessor would silently split the
16866        // paired [`Caixa::aplicacao_view`] seed's fold input from the
16867        // sibling M3 mesh-artifact emitter's projection input).
16868        //
16869        // Third outer top-level [`Caixa`] `Option<&Composite>`-return
16870        // composite-reference accessor pin on the substrate primitive
16871        // — peer of the sibling
16872        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16873        // (b2bd9d7) and
16874        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
16875        // (35d8b52) opening tetrad pins on the outer top-level
16876        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
16877        // here to the first of the three M3 mesh-slot axes so the
16878        // opening third of the outer `Option<&Composite>` sub-family
16879        // carries the same "byte-equal, borrow-shared, presence-bit-
16880        // preserved" outer-accessor discipline.
16881        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
16882        use std::time::Duration;
16883        let fixtures: Vec<Option<MeshPolicy>> = vec![
16884            None,
16885            Some(MeshPolicy::default()),
16886            Some(MeshPolicy {
16887                timeout: Some(Duration::from_secs(30)),
16888                ..Default::default()
16889            }),
16890            Some(MeshPolicy {
16891                timeout: Some(Duration::from_secs(30)),
16892                retries: Some(3),
16893                circuit_breaker: Some(CircuitBreaker {
16894                    max_failures: 5,
16895                    window: Duration::from_secs(60),
16896                }),
16897                mtls_required: Some(true),
16898                rate_limit: Some(RateLimit {
16899                    rate: 100,
16900                    window: Duration::from_secs(1),
16901                }),
16902            }),
16903        ];
16904        for politicas in fixtures {
16905            let c = caixa_aplicacao_with_politicas(politicas.clone());
16906            assert_eq!(
16907                c.politicas(),
16908                politicas.as_ref(),
16909                "Caixa::politicas must return :politicas verbatim (got \
16910                 {:?}, expected {:?})",
16911                c.politicas(),
16912                politicas.as_ref(),
16913            );
16914            match (c.politicas(), c.politicas.as_ref()) {
16915                (Some(a), Some(b)) => assert!(
16916                    std::ptr::eq(a, b),
16917                    "Caixa::politicas accessor and self.politicas.as_ref() \
16918                     field access must borrow the same backing storage \
16919                     — the accessor is the substrate-primitive typed \
16920                     dispatch every downstream Aplicacao-mesh-overlay \
16921                     composite consumer must route through, and a \
16922                     reference-identity split would silently break \
16923                     every consumer that relied on the borrow sharing \
16924                     the composite's storage",
16925                ),
16926                (None, None) => {}
16927                _ => panic!(
16928                    "Caixa::politicas presence bit must byte-equal \
16929                     self.politicas.is_some() — a presence-bit drift \
16930                     would silently split the paired \
16931                     Caixa::aplicacao_view Aplicacao-composition seed's \
16932                     traversal head from the peer \
16933                     Caixa::declared_mesh_slots M3 declared-slot \
16934                     enumerator's presence probe",
16935                ),
16936            }
16937            assert_eq!(
16938                c.politicas().is_some(),
16939                c.politicas.is_some(),
16940                "Caixa::politicas().is_some() must byte-equal \
16941                 self.politicas.is_some() — a presence-bit drift would \
16942                 silently split every downstream Option<&MeshPolicy> \
16943                 consumer's partition on the cluster-default arm",
16944            );
16945        }
16946    }
16947
16948    #[test]
16949    fn declared_mesh_slots_politicas_arm_routes_through_accessor() {
16950        // Composition pin: [`Caixa::declared_mesh_slots`]'s
16951        // `:politicas` presence-probe arm must key off
16952        // [`Caixa::politicas`], not the raw `self.politicas.is_some()`
16953        // field-probe. Structurally: a `Caixa { politicas:
16954        // Some(MeshPolicy::default()), .. }` must still push
16955        // `M3_AUTHOR_KEY_POLITICAS` onto the declared-slot list (the
16956        // presence bit is `Some`, so the M3 kind-coherence gate must
16957        // surface the slot as "declared" even when every per-axis
16958        // scalar is unset), and a `Caixa { politicas: None, .. }` must
16959        // NOT push the label (the "author omitted the slot entirely"
16960        // partition). The pair jointly pins the accessor + declared-
16961        // slot enumerator composition: any future silent detour that
16962        // had the accessor collapse `Some(MeshPolicy::default())` to
16963        // `None` (a `.filter(|p| !p.is_empty())` projection) would
16964        // silently absorb the "declared but empty" arm at the
16965        // accessor boundary and the
16966        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
16967        // coherence gate would silently accept a struct-literal
16968        // `Caixa` carrying the drift.
16969        //
16970        // Peer of the sibling
16971        // `declared_servico_slots_limits_arm_routes_through_accessor`
16972        // (b2bd9d7) and
16973        // `declared_servico_slots_behavior_arm_routes_through_accessor`
16974        // (35d8b52) composition pins on the sibling `:limits` /
16975        // `:behavior` outer-`Option<&Composite>` arms of the peer
16976        // [`Caixa::declared_servico_slots`] M2 declared-slot
16977        // enumerator's traversal — same "the enumerator gate must
16978        // route through the substrate-primitive typed dispatch"
16979        // discipline extended onto the outer top-level [`Caixa`] M3
16980        // mesh-slot family so the [`Caixa::declared_mesh_slots`]
16981        // enumerator carries the same routing invariant as its M2
16982        // sibling.
16983        use crate::aplicacao::MeshPolicy;
16984        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
16985        let slots = c.declared_mesh_slots();
16986        assert!(
16987            slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
16988            "declared_mesh_slots must push M3_AUTHOR_KEY_POLITICAS \
16989             when `:politicas` is Some (even for MeshPolicy::default()) \
16990             — the accessor and the enumerator gate must route through \
16991             the same substrate-primitive typed dispatch on the outer \
16992             :politicas presence bit (got slots={slots:?})",
16993        );
16994        let c = caixa_aplicacao_with_politicas(None);
16995        let slots = c.declared_mesh_slots();
16996        assert!(
16997            !slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
16998            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_POLITICAS \
16999             when `:politicas` is None — the author-omitted arm must \
17000             route through the accessor's None-return unchanged (got \
17001             slots={slots:?})",
17002        );
17003    }
17004
17005    #[test]
17006    fn aplicacao_view_politicas_arm_folds_through_accessor() {
17007        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:politicas`
17008        // Aplicacao-composition seed must fold through
17009        // [`Caixa::politicas`], not the raw
17010        // `self.politicas.clone().unwrap_or_default()` field-borrow.
17011        // Structurally: a `Caixa { politicas: Some(MeshPolicy {
17012        // timeout: Some(30s), .. default }), kind: Aplicacao, .. }`
17013        // must surface a projected [`crate::AplicacaoSpec`] whose
17014        // `politicas().timeout()` field byte-equals the outer
17015        // composite's `timeout` scalar (the fold must project the
17016        // authored composite verbatim), a `Caixa { politicas:
17017        // Some(MeshPolicy::default()), kind: Aplicacao, .. }` must
17018        // surface an [`crate::AplicacaoSpec`] whose `politicas()`
17019        // byte-equals [`crate::aplicacao::MeshPolicy::default`] (the
17020        // fold's empty-composite arm collapses to the same default the
17021        // author-omitted arm does), and a `Caixa { politicas: None,
17022        // kind: Aplicacao, .. }` must surface an
17023        // [`crate::AplicacaoSpec`] whose `politicas()` byte-equals
17024        // [`crate::aplicacao::MeshPolicy::default`] (the "author
17025        // omitted the slot entirely" arm folds through the
17026        // `unwrap_or_default` onto the cluster-default). The triad
17027        // jointly pins the accessor + Aplicacao-composition seed
17028        // composition: any future silent detour that had the accessor
17029        // divert the raw slot away from the seed's fold (an operator-
17030        // resolved overlay's default-fold arm silently differing from
17031        // the raw slot's default-fold arm) would silently split the
17032        // build-time mesh-artifact emission gate from the caixa-mesh
17033        // renderer's Aplicacao-view input at the composition boundary.
17034        use crate::aplicacao::MeshPolicy;
17035        use std::time::Duration;
17036        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy {
17037            timeout: Some(Duration::from_secs(30)),
17038            ..Default::default()
17039        }));
17040        let view = c.aplicacao_view().unwrap();
17041        assert_eq!(
17042            view.politicas().timeout(),
17043            Some(Duration::from_secs(30)),
17044            "Caixa::aplicacao_view must fold the authored :politicas \
17045             :timeout scalar through the accessor verbatim onto the \
17046             projected AplicacaoSpec — a future silent detour at the \
17047             seed's fold arm would surface here as a projected-scalar \
17048             drift (got {:?})",
17049            view.politicas().timeout(),
17050        );
17051        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
17052        let view = c.aplicacao_view().unwrap();
17053        assert_eq!(
17054            view.politicas(),
17055            &MeshPolicy::default(),
17056            "Caixa::aplicacao_view must fold Some(MeshPolicy::default()) \
17057             through the accessor onto MeshPolicy::default — the empty- \
17058             composite arm collapses to the same default the author- \
17059             omitted arm does (got {:?})",
17060            view.politicas(),
17061        );
17062        let c = caixa_aplicacao_with_politicas(None);
17063        let view = c.aplicacao_view().unwrap();
17064        assert_eq!(
17065            view.politicas(),
17066            &MeshPolicy::default(),
17067            "Caixa::aplicacao_view must fold None through the accessor's \
17068             unwrap_or_default onto MeshPolicy::default — the author- \
17069             omitted arm must route through the accessor's None-return \
17070             unchanged (got {:?})",
17071            view.politicas(),
17072        );
17073    }
17074
17075    #[test]
17076    fn politicas_projects_option_ref_by_borrow() {
17077        // The by-borrow pin: [`Caixa::politicas`] returns
17078        // `Option<&MeshPolicy>` by borrow — the returned reference
17079        // borrows the underlying `Option<MeshPolicy>` storage of the
17080        // `:politicas` slot and the accessor must not clone the
17081        // backing composite on every call. Peer of the sibling
17082        // `limits_projects_option_ref_by_borrow` (b2bd9d7) and
17083        // `behavior_projects_option_ref_by_borrow` (35d8b52) by-borrow
17084        // pins on the outer top-level [`Caixa`]
17085        // `Option<&Composite>`-return sub-family — extended here to
17086        // the third axis of the same sub-family: the accessor's
17087        // returned reference must borrow from `&self` (the returned
17088        // reference's lifetime is tied to `&self`), and calling the
17089        // accessor twice on the same [`Caixa`] must yield references
17090        // that are pointer-equal (the underlying byte-buffer is the
17091        // storage `MeshPolicy`'s allocation, not a fresh copy) as
17092        // well as value-equal (idempotent, no side effects on
17093        // `&self`).
17094        //
17095        // Pins against a future silent detour that returned an owned
17096        // `MeshPolicy` (which would type-check via the `Clone` impl
17097        // but silently clone on every call), a `&MeshPolicy` panic-
17098        // return on the `None` arm (which would collapse the load-
17099        // bearing `Option` presence-bit into a runtime panic), or a
17100        // one-arm-only accessor that returned a saturating composite
17101        // on some sentinel input.
17102        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
17103        use std::time::Duration;
17104        for politicas in [
17105            Some(MeshPolicy::default()),
17106            Some(MeshPolicy {
17107                timeout: Some(Duration::from_secs(30)),
17108                retries: Some(3),
17109                circuit_breaker: Some(CircuitBreaker {
17110                    max_failures: 5,
17111                    window: Duration::from_secs(60),
17112                }),
17113                mtls_required: Some(true),
17114                rate_limit: Some(RateLimit {
17115                    rate: 100,
17116                    window: Duration::from_secs(1),
17117                }),
17118            }),
17119        ] {
17120            let c = caixa_aplicacao_with_politicas(politicas.clone());
17121            let first = c.politicas().unwrap();
17122            let second = c.politicas().unwrap();
17123            assert_eq!(
17124                first, second,
17125                "Caixa::politicas must be idempotent — two successive \
17126                 calls on the same &self must return the same \
17127                 &MeshPolicy",
17128            );
17129            assert!(
17130                std::ptr::eq(first, second),
17131                "Caixa::politicas must borrow the underlying \
17132                 Option<MeshPolicy> storage — two successive calls \
17133                 must return references with the same backing pointer \
17134                 (a fresh MeshPolicy clone would change the pointer on \
17135                 every call)",
17136            );
17137            assert_eq!(
17138                Some(first),
17139                politicas.as_ref(),
17140                "Caixa::politicas must return :politicas verbatim by \
17141                 borrow — got {first:?}, expected {:?}",
17142                politicas.as_ref(),
17143            );
17144        }
17145        let c = caixa_aplicacao_with_politicas(None);
17146        assert!(
17147            c.politicas().is_none(),
17148            "Caixa::politicas must return None when :politicas is \
17149             absent — the author-omitted arm must project through the \
17150             accessor's Option::None unchanged",
17151        );
17152    }
17153
17154    // ── Caixa::placement — outer top-level Option<&Placement> composite-reference accessor ──
17155
17156    fn caixa_aplicacao_with_placement(placement: Option<crate::aplicacao::Placement>) -> Caixa {
17157        use crate::aplicacao::{Membro, WitContract};
17158        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17159        c.kind = CaixaKind::Aplicacao;
17160        c.membros = vec![Membro {
17161            caixa: "a".into(),
17162            versao: "^0.1".into(),
17163        }];
17164        c.contratos = vec![WitContract {
17165            de: "a".into(),
17166            para: "a".into(),
17167            wit: "wasi:http/proxy".into(),
17168            endpoint: Some("/x".into()),
17169            subject: None,
17170            slot: None,
17171        }];
17172        c.placement = placement;
17173        c
17174    }
17175
17176    #[test]
17177    fn placement_returns_placement_option_ref_verbatim_across_permutations() {
17178        // The canonical per-`Caixa` `:placement` M3 mesh-slot outer-
17179        // composite optional-composite-reference-shape pin:
17180        // [`Caixa::placement`] must return the `:placement` typed
17181        // `Option<Placement>` verbatim as an `Option<&Placement>`
17182        // reference over the same backing storage the raw
17183        // `self.placement.as_ref()` field access borrows from,
17184        // byte-equal across every representative fixture in the
17185        // accept-set — the author-omitted `None` shape (the
17186        // "cluster-default applies" partition every downstream mesh-
17187        // artifact emitter treats as "emit no `:placement` overlay"),
17188        // the empty-composite `Some(Placement { .. default })` shape
17189        // (`estrategia: SingleNode`, empty clusters, no shard-key /
17190        // affinity — the outer presence-bit is `Some` so
17191        // [`Caixa::declared_mesh_slots`] still pushes the
17192        // `M3_AUTHOR_KEY_PLACEMENT` label), a single-axis
17193        // `Replicated`-on-two-clusters fixture (the canonical shape a
17194        // stateless HTTP Aplicacao carries), and a fully-populated
17195        // `Sharded`-with-shard-key-and-affinity fixture (the canonical
17196        // shape a stateful Akka-style cluster-sharding Aplicacao
17197        // carries).
17198        //
17199        // Pins against a future silent detour that returned a fresh-
17200        // cloned [`crate::aplicacao::Placement`] copy (which would
17201        // type-check via the `Clone` impl but silently break every
17202        // downstream caller that relied on the reference sharing the
17203        // composite's backing identity), a reference to an operator-
17204        // resolved overlay (the future per-cluster
17205        // `:placement-overrides` slot — its resolution must land at
17206        // exactly this accessor body, not silently divert the raw
17207        // slot away from the peer [`Caixa::declared_mesh_slots`]
17208        // enumerator's presence probe), a `None` →
17209        // `Some(Placement::default)` cluster-default projection (which
17210        // would collapse the load-bearing "author-omitted `:placement`
17211        // ⇒ cluster-default applies" partition the peer
17212        // [`Caixa::declared_mesh_slots`] enumerator and the peer
17213        // [`Caixa::aplicacao_view`] Aplicacao-composition seed both
17214        // read), or an axis-shuffled projection (a future detour that
17215        // swapped `clusters` and `affinity` through the accessor would
17216        // silently split the paired [`Caixa::aplicacao_view`] seed's
17217        // fold input from the sibling M3 mesh-artifact emitter's
17218        // projection input).
17219        //
17220        // Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
17221        // composite-reference accessor pin on the substrate primitive
17222        // — peer of the sibling
17223        // `limits_returns_limits_option_ref_verbatim_across_permutations`
17224        // (b2bd9d7),
17225        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
17226        // (35d8b52), and
17227        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
17228        // (5d23d29) opening triad pins on the outer top-level
17229        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
17230        // here to the second of the three M3 mesh-slot axes so the
17231        // opening four-fifths of the outer `Option<&Composite>` sub-
17232        // family carries the same "byte-equal, borrow-shared,
17233        // presence-bit-preserved" outer-accessor discipline.
17234        use crate::aplicacao::{Placement, PlacementStrategy};
17235        let fixtures: Vec<Option<Placement>> = vec![
17236            None,
17237            Some(Placement::default()),
17238            Some(Placement {
17239                estrategia: PlacementStrategy::Replicated,
17240                clusters: vec!["rio".into(), "sao-paulo".into()],
17241                affinity: None,
17242                shard_key: None,
17243            }),
17244            Some(Placement {
17245                estrategia: PlacementStrategy::Sharded,
17246                clusters: vec!["rio".into(), "sao-paulo".into(), "brasilia".into()],
17247                affinity: Some("data-locality".into()),
17248                shard_key: Some("$tenantId".into()),
17249            }),
17250        ];
17251        for placement in fixtures {
17252            let c = caixa_aplicacao_with_placement(placement.clone());
17253            assert_eq!(
17254                c.placement(),
17255                placement.as_ref(),
17256                "Caixa::placement must return :placement verbatim (got \
17257                 {:?}, expected {:?})",
17258                c.placement(),
17259                placement.as_ref(),
17260            );
17261            match (c.placement(), c.placement.as_ref()) {
17262                (Some(a), Some(b)) => assert!(
17263                    std::ptr::eq(a, b),
17264                    "Caixa::placement accessor and self.placement.as_ref() \
17265                     field access must borrow the same backing storage \
17266                     — the accessor is the substrate-primitive typed \
17267                     dispatch every downstream Aplicacao-distribution- \
17268                     overlay composite consumer must route through, and \
17269                     a reference-identity split would silently break \
17270                     every consumer that relied on the borrow sharing \
17271                     the composite's storage",
17272                ),
17273                (None, None) => {}
17274                _ => panic!(
17275                    "Caixa::placement presence bit must byte-equal \
17276                     self.placement.is_some() — a presence-bit drift \
17277                     would silently split the paired \
17278                     Caixa::aplicacao_view Aplicacao-composition seed's \
17279                     traversal head from the peer \
17280                     Caixa::declared_mesh_slots M3 declared-slot \
17281                     enumerator's presence probe",
17282                ),
17283            }
17284            assert_eq!(
17285                c.placement().is_some(),
17286                c.placement.is_some(),
17287                "Caixa::placement().is_some() must byte-equal \
17288                 self.placement.is_some() — a presence-bit drift would \
17289                 silently split every downstream Option<&Placement> \
17290                 consumer's partition on the cluster-default arm",
17291            );
17292        }
17293    }
17294
17295    #[test]
17296    fn declared_mesh_slots_placement_arm_routes_through_accessor() {
17297        // Composition pin: [`Caixa::declared_mesh_slots`]'s
17298        // `:placement` presence-probe arm must key off
17299        // [`Caixa::placement`], not the raw `self.placement.is_some()`
17300        // field-probe. Structurally: a `Caixa { placement:
17301        // Some(Placement::default()), .. }` must still push
17302        // `M3_AUTHOR_KEY_PLACEMENT` onto the declared-slot list (the
17303        // presence bit is `Some`, so the M3 kind-coherence gate must
17304        // surface the slot as "declared" even when every per-axis
17305        // scalar defers to the cluster-default arm), and a `Caixa {
17306        // placement: None, .. }` must NOT push the label (the "author
17307        // omitted the slot entirely" partition). The pair jointly pins
17308        // the accessor + declared-slot enumerator composition: any
17309        // future silent detour that had the accessor collapse
17310        // `Some(Placement::default())` to `None` (a `.filter(|p|
17311        // p.clusters().is_empty().not())` projection) would silently
17312        // absorb the "declared but empty" arm at the accessor boundary
17313        // and the [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
17314        // kind-coherence gate would silently accept a struct-literal
17315        // `Caixa` carrying the drift.
17316        //
17317        // Peer of the sibling
17318        // `declared_servico_slots_limits_arm_routes_through_accessor`
17319        // (b2bd9d7),
17320        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17321        // (35d8b52), and
17322        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
17323        // (5d23d29) composition pins on the sibling `:limits` /
17324        // `:behavior` / `:politicas` outer-`Option<&Composite>` arms
17325        // — same "the enumerator gate must route through the
17326        // substrate-primitive typed dispatch" discipline extended onto
17327        // the second of the three M3 mesh-slot axes so the
17328        // [`Caixa::declared_mesh_slots`] enumerator carries the same
17329        // routing invariant on the `:placement` arm as the peer
17330        // `:politicas` arm.
17331        use crate::aplicacao::Placement;
17332        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
17333        let slots = c.declared_mesh_slots();
17334        assert!(
17335            slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
17336            "declared_mesh_slots must push M3_AUTHOR_KEY_PLACEMENT \
17337             when `:placement` is Some (even for Placement::default()) \
17338             — the accessor and the enumerator gate must route through \
17339             the same substrate-primitive typed dispatch on the outer \
17340             :placement presence bit (got slots={slots:?})",
17341        );
17342        let c = caixa_aplicacao_with_placement(None);
17343        let slots = c.declared_mesh_slots();
17344        assert!(
17345            !slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
17346            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_PLACEMENT \
17347             when `:placement` is None — the author-omitted arm must \
17348             route through the accessor's None-return unchanged (got \
17349             slots={slots:?})",
17350        );
17351    }
17352
17353    #[test]
17354    fn aplicacao_view_placement_arm_folds_through_accessor() {
17355        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:placement`
17356        // Aplicacao-composition seed must fold through
17357        // [`Caixa::placement`], not the raw
17358        // `self.placement.clone().unwrap_or_default()` field-borrow.
17359        // Structurally: a `Caixa { placement: Some(Placement {
17360        // estrategia: Replicated, clusters: ["rio"], .. default }),
17361        // kind: Aplicacao, .. }` must surface a projected
17362        // [`crate::AplicacaoSpec`] whose `placement().estrategia()` +
17363        // `placement().clusters()` byte-equal the outer composite's
17364        // authored values (the fold must project the authored
17365        // composite verbatim), a `Caixa { placement:
17366        // Some(Placement::default()), kind: Aplicacao, .. }` must
17367        // surface an [`crate::AplicacaoSpec`] whose `placement()`
17368        // byte-equals [`crate::aplicacao::Placement::default`] (the
17369        // fold's empty-composite arm collapses to the same default
17370        // the author-omitted arm does), and a `Caixa { placement:
17371        // None, kind: Aplicacao, .. }` must surface an
17372        // [`crate::AplicacaoSpec`] whose `placement()` byte-equals
17373        // [`crate::aplicacao::Placement::default`] (the "author
17374        // omitted the slot entirely" arm folds through the
17375        // `unwrap_or_default` onto the cluster-default). The triad
17376        // jointly pins the accessor + Aplicacao-composition seed
17377        // composition: any future silent detour that had the accessor
17378        // divert the raw slot away from the seed's fold (an operator-
17379        // resolved overlay's default-fold arm silently differing from
17380        // the raw slot's default-fold arm) would silently split the
17381        // build-time distribution-artifact emission gate from the
17382        // caixa-mesh renderer's Aplicacao-view input at the
17383        // composition boundary.
17384        use crate::aplicacao::{Placement, PlacementStrategy};
17385        let c = caixa_aplicacao_with_placement(Some(Placement {
17386            estrategia: PlacementStrategy::Replicated,
17387            clusters: vec!["rio".into()],
17388            affinity: None,
17389            shard_key: None,
17390        }));
17391        let view = c.aplicacao_view().unwrap();
17392        assert_eq!(
17393            view.placement().estrategia(),
17394            PlacementStrategy::Replicated,
17395            "Caixa::aplicacao_view must fold the authored :placement \
17396             :estrategia scalar through the accessor verbatim onto the \
17397             projected AplicacaoSpec — a future silent detour at the \
17398             seed's fold arm would surface here as a projected-scalar \
17399             drift (got {:?})",
17400            view.placement().estrategia(),
17401        );
17402        assert_eq!(
17403            view.placement().clusters(),
17404            &["rio"],
17405            "Caixa::aplicacao_view must fold the authored :placement \
17406             :clusters list through the accessor verbatim onto the \
17407             projected AplicacaoSpec — a future silent detour at the \
17408             seed's fold arm would surface here as a projected-list \
17409             drift (got {:?})",
17410            view.placement().clusters(),
17411        );
17412        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
17413        let view = c.aplicacao_view().unwrap();
17414        assert_eq!(
17415            view.placement(),
17416            &Placement::default(),
17417            "Caixa::aplicacao_view must fold Some(Placement::default()) \
17418             through the accessor onto Placement::default — the empty- \
17419             composite arm collapses to the same default the author- \
17420             omitted arm does (got {:?})",
17421            view.placement(),
17422        );
17423        let c = caixa_aplicacao_with_placement(None);
17424        let view = c.aplicacao_view().unwrap();
17425        assert_eq!(
17426            view.placement(),
17427            &Placement::default(),
17428            "Caixa::aplicacao_view must fold None through the accessor's \
17429             unwrap_or_default onto Placement::default — the author- \
17430             omitted arm must route through the accessor's None-return \
17431             unchanged (got {:?})",
17432            view.placement(),
17433        );
17434    }
17435
17436    #[test]
17437    fn placement_projects_option_ref_by_borrow() {
17438        // The by-borrow pin: [`Caixa::placement`] returns
17439        // `Option<&Placement>` by borrow — the returned reference
17440        // borrows the underlying `Option<Placement>` storage of the
17441        // `:placement` slot and the accessor must not clone the
17442        // backing composite on every call. Peer of the sibling
17443        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
17444        // `behavior_projects_option_ref_by_borrow` (35d8b52), and
17445        // `politicas_projects_option_ref_by_borrow` (5d23d29) by-borrow
17446        // pins on the outer top-level [`Caixa`]
17447        // `Option<&Composite>`-return sub-family — extended here to
17448        // the fourth axis of the same sub-family: the accessor's
17449        // returned reference must borrow from `&self` (the returned
17450        // reference's lifetime is tied to `&self`), and calling the
17451        // accessor twice on the same [`Caixa`] must yield references
17452        // that are pointer-equal (the underlying byte-buffer is the
17453        // storage `Placement`'s allocation, not a fresh copy) as well
17454        // as value-equal (idempotent, no side effects on `&self`).
17455        //
17456        // Pins against a future silent detour that returned an owned
17457        // `Placement` (which would type-check via the `Clone` impl
17458        // but silently clone on every call), a `&Placement` panic-
17459        // return on the `None` arm (which would collapse the load-
17460        // bearing `Option` presence-bit into a runtime panic), or a
17461        // one-arm-only accessor that returned a saturating composite
17462        // on some sentinel input.
17463        use crate::aplicacao::{Placement, PlacementStrategy};
17464        for placement in [
17465            Some(Placement::default()),
17466            Some(Placement {
17467                estrategia: PlacementStrategy::Sharded,
17468                clusters: vec!["rio".into(), "sao-paulo".into()],
17469                affinity: Some("data-locality".into()),
17470                shard_key: Some("$tenantId".into()),
17471            }),
17472        ] {
17473            let c = caixa_aplicacao_with_placement(placement.clone());
17474            let first = c.placement().unwrap();
17475            let second = c.placement().unwrap();
17476            assert_eq!(
17477                first, second,
17478                "Caixa::placement must be idempotent — two successive \
17479                 calls on the same &self must return the same \
17480                 &Placement",
17481            );
17482            assert!(
17483                std::ptr::eq(first, second),
17484                "Caixa::placement must borrow the underlying \
17485                 Option<Placement> storage — two successive calls \
17486                 must return references with the same backing pointer \
17487                 (a fresh Placement clone would change the pointer on \
17488                 every call)",
17489            );
17490            assert_eq!(
17491                Some(first),
17492                placement.as_ref(),
17493                "Caixa::placement must return :placement verbatim by \
17494                 borrow — got {first:?}, expected {:?}",
17495                placement.as_ref(),
17496            );
17497        }
17498        let c = caixa_aplicacao_with_placement(None);
17499        assert!(
17500            c.placement().is_none(),
17501            "Caixa::placement must return None when :placement is \
17502             absent — the author-omitted arm must project through the \
17503             accessor's Option::None unchanged",
17504        );
17505    }
17506
17507    // ── Caixa::entrada — outer top-level Option<&Entrada> composite-reference accessor ──
17508
17509    fn caixa_aplicacao_with_entrada(entrada: Option<crate::aplicacao::Entrada>) -> Caixa {
17510        use crate::aplicacao::{Membro, WitContract};
17511        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17512        c.kind = CaixaKind::Aplicacao;
17513        c.membros = vec![Membro {
17514            caixa: "a".into(),
17515            versao: "^0.1".into(),
17516        }];
17517        c.contratos = vec![WitContract {
17518            de: "a".into(),
17519            para: "a".into(),
17520            wit: "wasi:http/proxy".into(),
17521            endpoint: Some("/x".into()),
17522            subject: None,
17523            slot: None,
17524        }];
17525        c.entrada = entrada;
17526        c
17527    }
17528
17529    #[test]
17530    fn entrada_returns_entrada_option_ref_verbatim_across_permutations() {
17531        // The canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
17532        // composite optional-composite-reference-shape pin:
17533        // [`Caixa::entrada`] must return the `:entrada` typed
17534        // `Option<Entrada>` verbatim as an `Option<&Entrada>`
17535        // reference over the same backing storage the raw
17536        // `self.entrada.as_ref()` field access borrows from,
17537        // byte-equal across every representative fixture in the
17538        // accept-set — the author-omitted `None` shape (the
17539        // "cluster-internal Aplicacao" partition every downstream
17540        // Gateway-API emitter treats as "emit no listener + no
17541        // HTTPRoute"), a bare-`host`/`para` minimum-composite fixture
17542        // (empty `paths` — the resolved-paths fallback the peer
17543        // [`crate::aplicacao::Entrada::resolved_paths`] cascade folds
17544        // onto the substrate catch-all), and a fully-populated
17545        // multi-path-with-non-default-port fixture (the canonical
17546        // shape a public HTTP Aplicacao carries).
17547        //
17548        // Pins against a future silent detour that returned a fresh-
17549        // cloned [`crate::aplicacao::Entrada`] copy (which would
17550        // type-check via the `Clone` impl but silently break every
17551        // downstream caller that relied on the reference sharing the
17552        // composite's backing identity), a reference to an operator-
17553        // resolved overlay (the future per-cluster
17554        // `:entrada-overrides` slot — its resolution must land at
17555        // exactly this accessor body, not silently divert the raw
17556        // slot away from the peer [`Caixa::declared_mesh_slots`]
17557        // enumerator's presence probe), or an axis-shuffled projection
17558        // (a future detour that swapped `host` and `para` through the
17559        // accessor would silently split the paired
17560        // [`Caixa::aplicacao_view`] seed's forward input from the
17561        // sibling M3 gateway-artifact emitter's projection input).
17562        //
17563        // Fifth and final outer top-level [`Caixa`]
17564        // `Option<&Composite>`-return composite-reference accessor pin
17565        // on the substrate primitive — peer of the sibling
17566        // `limits_returns_limits_option_ref_verbatim_across_permutations`
17567        // (b2bd9d7),
17568        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
17569        // (35d8b52),
17570        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
17571        // (5d23d29), and
17572        // `placement_returns_placement_option_ref_verbatim_across_permutations`
17573        // (4fb8074) opening tetrad pins on the outer top-level
17574        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
17575        // here to the third and final M3 mesh-slot axis so the closed
17576        // outer `Option<&Composite>` sub-family carries the same
17577        // "byte-equal, borrow-shared, presence-bit-preserved" outer-
17578        // accessor discipline across all five arms.
17579        use crate::aplicacao::Entrada;
17580        let fixtures: Vec<Option<Entrada>> = vec![
17581            None,
17582            Some(Entrada {
17583                host: "checkout.quero.cloud".into(),
17584                para: "gateway".into(),
17585                paths: Vec::new(),
17586                port: crate::DEFAULT_SERVICO_PORT,
17587            }),
17588            Some(Entrada {
17589                host: "api.pleme.io".into(),
17590                para: "public-api".into(),
17591                paths: vec!["/v1".into(), "/v2".into()],
17592                port: 8080,
17593            }),
17594        ];
17595        for entrada in fixtures {
17596            let c = caixa_aplicacao_with_entrada(entrada.clone());
17597            assert_eq!(
17598                c.entrada(),
17599                entrada.as_ref(),
17600                "Caixa::entrada must return :entrada verbatim (got \
17601                 {:?}, expected {:?})",
17602                c.entrada(),
17603                entrada.as_ref(),
17604            );
17605            match (c.entrada(), c.entrada.as_ref()) {
17606                (Some(a), Some(b)) => assert!(
17607                    std::ptr::eq(a, b),
17608                    "Caixa::entrada accessor and self.entrada.as_ref() \
17609                     field access must borrow the same backing storage \
17610                     — the accessor is the substrate-primitive typed \
17611                     dispatch every downstream Aplicacao-external- \
17612                     gateway composite consumer must route through, and \
17613                     a reference-identity split would silently break \
17614                     every consumer that relied on the borrow sharing \
17615                     the composite's storage",
17616                ),
17617                (None, None) => {}
17618                _ => panic!(
17619                    "Caixa::entrada presence bit must byte-equal \
17620                     self.entrada.is_some() — a presence-bit drift \
17621                     would silently split the paired \
17622                     Caixa::aplicacao_view Aplicacao-composition seed's \
17623                     traversal head from the peer \
17624                     Caixa::declared_mesh_slots M3 declared-slot \
17625                     enumerator's presence probe",
17626                ),
17627            }
17628            assert_eq!(
17629                c.entrada().is_some(),
17630                c.entrada.is_some(),
17631                "Caixa::entrada().is_some() must byte-equal \
17632                 self.entrada.is_some() — a presence-bit drift would \
17633                 silently split every downstream Option<&Entrada> \
17634                 consumer's partition on the cluster-internal arm",
17635            );
17636        }
17637    }
17638
17639    #[test]
17640    fn declared_mesh_slots_entrada_arm_routes_through_accessor() {
17641        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:entrada`
17642        // presence-probe arm must key off [`Caixa::entrada`], not the
17643        // raw `self.entrada.is_some()` field-probe. Structurally: a
17644        // `Caixa { entrada: Some(Entrada { host: "...", para: "...",
17645        // paths: [], port: DEFAULT_SERVICO_PORT }), .. }` must push
17646        // `M3_AUTHOR_KEY_ENTRADA` onto the declared-slot list (the
17647        // presence bit is `Some`, so the M3 kind-coherence gate must
17648        // surface the slot as "declared" even when every per-axis
17649        // scalar defers to the substrate catch-all / default port),
17650        // and a `Caixa { entrada: None, .. }` must NOT push the label
17651        // (the "author omitted the slot entirely" partition). The pair
17652        // jointly pins the accessor + declared-slot enumerator
17653        // composition: any future silent detour that had the accessor
17654        // collapse `Some(Entrada { paths: [], .. })` to `None` (a
17655        // `.filter(|e| !e.paths.is_empty())` projection) would silently
17656        // absorb the "declared but empty-paths" arm at the accessor
17657        // boundary and the
17658        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
17659        // coherence gate would silently accept a struct-literal
17660        // `Caixa` carrying the drift.
17661        //
17662        // Peer of the sibling
17663        // `declared_servico_slots_limits_arm_routes_through_accessor`
17664        // (b2bd9d7),
17665        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17666        // (35d8b52),
17667        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
17668        // (5d23d29), and
17669        // `declared_mesh_slots_placement_arm_routes_through_accessor`
17670        // (4fb8074) composition pins on the sibling `:limits` /
17671        // `:behavior` / `:politicas` / `:placement` outer-
17672        // `Option<&Composite>` arms — same "the enumerator gate must
17673        // route through the substrate-primitive typed dispatch"
17674        // discipline extended onto the third and final M3 mesh-slot
17675        // axis so the [`Caixa::declared_mesh_slots`] enumerator now
17676        // carries the routing invariant on every M3 mesh-slot arm.
17677        use crate::aplicacao::Entrada;
17678        let c = caixa_aplicacao_with_entrada(Some(Entrada {
17679            host: "checkout.quero.cloud".into(),
17680            para: "gateway".into(),
17681            paths: Vec::new(),
17682            port: crate::DEFAULT_SERVICO_PORT,
17683        }));
17684        let slots = c.declared_mesh_slots();
17685        assert!(
17686            slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
17687            "declared_mesh_slots must push M3_AUTHOR_KEY_ENTRADA when \
17688             `:entrada` is Some (even for empty-paths / default-port) \
17689             — the accessor and the enumerator gate must route through \
17690             the same substrate-primitive typed dispatch on the outer \
17691             :entrada presence bit (got slots={slots:?})",
17692        );
17693        let c = caixa_aplicacao_with_entrada(None);
17694        let slots = c.declared_mesh_slots();
17695        assert!(
17696            !slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
17697            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_ENTRADA \
17698             when `:entrada` is None — the author-omitted arm must \
17699             route through the accessor's None-return unchanged (got \
17700             slots={slots:?})",
17701        );
17702    }
17703
17704    #[test]
17705    fn aplicacao_view_entrada_arm_folds_through_accessor() {
17706        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:entrada`
17707        // Aplicacao-composition seed must fold through
17708        // [`Caixa::entrada`], not the raw `self.entrada.clone()` field-
17709        // borrow. Structurally: a `Caixa { entrada: Some(Entrada {
17710        // host: "api.pleme.io", para: "public-api", paths: ["/v1"],
17711        // port: 8080 }), kind: Aplicacao, .. }` must surface a projected
17712        // [`crate::AplicacaoSpec`] whose `entrada().unwrap()` byte-
17713        // equals the outer composite's authored value (the fold must
17714        // project the authored composite verbatim), and a `Caixa {
17715        // entrada: None, kind: Aplicacao, .. }` must surface an
17716        // [`crate::AplicacaoSpec`] whose `entrada()` is `None` (the
17717        // "author omitted the slot entirely" arm folds through the
17718        // accessor's `Option::cloned` onto the same `None` presence
17719        // bit — unlike the peer `:politicas` / `:placement` arms
17720        // `:entrada` has no cluster-default fold, the omitted arm
17721        // stays omitted). The pair jointly pins the accessor +
17722        // Aplicacao-composition seed composition: any future silent
17723        // detour that had the accessor divert the raw slot away from
17724        // the seed's fold (an operator-resolved overlay's forward arm
17725        // silently differing from the raw slot's forward arm) would
17726        // silently split the build-time gateway-artifact emission gate
17727        // from the caixa-mesh renderer's Aplicacao-view input at the
17728        // composition boundary.
17729        use crate::aplicacao::Entrada;
17730        let authored = Entrada {
17731            host: "api.pleme.io".into(),
17732            para: "public-api".into(),
17733            paths: vec!["/v1".into()],
17734            port: 8080,
17735        };
17736        let c = caixa_aplicacao_with_entrada(Some(authored.clone()));
17737        let view = c.aplicacao_view().unwrap();
17738        assert_eq!(
17739            view.entrada(),
17740            Some(&authored),
17741            "Caixa::aplicacao_view must fold the authored :entrada \
17742             composite through the accessor verbatim onto the \
17743             projected AplicacaoSpec — a future silent detour at the \
17744             seed's fold arm would surface here as a projected- \
17745             composite drift (got {:?})",
17746            view.entrada(),
17747        );
17748        let c = caixa_aplicacao_with_entrada(None);
17749        let view = c.aplicacao_view().unwrap();
17750        assert!(
17751            view.entrada().is_none(),
17752            "Caixa::aplicacao_view must fold None through the \
17753             accessor's Option::cloned onto None — the author- \
17754             omitted arm must route through the accessor's None-return \
17755             unchanged (got {:?})",
17756            view.entrada(),
17757        );
17758    }
17759
17760    #[test]
17761    fn entrada_projects_option_ref_by_borrow() {
17762        // The by-borrow pin: [`Caixa::entrada`] returns
17763        // `Option<&Entrada>` by borrow — the returned reference
17764        // borrows the underlying `Option<Entrada>` storage of the
17765        // `:entrada` slot and the accessor must not clone the backing
17766        // composite on every call. Peer of the sibling
17767        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
17768        // `behavior_projects_option_ref_by_borrow` (35d8b52),
17769        // `politicas_projects_option_ref_by_borrow` (5d23d29), and
17770        // `placement_projects_option_ref_by_borrow` (4fb8074) by-
17771        // borrow pins on the outer top-level [`Caixa`]
17772        // `Option<&Composite>`-return sub-family — extended here to
17773        // the fifth and final axis of the same sub-family, closing
17774        // the discipline: the accessor's returned reference must
17775        // borrow from `&self` (the returned reference's lifetime is
17776        // tied to `&self`), and calling the accessor twice on the
17777        // same [`Caixa`] must yield references that are pointer-equal
17778        // (the underlying byte-buffer is the storage `Entrada`'s
17779        // allocation, not a fresh copy) as well as value-equal
17780        // (idempotent, no side effects on `&self`).
17781        //
17782        // Pins against a future silent detour that returned an owned
17783        // `Entrada` (which would type-check via the `Clone` impl but
17784        // silently clone on every call), a `&Entrada` panic-return on
17785        // the `None` arm (which would collapse the load-bearing
17786        // `Option` presence-bit into a runtime panic), or a one-arm-
17787        // only accessor that returned a saturating composite on some
17788        // sentinel input.
17789        use crate::aplicacao::Entrada;
17790        for entrada in [
17791            Some(Entrada {
17792                host: "checkout.quero.cloud".into(),
17793                para: "gateway".into(),
17794                paths: Vec::new(),
17795                port: crate::DEFAULT_SERVICO_PORT,
17796            }),
17797            Some(Entrada {
17798                host: "api.pleme.io".into(),
17799                para: "public-api".into(),
17800                paths: vec!["/v1".into(), "/v2".into()],
17801                port: 8080,
17802            }),
17803        ] {
17804            let c = caixa_aplicacao_with_entrada(entrada.clone());
17805            let first = c.entrada().unwrap();
17806            let second = c.entrada().unwrap();
17807            assert_eq!(
17808                first, second,
17809                "Caixa::entrada must be idempotent — two successive \
17810                 calls on the same &self must return the same &Entrada",
17811            );
17812            assert!(
17813                std::ptr::eq(first, second),
17814                "Caixa::entrada must borrow the underlying \
17815                 Option<Entrada> storage — two successive calls must \
17816                 return references with the same backing pointer (a \
17817                 fresh Entrada clone would change the pointer on every \
17818                 call)",
17819            );
17820            assert_eq!(
17821                Some(first),
17822                entrada.as_ref(),
17823                "Caixa::entrada must return :entrada verbatim by \
17824                 borrow — got {first:?}, expected {:?}",
17825                entrada.as_ref(),
17826            );
17827        }
17828        let c = caixa_aplicacao_with_entrada(None);
17829        assert!(
17830            c.entrada().is_none(),
17831            "Caixa::entrada must return None when :entrada is absent \
17832             — the author-omitted arm must project through the \
17833             accessor's Option::None unchanged",
17834        );
17835    }
17836
17837    // ── Caixa::estrategia — outer top-level Option<RestartStrategy> flat-spread supervisor-tree accessor ──
17838
17839    fn caixa_with_estrategia(estrategia: Option<crate::supervisor::RestartStrategy>) -> Caixa {
17840        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17841        c.estrategia = estrategia;
17842        c
17843    }
17844
17845    #[test]
17846    fn estrategia_returns_estrategia_option_verbatim_across_permutations() {
17847        // The canonical per-`Caixa` `:estrategia` M2 supervisor-tree-slot
17848        // flat-spread `Option<RestartStrategy>`-return `Copy`-composite-
17849        // enum-arm scalar shape pin: [`Caixa::estrategia`] must return
17850        // the `:estrategia` typed `Option<crate::supervisor::RestartStrategy>`
17851        // verbatim as an `Option<RestartStrategy>` `Copy`-projected value
17852        // over the same discriminant the raw `self.estrategia` field
17853        // access carries, byte-equal across every representative fixture
17854        // in the accept-set — the author-omitted `None` shape (the
17855        // "defer to [`RestartStrategy::default`] through the
17856        // [`Self::supervisor_view`] `unwrap_or_default()` fold" partition
17857        // every non-`Supervisor`-kind `defcaixa` carries by
17858        // `#[serde(default)]`), and each of the four closed-set variants
17859        // [`RestartStrategy::OneForOne`] / [`RestartStrategy::OneForAll`]
17860        // / [`RestartStrategy::RestForOne`] /
17861        // [`RestartStrategy::SimpleOneForOne`] the author-declared arm
17862        // partitions on.
17863        //
17864        // Pins against a future silent detour that re-derived the
17865        // strategy from a peer axis (an accidental fallback to
17866        // `if children.is_empty() { SimpleOneForOne } else { OneForOne }`
17867        // collapse that read the outer `:children` list-length axis into
17868        // the strategy discriminator at the accessor boundary), a
17869        // stale-derive detour that substituted [`RestartStrategy::default`]
17870        // when the outer `Option` held `None` (which would silently
17871        // collapse the load-bearing "author explicitly declared
17872        // `:estrategia OneForOne`" vs "author omitted the slot and
17873        // inherited the default" partition the [`Self::declared_supervisor_slots`]
17874        // presence-probe reads — the enumerator gate would still push
17875        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` on the omitted arm, silently
17876        // splitting the paired [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
17877        // kind-coherence gate's traversal head from the
17878        // [`Self::supervisor_view`] `unwrap_or_default()` fold's
17879        // composition head), a reference to an operator-resolved overlay
17880        // (the future per-cluster `:estrategia-overrides` slot — its
17881        // resolution must land at exactly this accessor body, not
17882        // silently divert the raw slot away from a second consumer), or
17883        // an axis-remap projection (a future detour that mapped
17884        // `OneForAll` through the accessor onto `OneForOne` would
17885        // silently split every downstream sibling-restart-strategy
17886        // consumer's per-arm fan-out).
17887        //
17888        // First outer top-level [`Caixa`] `Option<Copy>`-return
17889        // supervisor-tree-slot flat-spread accessor pin on the substrate
17890        // primitive — opens the outer-`Caixa` `Option<Copy>` flat-spread
17891        // projection pattern the sibling per-`Caixa` `:max-restarts` /
17892        // `:restart-window` future outer-scalar pins fold on. Peer of
17893        // the inner-altitude
17894        // `supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
17895        // (eafb619) pin on the post-composition [`SupervisorSpec`]
17896        // altitude — same "the substrate-primitive accessor must byte-
17897        // equal the raw field access verbatim across every author-
17898        // declared value" discipline extended onto the pre-composition
17899        // outer author-surface [`Caixa`] altitude. Peer of the closed
17900        // outer-`Caixa` `Option<&Composite>` composite-reference family
17901        // the sibling `limits` / `behavior` / `politicas` / `placement` /
17902        // `entrada`
17903        // `..._returns_..._option_ref_verbatim_across_permutations` pins
17904        // already carry on the outer `Option<&Composite>` altitude.
17905        use crate::supervisor::RestartStrategy;
17906        let fixtures: Vec<Option<RestartStrategy>> = vec![
17907            None,
17908            Some(RestartStrategy::OneForOne),
17909            Some(RestartStrategy::OneForAll),
17910            Some(RestartStrategy::RestForOne),
17911            Some(RestartStrategy::SimpleOneForOne),
17912        ];
17913        for estrategia in fixtures {
17914            let c = caixa_with_estrategia(estrategia);
17915            assert_eq!(
17916                c.estrategia(),
17917                estrategia,
17918                "Caixa::estrategia must return :estrategia verbatim (got \
17919                 {:?}, expected {:?})",
17920                c.estrategia(),
17921                estrategia,
17922            );
17923            assert_eq!(
17924                c.estrategia(),
17925                c.estrategia,
17926                "Caixa::estrategia accessor and self.estrategia field \
17927                 access must byte-equal — the accessor is the substrate-\
17928                 primitive typed dispatch every downstream supervisor-\
17929                 tree flat-spread consumer must route through, and a \
17930                 discriminant split would silently break every consumer \
17931                 that relied on the accessor sharing the field's own \
17932                 Option<Copy> shape",
17933            );
17934            assert_eq!(
17935                c.estrategia().is_some(),
17936                c.estrategia.is_some(),
17937                "Caixa::estrategia().is_some() must byte-equal \
17938                 self.estrategia.is_some() — a presence-bit drift would \
17939                 silently split the paired Caixa::declared_supervisor_slots \
17940                 presence-probe arm from the Caixa::supervisor_view \
17941                 unwrap_or_default() fold's composition input",
17942            );
17943        }
17944    }
17945
17946    #[test]
17947    fn declared_supervisor_slots_estrategia_arm_routes_through_accessor() {
17948        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
17949        // `:estrategia` presence-probe arm must key off
17950        // [`Caixa::estrategia`], not the raw `self.estrategia.is_some()`
17951        // field-probe. Structurally: every `Caixa { estrategia:
17952        // Some(RestartStrategy::_), .. }` variant must push
17953        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` onto the declared-slot list
17954        // (the presence bit is `Some` for every closed-set variant, so
17955        // the M2 supervisor-tree kind-coherence gate must surface the
17956        // slot as "declared" regardless of which variant the author
17957        // picked), and a `Caixa { estrategia: None, .. }` must NOT push
17958        // the label (the "author omitted the slot entirely, deferring
17959        // to [`RestartStrategy::default`] through the supervisor_view
17960        // fold" partition). The pair jointly pins the accessor +
17961        // declared-slot enumerator composition: any future silent detour
17962        // that had the accessor collapse `Some(RestartStrategy::default())`
17963        // to `None` (a `.filter(|e| *e != RestartStrategy::default())`
17964        // projection) would silently absorb the "declared but default-
17965        // valued" arm at the accessor boundary and the
17966        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
17967        // coherence gate would silently accept a struct-literal `Caixa`
17968        // carrying the drift.
17969        //
17970        // Peer of the sibling per-`Caixa`
17971        // `declared_servico_slots_limits_arm_routes_through_accessor`
17972        // (b2bd9d7) accessor-composition pin on the sibling outer-`Caixa`
17973        // `Option<&LimitsSpec>` composition axis — same "the enumerator
17974        // gate must route through the substrate-primitive typed
17975        // dispatch" discipline extended onto the flat-spread M2
17976        // supervisor-tree `Option<RestartStrategy>`-composition surface,
17977        // opening the outer-`Caixa` supervisor-tree-slot arm of the
17978        // composition-pin family.
17979        use crate::supervisor::RestartStrategy;
17980        for estrategia in [
17981            RestartStrategy::OneForOne,
17982            RestartStrategy::OneForAll,
17983            RestartStrategy::RestForOne,
17984            RestartStrategy::SimpleOneForOne,
17985        ] {
17986            let c = caixa_with_estrategia(Some(estrategia));
17987            let slots = c.declared_supervisor_slots();
17988            assert!(
17989                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
17990                "declared_supervisor_slots must push \
17991                 SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is \
17992                 Some({estrategia:?}) — the accessor and the enumerator \
17993                 gate must route through the same substrate-primitive \
17994                 typed dispatch on the outer :estrategia presence bit \
17995                 (got slots={slots:?})",
17996            );
17997        }
17998        let c = caixa_with_estrategia(None);
17999        let slots = c.declared_supervisor_slots();
18000        assert!(
18001            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
18002            "declared_supervisor_slots must NOT push \
18003             SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is None \
18004             — the author-omitted arm must route through the accessor's \
18005             None-return unchanged (got slots={slots:?})",
18006        );
18007    }
18008
18009    #[test]
18010    fn supervisor_view_estrategia_arm_routes_through_accessor() {
18011        // Composition pin: [`Caixa::supervisor_view`]'s per-`:estrategia`
18012        // [`SupervisorSpec`] construction arm must key off
18013        // [`Caixa::estrategia`]'s `unwrap_or_default()` fold, not the raw
18014        // `self.estrategia.unwrap_or_default()` field-fold. Structurally:
18015        // for every `:kind Supervisor` `Caixa` carrying an author-
18016        // declared `Some(RestartStrategy::_)` variant, the composed
18017        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal the
18018        // outer accessor's declared variant unchanged; and for a
18019        // `:kind Supervisor` `Caixa` carrying `None`, the composed
18020        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal
18021        // [`RestartStrategy::default`] (the [`RestartStrategy::OneForOne`]
18022        // arm the flat-spread `unwrap_or_default()` fold projects to on
18023        // the author-omitted arm — this is the *composition* between the
18024        // outer `Option<RestartStrategy>` accessor's presence-bit
18025        // surface and the inner post-composition non-`Option`
18026        // [`SupervisorSpec::estrategia`] altitude). The pair jointly
18027        // pins the accessor + supervisor_view composition: any future
18028        // silent detour that had the accessor promote `None` to
18029        // `Some(RestartStrategy::default())` (a `.or_else(|| Some(RestartStrategy::default()))`
18030        // projection) would silently collapse the two arms into one at
18031        // the accessor boundary and the [`Self::declared_supervisor_slots`]
18032        // presence probe would silently drift from the composition site.
18033        //
18034        // Peer of the sibling M2 supervisor-slot post-composition
18035        // `validate_reads_through_lifted_estrategia_accessor` (eafb619)
18036        // pin on the [`SupervisorSpec::validate`] altitude — this pin
18037        // extends that inner-altitude accessor-routing discipline onto
18038        // the pre-composition outer author-surface [`Caixa`] altitude,
18039        // pinning the composition edge between the flat-spread outer
18040        // `Option<RestartStrategy>` and the composed [`SupervisorSpec`]
18041        // `RestartStrategy` axes.
18042        use crate::CaixaKind;
18043        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
18044        for estrategia in [
18045            RestartStrategy::OneForOne,
18046            RestartStrategy::OneForAll,
18047            RestartStrategy::RestForOne,
18048            RestartStrategy::SimpleOneForOne,
18049        ] {
18050            let mut c = caixa_with_estrategia(Some(estrategia));
18051            c.kind = CaixaKind::Supervisor;
18052            // Route the `SimpleOneForOne ↔ non-SimpleOneForOne` fixture-
18053            // shape partition through the [`gen_platform::IsVariant`]
18054            // derive-generated
18055            // [`RestartStrategy::is_simple_one_for_one`] predicate rather
18056            // than the raw `matches!(estrategia, RestartStrategy::
18057            // SimpleOneForOne)` open-coded pattern-match — same closed-
18058            // set-typed-enum arm-discriminator dispatch discipline the
18059            // sibling [`crate::upgrade::UpgradeInstruction::is_restart`]
18060            // convergence (915a934) extended onto its two paired positive
18061            // / negated `matches!` sites and the peer
18062            // [`crate::aplicacao::PlacementStrategy`] `IsVariant`-derived
18063            // predicate convergence (766ec63) extended onto the M3 mesh-
18064            // slot per-`:placement` distribution-strategy discriminator
18065            // axis. See the sibling `supervisor::tests::
18066            // round_trip_all_strategies` and
18067            // `supervisor::tests::supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
18068            // fixtures — the three sites (all test-only,
18069            // acknowledged in 915a934's Prior-commits footnote as the
18070            // outstanding follow-up) now consult one typed dispatch on
18071            // the substrate primitive.
18072            c.children = if estrategia.is_simple_one_for_one() {
18073                Vec::new()
18074            } else {
18075                vec![ChildSpec {
18076                    caixa: "worker".into(),
18077                    versao: "^0.1".into(),
18078                    restart: RestartPolicy::Permanent,
18079                }]
18080            };
18081            let view = c.supervisor_view().expect(
18082                "supervisor_view must materialize a SupervisorSpec for a \
18083                 :kind Supervisor Caixa carrying a Some(:estrategia) slot",
18084            );
18085            assert_eq!(
18086                view.estrategia(),
18087                c.estrategia().unwrap(),
18088                "supervisor_view must carry the outer Caixa::estrategia() \
18089                 declared variant onto the composed SupervisorSpec.estrategia \
18090                 field verbatim on the Some arm (got {:?}, expected {:?})",
18091                view.estrategia(),
18092                c.estrategia().unwrap(),
18093            );
18094        }
18095        // The author-omitted arm: outer `None` → composed
18096        // `RestartStrategy::default()` through the flat-spread
18097        // `unwrap_or_default()` fold.
18098        let mut c = caixa_with_estrategia(None);
18099        c.kind = CaixaKind::Supervisor;
18100        // Populate children so the sibling supervisor slots are coherent
18101        // for the [`Self::supervisor_view`] projection; the `:estrategia`
18102        // arm still defers to [`RestartStrategy::default`] on the
18103        // author-omitted arm even when the sibling slots carry values.
18104        c.children = vec![ChildSpec {
18105            caixa: "worker".into(),
18106            versao: "^0.1".into(),
18107            restart: RestartPolicy::Permanent,
18108        }];
18109        let view = c.supervisor_view().expect(
18110            "supervisor_view must materialize a SupervisorSpec for a \
18111             :kind Supervisor Caixa carrying a None `:estrategia` slot",
18112        );
18113        assert_eq!(
18114            view.estrategia(),
18115            RestartStrategy::default(),
18116            "supervisor_view must project the outer Caixa::estrategia() \
18117             None arm onto RestartStrategy::default() through the flat-\
18118             spread unwrap_or_default() fold (got {:?}, expected {:?})",
18119            view.estrategia(),
18120            RestartStrategy::default(),
18121        );
18122        assert!(
18123            c.estrategia().is_none(),
18124            "Caixa::estrategia() must remain None on the author-omitted \
18125             arm — the supervisor_view fold must not mutate the outer \
18126             flat-spread presence bit",
18127        );
18128    }
18129
18130    #[test]
18131    fn estrategia_projects_option_by_copy() {
18132        // The by-`Copy` pin: [`Caixa::estrategia`] returns
18133        // `Option<RestartStrategy>` by value (`RestartStrategy: Copy`) —
18134        // the accessor does not borrow `&self` past the call (no
18135        // lifetime on the return type), and calling the accessor twice
18136        // on the same [`Caixa`] must yield discriminant-equal values
18137        // (idempotent, no side effects on `&self`). Peer of the sibling
18138        // outer-`Caixa` `Option<&Composite>` by-borrow
18139        // `limits_projects_option_ref_by_borrow` (b2bd9d7) /
18140        // `behavior_projects_option_ref_by_borrow` (35d8b52) /
18141        // `politicas_projects_option_ref_by_borrow` (5d23d29) /
18142        // `placement_projects_option_ref_by_borrow` (4fb8074) /
18143        // `entrada_projects_option_ref_by_borrow` (e4128e4) by-borrow
18144        // pins on the outer-`Caixa` `Option<&Composite>`-return axes —
18145        // extended here to the outer-`Caixa` `Option<Copy>`-return
18146        // flat-spread axis. The `Copy` discipline replaces the pointer-
18147        // equality claim the by-borrow siblings pin (a fresh `Copy` of a
18148        // `Copy` discriminant is definitionally the same discriminant, so
18149        // the axis reduces to discriminant equality).
18150        //
18151        // Pins against a future silent detour that returned a fresh
18152        // `Option<&RestartStrategy>` (which would type-check but silently
18153        // introduce a borrow of `&self` past the call, collapsing the
18154        // load-bearing "no lifetime on the return type" `Copy` projection
18155        // the flat-spread axis's `Option<Copy>` shape carries), a stale-
18156        // read side effect that flipped the outer discriminant on
18157        // successive calls, or an axis-remap projection that returned a
18158        // different variant than the field storage.
18159        use crate::supervisor::RestartStrategy;
18160        for estrategia in [
18161            Some(RestartStrategy::OneForOne),
18162            Some(RestartStrategy::OneForAll),
18163            Some(RestartStrategy::RestForOne),
18164            Some(RestartStrategy::SimpleOneForOne),
18165        ] {
18166            let c = caixa_with_estrategia(estrategia);
18167            let first = c.estrategia();
18168            let second = c.estrategia();
18169            assert_eq!(
18170                first, second,
18171                "Caixa::estrategia must be idempotent — two successive \
18172                 calls on the same &self must return the same \
18173                 Option<RestartStrategy>",
18174            );
18175            assert_eq!(
18176                first, estrategia,
18177                "Caixa::estrategia must return :estrategia verbatim by \
18178                 Copy — got {first:?}, expected {estrategia:?}",
18179            );
18180        }
18181        let c = caixa_with_estrategia(None);
18182        assert!(
18183            c.estrategia().is_none(),
18184            "Caixa::estrategia must return None when :estrategia is \
18185             absent — the author-omitted arm must project through the \
18186             accessor's Option::None unchanged",
18187        );
18188    }
18189
18190    // ── Caixa::max_restarts / Caixa::restart_window —
18191    //    outer top-level M2 supervisor-tree-slot flat-spread accessors
18192    //    (Option<u32> / Option<&str>) folding on the ed04d3c
18193    //    Caixa::estrategia Option<Copy> sub-family ─────────────────────
18194
18195    fn caixa_with_max_restarts(max_restarts: Option<u32>) -> Caixa {
18196        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18197        c.max_restarts = max_restarts;
18198        c
18199    }
18200
18201    fn caixa_supervisor_with_max_restarts_and_window(
18202        max_restarts: Option<u32>,
18203        restart_window: Option<&str>,
18204    ) -> Caixa {
18205        use crate::CaixaKind;
18206        use crate::supervisor::{ChildSpec, RestartPolicy};
18207        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
18208        c.kind = CaixaKind::Supervisor;
18209        c.max_restarts = max_restarts;
18210        c.restart_window = restart_window.map(str::to_string);
18211        c.children = vec![ChildSpec {
18212            caixa: "worker".into(),
18213            versao: "^0.1".into(),
18214            restart: RestartPolicy::Permanent,
18215        }];
18216        c
18217    }
18218
18219    #[test]
18220    fn max_restarts_returns_max_restarts_option_verbatim_across_permutations() {
18221        // Value-shape pin: [`Caixa::max_restarts`] returns the
18222        // `:max-restarts` typed `Option<u32>` verbatim, `Copy`-projected
18223        // from the typed slot's own storage, byte-equal across the
18224        // author-omitted `None` arm (the "defer to the
18225        // [`Self::supervisor_view`] `unwrap_or(5)` OTP-canonical
18226        // `{intensity, 5, 60}` default" partition every
18227        // non-`Supervisor`-kind caixa carries by `#[serde(default)]`)
18228        // and each of the representative fixtures in the accept-set —
18229        // `0` (the zero-floor arm the peer
18230        // [`crate::supervisor::SupervisorSpec::validate`]
18231        // [`crate::SupervisorError::ZeroMaxRestarts`] gate refuses on
18232        // the post-composition altitude — the accessor must ship the
18233        // raw slot verbatim so struct-literal fixtures continue to
18234        // expose the zero at the accessor boundary), the OTP-canonical
18235        // `5` default (`{intensity, 5, 60}` worker-supervisor from
18236        // Learn You Some Erlang), `1000` (the
18237        // [`SUPERVISOR_MAX_RESTARTS_MAX`] cap the peer post-composition
18238        // upper-bound gate accepts on the boundary), `u32::MAX` (a
18239        // past-the-cap sentinel that the substrate-primitive accessor
18240        // must still ship verbatim). Second outer top-level
18241        // [`Caixa`] `Option<Copy>`-return supervisor-tree flat-spread
18242        // pin — folds on the sibling
18243        // `estrategia_returns_estrategia_option_verbatim_across_permutations`
18244        // (ed04d3c) pin's `Option<Copy>` shape, extending the sub-family
18245        // onto the sibling `Option<u32>` restart-budget-count arm.
18246        let fixtures: Vec<Option<u32>> = vec![None, Some(0), Some(5), Some(1000), Some(u32::MAX)];
18247        for max_restarts in fixtures {
18248            let c = caixa_with_max_restarts(max_restarts);
18249            assert_eq!(
18250                c.max_restarts(),
18251                max_restarts,
18252                "Caixa::max_restarts must return :max-restarts verbatim \
18253                 (got {:?}, expected {max_restarts:?})",
18254                c.max_restarts(),
18255            );
18256            assert_eq!(
18257                c.max_restarts(),
18258                c.max_restarts,
18259                "Caixa::max_restarts accessor and self.max_restarts \
18260                 field access must byte-equal — a presence-bit or count \
18261                 drift would silently split the paired \
18262                 Caixa::declared_supervisor_slots presence-probe arm \
18263                 from the Caixa::supervisor_view unwrap_or(5) fold's \
18264                 composition input",
18265            );
18266        }
18267    }
18268
18269    #[test]
18270    fn max_restarts_projects_option_by_copy() {
18271        // The by-`Copy` pin: [`Caixa::max_restarts`] returns
18272        // `Option<u32>` by value (`u32: Copy`) — the accessor does not
18273        // borrow `&self` past the call (no lifetime on the return type),
18274        // and calling the accessor twice on the same [`Caixa`] must
18275        // yield equal values (idempotent, no side effects). Peer of the
18276        // sibling `estrategia_projects_option_by_copy` (ed04d3c) pin on
18277        // the outer-`Caixa` `Option<Copy>`-return flat-spread axis.
18278        for max_restarts in [Some(0u32), Some(5), Some(1000), Some(u32::MAX), None] {
18279            let c = caixa_with_max_restarts(max_restarts);
18280            let first = c.max_restarts();
18281            let second = c.max_restarts();
18282            assert_eq!(
18283                first, second,
18284                "Caixa::max_restarts must be idempotent — two successive \
18285                 calls on the same &self must return the same Option<u32>",
18286            );
18287            assert_eq!(
18288                first, max_restarts,
18289                "Caixa::max_restarts must return :max-restarts verbatim \
18290                 by Copy — got {first:?}, expected {max_restarts:?}",
18291            );
18292        }
18293    }
18294
18295    #[test]
18296    fn declared_supervisor_slots_max_restarts_arm_routes_through_accessor() {
18297        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
18298        // `:max-restarts` presence-probe arm must key off
18299        // [`Caixa::max_restarts`], not the raw
18300        // `self.max_restarts.is_some()` field-probe. Structurally: every
18301        // `Caixa { max_restarts: Some(_), .. }` variant must push
18302        // `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS` onto the declared-slot
18303        // list (the presence bit is `Some` for every representative
18304        // count, so the M2 kind-coherence gate must surface the slot as
18305        // "declared"), and a `Caixa { max_restarts: None, .. }` must
18306        // NOT push the label. Peer of the sibling
18307        // `declared_supervisor_slots_estrategia_arm_routes_through_accessor`
18308        // (ed04d3c) composition pin — same routing-through-accessor
18309        // discipline extended onto the sibling flat-spread `Option<u32>`
18310        // arm.
18311        for max_restarts in [0u32, 5, 1000, u32::MAX] {
18312            let c = caixa_with_max_restarts(Some(max_restarts));
18313            let slots = c.declared_supervisor_slots();
18314            assert!(
18315                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
18316                "declared_supervisor_slots must push \
18317                 SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` \
18318                 is Some({max_restarts}) — the accessor and the \
18319                 enumerator gate must route through the same \
18320                 substrate-primitive typed dispatch on the outer \
18321                 :max-restarts presence bit (got slots={slots:?})",
18322            );
18323        }
18324        let c = caixa_with_max_restarts(None);
18325        let slots = c.declared_supervisor_slots();
18326        assert!(
18327            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
18328            "declared_supervisor_slots must NOT push \
18329             SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` is \
18330             None — the author-omitted arm must route through the \
18331             accessor's None-return unchanged (got slots={slots:?})",
18332        );
18333    }
18334
18335    #[test]
18336    fn supervisor_view_max_restarts_arm_routes_through_accessor() {
18337        // Composition pin: [`Caixa::supervisor_view`]'s per-`:max-restarts`
18338        // [`SupervisorSpec`] construction arm must key off
18339        // [`Caixa::max_restarts`]'s `unwrap_or(5)` fold, not the raw
18340        // `self.max_restarts.unwrap_or(5)` field-fold. Structurally: for
18341        // every `:kind Supervisor` `Caixa` carrying an author-declared
18342        // `Some(n)`, the composed [`SupervisorSpec`]'s `.max_restarts()`
18343        // must byte-equal `n`; and for a `:kind Supervisor` `Caixa`
18344        // carrying `None`, the composed [`SupervisorSpec`]'s
18345        // `.max_restarts()` must byte-equal the OTP-canonical `5`. Peer
18346        // of the sibling
18347        // `supervisor_view_estrategia_arm_routes_through_accessor`
18348        // (ed04d3c) composition pin.
18349        for max_restarts in [1u32, 5, 1000] {
18350            let c = caixa_supervisor_with_max_restarts_and_window(Some(max_restarts), None);
18351            let view = c.supervisor_view().expect(
18352                "supervisor_view must materialize a SupervisorSpec for a \
18353                 :kind Supervisor Caixa carrying a Some(:max-restarts)",
18354            );
18355            assert_eq!(
18356                view.max_restarts(),
18357                max_restarts,
18358                "supervisor_view must carry the outer \
18359                 Caixa::max_restarts() Some arm onto the composed \
18360                 SupervisorSpec.max_restarts field verbatim (got {}, \
18361                 expected {max_restarts})",
18362                view.max_restarts(),
18363            );
18364        }
18365        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18366        let view = c.supervisor_view().expect(
18367            "supervisor_view must materialize a SupervisorSpec for a \
18368             :kind Supervisor Caixa carrying a None :max-restarts",
18369        );
18370        assert_eq!(
18371            view.max_restarts(),
18372            5,
18373            "supervisor_view must project the outer \
18374             Caixa::max_restarts() None arm onto the OTP-canonical \
18375             {{intensity, 5, 60}} default (5) through the flat-spread \
18376             unwrap_or(5) fold (got {})",
18377            view.max_restarts(),
18378        );
18379        assert!(
18380            c.max_restarts().is_none(),
18381            "Caixa::max_restarts() must remain None on the author-\
18382             omitted arm — the supervisor_view fold must not mutate \
18383             the outer flat-spread presence bit",
18384        );
18385    }
18386
18387    #[test]
18388    fn supervisor_view_estrategia_fallback_routes_through_lifted_default() {
18389        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
18390        // `:estrategia` arm must degrade onto the substrate-canonical
18391        // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
18392        // `pub const` — the Erlang/OTP-canonical `one_for_one` strategy
18393        // half of Learn You Some Erlang's `{one_for_one, intensity, 5, 60}`
18394        // worker-supervisor default — rather than the transitively-
18395        // derived [`crate::supervisor::RestartStrategy::default`] route
18396        // the prior `.unwrap_or_default()` fold reached for. Prior to the
18397        // lift the composition site carried `.unwrap_or_default()` with
18398        // no compile-time link back to the shared OTP-canonical strategy
18399        // default that the paired [`crate::supervisor::Default for
18400        // RestartStrategy`] impl and the [`crate::supervisor::Default for
18401        // SupervisorSpec`] impl's struct-literal `estrategia` field both
18402        // (now) route through the same lifted constant — so a future
18403        // rebrand of the OTP-canonical strategy default (an OTP
18404        // `rest_for_one` widening once the substrate discovers startup-
18405        // order-coupled child cohorts as the more common worker-
18406        // supervisor shape, a per-cluster overlay the operator pins
18407        // through the MESH-COMPOSITION §III.2 supervision-canary
18408        // `:estrategia-overrides` roadmap slot) would have had to migrate
18409        // the paired `MaxIntensity` + `Period` halves through the lifted
18410        // constants and the `one_for_one` half through a
18411        // `RestartStrategy::default()` route in lockstep or a
18412        // `:kind Supervisor` caixa carrying an author-omitted
18413        // `:estrategia` slot would silently resolve to a `SupervisorSpec`
18414        // whose `estrategia` disagreed with the paired
18415        // `SupervisorSpec::default()` view. Byte-parity against the
18416        // lifted constant closes the split. Peer of the sibling
18417        // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
18418        // composition pin on the paired `MaxIntensity` half + the
18419        // [`crate::supervisor::restart_strategy_default_routes_through_lifted_default`]
18420        // + [`crate::supervisor::supervisor_spec_default_estrategia_routes_through_lifted_default`]
18421        // pins on the sibling entry points onto the shared substrate
18422        // constant.
18423        use crate::CaixaKind;
18424        use crate::supervisor::{ChildSpec, RestartPolicy};
18425        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
18426        c.kind = CaixaKind::Supervisor;
18427        c.estrategia = None;
18428        c.children = vec![ChildSpec {
18429            caixa: "worker".into(),
18430            versao: "^0.1".into(),
18431            restart: RestartPolicy::Permanent,
18432        }];
18433        let view = c.supervisor_view().expect(
18434            "supervisor_view must materialize a SupervisorSpec for a \
18435             :kind Supervisor Caixa carrying a None :estrategia",
18436        );
18437        assert_eq!(
18438            view.estrategia(),
18439            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
18440            "supervisor_view must degrade the outer \
18441             Caixa::estrategia() None arm onto the lifted \
18442             SUPERVISOR_ESTRATEGIA_DEFAULT typed pub const (got {:?}, \
18443             expected {:?})",
18444            view.estrategia(),
18445            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
18446        );
18447    }
18448
18449    #[test]
18450    fn supervisor_view_max_restarts_fallback_routes_through_lifted_default() {
18451        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
18452        // `:max-restarts` arm must degrade onto the substrate-canonical
18453        // [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`] typed
18454        // `pub const` — the Erlang/OTP-canonical `{intensity, 5, 60}`
18455        // `MaxIntensity` default — rather than a raw `5` literal. Prior
18456        // to the lift the composition site carried an inline
18457        // `.unwrap_or(5)` with no compile-time link back to the shared
18458        // OTP-canonical default that the serde-side
18459        // `#[serde(default = "default_max_restarts")]` wire-format arm
18460        // and the [`Default for crate::supervisor::SupervisorSpec`]
18461        // struct-literal default arm both key off — so a future rebrand
18462        // of the OTP-canonical default (Elixir's `Supervisor` `3`
18463        // default, a per-cluster overlay the operator pins through the
18464        // MESH-COMPOSITION §III.2 supervision-canary
18465        // `:supervisor :max-restarts-overrides` roadmap slot) would
18466        // have had to be threaded through both the serde-side helper
18467        // and this view-construction arm in lockstep or a `:kind
18468        // Supervisor` caixa carrying `:max-restarts ()` would silently
18469        // resolve to a `SupervisorSpec` whose `max_restarts` disagreed
18470        // with the same fixture's serde-side `SupervisorSpec` view (an
18471        // author-omitted slot round-tripping through
18472        // `SupervisorSpec::default()` to the lifted constant, then
18473        // splitting to a stale literal past `supervisor_view`).
18474        // Byte-parity against the lifted constant closes the split.
18475        // Peer of the sibling
18476        // [`crate::supervisor::default_max_restarts_helper_routes_through_lifted_default`]
18477        // + [`crate::supervisor::supervisor_spec_default_max_restarts_routes_through_lifted_default`]
18478        // composition pins that close the same routing on the two
18479        // sibling entry points onto the shared substrate constant.
18480        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18481        let view = c.supervisor_view().expect(
18482            "supervisor_view must materialize a SupervisorSpec for a \
18483             :kind Supervisor Caixa carrying a None :max-restarts",
18484        );
18485        assert_eq!(
18486            view.max_restarts(),
18487            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
18488            "supervisor_view must degrade the outer \
18489             Caixa::max_restarts() None arm onto the lifted \
18490             SUPERVISOR_MAX_RESTARTS_DEFAULT typed pub const (got {}, \
18491             expected {})",
18492            view.max_restarts(),
18493            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
18494        );
18495    }
18496
18497    #[test]
18498    fn restart_window_returns_restart_window_option_verbatim_across_permutations() {
18499        // Value-shape pin: [`Caixa::restart_window`] returns the
18500        // `:restart-window` typed `Option<String>` verbatim as an
18501        // `Option<&str>`, borrowed from the typed slot's own storage,
18502        // byte-equal across the author-omitted `None` arm and each of
18503        // the representative fixtures in the accept-set — the canonical
18504        // `"60s"` from `{intensity, 5, 60}`, the sibling
18505        // canonical-magnitude forms (`"5m"` / `"1h"` / `"500ms"` / `"30"`
18506        // / `"0s"`) the shared codec's positive-set sweep pin covers,
18507        // plus a past-the-guard sentinel (`"1.5s"` — the fractional-
18508        // seconds drift the sibling [`Self::validate_restart_window`]
18509        // gate refuses; the accessor must ship the raw slot verbatim
18510        // so struct-literal fixtures continue to expose the drift at
18511        // the accessor boundary). Third outer top-level [`Caixa`]
18512        // supervisor-tree flat-spread pin — extends the sub-family onto
18513        // the sibling `Option<&str>` raw-duration-string arm.
18514        for window in [
18515            None,
18516            Some("60s"),
18517            Some("5m"),
18518            Some("1h"),
18519            Some("500ms"),
18520            Some("1.5s"),
18521            Some(""),
18522        ] {
18523            let c = caixa_with_restart_window(window);
18524            assert_eq!(
18525                c.restart_window(),
18526                window,
18527                "Caixa::restart_window must return :restart-window \
18528                 verbatim as Option<&str> (got {:?}, expected {window:?})",
18529                c.restart_window(),
18530            );
18531            assert_eq!(
18532                c.restart_window(),
18533                c.restart_window.as_deref(),
18534                "Caixa::restart_window accessor and \
18535                 self.restart_window.as_deref() field access must \
18536                 byte-equal — a byte-level drift would silently split \
18537                 the paired Caixa::declared_supervisor_slots \
18538                 presence-probe arm from the \
18539                 Caixa::validate_restart_window shared-codec gate and \
18540                 the Caixa::supervisor_view soft-swallowing fold",
18541            );
18542        }
18543    }
18544
18545    #[test]
18546    fn restart_window_projects_slice_by_borrow() {
18547        // The by-borrow pin: [`Caixa::restart_window`] returns
18548        // `Option<&str>` by borrow — the returned string slice borrows
18549        // the underlying `Option<String>` storage of the `:restart-window`
18550        // slot and the accessor must not clone on every call. Peer of
18551        // the sibling outer top-level [`Caixa`] `Option<&str>`-return
18552        // by-borrow pins on the universal-axis scalar family
18553        // (`licenca_projects_option_ref_by_borrow` /
18554        // `descricao_projects_option_ref_by_borrow` and siblings) —
18555        // extended onto the M2 supervisor-tree flat-spread
18556        // `Option<&str>` raw-duration-string axis.
18557        for window in [None, Some("60s"), Some("5m"), Some("")] {
18558            let c = caixa_with_restart_window(window);
18559            let first = c.restart_window();
18560            let second = c.restart_window();
18561            assert_eq!(
18562                first, second,
18563                "Caixa::restart_window must be idempotent — two \
18564                 successive calls on the same &self must return the \
18565                 same Option<&str>",
18566            );
18567            if let (Some(a), Some(b)) = (first, second) {
18568                assert_eq!(
18569                    a.as_ptr(),
18570                    b.as_ptr(),
18571                    "Caixa::restart_window must borrow the underlying \
18572                     String storage — two successive Some-arm calls must \
18573                     return slices with the same backing pointer (a fresh \
18574                     String clone would change the pointer on every call)",
18575                );
18576            }
18577            assert_eq!(
18578                first, window,
18579                "Caixa::restart_window must return :restart-window \
18580                 verbatim by borrow — got {first:?}, expected {window:?}",
18581            );
18582        }
18583    }
18584
18585    #[test]
18586    fn declared_supervisor_slots_restart_window_arm_routes_through_accessor() {
18587        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
18588        // `:restart-window` presence-probe arm must key off
18589        // [`Caixa::restart_window`], not the raw
18590        // `self.restart_window.is_some()` field-probe. Structurally:
18591        // every `Caixa { restart_window: Some(_), .. }` must push
18592        // `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` onto the declared-slot
18593        // list, and a `Caixa { restart_window: None, .. }` must NOT
18594        // push the label. Peer of the sibling
18595        // `declared_supervisor_slots_max_restarts_arm_routes_through_accessor`
18596        // routing pin.
18597        for window in ["60s", "5m", "1h", "500ms", "1.5s", ""] {
18598            let c = caixa_with_restart_window(Some(window));
18599            let slots = c.declared_supervisor_slots();
18600            assert!(
18601                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
18602                "declared_supervisor_slots must push \
18603                 SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when \
18604                 `:restart-window` is Some({window:?}) — the accessor \
18605                 and the enumerator gate must route through the same \
18606                 substrate-primitive typed dispatch on the outer \
18607                 :restart-window presence bit (got slots={slots:?})",
18608            );
18609        }
18610        let c = caixa_with_restart_window(None);
18611        let slots = c.declared_supervisor_slots();
18612        assert!(
18613            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
18614            "declared_supervisor_slots must NOT push \
18615             SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when `:restart-window` \
18616             is None — the author-omitted arm must route through the \
18617             accessor's None-return unchanged (got slots={slots:?})",
18618        );
18619    }
18620
18621    #[test]
18622    fn validate_restart_window_arm_routes_through_accessor() {
18623        // Composition pin: [`Caixa::validate_restart_window`]'s
18624        // shared-codec fold arm must key off [`Caixa::restart_window`],
18625        // not the raw `self.restart_window.as_deref()` field-projection.
18626        // Structurally: (1) `None` → `Ok(())` (the "omit the slot to
18627        // express no reset" canonical shape); (2) a canonical `Some`
18628        // arm (`"60s"`) → `Ok(())`; (3) a codec-rejected `Some` arm
18629        // (`"1.5s"`) → `Err(RestartWindowMalformed { restart_window,
18630        // .. })` carrying the offending raw string verbatim. The three
18631        // arms jointly pin that the validator's raw-string binding is
18632        // the accessor's return, not a peer projection — any future
18633        // silent detour that had the accessor collapse `Some("")` to
18634        // `None` would silently absorb the empty-after-trim refusal
18635        // case at the accessor boundary.
18636        caixa_with_restart_window(None)
18637            .validate_restart_window()
18638            .expect("None :restart-window must validate through the accessor");
18639        caixa_with_restart_window(Some("60s"))
18640            .validate_restart_window()
18641            .expect("canonical :restart-window \"60s\" must validate through the accessor");
18642        let err = caixa_with_restart_window(Some("1.5s"))
18643            .validate_restart_window()
18644            .expect_err("fractional-seconds :restart-window must fail through the accessor");
18645        assert!(
18646            matches!(
18647                err,
18648                ManifestError::RestartWindowMalformed { ref restart_window, .. }
18649                    if restart_window == "1.5s"
18650            ),
18651            "validator must carry the offending raw string verbatim \
18652             from the accessor's borrowed &str (got {err:?})",
18653        );
18654    }
18655
18656    #[test]
18657    fn supervisor_view_restart_window_arm_routes_through_accessor() {
18658        // Composition pin: [`Caixa::supervisor_view`]'s
18659        // per-`:restart-window` [`SupervisorSpec`] construction arm
18660        // must key off [`Caixa::restart_window`]'s soft-swallowing
18661        // `.and_then(|s| duration_codec::parse(s).ok())` fold, not the
18662        // raw `self.restart_window.as_deref().and_then(…)` field-fold.
18663        // Structurally: (1) `None` → `SupervisorSpec.restart_window ==
18664        // None` (the "never reset" sentinel); (2) canonical `Some("60s")`
18665        // → `SupervisorSpec.restart_window == Some(Duration::from_secs(60))`
18666        // (the shared codec's canonical parse); (3) codec-rejected
18667        // `Some("1.5s")` → `SupervisorSpec.restart_window == None`
18668        // (the soft-swallow preserving the view's best-effort shape).
18669        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18670        let view = c.supervisor_view().expect("Supervisor kind has a view");
18671        assert_eq!(
18672            view.restart_window(),
18673            None,
18674            "supervisor_view must project outer None :restart-window \
18675             onto None on the composed SupervisorSpec (never-reset \
18676             sentinel) through the accessor's None-return unchanged",
18677        );
18678
18679        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("60s"));
18680        let view = c.supervisor_view().expect("Supervisor kind has a view");
18681        assert_eq!(
18682            view.restart_window(),
18683            Some(std::time::Duration::from_secs(60)),
18684            "supervisor_view must fold outer Some(\"60s\") through the \
18685             shared duration_codec into Duration::from_secs(60) on the \
18686             composed SupervisorSpec (accessor's Some(&str) → codec \
18687             parse → Some(Duration))",
18688        );
18689
18690        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("1.5s"));
18691        let view = c.supervisor_view().expect("Supervisor kind has a view");
18692        assert_eq!(
18693            view.restart_window(),
18694            None,
18695            "supervisor_view must soft-swallow the shared-codec parse \
18696             failure to None (the view's best-effort shape the sibling \
18697             manifest-level validate_restart_window surfaces as \
18698             RestartWindowMalformed); the accessor's raw-string return \
18699             is the single input every downstream consumer keys off",
18700        );
18701    }
18702
18703    // ── Caixa::upgrade_from — outer top-level &[UpgradeFromEntry] composite-slice accessor ──
18704
18705    fn caixa_with_upgrade_from(upgrade_from: Vec<crate::upgrade::UpgradeFromEntry>) -> Caixa {
18706        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18707        c.upgrade_from = upgrade_from;
18708        c
18709    }
18710
18711    #[test]
18712    fn upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations() {
18713        // The canonical per-`Caixa` `:upgrade-from` M2 typed-slot
18714        // outer-composite `&[UpgradeFromEntry]`-return slice-shape
18715        // pin: [`Caixa::upgrade_from`] must return the `:upgrade-from`
18716        // typed `Vec<UpgradeFromEntry>` verbatim as a
18717        // `&[UpgradeFromEntry]` slice-view over the same backing
18718        // buffer the raw `self.upgrade_from.as_slice()` field access
18719        // borrows from, element-equal across every representative
18720        // fixture in the accept-set — `[]` (the "no hot-upgrade path
18721        // declared" arm every `defcaixa` without an `:upgrade-from`
18722        // block carries; `#[serde(default)]` folds an omitted slot
18723        // onto `Vec::new()`), a canonical single-entry `Restart`
18724        // fixture (the shape most Servicos carry — a single prior
18725        // version with the fallback strategy), a canonical multi-
18726        // entry list carrying every typed instruction variant
18727        // (`LoadModule` / `StateChange` / `SoftPurge` / `Purge` /
18728        // `Restart`), and a past-the-guard sentinel — a duplicate-
18729        // `:from` `[(0.1.0, Restart), (0.1.0, Restart)]` entry pair
18730        // ([`crate::upgrade::validate_upgrade_from`] rejects through
18731        // `DuplicateFrom { from: "0.1.0" }` but the accessor must
18732        // ship the raw slot verbatim so struct-literal fixtures
18733        // continue to expose the duplicate at the accessor boundary).
18734        //
18735        // Pins against a future silent detour that returned an owned
18736        // `Vec<UpgradeFromEntry>` (which would type-check but silently
18737        // clone on every accessor call, breaking the zero-cost
18738        // projection every peer sibling slice accessor carries), a
18739        // `[dup, dup] → [dup]` dedup collapse (which would silently
18740        // absorb the `DuplicateFrom` refusal case at the accessor
18741        // boundary and the [`crate::StandardLayout::verify`] cross-
18742        // entry gate would silently accept a struct-literal `Caixa`
18743        // carrying the drift), a reference to an operator-resolved
18744        // overlay (the future per-cluster `:upgrade-overrides` slot
18745        // — its resolution must land at exactly this accessor body,
18746        // not silently divert the raw slot away from a second
18747        // consumer), or an axis-shuffled projection (a future detour
18748        // that reordered entries through the accessor would silently
18749        // split the paired [`crate::StandardLayout::verify`] per-
18750        // `:upgrade-from` shape gate's traversal input from the peer
18751        // [`crate::render::servico_m2_overlay`] emitter's projection
18752        // input, since the operator's hot-upgrade dispatch matches
18753        // per-`:from` and axis reordering would silently split the
18754        // per-entry script-path existence probe's iteration order
18755        // from the M2 overlay emitter's serialized-entry order).
18756        //
18757        // First outer top-level [`Caixa`] `&[Composite]`-return
18758        // slice accessor pin on the substrate primitive for M2 / M3
18759        // typed-slot vec-carry axes — opens the outer-`Caixa`
18760        // `&[Composite]` composite-slice projection pattern the
18761        // sibling `:children` [`crate::supervisor::ChildSpec`] /
18762        // `:membros` [`crate::aplicacao::Membro`] / `:contratos`
18763        // [`crate::aplicacao::WitContract`] future outer-composite-
18764        // slice pins fold on. Peer of the closed outer-`Caixa`
18765        // scalar `Option<&Composite>` composite-reference family the
18766        // sibling `limits` / `behavior` / `politicas` / `placement`
18767        // / `entrada` `..._returns_..._option_ref_verbatim_across_
18768        // permutations` pins closed (b2bd9d7 → e4128e4) — extends
18769        // the "byte-equal, borrow-shared" outer-accessor discipline
18770        // onto the outer-`Caixa` `&[Composite]` vec-carry altitude.
18771        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18772        let fixtures: Vec<Vec<UpgradeFromEntry>> = vec![
18773            vec![],
18774            vec![UpgradeFromEntry {
18775                from: "0.0.1".into(),
18776                instructions: vec![UpgradeInstruction::Restart],
18777            }],
18778            vec![
18779                UpgradeFromEntry {
18780                    from: "0.0.1".into(),
18781                    instructions: vec![
18782                        UpgradeInstruction::LoadModule {
18783                            module: "demo".into(),
18784                        },
18785                        UpgradeInstruction::SoftPurge {
18786                            module: "demo".into(),
18787                        },
18788                    ],
18789                },
18790                UpgradeFromEntry {
18791                    from: "0.0.2".into(),
18792                    instructions: vec![
18793                        UpgradeInstruction::StateChange {
18794                            script: "servicos/upgrade.lisp".into(),
18795                        },
18796                        UpgradeInstruction::Purge {
18797                            module: "demo".into(),
18798                        },
18799                        UpgradeInstruction::Restart,
18800                    ],
18801                },
18802            ],
18803            vec![
18804                UpgradeFromEntry {
18805                    from: "0.1.0".into(),
18806                    instructions: vec![UpgradeInstruction::Restart],
18807                },
18808                UpgradeFromEntry {
18809                    from: "0.1.0".into(),
18810                    instructions: vec![UpgradeInstruction::Restart],
18811                },
18812            ],
18813        ];
18814        for upgrade_from in fixtures {
18815            let c = caixa_with_upgrade_from(upgrade_from.clone());
18816            assert_eq!(
18817                c.upgrade_from(),
18818                upgrade_from.as_slice(),
18819                "Caixa::upgrade_from must return :upgrade-from \
18820                 verbatim (got {:?}, expected {upgrade_from:?})",
18821                c.upgrade_from(),
18822            );
18823            assert_eq!(
18824                c.upgrade_from(),
18825                c.upgrade_from.as_slice(),
18826                "Caixa::upgrade_from must element-equal the raw \
18827                 `self.upgrade_from.as_slice()` field access across \
18828                 every value in the Vec<UpgradeFromEntry> accept-set",
18829            );
18830            assert_eq!(
18831                c.upgrade_from().is_empty(),
18832                c.upgrade_from.is_empty(),
18833                "Caixa::upgrade_from().is_empty() must byte-equal \
18834                 self.upgrade_from.is_empty() — a presence-bit drift \
18835                 would silently split the paired \
18836                 Caixa::declared_servico_slots M2 declared-slot \
18837                 enumerator's presence probe from the peer \
18838                 crate::render::servico_m2_overlay M2 overlay \
18839                 emitter's presence gate",
18840            );
18841        }
18842    }
18843
18844    #[test]
18845    fn declared_servico_slots_upgrade_from_arm_routes_through_accessor() {
18846        // Composition pin: [`Caixa::declared_servico_slots`]'s
18847        // `:upgrade-from` presence-probe arm must key off
18848        // [`Caixa::upgrade_from`], not the raw
18849        // `self.upgrade_from.is_empty()` field-probe. Structurally: a
18850        // `Caixa { upgrade_from: vec![UpgradeFromEntry { from: "0.0.1",
18851        // instructions: vec![Restart] }], .. }` must push
18852        // `M2_AUTHOR_KEY_UPGRADE_FROM` onto the declared-slot list
18853        // (the presence bit is non-empty, so the M2 kind-coherence
18854        // gate must surface the slot as "declared"), and a `Caixa {
18855        // upgrade_from: vec![], .. }` must NOT push the label (the
18856        // "author omitted the slot entirely" arm — the empty-slice
18857        // partition the serde-default folds onto). The pair jointly
18858        // pins the accessor + declared-slot enumerator composition:
18859        // any future silent detour that had the accessor collapse
18860        // `[Restart]` to `[]` (a `.filter(|e| !e.instructions.
18861        // is_empty())` projection) would silently absorb the
18862        // "declared but degenerate" arm at the accessor boundary and
18863        // the [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-
18864        // coherence gate would silently accept a struct-literal
18865        // `Caixa` carrying the drift.
18866        //
18867        // Peer of the sibling
18868        // `declared_servico_slots_limits_arm_routes_through_accessor`
18869        // (b2bd9d7) and
18870        // `declared_servico_slots_behavior_arm_routes_through_accessor`
18871        // (35d8b52) composition pins on the sibling `:limits` /
18872        // `:behavior` outer-`Option<&Composite>` arms — same "the
18873        // enumerator gate must route through the substrate-primitive
18874        // typed dispatch" discipline extended onto the third M2
18875        // Servico-runtime slot axis, closing the enumerator's routing
18876        // invariant on every M2 arm.
18877        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18878        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
18879            from: "0.0.1".into(),
18880            instructions: vec![UpgradeInstruction::Restart],
18881        }]);
18882        let slots = c.declared_servico_slots();
18883        assert!(
18884            slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
18885            "declared_servico_slots must push \
18886             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
18887             non-empty — the accessor and the enumerator gate must \
18888             route through the same substrate-primitive typed \
18889             dispatch on the outer :upgrade-from presence bit (got \
18890             slots={slots:?})",
18891        );
18892        let c = caixa_with_upgrade_from(vec![]);
18893        let slots = c.declared_servico_slots();
18894        assert!(
18895            !slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
18896            "declared_servico_slots must NOT push \
18897             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
18898             empty — the author-omitted arm must route through the \
18899             accessor's empty-slice return unchanged (got \
18900             slots={slots:?})",
18901        );
18902    }
18903
18904    #[test]
18905    fn servico_m2_overlay_upgrade_from_arm_routes_through_accessor() {
18906        // Composition pin: [`crate::render::servico_m2_overlay`]'s
18907        // per-`:upgrade-from` M2 overlay emit arm must key off
18908        // [`Caixa::upgrade_from`], not the raw
18909        // `!caixa.upgrade_from.is_empty()` presence gate + the
18910        // `serde_yaml::to_value(&caixa.upgrade_from)` projection.
18911        // Structurally: a `Caixa { upgrade_from: vec![UpgradeFromEntry
18912        // { from: "0.0.1", instructions: vec![Restart] }], .. }` must
18913        // surface the `M2_KEY_UPGRADE_FROM` key with a per-entry
18914        // sequence in the overlay (the emitter fans onto the serde
18915        // slice-serialization), and a `Caixa { upgrade_from: vec![],
18916        // .. }` must omit the key entirely (the empty-slice
18917        // partition — the `!.is_empty()` outer gate elides the key
18918        // when the author omitted the slot). The pair jointly pins
18919        // the accessor + M2 overlay emitter composition: any future
18920        // silent detour that had the accessor return a fresh-cloned
18921        // `Vec<UpgradeFromEntry>` copy would silently break the
18922        // reference-identity pin the peer per-entry
18923        // `serde_yaml::to_value(caixa.upgrade_from())` projection
18924        // reads from — the projection would clone once per accessor
18925        // call instead of borrowing the storage buffer verbatim.
18926        //
18927        // Peer of the sibling
18928        // `servico_m2_overlay_limits_arm_routes_through_accessor`
18929        // (b2bd9d7) and
18930        // `servico_m2_overlay_behavior_arm_routes_through_accessor`
18931        // (35d8b52) composition pins on the sibling `:limits` /
18932        // `:behavior` outer-`Option<&Composite>` arms — same "the
18933        // M2 overlay emitter must route through the substrate-
18934        // primitive typed dispatch" discipline extended onto the
18935        // third M2 Servico-runtime slot axis, closing the overlay
18936        // emitter's routing invariant on every M2 arm.
18937        use crate::render::{M2_KEY_UPGRADE_FROM, servico_m2_overlay};
18938        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18939        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
18940            from: "0.0.1".into(),
18941            instructions: vec![UpgradeInstruction::Restart],
18942        }]);
18943        let overlay = servico_m2_overlay(&c).unwrap();
18944        assert!(
18945            overlay.contains_key(M2_KEY_UPGRADE_FROM),
18946            "servico_m2_overlay must surface M2_KEY_UPGRADE_FROM when \
18947             `:upgrade-from` is non-empty — the accessor and the M2 \
18948             overlay emitter must route through the same substrate- \
18949             primitive typed dispatch on the outer :upgrade-from \
18950             slice (got overlay={overlay:?})",
18951        );
18952        let c = caixa_with_upgrade_from(vec![]);
18953        let overlay = servico_m2_overlay(&c).unwrap();
18954        assert!(
18955            !overlay.contains_key(M2_KEY_UPGRADE_FROM),
18956            "servico_m2_overlay must omit M2_KEY_UPGRADE_FROM when \
18957             `:upgrade-from` is empty — the empty-slice partition \
18958             must route through the accessor's empty-slice return \
18959             unchanged (got overlay={overlay:?})",
18960        );
18961    }
18962
18963    #[test]
18964    fn upgrade_from_projects_slice_by_borrow() {
18965        // The by-borrow pin: [`Caixa::upgrade_from`] returns
18966        // `&[UpgradeFromEntry]` by borrow — the returned slice
18967        // borrows the underlying `Vec<UpgradeFromEntry>` storage of
18968        // the `:upgrade-from` slot and the accessor must not clone
18969        // the backing `Vec` on every call. Peer of the sibling
18970        // outer top-level [`Caixa`] `&[T]`-return by-borrow pins
18971        // (`autores_projects_slice_by_borrow` b5d813f,
18972        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
18973        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
18974        // `exe_projects_slice_by_borrow` 65d9527,
18975        // `servicos_projects_slice_by_borrow` 611f78b,
18976        // `deps_projects_slice_by_borrow` ad34b4e,
18977        // `deps_dev_projects_slice_by_borrow` f7fd81e) on the
18978        // sibling outer top-level [`Caixa`] scalar-element `&[T]`
18979        // axes — extended here to the first outer-`Caixa`
18980        // composite-element `&[Composite]` axis: the accessor's
18981        // returned slice must borrow from `&self` (the returned
18982        // reference's lifetime is tied to `&self`), and calling the
18983        // accessor twice on the same [`Caixa`] must yield slices
18984        // that are pointer-equal (the underlying byte-buffer is the
18985        // storage `Vec`'s allocation, not a fresh copy) as well as
18986        // value-equal (idempotent, no side effects on `&self`).
18987        //
18988        // Pins against a future silent detour that returned an owned
18989        // `Vec<UpgradeFromEntry>` (which would type-check but
18990        // silently clone on every call), a `&Vec<UpgradeFromEntry>`
18991        // return (which would leak the backing `Vec`'s
18992        // grow/push/reserve surface no downstream consumer reaches
18993        // for), or a one-arm-only accessor that returned a
18994        // saturating value on some sentinel input.
18995        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18996        for upgrade_from in [
18997            vec![],
18998            vec![UpgradeFromEntry {
18999                from: "0.0.1".into(),
19000                instructions: vec![UpgradeInstruction::Restart],
19001            }],
19002            vec![
19003                UpgradeFromEntry {
19004                    from: "0.0.1".into(),
19005                    instructions: vec![UpgradeInstruction::Restart],
19006                },
19007                UpgradeFromEntry {
19008                    from: "0.0.2".into(),
19009                    instructions: vec![UpgradeInstruction::SoftPurge {
19010                        module: "demo".into(),
19011                    }],
19012                },
19013            ],
19014        ] {
19015            let c = caixa_with_upgrade_from(upgrade_from.clone());
19016            let first = c.upgrade_from();
19017            let second = c.upgrade_from();
19018            assert_eq!(
19019                first, second,
19020                "Caixa::upgrade_from must be idempotent — two \
19021                 successive calls on the same &self must return the \
19022                 same &[UpgradeFromEntry]",
19023            );
19024            assert_eq!(
19025                first.as_ptr(),
19026                second.as_ptr(),
19027                "Caixa::upgrade_from must borrow the underlying \
19028                 Vec<UpgradeFromEntry> storage — two successive calls \
19029                 must return slices with the same backing pointer (a \
19030                 fresh Vec<UpgradeFromEntry> clone would change the \
19031                 pointer on every call)",
19032            );
19033            assert_eq!(
19034                first,
19035                upgrade_from.as_slice(),
19036                "Caixa::upgrade_from must return :upgrade-from \
19037                 verbatim by borrow — got {first:?}, expected \
19038                 {upgrade_from:?}",
19039            );
19040        }
19041    }
19042
19043    // ── Caixa::children — outer top-level &[ChildSpec] composite-slice accessor ──
19044
19045    fn caixa_with_children(children: Vec<crate::supervisor::ChildSpec>) -> Caixa {
19046        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19047        c.children = children;
19048        c
19049    }
19050
19051    #[test]
19052    fn children_returns_children_slice_verbatim_across_permutations() {
19053        // The canonical per-`Caixa` `:children` M2 supervisor-tree-slot
19054        // outer-composite `&[ChildSpec]`-return slice-shape pin:
19055        // [`Caixa::children`] must return the `:children` typed
19056        // `Vec<ChildSpec>` verbatim as a `&[ChildSpec]` slice-view over
19057        // the same backing buffer the raw `self.children.as_slice()`
19058        // field access borrows from, element-equal across every
19059        // representative fixture in the accept-set — `[]` (the "no
19060        // static children declared" arm every non-`Supervisor`-kind
19061        // `defcaixa` carries by `#[serde(default)]` and every
19062        // `SimpleOneForOne` supervisor carries by cross-slot refusal),
19063        // a canonical single-child `Permanent` fixture (the shape
19064        // most `OneForOne` supervisors carry — a single long-running
19065        // worker child), a canonical multi-child list carrying every
19066        // typed restart-policy variant (`Permanent` / `Transient` /
19067        // `Temporary`), and a past-the-guard sentinel — a duplicate
19068        // `:caixa` `[("w", ...), ("w", ...)]` entry pair
19069        // ([`crate::SupervisorSpec::validate`] rejects through
19070        // `DuplicateChildNome { nome: "w" }` but the accessor must
19071        // ship the raw slot verbatim so struct-literal fixtures
19072        // continue to expose the duplicate at the accessor boundary).
19073        //
19074        // Pins against a future silent detour that returned an owned
19075        // `Vec<ChildSpec>` (which would type-check but silently clone
19076        // on every accessor call, breaking the zero-cost projection
19077        // every peer sibling slice accessor carries), a `[dup, dup] →
19078        // [dup]` dedup collapse (which would silently absorb the
19079        // `DuplicateChildNome` refusal case at the accessor boundary
19080        // and the [`crate::StandardLayout::verify`] cross-child gate
19081        // would silently accept a struct-literal `Caixa` carrying the
19082        // drift), a reference to an operator-resolved overlay (the
19083        // future per-cluster `:children-overrides` slot — its
19084        // resolution must land at exactly this accessor body, not
19085        // silently divert the raw slot away from a second consumer),
19086        // or an axis-shuffled projection (a future detour that
19087        // reordered children through the accessor would silently
19088        // split the paired [`crate::StandardLayout::verify`] per-
19089        // supervisor gate's traversal input from the peer
19090        // [`Self::supervisor_view`] fold-in path's clone-order input,
19091        // since the OTP `RestForOne` restart strategy dispatches on
19092        // declared child order and axis reordering would silently
19093        // split the operator's per-cluster restart-fan-out order
19094        // from the caixa.lisp source-order).
19095        //
19096        // Second outer top-level [`Caixa`] `&[Composite]`-return slice
19097        // accessor pin on the substrate primitive for M2 / M3 typed-
19098        // slot vec-carry axes — folds on the outer-`Caixa`
19099        // `&[Composite]` composite-slice sub-family the sibling
19100        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19101        // (2a1f907) pin opened, peer at the outer altitude of the
19102        // closed inner-`SupervisorSpec` `SupervisorSpec::children`
19103        // (bc92bce) accessor on the same OTP-supervisor static-child-
19104        // list axis.
19105        use crate::supervisor::{ChildSpec, RestartPolicy};
19106        let fixtures: Vec<Vec<ChildSpec>> = vec![
19107            vec![],
19108            vec![ChildSpec {
19109                caixa: "worker".into(),
19110                versao: "^0.1".into(),
19111                restart: RestartPolicy::Permanent,
19112            }],
19113            vec![
19114                ChildSpec {
19115                    caixa: "worker-a".into(),
19116                    versao: "^0.1".into(),
19117                    restart: RestartPolicy::Permanent,
19118                },
19119                ChildSpec {
19120                    caixa: "worker-b".into(),
19121                    versao: "^0.1".into(),
19122                    restart: RestartPolicy::Transient,
19123                },
19124                ChildSpec {
19125                    caixa: "worker-c".into(),
19126                    versao: "^0.1".into(),
19127                    restart: RestartPolicy::Temporary,
19128                },
19129            ],
19130            vec![
19131                ChildSpec {
19132                    caixa: "w".into(),
19133                    versao: "^0.1".into(),
19134                    restart: RestartPolicy::Permanent,
19135                },
19136                ChildSpec {
19137                    caixa: "w".into(),
19138                    versao: "^0.1".into(),
19139                    restart: RestartPolicy::Permanent,
19140                },
19141            ],
19142        ];
19143        for children in fixtures {
19144            let c = caixa_with_children(children.clone());
19145            assert_eq!(
19146                c.children(),
19147                children.as_slice(),
19148                "Caixa::children must return :children verbatim \
19149                 (got {:?}, expected {children:?})",
19150                c.children(),
19151            );
19152            assert_eq!(
19153                c.children(),
19154                c.children.as_slice(),
19155                "Caixa::children must element-equal the raw \
19156                 `self.children.as_slice()` field access across \
19157                 every value in the Vec<ChildSpec> accept-set",
19158            );
19159            assert_eq!(
19160                c.children().is_empty(),
19161                c.children.is_empty(),
19162                "Caixa::children().is_empty() must byte-equal \
19163                 self.children.is_empty() — a presence-bit drift \
19164                 would silently split the paired \
19165                 Caixa::declared_supervisor_slots supervisor-tree \
19166                 declared-slot enumerator's presence probe from the \
19167                 peer Caixa::supervisor_view typed-view composer's \
19168                 fold-in path",
19169            );
19170        }
19171    }
19172
19173    #[test]
19174    fn declared_supervisor_slots_children_arm_routes_through_accessor() {
19175        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
19176        // `:children` presence-probe arm must key off
19177        // [`Caixa::children`], not the raw
19178        // `!self.children.is_empty()` field-probe. Structurally: a
19179        // `Caixa { children: vec![ChildSpec { caixa: "w", versao:
19180        // "^0.1", restart: Permanent }], .. }` must push
19181        // `SUPERVISOR_AUTHOR_KEY_CHILDREN` onto the declared-slot list
19182        // (the presence bit is non-empty, so the supervisor-tree
19183        // kind-coherence gate must surface the slot as "declared"),
19184        // and a `Caixa { children: vec![], .. }` must NOT push the
19185        // label (the "author omitted the slot entirely" arm — the
19186        // empty-slice partition the serde-default folds onto). The
19187        // pair jointly pins the accessor + declared-slot enumerator
19188        // composition: any future silent detour that had the accessor
19189        // collapse `[Permanent]` to `[]` (a `.filter(|c| c.nome() !=
19190        // "__reserved__")` projection) would silently absorb the
19191        // "declared but degenerate" arm at the accessor boundary and
19192        // the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
19193        // kind-coherence gate would silently accept a struct-literal
19194        // `Caixa` carrying the drift.
19195        //
19196        // Peer of the sibling
19197        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19198        // (2a1f907) on the M2 `:upgrade-from` composite-slice arm —
19199        // same "the enumerator gate must route through the substrate-
19200        // primitive typed dispatch" discipline extended onto the
19201        // supervisor-tree `:children` composite-slice arm.
19202        use crate::supervisor::{ChildSpec, RestartPolicy};
19203        let c = caixa_with_children(vec![ChildSpec {
19204            caixa: "w".into(),
19205            versao: "^0.1".into(),
19206            restart: RestartPolicy::Permanent,
19207        }]);
19208        let slots = c.declared_supervisor_slots();
19209        assert!(
19210            slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
19211            "declared_supervisor_slots must push \
19212             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
19213             non-empty — the accessor and the enumerator gate must \
19214             route through the same substrate-primitive typed \
19215             dispatch on the outer :children presence bit (got \
19216             slots={slots:?})",
19217        );
19218        let c = caixa_with_children(vec![]);
19219        let slots = c.declared_supervisor_slots();
19220        assert!(
19221            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
19222            "declared_supervisor_slots must NOT push \
19223             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
19224             empty — the author-omitted arm must route through the \
19225             accessor's empty-slice return unchanged (got \
19226             slots={slots:?})",
19227        );
19228    }
19229
19230    #[test]
19231    fn supervisor_view_children_arm_routes_through_accessor() {
19232        // Composition pin: [`Caixa::supervisor_view`]'s per-`:children`
19233        // fold-in arm must key off [`Caixa::children`], not the raw
19234        // `self.children.clone()` field-clone. Structurally: a `Caixa {
19235        // kind: Supervisor, estrategia: Some(OneForOne), children:
19236        // vec![ChildSpec { caixa: "w", .. }], .. }` must fold the
19237        // per-child list through the accessor into the typed
19238        // [`SupervisorSpec`] view's `children` field verbatim — every
19239        // entry the accessor surfaces must land in the view's
19240        // `children` slot in the same order. The pair jointly pins the
19241        // accessor + view-composer composition: any future silent
19242        // detour that had the accessor return a fresh-cloned
19243        // `Vec<ChildSpec>` copy would silently break the reference-
19244        // identity pin the peer `supervisor_view` fold-in path reads
19245        // from — the fold would clone once more per accessor call
19246        // instead of borrowing the storage buffer verbatim once.
19247        //
19248        // Peer of the sibling
19249        // `supervisor_view_kind_gate_routes_through_accessor` (35d8b52-
19250        // family) composition pin on the peer kind-gate arm — same
19251        // "the view composer must route through the substrate-
19252        // primitive typed dispatch" discipline extended onto the
19253        // per-`:children` fold-in arm, closing the supervisor-view
19254        // composer's routing invariant on the composite-slice input.
19255        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
19256        let mut c = caixa_with_children(vec![
19257            ChildSpec {
19258                caixa: "worker-a".into(),
19259                versao: "^0.1".into(),
19260                restart: RestartPolicy::Permanent,
19261            },
19262            ChildSpec {
19263                caixa: "worker-b".into(),
19264                versao: "^0.1".into(),
19265                restart: RestartPolicy::Transient,
19266            },
19267        ]);
19268        c.kind = crate::CaixaKind::Supervisor;
19269        c.estrategia = Some(RestartStrategy::OneForOne);
19270        let view = c
19271            .supervisor_view()
19272            .expect("Supervisor kind must produce a supervisor_view");
19273        assert_eq!(
19274            view.children(),
19275            c.children(),
19276            "supervisor_view must fold Caixa::children verbatim into \
19277             SupervisorSpec::children — the accessor and the view \
19278             composer must route through the same substrate-primitive \
19279             typed dispatch on the outer :children slice (got view \
19280             children={:?}, expected {:?})",
19281            view.children(),
19282            c.children(),
19283        );
19284    }
19285
19286    #[test]
19287    fn children_projects_slice_by_borrow() {
19288        // The by-borrow pin: [`Caixa::children`] returns
19289        // `&[ChildSpec]` by borrow — the returned slice borrows the
19290        // underlying `Vec<ChildSpec>` storage of the `:children` slot
19291        // and the accessor must not clone the backing `Vec` on every
19292        // call. Peer of the sibling outer top-level [`Caixa`]
19293        // `&[T]`-return by-borrow pins (`autores_projects_slice_by_borrow`
19294        // b5d813f, `etiquetas_projects_slice_by_borrow` 78c7d3c,
19295        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19296        // `exe_projects_slice_by_borrow` 65d9527,
19297        // `servicos_projects_slice_by_borrow` 611f78b,
19298        // `deps_projects_slice_by_borrow` ad34b4e,
19299        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19300        // `upgrade_from_projects_slice_by_borrow` 2a1f907) on the
19301        // sibling outer top-level [`Caixa`] scalar-element and
19302        // composite-element `&[T]` axes — folds on the outer-`Caixa`
19303        // composite-element `&[Composite]` axis: the accessor's
19304        // returned slice must borrow from `&self` (the returned
19305        // reference's lifetime is tied to `&self`), and calling the
19306        // accessor twice on the same [`Caixa`] must yield slices
19307        // that are pointer-equal (the underlying byte-buffer is the
19308        // storage `Vec`'s allocation, not a fresh copy) as well as
19309        // value-equal (idempotent, no side effects on `&self`).
19310        //
19311        // Pins against a future silent detour that returned an owned
19312        // `Vec<ChildSpec>` (which would type-check but silently clone
19313        // on every call), a `&Vec<ChildSpec>` return (which would leak
19314        // the backing `Vec`'s grow/push/reserve surface no downstream
19315        // consumer reaches for), or a one-arm-only accessor that
19316        // returned a saturating value on some sentinel input.
19317        use crate::supervisor::{ChildSpec, RestartPolicy};
19318        for children in [
19319            vec![],
19320            vec![ChildSpec {
19321                caixa: "w".into(),
19322                versao: "^0.1".into(),
19323                restart: RestartPolicy::Permanent,
19324            }],
19325            vec![
19326                ChildSpec {
19327                    caixa: "worker-a".into(),
19328                    versao: "^0.1".into(),
19329                    restart: RestartPolicy::Permanent,
19330                },
19331                ChildSpec {
19332                    caixa: "worker-b".into(),
19333                    versao: "^0.1".into(),
19334                    restart: RestartPolicy::Transient,
19335                },
19336            ],
19337        ] {
19338            let c = caixa_with_children(children.clone());
19339            let first = c.children();
19340            let second = c.children();
19341            assert_eq!(
19342                first, second,
19343                "Caixa::children must be idempotent — two successive \
19344                 calls on the same &self must return the same \
19345                 &[ChildSpec]",
19346            );
19347            assert_eq!(
19348                first.as_ptr(),
19349                second.as_ptr(),
19350                "Caixa::children must borrow the underlying \
19351                 Vec<ChildSpec> storage — two successive calls must \
19352                 return slices with the same backing pointer (a fresh \
19353                 Vec<ChildSpec> clone would change the pointer on \
19354                 every call)",
19355            );
19356            assert_eq!(
19357                first,
19358                children.as_slice(),
19359                "Caixa::children must return :children verbatim by \
19360                 borrow — got {first:?}, expected {children:?}",
19361            );
19362        }
19363    }
19364
19365    // ── Caixa::membros — outer top-level &[Membro] composite-slice accessor ──
19366
19367    fn caixa_aplicacao_with_membros(membros: Vec<crate::aplicacao::Membro>) -> Caixa {
19368        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19369        c.kind = CaixaKind::Aplicacao;
19370        c.membros = membros;
19371        c
19372    }
19373
19374    #[test]
19375    fn membros_returns_membros_slice_verbatim_across_permutations() {
19376        // The canonical per-`Caixa` `:membros` M3 mesh-slot outer-
19377        // composite `&[Membro]`-return slice-shape pin:
19378        // [`Caixa::membros`] must return the `:membros` typed
19379        // `Vec<Membro>` verbatim as a `&[Membro]` slice-view over the
19380        // same backing buffer the raw `self.membros.as_slice()` field
19381        // access borrows from, element-equal across every
19382        // representative fixture in the accept-set — `[]` (the "no
19383        // members declared" arm every non-`Aplicacao`-kind `defcaixa`
19384        // carries by `#[serde(default)]` and every partially-authored
19385        // Aplicacao carries before the
19386        // [`crate::AplicacaoError::MembrosEmpty`] gate fires), a
19387        // canonical single-member fixture (the shape a minimal
19388        // Aplicacao carries — one Servico wrapping one contained
19389        // computation), a canonical multi-member list carrying three
19390        // distinct entries (the canonical checkout-shape Aplicacao —
19391        // cart / pricing / auth — every canonical example carries), and
19392        // a past-the-guard sentinel — a duplicate `:caixa`
19393        // `[("cart", ...), ("cart", ...)]` entry pair
19394        // ([`crate::AplicacaoSpec::validate`] rejects through
19395        // `DuplicateMembro { nome: "cart" }` but the accessor must ship
19396        // the raw slot verbatim so struct-literal fixtures continue to
19397        // expose the duplicate at the accessor boundary).
19398        //
19399        // Pins against a future silent detour that returned an owned
19400        // `Vec<Membro>` (which would type-check but silently clone on
19401        // every accessor call, breaking the zero-cost projection every
19402        // peer sibling slice accessor carries), a `[dup, dup] → [dup]`
19403        // dedup collapse (which would silently absorb the
19404        // `DuplicateMembro` refusal case at the accessor boundary and
19405        // the [`crate::StandardLayout::verify`] cross-member gate would
19406        // silently accept a struct-literal `Caixa` carrying the drift),
19407        // a reference to an operator-resolved overlay (the future per-
19408        // cluster `:membros-overrides` slot — its resolution must land
19409        // at exactly this accessor body, not silently divert the raw
19410        // slot away from a second consumer), or an axis-shuffled
19411        // projection (a future detour that reordered members through
19412        // the accessor would silently split the paired
19413        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
19414        // traversal input from the peer [`Self::aplicacao_view`] fold-
19415        // in path's clone-order input, since the canonical `:contratos`
19416        // `:de`/`:para` and `:entrada :para` cross-slot refusal probes
19417        // read the member set through the same slice).
19418        //
19419        // Third outer top-level [`Caixa`] `&[Composite]`-return slice
19420        // accessor pin on the substrate primitive for M2 / M3 typed-
19421        // slot vec-carry axes — opens the outer-`Caixa` M3 mesh-slot
19422        // arm of the `&[Composite]` composite-slice sub-family the
19423        // sibling M2 `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19424        // (2a1f907) and
19425        // `children_returns_children_slice_verbatim_across_permutations`
19426        // (c17b51e) pins opened, peer at the outer altitude of the
19427        // closed inner-[`crate::AplicacaoSpec::membros`] (6c77e36)
19428        // accessor on the same MESH-COMPOSITION per-Aplicacao member-
19429        // list axis.
19430        use crate::aplicacao::Membro;
19431        let fixtures: Vec<Vec<Membro>> = vec![
19432            vec![],
19433            vec![Membro {
19434                caixa: "cart".into(),
19435                versao: "^0.1".into(),
19436            }],
19437            vec![
19438                Membro {
19439                    caixa: "cart".into(),
19440                    versao: "^0.1".into(),
19441                },
19442                Membro {
19443                    caixa: "pricing".into(),
19444                    versao: "^0.2".into(),
19445                },
19446                Membro {
19447                    caixa: "auth".into(),
19448                    versao: "^1.0".into(),
19449                },
19450            ],
19451            vec![
19452                Membro {
19453                    caixa: "cart".into(),
19454                    versao: "^0.1".into(),
19455                },
19456                Membro {
19457                    caixa: "cart".into(),
19458                    versao: "^0.1".into(),
19459                },
19460            ],
19461        ];
19462        for membros in fixtures {
19463            let c = caixa_aplicacao_with_membros(membros.clone());
19464            assert_eq!(
19465                c.membros(),
19466                membros.as_slice(),
19467                "Caixa::membros must return :membros verbatim \
19468                 (got {:?}, expected {membros:?})",
19469                c.membros(),
19470            );
19471            assert_eq!(
19472                c.membros(),
19473                c.membros.as_slice(),
19474                "Caixa::membros must element-equal the raw \
19475                 `self.membros.as_slice()` field access across every \
19476                 value in the Vec<Membro> accept-set",
19477            );
19478            assert_eq!(
19479                c.membros().is_empty(),
19480                c.membros.is_empty(),
19481                "Caixa::membros().is_empty() must byte-equal \
19482                 self.membros.is_empty() — a presence-bit drift would \
19483                 silently split the paired Caixa::declared_mesh_slots \
19484                 mesh declared-slot enumerator's presence probe from \
19485                 the peer Caixa::aplicacao_view typed-view composer's \
19486                 fold-in path",
19487            );
19488        }
19489    }
19490
19491    #[test]
19492    fn declared_mesh_slots_membros_arm_routes_through_accessor() {
19493        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:membros`
19494        // presence-probe arm must key off [`Caixa::membros`], not the
19495        // raw `!self.membros.is_empty()` field-probe. Structurally: a
19496        // `Caixa { membros: vec![Membro { caixa: "cart", versao:
19497        // "^0.1" }], .. }` must push `M3_AUTHOR_KEY_MEMBROS` onto the
19498        // declared-slot list (the presence bit is non-empty, so the
19499        // mesh kind-coherence gate must surface the slot as
19500        // "declared"), and a `Caixa { membros: vec![], .. }` must NOT
19501        // push the label (the "author omitted the slot entirely" arm
19502        // — the empty-slice partition the serde-default folds onto).
19503        // The pair jointly pins the accessor + declared-slot
19504        // enumerator composition: any future silent detour that had
19505        // the accessor collapse `[Membro { .. }]` to `[]` (a
19506        // `.filter(|m| m.nome() != "__reserved__")` projection) would
19507        // silently absorb the "declared but degenerate" arm at the
19508        // accessor boundary and the
19509        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
19510        // coherence gate would silently accept a struct-literal
19511        // `Caixa` carrying the drift.
19512        //
19513        // Peer of the sibling
19514        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19515        // (2a1f907) and
19516        // `declared_supervisor_slots_children_arm_routes_through_accessor`
19517        // (c17b51e) composition pins on the M2 `:upgrade-from` /
19518        // `:children` composite-slice arms — same "the enumerator gate
19519        // must route through the substrate-primitive typed dispatch"
19520        // discipline extended onto the M3 `:membros` composite-slice
19521        // arm, opening the M3 arm of the declared-slot enumerator's
19522        // routing invariant.
19523        use crate::aplicacao::Membro;
19524        let c = caixa_aplicacao_with_membros(vec![Membro {
19525            caixa: "cart".into(),
19526            versao: "^0.1".into(),
19527        }]);
19528        let slots = c.declared_mesh_slots();
19529        assert!(
19530            slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
19531            "declared_mesh_slots must push M3_AUTHOR_KEY_MEMBROS when \
19532             `:membros` is non-empty — the accessor and the enumerator \
19533             gate must route through the same substrate-primitive \
19534             typed dispatch on the outer :membros presence bit (got \
19535             slots={slots:?})",
19536        );
19537        let c = caixa_aplicacao_with_membros(vec![]);
19538        let slots = c.declared_mesh_slots();
19539        assert!(
19540            !slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
19541            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_MEMBROS \
19542             when `:membros` is empty — the author-omitted arm must \
19543             route through the accessor's empty-slice return unchanged \
19544             (got slots={slots:?})",
19545        );
19546    }
19547
19548    #[test]
19549    fn aplicacao_view_membros_arm_routes_through_accessor() {
19550        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:membros`
19551        // fold-in arm must key off [`Caixa::membros`], not the raw
19552        // `self.membros.clone()` field-clone. Structurally: a `Caixa {
19553        // kind: Aplicacao, membros: vec![Membro { caixa: "cart", .. },
19554        // Membro { caixa: "pricing", .. }], .. }` must fold the per-
19555        // member list through the accessor into the typed
19556        // [`crate::AplicacaoSpec`] view's `membros` slot verbatim —
19557        // every entry the accessor surfaces must land in the view's
19558        // `membros` slot in the same order. The pair jointly pins the
19559        // accessor + view-composer composition: any future silent
19560        // detour that had the accessor return a fresh-cloned
19561        // `Vec<Membro>` copy would silently break the reference-
19562        // identity pin the peer `aplicacao_view` fold-in path reads
19563        // from — the fold would clone once more per accessor call
19564        // instead of borrowing the storage buffer verbatim once.
19565        //
19566        // Peer of the sibling
19567        // `aplicacao_view_politicas_arm_folds_through_accessor`
19568        // (5d23d29) /
19569        // `aplicacao_view_placement_arm_folds_through_accessor`
19570        // (4fb8074) /
19571        // `aplicacao_view_entrada_arm_folds_through_accessor` (e4128e4)
19572        // composition pins on the M3 `:politicas` / `:placement` /
19573        // `:entrada` outer-`Option<&Composite>` arms — extended here to
19574        // the M3 `:membros` outer-`&[Composite]` composite-slice arm,
19575        // closing the aplicacao-view composer's routing invariant on
19576        // the composite-slice input.
19577        use crate::aplicacao::Membro;
19578        let c = caixa_aplicacao_with_membros(vec![
19579            Membro {
19580                caixa: "cart".into(),
19581                versao: "^0.1".into(),
19582            },
19583            Membro {
19584                caixa: "pricing".into(),
19585                versao: "^0.2".into(),
19586            },
19587        ]);
19588        let view = c
19589            .aplicacao_view()
19590            .expect("Aplicacao kind must produce an aplicacao_view");
19591        assert_eq!(
19592            view.membros(),
19593            c.membros(),
19594            "aplicacao_view must fold Caixa::membros verbatim into \
19595             AplicacaoSpec::membros — the accessor and the view \
19596             composer must route through the same substrate-primitive \
19597             typed dispatch on the outer :membros slice (got view \
19598             membros={:?}, expected {:?})",
19599            view.membros(),
19600            c.membros(),
19601        );
19602    }
19603
19604    #[test]
19605    fn membros_projects_slice_by_borrow() {
19606        // The by-borrow pin: [`Caixa::membros`] returns `&[Membro]` by
19607        // borrow — the returned slice borrows the underlying
19608        // `Vec<Membro>` storage of the `:membros` slot and the
19609        // accessor must not clone the backing `Vec` on every call.
19610        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
19611        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
19612        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
19613        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19614        // `exe_projects_slice_by_borrow` 65d9527,
19615        // `servicos_projects_slice_by_borrow` 611f78b,
19616        // `deps_projects_slice_by_borrow` ad34b4e,
19617        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19618        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
19619        // `children_projects_slice_by_borrow` c17b51e) on the sibling
19620        // outer top-level [`Caixa`] scalar-element and composite-
19621        // element `&[T]` axes — folds on the outer-`Caixa` M3 mesh-
19622        // slot composite-element `&[Composite]` axis: the accessor's
19623        // returned slice must borrow from `&self` (the returned
19624        // reference's lifetime is tied to `&self`), and calling the
19625        // accessor twice on the same [`Caixa`] must yield slices that
19626        // are pointer-equal (the underlying byte-buffer is the storage
19627        // `Vec`'s allocation, not a fresh copy) as well as value-equal
19628        // (idempotent, no side effects on `&self`).
19629        //
19630        // Pins against a future silent detour that returned an owned
19631        // `Vec<Membro>` (which would type-check but silently clone on
19632        // every call), a `&Vec<Membro>` return (which would leak the
19633        // backing `Vec`'s grow/push/reserve surface no downstream
19634        // consumer reaches for), or a one-arm-only accessor that
19635        // returned a saturating value on some sentinel input.
19636        use crate::aplicacao::Membro;
19637        for membros in [
19638            vec![],
19639            vec![Membro {
19640                caixa: "cart".into(),
19641                versao: "^0.1".into(),
19642            }],
19643            vec![
19644                Membro {
19645                    caixa: "cart".into(),
19646                    versao: "^0.1".into(),
19647                },
19648                Membro {
19649                    caixa: "pricing".into(),
19650                    versao: "^0.2".into(),
19651                },
19652            ],
19653        ] {
19654            let c = caixa_aplicacao_with_membros(membros.clone());
19655            let first = c.membros();
19656            let second = c.membros();
19657            assert_eq!(
19658                first, second,
19659                "Caixa::membros must be idempotent — two successive \
19660                 calls on the same &self must return the same &[Membro]",
19661            );
19662            assert_eq!(
19663                first.as_ptr(),
19664                second.as_ptr(),
19665                "Caixa::membros must borrow the underlying Vec<Membro> \
19666                 storage — two successive calls must return slices with \
19667                 the same backing pointer (a fresh Vec<Membro> clone \
19668                 would change the pointer on every call)",
19669            );
19670            assert_eq!(
19671                first,
19672                membros.as_slice(),
19673                "Caixa::membros must return :membros verbatim by borrow \
19674                 — got {first:?}, expected {membros:?}",
19675            );
19676        }
19677    }
19678
19679    // ── Caixa::contratos — outer top-level &[WitContract] composite-slice accessor ──
19680
19681    fn caixa_aplicacao_with_contratos(contratos: Vec<crate::aplicacao::WitContract>) -> Caixa {
19682        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19683        c.kind = CaixaKind::Aplicacao;
19684        c.contratos = contratos;
19685        c
19686    }
19687
19688    fn contrato_http_for_test(
19689        de: &str,
19690        para: &str,
19691        endpoint: &str,
19692    ) -> crate::aplicacao::WitContract {
19693        crate::aplicacao::WitContract {
19694            de: de.into(),
19695            para: para.into(),
19696            wit: "wasi:http/proxy".into(),
19697            endpoint: Some(endpoint.into()),
19698            subject: None,
19699            slot: None,
19700        }
19701    }
19702
19703    #[test]
19704    fn contratos_returns_contratos_slice_verbatim_across_permutations() {
19705        // The canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
19706        // composite `&[WitContract]`-return slice-shape pin:
19707        // [`Caixa::contratos`] must return the `:contratos` typed
19708        // `Vec<WitContract>` verbatim as a `&[WitContract]` slice-view
19709        // over the same backing buffer the raw
19710        // `self.contratos.as_slice()` field access borrows from,
19711        // element-equal across every representative fixture in the
19712        // accept-set — `[]` (the "no contracts declared" arm every
19713        // non-`Aplicacao`-kind `defcaixa` carries by
19714        // `#[serde(default)]` and every leaf-Aplicacao with a single
19715        // member carries), a canonical single-edge fixture (the
19716        // minimal directed-graph shape: one HTTP-shape `(cart → catalog)`
19717        // edge), and a canonical multi-edge fixture with three distinct
19718        // edges (the checkout-shape Aplicacao's HTTP-fan pattern:
19719        // `(cart → catalog)`, `(cart → pricing)`, `(cart → auth)`).
19720        //
19721        // Pins against a future silent detour that returned an owned
19722        // `Vec<WitContract>` (which would type-check but silently clone
19723        // on every accessor call, breaking the zero-cost projection
19724        // every peer sibling slice accessor carries), an axis-shuffled
19725        // projection (a future detour that reordered edges through the
19726        // accessor would silently split the paired
19727        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
19728        // traversal input from the peer [`Self::aplicacao_view`] fold-
19729        // in path's clone-order input, since every canonical
19730        // `caixa-mesh` renderer's per-`(:de, :para)` adjacency-list
19731        // seed dispatch reads the edge set through the same slice),
19732        // or a reference to an operator-resolved overlay (the future
19733        // per-cluster `:contratos-overrides` slot — its resolution
19734        // must land at exactly this accessor body, not silently divert
19735        // the raw slot away from a second consumer).
19736        //
19737        // Fourth outer top-level [`Caixa`] `&[Composite]`-return slice
19738        // accessor pin on the substrate primitive for M2 / M3 typed-
19739        // slot vec-carry axes — closes the outer-`Caixa`
19740        // `&[Composite]` composite-slice sub-family the sibling M2
19741        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19742        // (2a1f907) and
19743        // `children_returns_children_slice_verbatim_across_permutations`
19744        // (c17b51e) pins opened and the M3
19745        // `membros_returns_membros_slice_verbatim_across_permutations`
19746        // (0f26987) pin folded on, closing the outer-`Caixa` M3 mesh-
19747        // slot arm of the composite-slice sub-family. Peer at the outer
19748        // altitude of the closed inner-
19749        // [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
19750        // same MESH-COMPOSITION per-Aplicacao contract-list axis.
19751        let fixtures: Vec<Vec<crate::aplicacao::WitContract>> = vec![
19752            vec![],
19753            vec![contrato_http_for_test("cart", "catalog", "/items")],
19754            vec![
19755                contrato_http_for_test("cart", "catalog", "/items"),
19756                contrato_http_for_test("cart", "pricing", "/price"),
19757                contrato_http_for_test("cart", "auth", "/whoami"),
19758            ],
19759        ];
19760        for contratos in fixtures {
19761            let c = caixa_aplicacao_with_contratos(contratos.clone());
19762            assert_eq!(
19763                c.contratos(),
19764                contratos.as_slice(),
19765                "Caixa::contratos must return :contratos verbatim \
19766                 (got {:?}, expected {contratos:?})",
19767                c.contratos(),
19768            );
19769            assert_eq!(
19770                c.contratos(),
19771                c.contratos.as_slice(),
19772                "Caixa::contratos must element-equal the raw \
19773                 `self.contratos.as_slice()` field access across every \
19774                 value in the Vec<WitContract> accept-set",
19775            );
19776            assert_eq!(
19777                c.contratos().is_empty(),
19778                c.contratos.is_empty(),
19779                "Caixa::contratos().is_empty() must byte-equal \
19780                 self.contratos.is_empty() — a presence-bit drift would \
19781                 silently split the paired Caixa::declared_mesh_slots \
19782                 mesh declared-slot enumerator's presence probe from \
19783                 the peer Caixa::aplicacao_view typed-view composer's \
19784                 fold-in path",
19785            );
19786        }
19787    }
19788
19789    #[test]
19790    fn declared_mesh_slots_contratos_arm_routes_through_accessor() {
19791        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:contratos`
19792        // presence-probe arm must key off [`Caixa::contratos`], not the
19793        // raw `!self.contratos.is_empty()` field-probe. Structurally: a
19794        // `Caixa { contratos: vec![WitContract { .. }], .. }` must push
19795        // `M3_AUTHOR_KEY_CONTRATOS` onto the declared-slot list (the
19796        // presence bit is non-empty, so the mesh kind-coherence gate
19797        // must surface the slot as "declared"), and a `Caixa {
19798        // contratos: vec![], .. }` must NOT push the label (the "author
19799        // omitted the slot entirely" arm — the empty-slice partition
19800        // the serde-default folds onto). The pair jointly pins the
19801        // accessor + declared-slot enumerator composition: any future
19802        // silent detour that had the accessor collapse
19803        // `[WitContract { .. }]` to `[]` (a `.filter(|c| c.de() !=
19804        // "__reserved__")` projection) would silently absorb the
19805        // "declared but degenerate" arm at the accessor boundary and
19806        // the [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
19807        // coherence gate would silently accept a struct-literal
19808        // `Caixa` carrying the drift.
19809        //
19810        // Peer of the sibling
19811        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19812        // (2a1f907),
19813        // `declared_supervisor_slots_children_arm_routes_through_accessor`
19814        // (c17b51e), and
19815        // `declared_mesh_slots_membros_arm_routes_through_accessor`
19816        // (0f26987) composition pins on the M2 `:upgrade-from` /
19817        // `:children` / M3 `:membros` composite-slice arms — same "the
19818        // enumerator gate must route through the substrate-primitive
19819        // typed dispatch" discipline extended onto the M3 `:contratos`
19820        // composite-slice arm, closing the M3 mesh-slot arm of the
19821        // declared-slot enumerator's routing invariant on the
19822        // composite-slice inputs.
19823        let c = caixa_aplicacao_with_contratos(vec![contrato_http_for_test(
19824            "cart", "catalog", "/items",
19825        )]);
19826        let slots = c.declared_mesh_slots();
19827        assert!(
19828            slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
19829            "declared_mesh_slots must push M3_AUTHOR_KEY_CONTRATOS when \
19830             `:contratos` is non-empty — the accessor and the enumerator \
19831             gate must route through the same substrate-primitive \
19832             typed dispatch on the outer :contratos presence bit (got \
19833             slots={slots:?})",
19834        );
19835        let c = caixa_aplicacao_with_contratos(vec![]);
19836        let slots = c.declared_mesh_slots();
19837        assert!(
19838            !slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
19839            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_CONTRATOS \
19840             when `:contratos` is empty — the author-omitted arm must \
19841             route through the accessor's empty-slice return unchanged \
19842             (got slots={slots:?})",
19843        );
19844    }
19845
19846    #[test]
19847    fn aplicacao_view_contratos_arm_routes_through_accessor() {
19848        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:contratos`
19849        // fold-in arm must key off [`Caixa::contratos`], not the raw
19850        // `self.contratos.clone()` field-clone. Structurally: a `Caixa
19851        // { kind: Aplicacao, contratos: vec![WitContract { de: "cart",
19852        // .. }, WitContract { de: "pricing", .. }], .. }` must fold the
19853        // per-edge list through the accessor into the typed
19854        // [`crate::AplicacaoSpec`] view's `contratos` slot verbatim —
19855        // every entry the accessor surfaces must land in the view's
19856        // `contratos` slot in the same order. The pair jointly pins
19857        // the accessor + view-composer composition: a future silent
19858        // detour that had the accessor shuffle or drop an edge would
19859        // silently split the paired declared-slot enumerator's
19860        // presence bit from the typed-view composer's edge-list, a
19861        // two-consumer split at the enumerator and the view composer
19862        // far from the source `caixa.lisp`.
19863        //
19864        // Peer of the sibling
19865        // `aplicacao_view_membros_arm_routes_through_accessor`
19866        // (0f26987) composition pin on the M3 `:membros` outer-
19867        // `&[Composite]` composite-slice arm, closing the aplicacao-
19868        // view composer's routing invariant on the composite-slice
19869        // inputs at the outer altitude.
19870        let c = caixa_aplicacao_with_contratos(vec![
19871            contrato_http_for_test("cart", "catalog", "/items"),
19872            contrato_http_for_test("cart", "pricing", "/price"),
19873        ]);
19874        let view = c
19875            .aplicacao_view()
19876            .expect("Aplicacao kind must produce an aplicacao_view");
19877        assert_eq!(
19878            view.contratos(),
19879            c.contratos(),
19880            "aplicacao_view must fold Caixa::contratos verbatim into \
19881             AplicacaoSpec::contratos — the accessor and the view \
19882             composer must route through the same substrate-primitive \
19883             typed dispatch on the outer :contratos slice (got view \
19884             contratos={:?}, expected {:?})",
19885            view.contratos(),
19886            c.contratos(),
19887        );
19888    }
19889
19890    #[test]
19891    fn contratos_projects_slice_by_borrow() {
19892        // The by-borrow pin: [`Caixa::contratos`] returns `&[WitContract]`
19893        // by borrow — the returned slice borrows the underlying
19894        // `Vec<WitContract>` storage of the `:contratos` slot and the
19895        // accessor must not clone the backing `Vec` on every call.
19896        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
19897        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
19898        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
19899        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19900        // `exe_projects_slice_by_borrow` 65d9527,
19901        // `servicos_projects_slice_by_borrow` 611f78b,
19902        // `deps_projects_slice_by_borrow` ad34b4e,
19903        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19904        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
19905        // `children_projects_slice_by_borrow` c17b51e,
19906        // `membros_projects_slice_by_borrow` 0f26987) on the sibling
19907        // outer top-level [`Caixa`] scalar-element and composite-
19908        // element `&[T]` axes — closes the outer-`Caixa` M3 mesh-slot
19909        // composite-element `&[Composite]` axis on the by-borrow pin:
19910        // the accessor's returned slice must borrow from `&self` (the
19911        // returned reference's lifetime is tied to `&self`), and
19912        // calling the accessor twice on the same [`Caixa`] must yield
19913        // slices that are pointer-equal (the underlying byte-buffer is
19914        // the storage `Vec`'s allocation, not a fresh copy) as well as
19915        // value-equal (idempotent, no side effects on `&self`).
19916        //
19917        // Pins against a future silent detour that returned an owned
19918        // `Vec<WitContract>` (which would type-check but silently clone
19919        // on every call), a `&Vec<WitContract>` return (which would
19920        // leak the backing `Vec`'s grow/push/reserve surface no
19921        // downstream consumer reaches for), or a one-arm-only accessor
19922        // that returned a saturating value on some sentinel input.
19923        for contratos in [
19924            vec![],
19925            vec![contrato_http_for_test("cart", "catalog", "/items")],
19926            vec![
19927                contrato_http_for_test("cart", "catalog", "/items"),
19928                contrato_http_for_test("cart", "pricing", "/price"),
19929            ],
19930        ] {
19931            let c = caixa_aplicacao_with_contratos(contratos.clone());
19932            let first = c.contratos();
19933            let second = c.contratos();
19934            assert_eq!(
19935                first, second,
19936                "Caixa::contratos must be idempotent — two successive \
19937                 calls on the same &self must return the same \
19938                 &[WitContract]",
19939            );
19940            assert_eq!(
19941                first.as_ptr(),
19942                second.as_ptr(),
19943                "Caixa::contratos must borrow the underlying \
19944                 Vec<WitContract> storage — two successive calls must \
19945                 return slices with the same backing pointer (a fresh \
19946                 Vec<WitContract> clone would change the pointer on \
19947                 every call)",
19948            );
19949            assert_eq!(
19950                first,
19951                contratos.as_slice(),
19952                "Caixa::contratos must return :contratos verbatim by \
19953                 borrow — got {first:?}, expected {contratos:?}",
19954            );
19955        }
19956    }
19957
19958    // ── drift-detection: Caixa top-level multi-word serde-derive-to-const identity ──
19959
19960    #[test]
19961    fn caixa_multi_word_serde_keys_match_lifted_top_level_key_consts() {
19962        // Load-bearing invariant: every multi-word top-level [`Caixa`]
19963        // serde-derived JSON key routes through a lifted `&'static str`
19964        // const. The Rust field names are `snake_case`
19965        // (`deps_dev` / `upgrade_from` / `max_restarts` /
19966        // `restart_window`); [`Caixa`]'s `#[serde(rename_all =
19967        // "camelCase")]` derive attribute maps each to the camelCase
19968        // byte-string the [`Caixa::to_lisp`] round-trip's
19969        // `serde_json::to_value(self)` step lands under before
19970        // `tatara_lisp::domain::json_to_sexp` re-projects the JSON keys
19971        // to the kebab-case `:deps-dev` / `:upgrade-from` /
19972        // `:max-restarts` / `:restart-window` author surface. Serialize
19973        // a fully-populated [`Caixa`] and pin that each canonical
19974        // byte-sequence appears verbatim in the JSON — a future
19975        // accidental `rename_all = "snake_case"` / `"kebab-case"` /
19976        // verbatim-field-name flip at the derive attribute (any of
19977        // which would silently break every [`Caixa::to_lisp`]
19978        // round-trip and the future M4 operator-side manifest ingest's
19979        // `Value::get(<key>)` navigation) surfaces here as a build-time
19980        // test failure at `manifest.rs`, not as an apply-time
19981        // `.get(<stale-canonical-const>)` returning `None` far from the
19982        // derive-attr drift's commit. Same discipline the sibling
19983        // `supervisor_spec_serde_keys_match_lifted_supervisor_key_consts`
19984        // (40cc4e5), `membro_serde_keys_match_lifted_membro_key_consts`
19985        // (ce80ca0), and `upgrade_from_entry_serde_keys_match_lifted_
19986        // m2_upgrade_from_key_consts` (36ffe65) pins established on the
19987        // sibling M2 supervision-tree, M3 [`Membro`] per-entry, and M2
19988        // [`UpgradeFromEntry`] per-entry axes — extended here to the
19989        // enclosing M0 [`Caixa`] top-level axis so the last of the four
19990        // multi-word top-level [`Caixa`] serde-derived JSON keys
19991        // (`depsDev`) joins the substrate's "one canonical byte-string
19992        // per typed serialized-key axis" discipline.
19993        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
19994        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
19995        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19996        c.deps_dev = vec![Dep::simple("tatara-check", "^0.1")];
19997        c.upgrade_from = vec![UpgradeFromEntry {
19998            from: "0.0.1".into(),
19999            instructions: vec![UpgradeInstruction::Restart],
20000        }];
20001        c.estrategia = Some(RestartStrategy::OneForOne);
20002        c.max_restarts = Some(3);
20003        c.restart_window = Some("60s".into());
20004        c.children = vec![ChildSpec {
20005            caixa: "child".into(),
20006            versao: "^0.1".into(),
20007            restart: RestartPolicy::Permanent,
20008        }];
20009        let json = serde_json::to_string(&c).unwrap();
20010        for key in [
20011            crate::render::CAIXA_KEY_DEPS_DEV,
20012            crate::render::M2_KEY_UPGRADE_FROM,
20013            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20014            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20015        ] {
20016            let quoted = format!("\"{key}\"");
20017            assert!(
20018                json.contains(&quoted),
20019                "serialized Caixa must carry the lifted top-level \
20020                 multi-word byte-sequence {quoted} verbatim in the JSON \
20021                 emission (got: {json})",
20022            );
20023        }
20024    }
20025
20026    #[test]
20027    fn caixa_top_level_multi_word_key_consts_are_pairwise_distinct() {
20028        // Cross-axis drift-detection pin: a future collapse of the four
20029        // canonical [`Caixa`] top-level multi-word byte-strings onto the
20030        // same value (e.g. an accidental copy-paste flip of
20031        // [`crate::render::CAIXA_KEY_DEPS_DEV`] to also read
20032        // `"upgradeFrom"`) would silently reroute every downstream
20033        // `Value::get(<key>)` probe on one axis onto the sibling axis's
20034        // top-level entry and pass every propagation-probe test that
20035        // expected only the stale axis's value. Peer of the sibling
20036        // four-way distinct pin on the `SUPERVISOR_KEY_*` tetrad
20037        // (40cc4e5) and the two-way pin on `MEMBRO_KEY_*` (ce80ca0).
20038        let all = [
20039            crate::render::CAIXA_KEY_DEPS_DEV,
20040            crate::render::M2_KEY_UPGRADE_FROM,
20041            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20042            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20043        ];
20044        for (i, a) in all.iter().enumerate() {
20045            for b in all.iter().skip(i + 1) {
20046                assert_ne!(
20047                    a, b,
20048                    "Caixa top-level multi-word key consts must be \
20049                     pairwise-distinct canonical byte-sequences — got \
20050                     `{a}` == `{b}`",
20051                );
20052            }
20053        }
20054    }
20055
20056    #[test]
20057    fn caixa_top_level_multi_word_key_consts_are_lower_camel_case_shape() {
20058        // Shape-pin: every [`Caixa`] top-level multi-word key const must
20059        // be a lowerCamelCase byte-sequence (no `snake_case`
20060        // underscores, no `kebab-case` hyphens, no leading colon, no
20061        // `PascalCase` leading capital, no whitespace / dots) — the
20062        // canonical shape the `#[serde(rename_all = "camelCase")]`
20063        // derive produces on [`Caixa`]. A future flip to a
20064        // non-camelCase attribute at the derive surfaces both here
20065        // (this test fails on the stale-constant shape) and at
20066        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20067        // (that test fails on the mismatch between const and derive).
20068        // Peer with `membro_key_consts_are_lower_camel_case_shape`
20069        // (ce80ca0) and `supervisor_key_consts_are_lower_camel_case_shape`
20070        // (40cc4e5) on the sibling per-entry / supervisor-tree axes.
20071        for key in [
20072            crate::render::CAIXA_KEY_DEPS_DEV,
20073            crate::render::M2_KEY_UPGRADE_FROM,
20074            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20075            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20076        ] {
20077            assert!(
20078                !key.is_empty(),
20079                "Caixa top-level multi-word key const must be non-empty \
20080                 (got {key:?})"
20081            );
20082            let first = key.chars().next().unwrap();
20083            assert!(
20084                first.is_ascii_lowercase(),
20085                "Caixa top-level multi-word key const must lead with an \
20086                 ASCII-lowercase byte (got {key:?}, leads with {first:?})",
20087            );
20088            assert!(
20089                key.chars().all(|c| c.is_ascii_alphanumeric()),
20090                "Caixa top-level multi-word key const must be \
20091                 ASCII-alphanumeric only — no `_` / `-` / `:` / `.` / \
20092                 whitespace (got {key:?})",
20093            );
20094        }
20095    }
20096
20097    #[test]
20098    fn caixa_key_deps_dev_pins_canonical_camel_case_byte_string() {
20099        // Scalar-value pin: the byte-string the
20100        // [`crate::render::CAIXA_KEY_DEPS_DEV`] const resolves to,
20101        // asserted verbatim. A future rebrand (`depsDev` → `devDeps`
20102        // matching Cargo's verbatim `dev-dependencies` axis, `depsDev`
20103        // → `depsTest` matching a hypothetical per-test-target
20104        // vocabulary flip) lands as an edit to exactly one const AND
20105        // one derive attribute — the sibling
20106        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20107        // pin already ties the const to the derive attribute, so a
20108        // rebrand that touches only one side of the pair fails at
20109        // caixa-core build time. Same "scalar-value pin per const"
20110        // discipline the sibling
20111        // `m2_top_level_author_key_consts_pin_canonical_kebab_case_labels`
20112        // (f49c8b0) and `contrato_key_consts_pin_canonical_camel_case_labels`
20113        // (ca463a4) pins carry on the peer M2 / M3 top-level slot axes.
20114        assert_eq!(crate::render::CAIXA_KEY_DEPS_DEV, "depsDev");
20115    }
20116
20117    #[test]
20118    fn caixa_key_deps_pins_canonical_byte_string() {
20119        // Scalar-value pin: the byte-string the
20120        // [`crate::render::CAIXA_KEY_DEPS`] const resolves to, asserted
20121        // verbatim. Peer of `caixa_key_deps_dev_pins_canonical_camel_case_byte_string`
20122        // on the two-list dep-graph serialized-key axis — the sibling
20123        // pin covers the multi-word `deps_dev → depsDev` camelCase
20124        // arm, this pin covers the single-word `deps → deps` no-op arm
20125        // (the [`crate::Caixa::deps`] field name carries no `_`, so the
20126        // `#[serde(rename_all = "camelCase")]` derive is a no-op on this
20127        // axis and the emitted JSON key equals the source-side field
20128        // name byte-for-byte). A future [`crate::Caixa::deps`] field
20129        // rename (`deps` → `dependencies` matching Cargo's verbatim
20130        // `[dependencies]` axis, `deps` → `runtime_deps` matching a
20131        // hypothetical per-runtime-target vocabulary flip) OR an added
20132        // `#[serde(rename = "…")]` explicit override lands as an edit
20133        // to exactly one const AND one derive-attr / field name — the
20134        // sibling `caixa_deps_serde_key_matches_lifted_caixa_key_deps`
20135        // pin ties the const to the emitted JSON key, so a rebrand
20136        // that touches only one side of the pair fails at caixa-core
20137        // build time.
20138        assert_eq!(crate::render::CAIXA_KEY_DEPS, "deps");
20139    }
20140
20141    #[test]
20142    fn caixa_deps_serde_key_matches_lifted_caixa_key_deps() {
20143        // Load-bearing invariant on the single-word `deps` top-level
20144        // axis: the byte-string [`crate::render::CAIXA_KEY_DEPS`] pins
20145        // must appear verbatim in the JSON [`Caixa::to_lisp`]'s
20146        // `serde_json::to_value(self)` step emits. Serialize a
20147        // populated [`Caixa`] whose `:deps` slot carries at least one
20148        // entry (the `#[serde(default)]` attribute on the field emits
20149        // an empty `[]` even without members, but a non-empty vec
20150        // additionally covers the codec's per-`Dep`-entry emission
20151        // path) and pin that `"deps"` appears verbatim in the JSON
20152        // emission — a future accidental `rename_all = "snake_case"` /
20153        // `"kebab-case"` flip at the derive attribute (or an added
20154        // `#[serde(rename = "…")]` explicit override on the field, or
20155        // a Rust field rename) would break every [`Caixa::to_lisp`]
20156        // round-trip and the future M4 operator-side manifest ingest's
20157        // `Value::get(CAIXA_KEY_DEPS)` navigation — surfaces here as a
20158        // build-time test failure at `manifest.rs`, not as an
20159        // apply-time `.get(<stale-canonical-const>)` returning `None`
20160        // far from the drift's commit. Peer of the sibling
20161        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20162        // multi-word pin on the same M0 [`Caixa`] top-level
20163        // serialized-key axis, extended here to the single-word arm
20164        // the multi-word test's `rename_all = "camelCase"` sweep can't
20165        // reach (single-word `deps → deps` is a no-op the multi-word
20166        // pin's `\"depsDev\"` / `\"upgradeFrom\"` / `\"maxRestarts\"` /
20167        // `\"restartWindow\"` byte-scan can never observe).
20168        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20169        c.deps = vec![Dep::simple("caixa-core", "^0.1")];
20170        let json = serde_json::to_string(&c).unwrap();
20171        let quoted = format!("\"{}\"", crate::render::CAIXA_KEY_DEPS);
20172        assert!(
20173            json.contains(&quoted),
20174            "serialized Caixa must carry the lifted top-level `deps` \
20175             byte-sequence {quoted} verbatim in the JSON emission (got: \
20176             {json})",
20177        );
20178    }
20179
20180    #[test]
20181    fn caixa_dep_graph_two_list_key_consts_are_pairwise_distinct() {
20182        // Cross-axis drift-detection pin on the two-list dep-graph
20183        // renderer-side wire-key axis: a future collapse of the
20184        // canonical [`crate::render::CAIXA_KEY_DEPS`] /
20185        // [`crate::render::CAIXA_KEY_DEPS_DEV`] byte-strings onto the
20186        // same value (e.g. an accidental copy-paste flip of
20187        // `CAIXA_KEY_DEPS_DEV` to also read `"deps"`) would silently
20188        // reroute every downstream `Value::get(<key>)` probe on one
20189        // axis onto the sibling axis's dep-list and pass every
20190        // propagation-probe test that expected only the stale axis's
20191        // value — a dev-only dep would land in the runtime closure at
20192        // publish time, or a runtime dep would be excluded from the
20193        // published lacre. Peer of the sibling four-way distinct pin
20194        // on the top-level multi-word tetrad
20195        // (`caixa_top_level_multi_word_key_consts_are_pairwise_distinct`)
20196        // and the two-way pin on the sibling
20197        // [`DEP_AUTHOR_KEY_DEPS`] / [`DEP_AUTHOR_KEY_DEPS_DEV`]
20198        // author-facing arm (4da6fba's test), extended here to the
20199        // renderer-side wire-key arm of the same two-list dep-graph
20200        // axis so both halves of the "one canonical byte-string per
20201        // typed axis per (author, wire)" grid carry the same
20202        // distinct-ness discipline.
20203        assert_ne!(
20204            crate::render::CAIXA_KEY_DEPS,
20205            crate::render::CAIXA_KEY_DEPS_DEV,
20206            "CAIXA_KEY_DEPS and CAIXA_KEY_DEPS_DEV must be distinct \
20207             canonical byte-sequences on the two-list dep-graph \
20208             renderer-side wire-key axis"
20209        );
20210    }
20211
20212    // ── DepList / Caixa::push_dep pin ────────────────────────────────
20213    //
20214    // The compounding pin: the two-arm closed-set typed enum
20215    // [`crate::dep::DepList`] carries the runtime-closure `:deps`
20216    // (`Prod`) vs dev-only-closure `:deps-dev` (`Dev`) dispatch every
20217    // consumer of the top-level manifest's dep-mutation surface reads
20218    // through, and the typed dispatch [`Caixa::push_dep`] on the
20219    // substrate primitive folds the "select list → check within-list
20220    // dup → push" cascade onto one method call. Prior to this landing
20221    // the two axes lived across two `&'static str` constants
20222    // (`DEP_AUTHOR_KEY_DEPS`, `DEP_AUTHOR_KEY_DEPS_DEV`) with no closed-
20223    // set type carrying the pair; the `feira add` mutation site's
20224    // inline `if self.dev { &mut caixa.deps_dev } else { &mut
20225    // caixa.deps }` dispatch expressed no compile-time link back to
20226    // the substrate primitive, and a future third dep-list axis would
20227    // have silently split at every open-coded mutation site.
20228
20229    #[test]
20230    fn dep_list_as_str_routes_through_lifted_author_key_constants() {
20231        // Every arm returns the same `&'static str` the substrate's
20232        // canonical `DEP_AUTHOR_KEY_DEPS` / `DEP_AUTHOR_KEY_DEPS_DEV`
20233        // constants carry. A future rebrand on either constant reaches
20234        // the enum through one edit; a regression to inline literals
20235        // (e.g. `Prod => ":deps"`) would silently split the diagnostic
20236        // quotes from the wire-format constants every consumer routes
20237        // through and this pin flags it at build time.
20238        assert_eq!(
20239            crate::dep::DepList::Prod.as_str(),
20240            crate::render::DEP_AUTHOR_KEY_DEPS
20241        );
20242        assert_eq!(
20243            crate::dep::DepList::Dev.as_str(),
20244            crate::render::DEP_AUTHOR_KEY_DEPS_DEV
20245        );
20246    }
20247
20248    #[test]
20249    fn dep_list_display_routes_through_as_str() {
20250        // Same as-str-through-Display convergence discipline the
20251        // sibling closed-set typed enums carry — a `format!("{list}")`
20252        // call must land byte-for-byte on the accessor's return so a
20253        // future consumer that formats the enum for a diagnostic line
20254        // reaches the same wire-format constant the wire-format
20255        // producers do.
20256        assert_eq!(
20257            format!("{}", crate::dep::DepList::Prod),
20258            crate::dep::DepList::Prod.as_str()
20259        );
20260        assert_eq!(
20261            format!("{}", crate::dep::DepList::Dev),
20262            crate::dep::DepList::Dev.as_str()
20263        );
20264    }
20265
20266    #[test]
20267    fn dep_list_all_enumerates_every_variant_once() {
20268        // Exhaustive-iteration pin — every arm appears exactly once in
20269        // `ALL`, matching the closed set the compiler enforces on the
20270        // sibling `match self` arms. A future variant addition that
20271        // extends only one method's match without extending `ALL`
20272        // would silently drop the new arm from every consumer that
20273        // iterates the slice.
20274        let variants: &[crate::dep::DepList] = crate::dep::DepList::ALL;
20275        assert!(variants.contains(&crate::dep::DepList::Prod));
20276        assert!(variants.contains(&crate::dep::DepList::Dev));
20277        assert_eq!(variants.len(), 2);
20278    }
20279
20280    #[test]
20281    fn dep_list_from_wire_returns_prod_on_deps_wire_scalar() {
20282        // Reverse projection on the two-list dep-graph axis: the
20283        // author-surface wire tag the sibling `as_str` emitter walks
20284        // for `Prod` (`:deps` via `DEP_AUTHOR_KEY_DEPS`) parses back to
20285        // `Some(DepList::Prod)`. A regression that hand-rolled the
20286        // per-arm match without routing through the lifted
20287        // `DEP_AUTHOR_KEY_DEPS` const would silently disagree on any
20288        // future wire-tag rebrand and this pin flags it at build time.
20289        assert_eq!(
20290            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS),
20291            Some(crate::dep::DepList::Prod)
20292        );
20293    }
20294
20295    #[test]
20296    fn dep_list_from_wire_returns_dev_on_deps_dev_wire_scalar() {
20297        // Peer of the `Prod`-arm pin on the dev-only axis: the
20298        // author-surface wire tag the sibling `as_str` emitter walks
20299        // for `Dev` (`:deps-dev` via `DEP_AUTHOR_KEY_DEPS_DEV`) parses
20300        // back to `Some(DepList::Dev)`. Same drift-detection posture
20301        // as the peer arm — the sibling method `match` arms are
20302        // compiler-checked exhaustive so a future variant addition
20303        // trips at build time.
20304        assert_eq!(
20305            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS_DEV),
20306            Some(crate::dep::DepList::Dev)
20307        );
20308    }
20309
20310    #[test]
20311    fn dep_list_from_wire_returns_none_on_unknown_wire_scalar() {
20312        // Every input outside the closed-set arm-string set the
20313        // sibling `as_str` emitter walks lands on the terminal `None`
20314        // fallback — no silent-accept surface. Sweeps a set of
20315        // plausibly-adjacent scalars (unprefixed wire form, PascalCase
20316        // rebrand candidates, foreign wire tags, empty string) so a
20317        // future variant addition that widened one wire form without
20318        // extending the emitter's arm-set would trip the sibling
20319        // round-trip pin below rather than silently accepting the new
20320        // form here.
20321        for candidate in [
20322            "",
20323            "deps",
20324            "deps-dev",
20325            ":deps ",
20326            ":Deps",
20327            ":DEPS",
20328            ":build-dep",
20329            ":tool-dep",
20330            "prod",
20331            "dev",
20332        ] {
20333            assert_eq!(
20334                crate::dep::DepList::from_wire(candidate),
20335                None,
20336                "from_wire({candidate:?}) must return None; every input outside \
20337                 the {{DEP_AUTHOR_KEY_DEPS, DEP_AUTHOR_KEY_DEPS_DEV}} accept-set \
20338                 the sibling as_str emitter walks lands on the terminal fallback",
20339            );
20340        }
20341    }
20342
20343    #[test]
20344    fn dep_list_round_trips_through_as_str_and_from_wire() {
20345        // Load-bearing round-trip pin: every arm the `ALL` iteration
20346        // exposes survives the `as_str` → `from_wire` composition
20347        // byte-for-byte. Same discipline the sibling closed-set enums
20348        // carry — `CaixaKind` /
20349        // `RestartStrategy` / `RestartPolicy` /
20350        // `PlacementStrategy` — extended onto the two-list dep-graph
20351        // axis. A future variant addition that extends `ALL` +
20352        // `as_str` without extending `from_wire` (or vice versa)
20353        // trips at build time on this iteration because the compiler
20354        // enforces exhaustiveness on the sibling `match self` arms.
20355        for &list in crate::dep::DepList::ALL {
20356            assert_eq!(
20357                crate::dep::DepList::from_wire(list.as_str()),
20358                Some(list),
20359                "DepList::from_wire(as_str({list:?})) must round-trip to Some({list:?}) — \
20360                 a silent split between the forward emitter and the reverse parser \
20361                 would drift the two halves of the two-list dep-graph axis's typed dispatch",
20362            );
20363        }
20364    }
20365
20366    #[test]
20367    fn push_dep_routes_to_deps_slot_on_prod_arm() {
20368        // The `Prod` arm dispatches to the runtime-closure `:deps`
20369        // slot every downstream lacre-pipeline consumer resolves at
20370        // build time. A future arm that regressed to inline `&mut
20371        // self.deps_dev` on the `Prod` path would silently reroute
20372        // every runtime dep into the dev-only closure at publish time
20373        // — this pin refuses that regression.
20374        let src = Caixa::template("host");
20375        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20376        let before_deps = caixa.deps().len();
20377        let before_deps_dev = caixa.deps_dev().len();
20378        let dep = Dep {
20379            nome: "caixa-teia".to_string(),
20380            versao: "^0.1".to_string(),
20381            fonte: None,
20382            opcional: false,
20383            caracteristicas: Vec::new(),
20384        };
20385        caixa
20386            .push_dep(crate::dep::DepList::Prod, dep)
20387            .expect("first push into :deps succeeds");
20388        assert_eq!(caixa.deps().len(), before_deps + 1);
20389        assert_eq!(caixa.deps_dev().len(), before_deps_dev);
20390        assert_eq!(caixa.deps().last().unwrap().nome(), "caixa-teia");
20391    }
20392
20393    #[test]
20394    fn push_dep_routes_to_deps_dev_slot_on_dev_arm() {
20395        // Peer of the sibling `Prod`-arm dispatch pin — the `Dev` arm
20396        // must dispatch to the dev-only-closure `:deps-dev` slot every
20397        // downstream test-facing artifact resolver reads. A future
20398        // regression that inverted the two arms would silently route
20399        // every dev-only dep into the runtime closure at publish time
20400        // and this pin catches it before the drift ships.
20401        let src = Caixa::template("host");
20402        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20403        let dep = Dep {
20404            nome: "tatara-check".to_string(),
20405            versao: "*".to_string(),
20406            fonte: None,
20407            opcional: false,
20408            caracteristicas: Vec::new(),
20409        };
20410        caixa
20411            .push_dep(crate::dep::DepList::Dev, dep)
20412            .expect("first push into :deps-dev succeeds");
20413        assert!(caixa.deps().is_empty());
20414        assert_eq!(caixa.deps_dev().len(), 1);
20415        assert_eq!(caixa.deps_dev().last().unwrap().nome(), "tatara-check");
20416    }
20417
20418    #[test]
20419    fn push_dep_refuses_within_list_duplicate_nome_with_typed_error() {
20420        // Within-list dup check routes through the canonical
20421        // [`DepError::DuplicateNome`] carrier — the substrate's typed
20422        // diagnostic for the same axis [`Caixa::validate_deps`]'s
20423        // parse-time [`crate::render::insert_first_seen`] walk raises
20424        // on. Prior to the lift the mutation site's inline
20425        // `bail!("dep '{}' already declared", …)` string-diagnostic
20426        // path expressed no through-line back to the typed error;
20427        // routing every dep-list refusal through one carrier means an
20428        // author reading a `feira add` refusal and a `feira build`
20429        // refusal reaches for the same corrective surface without
20430        // switching diagnostic idioms.
20431        let src = Caixa::template("host");
20432        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20433        let dep = Dep {
20434            nome: "caixa-teia".to_string(),
20435            versao: "^0.1".to_string(),
20436            fonte: None,
20437            opcional: false,
20438            caracteristicas: Vec::new(),
20439        };
20440        caixa
20441            .push_dep(crate::dep::DepList::Prod, dep.clone())
20442            .expect("first push succeeds");
20443        let dup = Dep {
20444            nome: "caixa-teia".to_string(),
20445            versao: "^0.2".to_string(),
20446            fonte: None,
20447            opcional: false,
20448            caracteristicas: Vec::new(),
20449        };
20450        let err = caixa
20451            .push_dep(crate::dep::DepList::Prod, dup)
20452            .expect_err("second push with same :nome refuses");
20453        assert_eq!(
20454            err,
20455            DepError::DuplicateNome {
20456                nome: "caixa-teia".to_string(),
20457                list: crate::render::DEP_AUTHOR_KEY_DEPS,
20458            }
20459        );
20460        // The refused mutation must not corrupt the target list —
20461        // exactly one entry lives past the refusal, matching the
20462        // canonical single-source-of-truth invariant `Caixa::deps()`
20463        // carries.
20464        assert_eq!(caixa.deps().len(), 1);
20465    }
20466
20467    #[test]
20468    fn push_dep_refuses_dup_on_dev_list_arm_names_deps_dev_key() {
20469        // Peer of the sibling `Prod`-arm dup-refusal pin — the `Dev`
20470        // arm's refusal must carry `DEP_AUTHOR_KEY_DEPS_DEV` in the
20471        // `list` payload so a future author reading the refusal grep's
20472        // for the correct `:deps-dev` block in their `caixa.lisp`,
20473        // not the sibling `:deps` block the runtime closure resolves.
20474        let src = Caixa::template("host");
20475        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20476        let dep = Dep {
20477            nome: "tatara-check".to_string(),
20478            versao: "*".to_string(),
20479            fonte: None,
20480            opcional: false,
20481            caracteristicas: Vec::new(),
20482        };
20483        caixa
20484            .push_dep(crate::dep::DepList::Dev, dep.clone())
20485            .expect("first push succeeds");
20486        let err = caixa
20487            .push_dep(crate::dep::DepList::Dev, dep)
20488            .expect_err("second push with same :nome refuses");
20489        assert!(matches!(
20490            err,
20491            DepError::DuplicateNome {
20492                ref nome,
20493                list,
20494            } if nome == "tatara-check"
20495                && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
20496        ));
20497    }
20498
20499    #[test]
20500    fn push_dep_allows_same_nome_across_prod_and_dev_lists() {
20501        // The within-list dup check is scoped to the target arm — a
20502        // caixa may legitimately carry the same `:nome` under both
20503        // `:deps` and `:deps-dev` (though the substrate's peer
20504        // [`crate::Caixa::validate_deps`] walk still refuses the
20505        // shape at parse time; the mutation-site refusal is scoped to
20506        // the mutation-site's list to match the peer parse-time
20507        // per-list [`crate::render::insert_first_seen`] discipline).
20508        // The two arms hold independent seen-sets.
20509        let src = Caixa::template("host");
20510        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20511        let dep_prod = Dep {
20512            nome: "shared".to_string(),
20513            versao: "^0.1".to_string(),
20514            fonte: None,
20515            opcional: false,
20516            caracteristicas: Vec::new(),
20517        };
20518        let dep_dev = Dep {
20519            nome: "shared".to_string(),
20520            versao: "*".to_string(),
20521            fonte: None,
20522            opcional: false,
20523            caracteristicas: Vec::new(),
20524        };
20525        caixa
20526            .push_dep(crate::dep::DepList::Prod, dep_prod)
20527            .expect("push into :deps succeeds");
20528        caixa
20529            .push_dep(crate::dep::DepList::Dev, dep_dev)
20530            .expect("push same :nome into :deps-dev succeeds");
20531        assert_eq!(caixa.deps().len(), 1);
20532        assert_eq!(caixa.deps_dev().len(), 1);
20533    }
20534
20535    #[test]
20536    fn deps_of_prod_returns_the_deps_slot_verbatim() {
20537        // The `Prod` arm of the typed-dispatch [`Caixa::deps_of`] read
20538        // accessor must project onto the runtime-closure `:deps` slot —
20539        // element-equal and length-equal to the sibling per-slot
20540        // [`Caixa::deps`] accessor's return over every per-caixa fixture.
20541        // A future arm that regressed to `self.deps_dev()` on the `Prod`
20542        // path would silently reroute every downstream typed-dispatch
20543        // walker (the [`Caixa::validate_deps`] per-list
20544        // [`crate::render::insert_first_seen`] dedup walk, any future
20545        // per-axis-parametrised consumer) into the sibling dev-only
20546        // closure and this pin refuses that regression.
20547        let src = Caixa::template("host");
20548        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20549        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
20550        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 0);
20551        let dep = Dep {
20552            nome: "caixa-teia".to_string(),
20553            versao: "^0.1".to_string(),
20554            fonte: None,
20555            opcional: false,
20556            caracteristicas: Vec::new(),
20557        };
20558        caixa
20559            .push_dep(crate::dep::DepList::Prod, dep.clone())
20560            .expect("push into :deps succeeds");
20561        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
20562        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 1);
20563        assert_eq!(
20564            caixa.deps_of(crate::dep::DepList::Prod)[0].nome(),
20565            "caixa-teia"
20566        );
20567    }
20568
20569    #[test]
20570    fn deps_of_dev_returns_the_deps_dev_slot_verbatim() {
20571        // Peer of the sibling `Prod`-arm pin — the `Dev` arm of
20572        // [`Caixa::deps_of`] must project onto the dev-only-closure
20573        // `:deps-dev` slot, element-equal and length-equal to the
20574        // sibling per-slot [`Caixa::deps_dev`] accessor's return. A
20575        // future regression that inverted the two arms would silently
20576        // route every dev-list walker onto the runtime closure and this
20577        // pin catches it before the drift ships.
20578        let src = Caixa::template("host");
20579        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20580        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
20581        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 0);
20582        let dep = Dep {
20583            nome: "tatara-check".to_string(),
20584            versao: "*".to_string(),
20585            fonte: None,
20586            opcional: false,
20587            caracteristicas: Vec::new(),
20588        };
20589        caixa
20590            .push_dep(crate::dep::DepList::Dev, dep)
20591            .expect("push into :deps-dev succeeds");
20592        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
20593        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 1);
20594        assert_eq!(
20595            caixa.deps_of(crate::dep::DepList::Dev)[0].nome(),
20596            "tatara-check"
20597        );
20598    }
20599
20600    #[test]
20601    fn deps_of_exhaustive_over_dep_list_all_covers_the_two_slots() {
20602        // Composition pin: iterating [`crate::dep::DepList::ALL`] through
20603        // [`Caixa::deps_of`] must land on the same two-slot partition the
20604        // per-slot [`Caixa::deps`] / [`Caixa::deps_dev`] accessors
20605        // expose — the canonical dispatch a future per-axis-parametrised
20606        // walker (a future `feira app graph` per-list dep summary, a
20607        // future M4 per-cluster dev-closure-audit overlay the CR
20608        // materializer resolves per-CR) reads through. Prior to the
20609        // lift the two-block iteration lived open-coded at every walker,
20610        // so a future third dep-list axis (`:deps-build`, per CAIXA-SDLC
20611        // §I) would have had to grow a third block at every consumer.
20612        // A regression that dropped the `Dev` arm from `ALL` would flip
20613        // the collected pairs to `[(":deps", &[])]` alone and this pin
20614        // refuses that shape.
20615        let src = Caixa::template("host");
20616        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20617        let prod_dep = Dep {
20618            nome: "caixa-teia".to_string(),
20619            versao: "^0.1".to_string(),
20620            fonte: None,
20621            opcional: false,
20622            caracteristicas: Vec::new(),
20623        };
20624        let dev_dep = Dep {
20625            nome: "tatara-check".to_string(),
20626            versao: "*".to_string(),
20627            fonte: None,
20628            opcional: false,
20629            caracteristicas: Vec::new(),
20630        };
20631        caixa
20632            .push_dep(crate::dep::DepList::Prod, prod_dep)
20633            .expect("push into :deps succeeds");
20634        caixa
20635            .push_dep(crate::dep::DepList::Dev, dev_dep)
20636            .expect("push into :deps-dev succeeds");
20637        let collected: Vec<(&'static str, usize, &str)> = crate::dep::DepList::ALL
20638            .iter()
20639            .map(|&list| {
20640                let slice = caixa.deps_of(list);
20641                (list.as_str(), slice.len(), slice[0].nome())
20642            })
20643            .collect();
20644        assert_eq!(
20645            collected,
20646            vec![
20647                (crate::render::DEP_AUTHOR_KEY_DEPS, 1, "caixa-teia"),
20648                (crate::render::DEP_AUTHOR_KEY_DEPS_DEV, 1, "tatara-check"),
20649            ]
20650        );
20651    }
20652
20653    #[test]
20654    fn caixa_deps_of_is_const_fn() {
20655        // Fail-before-pass-after pin on [`Caixa::deps_of`]'s
20656        // `const`-eval-surface posture. The typed-dispatch read
20657        // accessor forwards through the sibling `pub const fn`
20658        // [`Caixa::deps`] / [`Caixa::deps_dev`] per-slot slice
20659        // accessors on the two [`crate::dep::DepList`] enum arms —
20660        // every operator in the body is already `const`-callable
20661        // (`DepList` is a plain `#[derive(Copy)]` closed-set
20662        // discriminator so the `match` arms are const-evaluable, and
20663        // each arm dispatches through the sibling `pub const fn`
20664        // slice accessor). Any future accidental downgrade to
20665        // non-`const` fails the `deps_of_via_const_fn` wrapper below
20666        // at caixa-core build time with E0015 (`cannot call non-const
20667        // method`), strictly stronger than a runtime `assert!` and
20668        // side-stepping the destructor-in-const restriction the
20669        // `Caixa` fixture's owning `String` / `Vec<Dep>` carriers
20670        // rule out on the direct-`const _: () = assert!(...)`
20671        // residence.
20672        //
20673        // Peer of the sibling outer-`Caixa` accessor family pins
20674        // ([`caixa_outer_string_slice_return_accessor_family_is_const_fn`]
20675        // on the `&[String]` universal-axis surface,
20676        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
20677        // on the outer `&[T]` composite-slice surface,
20678        // [`caixa_outer_option_composite_reference_return_accessor_family_is_const_fn`]
20679        // on the outer `Option<&Composite>` surface) — this pin
20680        // extends the `const`-eval-surface discipline onto the outer-
20681        // `Caixa` typed-dispatch read surface on the [`DepList`]-keyed
20682        // dep-list axis, closing the outer-`Caixa` accessor family's
20683        // last unlifted `pub fn` on the read side.
20684        const fn deps_of_via_const_fn(c: &Caixa, list: crate::dep::DepList) -> &[Dep] {
20685            c.deps_of(list)
20686        }
20687        let src = Caixa::template("host");
20688        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20689        // Empty-list arm: both `Prod` and `Dev` degenerate to the
20690        // empty slice with no silent `None` collapse — the
20691        // `#[serde(default)]` `Vec::new()` fold every `defcaixa` form
20692        // that omits the slot lands on.
20693        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod).is_empty());
20694        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev).is_empty());
20695        assert_eq!(
20696            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
20697            caixa.deps()
20698        );
20699        assert_eq!(
20700            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
20701            caixa.deps_dev()
20702        );
20703        // Populated arms: each list carries its own entry, and the
20704        // wrapper / direct dispatches agree byte-for-byte on the
20705        // slice-view under both non-empty arms.
20706        let prod_dep = Dep {
20707            nome: "caixa-teia".to_string(),
20708            versao: "^0.1".to_string(),
20709            fonte: None,
20710            opcional: false,
20711            caracteristicas: Vec::new(),
20712        };
20713        let dev_dep = Dep {
20714            nome: "tatara-check".to_string(),
20715            versao: "*".to_string(),
20716            fonte: None,
20717            opcional: false,
20718            caracteristicas: Vec::new(),
20719        };
20720        caixa
20721            .push_dep(crate::dep::DepList::Prod, prod_dep)
20722            .expect("push into :deps succeeds");
20723        caixa
20724            .push_dep(crate::dep::DepList::Dev, dev_dep)
20725            .expect("push into :deps-dev succeeds");
20726        assert_eq!(
20727            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
20728            caixa.deps()
20729        );
20730        assert_eq!(
20731            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
20732            caixa.deps_dev()
20733        );
20734        assert_eq!(
20735            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod)[0].nome(),
20736            "caixa-teia"
20737        );
20738        assert_eq!(
20739            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev)[0].nome(),
20740            "tatara-check"
20741        );
20742    }
20743
20744    #[test]
20745    fn validate_deps_iterates_through_dep_list_all_via_deps_of() {
20746        // Composition pin: the [`Caixa::validate_deps`] parse-time gate
20747        // must route its per-list [`crate::render::insert_first_seen`]
20748        // dedup walk through [`Caixa::deps_of`] + [`crate::dep::DepList::ALL`]
20749        // rather than the pre-lift open-coded two-block iteration over
20750        // `self.deps()` + `self.deps_dev()`. A regression that dropped
20751        // one arm (e.g. hand-inlining `self.deps()` alone) would silently
20752        // stop refusing within-list dups on the sibling arm; a
20753        // regression that flipped the arm-to-list-key mapping
20754        // (`Dev => DEP_AUTHOR_KEY_DEPS`) would silently mislabel the
20755        // diagnostic surface. Both drifts surface here through a paired
20756        // duplicate-name refusal per arm plus an offending-list-key
20757        // check on the emitted [`DepError::DuplicateNome`] carrier.
20758        for &list in crate::dep::DepList::ALL {
20759            let src = Caixa::template("host");
20760            let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20761            let dup = Dep {
20762                nome: "twin".to_string(),
20763                versao: "^0.1".to_string(),
20764                fonte: None,
20765                opcional: false,
20766                caracteristicas: Vec::new(),
20767            };
20768            match list {
20769                crate::dep::DepList::Prod => {
20770                    caixa.deps.push(dup.clone());
20771                    caixa.deps.push(dup);
20772                }
20773                crate::dep::DepList::Dev => {
20774                    caixa.deps_dev.push(dup.clone());
20775                    caixa.deps_dev.push(dup);
20776                }
20777            }
20778            let err = caixa
20779                .validate_deps()
20780                .expect_err("within-list duplicate :nome must refuse");
20781            assert_eq!(
20782                err,
20783                DepError::DuplicateNome {
20784                    nome: "twin".to_string(),
20785                    list: list.as_str(),
20786                },
20787                "validate_deps on {list} arm must emit \
20788                 DepError::DuplicateNome carrying the arm's own \
20789                 as_str() diagnostic — the arm-to-list-key mapping \
20790                 flowed through DepList::ALL + Caixa::deps_of"
20791            );
20792        }
20793    }
20794
20795    #[test]
20796    fn caixa_licenca_default_pins_canonical_mit_byte() {
20797        // Bridge-arm pin: [`CAIXA_LICENCA_DEFAULT`] resolves to the
20798        // canonical SPDX-`"MIT"` byte today, the same license expression
20799        // every peer substrate-side consumer of the author-omitted
20800        // `:licenca` slot ([`caixa-helm`]'s `build_readme` fallback arm at
20801        // `caixa-helm/src/lib.rs`, the future M4
20802        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-CR
20803        // `Chart.yaml annotations["artifacthub.io/license"]` emitter this
20804        // crate's [`Caixa::validate_licenca`] docstring roadmap already
20805        // names as the second consumer) fills into its per-consumer
20806        // README/annotation emit site. Pin the literal here (peer with the
20807        // [`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`] /
20808        // [`crate::version::DEFAULT_GIT_REMOTE`] /
20809        // [`crate::version::DEFAULT_PLEME_GIT_ORG`] canonical-literal pins
20810        // on the sibling lifted-constant surfaces) so a future
20811        // substrate-side license-fallback rebrand surfaces here as a
20812        // coordinated edit-point: the sibling caixa-helm
20813        // `build_readme_license_line_routes_through_lifted_caixa_licenca_default`
20814        // pinning test already pins the equality at the renderer-emit
20815        // axis; this pin closes the second coordinate of the pair by
20816        // anchoring the lifted constant's current byte to the canonical
20817        // CAIXA-SDLC §I license scaffold's documented shape.
20818        assert_eq!(CAIXA_LICENCA_DEFAULT, "MIT");
20819    }
20820
20821    // ── Caixa::validate_upgrade_from — compound per-Caixa entry gate on ──
20822    // ── the M2 `:upgrade-from` slot: folds the three top-level        ──
20823    // ── `crate::upgrade` validators (per-entry + cross-entry           ──
20824    // ── duplicate-`:from`, cross-slot `:from < :versao` precedence,   ──
20825    // ── cross-slot `:state-change` ↔ `:on-state-change` composition)  ──
20826    // ── onto one substrate primitive. Byte-for-byte equivalent to the ──
20827    // ── pre-fold three-block cascade at                               ──
20828    // ── `crate::layout::StandardLayout::verify` under the same        ──
20829    // ── canonical dispatch order.                                     ──
20830
20831    #[test]
20832    fn validate_upgrade_from_folds_per_entry_arm_matches_gate() {
20833        // Fail-before-pass-after per-arm equivalence pin on the
20834        // per-entry + cross-entry axis: a fixture whose `:upgrade-from`
20835        // carries a per-entry-invalid `:from` (git-tag shape `"v0.1.0"`,
20836        // which `semver::Version::parse` rejects) surfaces the same
20837        // [`crate::UpgradeError`] through the compound gate
20838        // [`Caixa::validate_upgrade_from`] and the standalone per-entry
20839        // gate [`crate::upgrade::validate_upgrade_from`] on the same
20840        // [`Caixa::upgrade_from`] slice. Pins the fold — a silent
20841        // regression that de-folded the per-entry arm would surface here
20842        // as a mismatch between the two dispatches. Sibling in shape to
20843        // the peer per-slot-≡-standalone equivalence pins the
20844        // [`crate::AplicacaoSpec::validate_contratos`] /
20845        // [`crate::MeshPolicy::validate`] /
20846        // [`crate::SupervisorSpec::validate_children`] compound gates
20847        // each carry on their axes.
20848        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20849        c.upgrade_from = vec![crate::UpgradeFromEntry {
20850            from: "v0.1.0".into(),
20851            instructions: vec![crate::UpgradeInstruction::Restart],
20852        }];
20853        let via_method = c.validate_upgrade_from().unwrap_err();
20854        let via_standalone = crate::upgrade::validate_upgrade_from(c.upgrade_from()).unwrap_err();
20855        assert_eq!(
20856            via_method, via_standalone,
20857            "Caixa::validate_upgrade_from must surface the per-entry \
20858             axis's diagnostic byte-equal to the standalone \
20859             `crate::upgrade::validate_upgrade_from` on the same \
20860             upgrade_from() slice"
20861        );
20862        assert!(
20863            matches!(
20864                via_method,
20865                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.1.0"
20866            ),
20867            "expected FromInvalid on the git-tag-shape `:from`, got {via_method:?}"
20868        );
20869    }
20870
20871    #[test]
20872    fn validate_upgrade_from_folds_versao_arm_matches_gate() {
20873        // Per-arm equivalence pin on the cross-slot `:from ↔ :versao`
20874        // precedence axis: a fixture with a well-formed `:from` (so the
20875        // per-entry arm passes) whose parsed semver is >= the caixa's
20876        // `:versao` under SemVer-2 precedence surfaces the same
20877        // [`crate::UpgradeError::FromNotBeforeVersao`] through both the
20878        // compound gate and the standalone
20879        // [`crate::upgrade::validate_upgrade_from_against_versao`] gate
20880        // keyed off the same `(upgrade_from, versao)` pair. Pins the
20881        // fold's second arm — reaching this arm through the compound
20882        // gate requires the per-entry arm to pass first, which itself
20883        // pins the per-arm cross-arm ordering.
20884        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20885        c.versao = "0.1.0".into();
20886        c.upgrade_from = vec![crate::UpgradeFromEntry {
20887            from: "0.2.0".into(),
20888            instructions: vec![crate::UpgradeInstruction::Restart],
20889        }];
20890        let via_method = c.validate_upgrade_from().unwrap_err();
20891        let via_standalone =
20892            crate::upgrade::validate_upgrade_from_against_versao(c.upgrade_from(), c.versao())
20893                .unwrap_err();
20894        assert_eq!(
20895            via_method, via_standalone,
20896            "Caixa::validate_upgrade_from must surface the \
20897             `:from >= :versao` diagnostic byte-equal to the standalone \
20898             `crate::upgrade::validate_upgrade_from_against_versao` on \
20899             the same (upgrade_from, versao) pair"
20900        );
20901        assert!(
20902            matches!(
20903                via_method,
20904                crate::UpgradeError::FromNotBeforeVersao { ref from, ref versao }
20905                    if from == "0.2.0" && versao == "0.1.0"
20906            ),
20907            "expected FromNotBeforeVersao carrying the offending pair, got {via_method:?}"
20908        );
20909    }
20910
20911    #[test]
20912    fn validate_upgrade_from_folds_behavior_arm_matches_gate() {
20913        // Per-arm equivalence pin on the cross-slot `:state-change ↔
20914        // :on-state-change` composition axis: a fixture with a
20915        // well-formed `:from` strictly less than `:versao` (so the
20916        // per-entry and versao arms both pass) whose `:instructions`
20917        // list carries a `(:state-change …)` instruction with no
20918        // `:behavior :on-state-change` callback declared surfaces the
20919        // same [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
20920        // through both the compound gate and the standalone
20921        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
20922        // gate keyed off the same `(upgrade_from, behavior)` pair.
20923        // Reaching this arm through the compound gate requires both
20924        // prior arms to pass first — the ordering pin below pins the
20925        // per-arm dispatch order explicitly.
20926        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20927        c.versao = "0.2.0".into();
20928        c.behavior = None;
20929        c.upgrade_from = vec![crate::UpgradeFromEntry {
20930            from: "0.1.0".into(),
20931            instructions: vec![
20932                crate::UpgradeInstruction::LoadModule {
20933                    module: "demo".into(),
20934                },
20935                crate::UpgradeInstruction::StateChange {
20936                    script: std::path::PathBuf::from("lib/m.lisp"),
20937                },
20938                crate::UpgradeInstruction::SoftPurge {
20939                    module: "demo-old".into(),
20940                },
20941            ],
20942        }];
20943        let via_method = c.validate_upgrade_from().unwrap_err();
20944        let via_standalone =
20945            crate::upgrade::validate_upgrade_from_against_behavior(c.upgrade_from(), c.behavior())
20946                .unwrap_err();
20947        assert_eq!(
20948            via_method, via_standalone,
20949            "Caixa::validate_upgrade_from must surface the \
20950             `:state-change` ↔ `:on-state-change` composition \
20951             diagnostic byte-equal to the standalone \
20952             `crate::upgrade::validate_upgrade_from_against_behavior` \
20953             on the same (upgrade_from, behavior) pair"
20954        );
20955        assert!(
20956            matches!(
20957                via_method,
20958                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback {
20959                    ref from,
20960                    ref script,
20961                } if from == "0.1.0" && script == &std::path::PathBuf::from("lib/m.lisp")
20962            ),
20963            "expected StateChangeWithoutOnStateChangeCallback carrying \
20964             the offending (from, script) pair, got {via_method:?}"
20965        );
20966    }
20967
20968    #[test]
20969    fn validate_upgrade_from_per_entry_arm_fires_before_versao_arm() {
20970        // Cross-arm ordering pin between the first two arms of the
20971        // fold: a fixture carrying BOTH a per-entry-invalid `:from`
20972        // (`"v0.0.5"` — git-tag shape rejected by
20973        // [`crate::upgrade::validate_upgrade_from`]) AND a would-be
20974        // versao-precedence violation on a second entry (`"0.2.0" >=
20975        // :versao "0.1.0"`) surfaces the per-entry diagnostic first
20976        // through the compound gate. Sanity assertion: the second
20977        // entry alone under the same `:versao` trips the versao arm
20978        // on its own via the standalone
20979        // [`crate::upgrade::validate_upgrade_from_against_versao`], so
20980        // the per-entry-first surfacing is a real ordering property,
20981        // not a case where the versao arm silently accepts the
20982        // fixture. Pins the pre-fold layout wire-up's canonical
20983        // dispatch order (per-entry → versao → behavior) as a
20984        // property of the substrate primitive rather than a
20985        // convention of the layout call site.
20986        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20987        c.versao = "0.1.0".into();
20988        c.upgrade_from = vec![
20989            crate::UpgradeFromEntry {
20990                from: "v0.0.5".into(),
20991                instructions: vec![crate::UpgradeInstruction::Restart],
20992            },
20993            crate::UpgradeFromEntry {
20994                from: "0.2.0".into(),
20995                instructions: vec![crate::UpgradeInstruction::Restart],
20996            },
20997        ];
20998        let err = c.validate_upgrade_from().unwrap_err();
20999        assert!(
21000            matches!(
21001                err,
21002                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.0.5"
21003            ),
21004            "per-entry arm must fire before versao arm — expected \
21005             FromInvalid on `v0.0.5`, got {err:?}"
21006        );
21007        // Sanity: the versao-violating second entry alone under the
21008        // same `:versao` trips the versao arm on its own — proves the
21009        // per-entry-first surfacing above is a real ordering property.
21010        let sanity = crate::upgrade::validate_upgrade_from_against_versao(
21011            &[crate::UpgradeFromEntry {
21012                from: "0.2.0".into(),
21013                instructions: vec![crate::UpgradeInstruction::Restart],
21014            }],
21015            "0.1.0",
21016        )
21017        .unwrap_err();
21018        assert!(
21019            matches!(sanity, crate::UpgradeError::FromNotBeforeVersao { .. }),
21020            "sanity: the versao-violating fixture alone must trip the \
21021             versao arm — got {sanity:?}"
21022        );
21023    }
21024
21025    #[test]
21026    fn validate_upgrade_from_versao_arm_fires_before_behavior_arm() {
21027        // Cross-arm ordering pin between the second and third arms of
21028        // the fold: a fixture carrying BOTH a versao-precedence
21029        // violation (`:from "0.2.0" >= :versao "0.1.0"`) AND a
21030        // would-be missing-callback violation (a `(:state-change …)`
21031        // instruction with no `:behavior :on-state-change`) surfaces
21032        // the versao diagnostic first through the compound gate.
21033        // Sanity assertion: the missing-callback fixture alone (with
21034        // the versao-precedence violation removed by bumping
21035        // `:versao` past `:from`) trips the behavior arm on its own
21036        // via the standalone
21037        // [`crate::upgrade::validate_upgrade_from_against_behavior`],
21038        // so the versao-first surfacing is a real ordering property,
21039        // not a case where the behavior arm silently accepts the
21040        // fixture.
21041        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21042        c.versao = "0.1.0".into();
21043        c.behavior = None;
21044        c.upgrade_from = vec![crate::UpgradeFromEntry {
21045            from: "0.2.0".into(),
21046            instructions: vec![
21047                crate::UpgradeInstruction::LoadModule {
21048                    module: "demo".into(),
21049                },
21050                crate::UpgradeInstruction::StateChange {
21051                    script: std::path::PathBuf::from("lib/m.lisp"),
21052                },
21053            ],
21054        }];
21055        let err = c.validate_upgrade_from().unwrap_err();
21056        assert!(
21057            matches!(
21058                err,
21059                crate::UpgradeError::FromNotBeforeVersao { ref from, .. } if from == "0.2.0"
21060            ),
21061            "versao arm must fire before behavior arm — expected \
21062             FromNotBeforeVersao on `0.2.0`, got {err:?}"
21063        );
21064        // Sanity: the same instructions under a `:versao` that
21065        // accepts the `:from` (so the versao arm passes) trips the
21066        // behavior arm — proves the versao-first surfacing above is a
21067        // real ordering property.
21068        let sanity = crate::upgrade::validate_upgrade_from_against_behavior(
21069            &[crate::UpgradeFromEntry {
21070                from: "0.2.0".into(),
21071                instructions: vec![
21072                    crate::UpgradeInstruction::LoadModule {
21073                        module: "demo".into(),
21074                    },
21075                    crate::UpgradeInstruction::StateChange {
21076                        script: std::path::PathBuf::from("lib/m.lisp"),
21077                    },
21078                ],
21079            }],
21080            None,
21081        )
21082        .unwrap_err();
21083        assert!(
21084            matches!(
21085                sanity,
21086                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback { .. }
21087            ),
21088            "sanity: the missing-callback fixture alone must trip the \
21089             behavior arm — got {sanity:?}"
21090        );
21091    }
21092
21093    #[test]
21094    fn validate_upgrade_from_accepts_clean_fixture() {
21095        // Positive control: a well-formed `:upgrade-from` (single entry
21096        // with `:from` strictly less than `:versao`, no
21097        // `:state-change` instruction so the behavior arm is vacuous)
21098        // passes the compound gate cleanly. A future tightening of any
21099        // one arm's accepted set surfaces here as a test failure
21100        // first. Mirrors the peer `validate_versao_accepts_canonical_forms`
21101        // positive-control posture on the sibling per-Caixa gate.
21102        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21103        c.versao = "0.2.0".into();
21104        c.upgrade_from = vec![crate::UpgradeFromEntry {
21105            from: "0.1.0".into(),
21106            instructions: vec![crate::UpgradeInstruction::Restart],
21107        }];
21108        c.validate_upgrade_from()
21109            .expect("clean fixture must pass the compound `:upgrade-from` gate");
21110    }
21111
21112    #[test]
21113    fn validate_upgrade_from_accepts_empty_upgrade_from() {
21114        // Positive control on the empty-list arm: a caixa without any
21115        // `:upgrade-from` block (the default `Vec::new()`
21116        // `#[serde(default)]` folds an omitted slot onto) passes the
21117        // compound gate cleanly regardless of `:versao` or `:behavior`
21118        // — each of the three standalone validators is vacuous on the
21119        // empty entry list. Pins the identity element of the fold on
21120        // the empty-slot side.
21121        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21122        assert!(
21123            c.upgrade_from().is_empty(),
21124            "template caixa must carry an empty :upgrade-from — got {:?}",
21125            c.upgrade_from()
21126        );
21127        c.validate_upgrade_from()
21128            .expect("empty :upgrade-from must pass the compound gate cleanly");
21129    }
21130
21131    // ── Caixa::validate_limits — compound per-Caixa entry gate on   ──
21132    // ── the M2 `:limits` slot: folds the                            ──
21133    // ── [`crate::LimitsSpec::validate`] four-axis cascade on the    ──
21134    // ── present-slot arm and the `Option::None` identity element on ──
21135    // ── the absent-slot arm onto one substrate primitive.           ──
21136    // ── Byte-for-byte equivalent to the pre-fold                    ──
21137    // ── `if let Some(l) = caixa.limits() { l.validate() }`          ──
21138    // ── unwrap-and-dispatch pattern at                              ──
21139    // ── `crate::layout::StandardLayout::verify` (`layout.rs`).      ──
21140
21141    #[test]
21142    fn validate_limits_folds_arm_matches_gate() {
21143        // Fail-before-pass-after per-arm equivalence pin on the
21144        // present-slot arm: a fixture whose `:limits` carries a
21145        // zero-floor-violating `:fuel` (`Some(0)`, which
21146        // [`crate::LimitsSpec::validate`] rejects through
21147        // [`crate::LimitsError::FuelZero`]) surfaces the same
21148        // [`crate::LimitsError`] byte-equal through both the compound
21149        // gate [`Caixa::validate_limits`] and the standalone
21150        // [`crate::LimitsSpec::validate`] gate on the same `LimitsSpec`
21151        // value. Pins the fold — a silent regression that de-folded
21152        // the present-slot arm would surface here as a mismatch
21153        // between the two dispatches. Sibling in shape to the peer
21154        // per-arm equivalence pins the
21155        // [`crate::AplicacaoSpec::validate_contratos`] /
21156        // [`crate::MeshPolicy::validate`] /
21157        // [`crate::SupervisorSpec::validate_children`] /
21158        // [`Caixa::validate_upgrade_from`] compound gates each carry
21159        // on their axes.
21160        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21161        let l = crate::LimitsSpec {
21162            memory: None,
21163            fuel: Some(0),
21164            wall_clock: None,
21165            cpu: None,
21166        };
21167        c.limits = Some(l);
21168        let via_method = c.validate_limits().unwrap_err();
21169        let via_standalone = l.validate().unwrap_err();
21170        assert_eq!(
21171            via_method, via_standalone,
21172            "Caixa::validate_limits must surface the present-slot \
21173             arm's diagnostic byte-equal to the standalone \
21174             `LimitsSpec::validate` on the same `LimitsSpec` value"
21175        );
21176        assert!(
21177            matches!(via_method, crate::LimitsError::FuelZero),
21178            "expected FuelZero on the zero-floor-violating `:fuel`, \
21179             got {via_method:?}"
21180        );
21181    }
21182
21183    #[test]
21184    fn validate_limits_accepts_none() {
21185        // Positive control on the absent-slot arm (the fold's identity
21186        // element): a caixa without any `:limits` block (the
21187        // canonical "no bound declared — engine-default applies"
21188        // author shape [`crate::LimitsSpec::is_empty`]'s per-axis
21189        // `None` cascade reads, and the shape the [`Caixa::template`]
21190        // scaffold emits by construction) passes the compound gate
21191        // cleanly, regardless of any per-axis defect a subsequent
21192        // `Some(_)` binding would surface. Pins the identity element
21193        // of the fold on the absent-slot side, matching the peer
21194        // `validate_upgrade_from_accepts_empty_upgrade_from` positive-
21195        // control posture on the sibling M2 slot.
21196        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21197        assert!(
21198            c.limits().is_none(),
21199            "template caixa must carry an absent :limits — got {:?}",
21200            c.limits()
21201        );
21202        c.validate_limits()
21203            .expect("absent :limits must pass the compound gate cleanly");
21204    }
21205
21206    #[test]
21207    fn validate_limits_accepts_clean_fixture() {
21208        // Positive control on the present-slot arm: a caixa whose
21209        // `:limits` is `Some(LimitsSpec::default())` (all four axes
21210        // `None` — every axis absent under the outer `Some(_)`
21211        // binding, so every present-slot arm on
21212        // [`crate::LimitsSpec::validate`] is vacuous) passes the
21213        // compound gate cleanly. A future tightening of any one axis
21214        // that surfaces a diagnostic on the all-`None` `LimitsSpec`
21215        // would land here as a test failure first. Pins the
21216        // present-slot arm's accept-shape on the canonical
21217        // "declared-but-empty" author fixture the
21218        // `limits_round_trip_via_json` peer already round-trips
21219        // (`caixa-core/src/manifest.rs:6971`).
21220        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21221        c.limits = Some(crate::LimitsSpec::default());
21222        c.validate_limits()
21223            .expect("Some(LimitsSpec::default()) must pass the compound gate cleanly");
21224    }
21225
21226    // ── Caixa::validate_behavior — compound per-Caixa entry gate on ──
21227    // ── the M2 `:behavior` slot's pure value-shape surface: folds   ──
21228    // ── the [`crate::BehaviorSpec::validate`] six-slot cascade on   ──
21229    // ── the present-slot arm and the `Option::None` identity        ──
21230    // ── element on the absent-slot arm onto one substrate primitive.──
21231    // ── Byte-for-byte equivalent to the pre-fold                    ──
21232    // ── `if let Some(b) = caixa.behavior() { b.validate() }`        ──
21233    // ── unwrap-and-dispatch pattern at                              ──
21234    // ── `crate::layout::StandardLayout::verify` (`layout.rs`). The  ──
21235    // ── on-disk callback-path existence walk stays open-coded at    ──
21236    // ── the layout altitude because it needs the                    ──
21237    // ── [`crate::layout::LayoutInvariants::exists`] filesystem       ──
21238    // ── oracle the pure typed-shape surface has no reference to —   ──
21239    // ── mirror of the peer M2 `:upgrade-from` per-instruction       ──
21240    // ── script-path existence probe that stayed at the layout       ──
21241    // ── altitude after the [`Caixa::validate_upgrade_from`] lift    ──
21242    // ── (d6801df) for the same reason.                              ──
21243
21244    #[test]
21245    fn validate_behavior_folds_arm_matches_gate() {
21246        // Fail-before-pass-after per-arm equivalence pin on the
21247        // present-slot arm: a fixture whose `:behavior` carries an
21248        // absolute-path `:on-init` (`"/etc/passwd"`, which
21249        // [`crate::BehaviorSpec::validate`] rejects through
21250        // [`crate::BehaviorError::AbsolutePath`]) surfaces the same
21251        // [`crate::BehaviorError`] byte-equal through both the
21252        // compound gate [`Caixa::validate_behavior`] and the standalone
21253        // [`crate::BehaviorSpec::validate`] gate on the same
21254        // `BehaviorSpec` value. Pins the fold — a silent regression
21255        // that de-folded the present-slot arm would surface here as a
21256        // mismatch between the two dispatches. Sibling in shape to the
21257        // peer per-arm equivalence pins the
21258        // [`Caixa::validate_limits`] (baa4688),
21259        // [`Caixa::validate_upgrade_from`] (d6801df),
21260        // [`crate::MeshPolicy::validate`],
21261        // [`crate::AplicacaoSpec::validate_contratos`], and
21262        // [`crate::SupervisorSpec::validate_children`] compound gates
21263        // each carry on their axes.
21264        use crate::BehaviorSpec;
21265        use std::path::PathBuf;
21266        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21267        let b = BehaviorSpec {
21268            on_init: Some(PathBuf::from("/etc/passwd")),
21269            ..Default::default()
21270        };
21271        c.behavior = Some(b.clone());
21272        let via_method = c.validate_behavior().unwrap_err();
21273        let via_standalone = b.validate().unwrap_err();
21274        assert_eq!(
21275            via_method, via_standalone,
21276            "Caixa::validate_behavior must surface the present-slot \
21277             arm's diagnostic byte-equal to the standalone \
21278             `BehaviorSpec::validate` on the same `BehaviorSpec` value"
21279        );
21280        assert!(
21281            matches!(via_method, crate::BehaviorError::AbsolutePath { .. }),
21282            "expected AbsolutePath on the absolute `:on-init` path, \
21283             got {via_method:?}"
21284        );
21285    }
21286
21287    #[test]
21288    fn validate_behavior_accepts_none() {
21289        // Positive control on the absent-slot arm (the fold's identity
21290        // element): a caixa without any `:behavior` block (the
21291        // canonical "no callback declared — the runtime falls back to
21292        // the wasm-engine's default per arm" author shape
21293        // [`crate::BehaviorSpec::is_empty`]'s per-slot `None` cascade
21294        // reads, and the shape the [`Caixa::template`] scaffold emits
21295        // by construction) passes the compound gate cleanly,
21296        // regardless of any per-slot defect a subsequent `Some(_)`
21297        // binding would surface. Pins the identity element of the fold
21298        // on the absent-slot side, matching the peer
21299        // `validate_limits_accepts_none` (baa4688) and
21300        // `validate_upgrade_from_accepts_empty_upgrade_from` (d6801df)
21301        // positive-control postures on the sibling M2 slots.
21302        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21303        assert!(
21304            c.behavior().is_none(),
21305            "template caixa must carry an absent :behavior — got {:?}",
21306            c.behavior()
21307        );
21308        c.validate_behavior()
21309            .expect("absent :behavior must pass the compound gate cleanly");
21310    }
21311
21312    #[test]
21313    fn validate_behavior_accepts_clean_fixture() {
21314        // Positive control on the present-slot arm: a caixa whose
21315        // `:behavior` is `Some(BehaviorSpec::default())` (all six
21316        // slots `None` — every slot absent under the outer `Some(_)`
21317        // binding, so every present-slot arm on
21318        // [`crate::BehaviorSpec::validate`] is vacuous) passes the
21319        // compound gate cleanly. A future tightening of any one arm
21320        // that surfaces a diagnostic on the all-`None` `BehaviorSpec`
21321        // would land here as a test failure first. Pins the
21322        // present-slot arm's accept-shape on the canonical
21323        // "declared-but-empty" author fixture the sibling
21324        // `empty_behavior_round_trip` peer already round-trips
21325        // (`caixa-core/src/behavior.rs` tests). Mirror of the peer
21326        // `validate_limits_accepts_clean_fixture` (baa4688)
21327        // positive-control posture on the sibling M2 `:limits` slot.
21328        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21329        c.behavior = Some(crate::BehaviorSpec::default());
21330        c.validate_behavior()
21331            .expect("Some(BehaviorSpec::default()) must pass the compound gate cleanly");
21332    }
21333
21334    // ── Caixa::validate_deps — compound per-Caixa entry gate on the ──
21335    // ── dep-graph axis: folds the two standalone validators         ──
21336    // ── (per-entry + within-list duplicate walk that this method    ──
21337    // ── opened on, cross-slot self-edge via                         ──
21338    // ── `crate::dep::validate_no_self_dep`) onto one substrate      ──
21339    // ── primitive. Byte-for-byte equivalent to the pre-fold         ──
21340    // ── two-block cascade at                                        ──
21341    // ── `crate::layout::StandardLayout::verify` under the same      ──
21342    // ── canonical dispatch order (per-entry → self-edge).           ──
21343
21344    #[test]
21345    fn validate_deps_folds_per_entry_arm_matches_gate() {
21346        // Fail-before-pass-after per-arm equivalence pin on the
21347        // per-entry + within-list duplicate axis: a fixture whose
21348        // `:deps` carries a per-entry-invalid `:versao` (`"^bad"`,
21349        // which [`crate::parse_requirement`] rejects) surfaces the
21350        // same [`crate::DepError`] through the compound gate
21351        // [`Caixa::validate_deps`] and the standalone per-entry walk
21352        // ([`Dep::validate`]) on the offending entry. Pins the
21353        // fold — a silent regression that de-folded the per-entry arm
21354        // would surface here as a mismatch between the two
21355        // dispatches. Sibling in shape to the peer
21356        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
21357        // per-arm equivalence pin (d6801df) on the M2
21358        // `:upgrade-from` compound gate's per-entry arm, extended
21359        // here onto the universal-axis `:deps` compound gate's
21360        // per-entry arm.
21361        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21362        c.deps = vec![Dep::simple("d", "^bad")];
21363        let via_method = c.validate_deps().unwrap_err();
21364        let via_standalone = c.deps()[0].validate().unwrap_err();
21365        assert_eq!(
21366            via_method, via_standalone,
21367            "Caixa::validate_deps must surface the per-entry arm's \
21368             diagnostic byte-equal to the standalone \
21369             `Dep::validate` on the same offending entry",
21370        );
21371        assert!(
21372            matches!(
21373                via_method,
21374                DepError::VersaoInvalid { ref nome, .. } if nome == "d"
21375            ),
21376            "expected VersaoInvalid on the malformed :versao, got {via_method:?}",
21377        );
21378    }
21379
21380    #[test]
21381    fn validate_deps_folds_self_edge_arm_matches_gate() {
21382        // Per-arm equivalence pin on the cross-slot self-edge axis:
21383        // a fixture whose `:deps` lists the caixa's own `:nome`
21384        // (a self-dep, which
21385        // [`crate::dep::validate_no_self_dep`] rejects as a
21386        // structurally-invalid one-node cycle in the lacre closure's
21387        // dep-graph) surfaces the same [`crate::DepError::DepIsSelf`]
21388        // through both the compound gate and the standalone
21389        // [`crate::dep::validate_no_self_dep`] gate keyed off the
21390        // same `(deps, deps_dev, nome)` triple. Pins the fold's
21391        // second arm — reaching this arm through the compound gate
21392        // requires the per-entry + within-list duplicate walk to
21393        // pass first, which itself pins one cross-arm ordering step.
21394        // Sibling in shape to the peer
21395        // `validate_upgrade_from_folds_versao_arm_matches_gate` /
21396        // `_folds_behavior_arm_matches_gate` cross-slot equivalence
21397        // pins (d6801df) on the M2 `:upgrade-from` compound gate's
21398        // cross-slot arms.
21399        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21400        c.deps = vec![Dep::simple("demo", "^0.1")];
21401        let via_method = c.validate_deps().unwrap_err();
21402        let via_standalone =
21403            crate::dep::validate_no_self_dep(c.deps(), c.deps_dev(), c.nome()).unwrap_err();
21404        assert_eq!(
21405            via_method, via_standalone,
21406            "Caixa::validate_deps must surface the cross-slot \
21407             self-edge diagnostic byte-equal to the standalone \
21408             `crate::dep::validate_no_self_dep` on the same \
21409             (deps, deps_dev, nome) triple",
21410        );
21411        assert!(
21412            matches!(
21413                via_method,
21414                DepError::DepIsSelf { ref nome, list }
21415                    if nome == "demo" && list == crate::render::DEP_AUTHOR_KEY_DEPS
21416            ),
21417            "expected DepIsSelf carrying (nome=\"demo\", list=\":deps\"), got {via_method:?}",
21418        );
21419    }
21420
21421    #[test]
21422    fn validate_deps_per_entry_arm_fires_before_self_edge_arm() {
21423        // Cross-arm ordering pin between the two arms of the fold:
21424        // a fixture carrying BOTH a per-entry-invalid `:versao`
21425        // (`"^bad"` — [`crate::parse_requirement`] rejects the
21426        // requirement grammar) on a non-self-dep entry AND a
21427        // would-be self-edge violation on a second entry (the
21428        // caixa's own `:nome` "demo") surfaces the per-entry
21429        // diagnostic first through the compound gate. Sanity
21430        // assertion: the second entry alone under the same parent
21431        // `:nome` trips the self-edge arm on its own via the
21432        // standalone [`crate::dep::validate_no_self_dep`], so the
21433        // per-entry-first surfacing is a real ordering property,
21434        // not a case where the self-edge arm silently accepts the
21435        // fixture. Pins the pre-fold layout wire-up's canonical
21436        // dispatch order (per-entry + within-list duplicate →
21437        // self-edge) as a property of the substrate primitive
21438        // rather than a convention of the layout call site. Sibling
21439        // in shape to
21440        // `validate_upgrade_from_per_entry_arm_fires_before_versao_arm`
21441        // (d6801df) on the M2 `:upgrade-from` compound gate's
21442        // per-arm ordering property.
21443        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21444        c.deps = vec![
21445            Dep::simple("orquestra", "^bad"),
21446            Dep::simple("demo", "^0.1"),
21447        ];
21448        let err = c.validate_deps().unwrap_err();
21449        assert!(
21450            matches!(
21451                err,
21452                DepError::VersaoInvalid { ref nome, .. } if nome == "orquestra"
21453            ),
21454            "per-entry arm must fire before self-edge arm — expected \
21455             VersaoInvalid on \"orquestra\", got {err:?}",
21456        );
21457        // Sanity: the self-referential entry alone under the same
21458        // parent `:nome` trips the self-edge arm on its own — proves
21459        // the per-entry-first surfacing above is a real ordering
21460        // property, not a case where the self-edge arm silently
21461        // accepts the fixture.
21462        let sanity = crate::dep::validate_no_self_dep(&[Dep::simple("demo", "^0.1")], &[], "demo")
21463            .unwrap_err();
21464        assert!(
21465            matches!(sanity, DepError::DepIsSelf { ref nome, .. } if nome == "demo"),
21466            "sanity: the self-referential entry alone must trip the \
21467             self-edge arm — got {sanity:?}",
21468        );
21469    }
21470
21471    #[test]
21472    fn validate_deps_accepts_clean_fixture() {
21473        // Positive control: a well-formed dep-graph (one `:deps`
21474        // entry naming a non-self DNS-1123 nome + Cargo-shaped
21475        // requirement, one `:deps-dev` entry on a distinct non-self
21476        // nome) passes the compound gate cleanly. A future
21477        // tightening of either arm's accepted set surfaces here as
21478        // a test failure first. Mirrors the peer
21479        // `validate_upgrade_from_accepts_clean_fixture` positive-
21480        // control posture on the sibling per-Caixa compound gate.
21481        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21482        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
21483        c.deps_dev = vec![Dep::simple("caixa-lint", "^0.2")];
21484        c.validate_deps()
21485            .expect("clean fixture must pass the compound `:deps` gate");
21486    }
21487
21488    #[test]
21489    fn validate_deps_accepts_empty_deps_lists() {
21490        // Positive control on the empty-list arm: a caixa without
21491        // any `:deps` or `:deps-dev` entries (the default
21492        // `Vec::new()` `#[serde(default)]` folds an omitted slot
21493        // onto) passes the compound gate cleanly regardless of
21494        // `:nome` — both the per-entry walk and the self-edge walk
21495        // are vacuous on the empty entry list. Pins the identity
21496        // element of the fold on the empty-slot side, peer with the
21497        // `validate_upgrade_from_accepts_empty_upgrade_from` empty-
21498        // arm positive control (d6801df) on the sibling
21499        // `:upgrade-from` compound gate.
21500        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21501        assert!(
21502            c.deps().is_empty(),
21503            "template caixa must carry an empty :deps — got {:?}",
21504            c.deps(),
21505        );
21506        assert!(
21507            c.deps_dev().is_empty(),
21508            "template caixa must carry an empty :deps-dev — got {:?}",
21509            c.deps_dev(),
21510        );
21511        c.validate_deps()
21512            .expect("empty :deps / :deps-dev must pass the compound gate cleanly");
21513    }
21514
21515    // ── Caixa::validate_aplicacao_shape — compound per-Caixa gate ────────
21516
21517    /// Build a minimal well-formed Aplicacao fixture on top of the
21518    /// canonical template. Every arm of the compound gate then patches
21519    /// exactly one axis away from clean so its per-arm diagnostic
21520    /// surfaces without collateral noise from a peer slot.
21521    fn aplicacao_fixture(nome: &str) -> Caixa {
21522        use crate::aplicacao::{Membro, Placement, PlacementStrategy};
21523        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
21524        c.kind = CaixaKind::Aplicacao;
21525        c.bibliotecas = vec![];
21526        c.membros = vec![
21527            Membro {
21528                caixa: "checkout".into(),
21529                versao: "^0.1".into(),
21530            },
21531            Membro {
21532                caixa: "cart".into(),
21533                versao: "^0.1".into(),
21534            },
21535        ];
21536        // `:placement` defaults to `Replicated` with an empty
21537        // `:clusters` list which
21538        // [`crate::AplicacaoSpec::validate_placement`] refuses; every
21539        // per-strategy variant needs at least one named cluster (per
21540        // MESH-COMPOSITION §II.1). Pin a single-cluster `SingleNode`
21541        // placement so the typed-shape cascade passes cleanly and the
21542        // per-arm fixtures below can each patch exactly one axis.
21543        c.placement = Some(Placement {
21544            estrategia: PlacementStrategy::SingleNode,
21545            clusters: vec!["rio".into()],
21546            shard_key: None,
21547            affinity: None,
21548        });
21549        c
21550    }
21551
21552    #[test]
21553    fn validate_aplicacao_shape_folds_view_arm_matches_gate() {
21554        // Fail-before-pass-after per-arm equivalence pin on the
21555        // typed-shape cascade arm: a fixture whose typed
21556        // [`crate::AplicacaoSpec`] view fails
21557        // [`crate::AplicacaoSpec::validate`] (here — empty `:membros`,
21558        // which [`crate::AplicacaoSpec::validate_membros`] rejects as
21559        // [`crate::AplicacaoError::NoMembros`] at the first per-slot
21560        // gate) surfaces the same [`crate::AplicacaoError`] diagnostic
21561        // through both the compound gate
21562        // [`Caixa::validate_aplicacao_shape`] and the standalone
21563        // [`crate::AplicacaoSpec::validate`] on the same folded view.
21564        // Pins the fold — a silent regression that de-folded the
21565        // typed-shape arm would surface here as a mismatch between the
21566        // two dispatches. Sibling in shape to the peer
21567        // `validate_deps_folds_per_entry_arm_matches_gate` (b5dd55e) /
21568        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
21569        // (d6801df) per-arm equivalence pins on the sibling per-slot
21570        // compound gates.
21571        let mut c = aplicacao_fixture("demo");
21572        c.membros = vec![];
21573        let via_method = c.validate_aplicacao_shape().unwrap_err();
21574        let via_standalone = c.aplicacao_view().unwrap().validate().unwrap_err();
21575        assert_eq!(
21576            via_method, via_standalone,
21577            "Caixa::validate_aplicacao_shape must surface the typed-\
21578             shape arm's diagnostic byte-equal to the standalone \
21579             `AplicacaoSpec::validate` on the same folded view",
21580        );
21581        assert!(
21582            matches!(via_method, crate::AplicacaoError::NoMembros),
21583            "expected NoMembros on the empty :membros, got {via_method:?}",
21584        );
21585    }
21586
21587    #[test]
21588    fn validate_aplicacao_shape_folds_self_membership_arm_matches_gate() {
21589        // Per-arm equivalence pin on the cross-slot self-edge axis: a
21590        // fixture whose `:membros` names the Aplicacao's own `:nome`
21591        // (which [`crate::aplicacao::validate_no_self_membership`]
21592        // rejects as [`crate::AplicacaoError::MembroIsSelfAplicacao`],
21593        // a one-node lacre-closure recursion in the Aplicacao's
21594        // mesh-graph) surfaces the same
21595        // [`crate::AplicacaoError::MembroIsSelfAplicacao`] through both
21596        // the compound gate and the standalone
21597        // [`crate::aplicacao::validate_no_self_membership`] keyed off
21598        // the same `(membros, nome)` pair. Pins the fold's second arm
21599        // — reaching this arm through the compound gate requires the
21600        // typed-shape cascade to pass first, which itself pins one
21601        // cross-arm ordering step. Sibling in shape to the peer
21602        // `validate_deps_folds_self_edge_arm_matches_gate` (b5dd55e)
21603        // cross-slot equivalence pin on the sibling per-slot compound
21604        // gate.
21605        use crate::aplicacao::Membro;
21606        let mut c = aplicacao_fixture("demo");
21607        c.membros = vec![Membro {
21608            caixa: "demo".into(),
21609            versao: "^0.1".into(),
21610        }];
21611        let via_method = c.validate_aplicacao_shape().unwrap_err();
21612        let via_standalone =
21613            crate::aplicacao::validate_no_self_membership(c.membros(), c.nome()).unwrap_err();
21614        assert_eq!(
21615            via_method, via_standalone,
21616            "Caixa::validate_aplicacao_shape must surface the cross-\
21617             slot self-edge diagnostic byte-equal to the standalone \
21618             `aplicacao::validate_no_self_membership` on the same \
21619             (membros, nome) pair",
21620        );
21621        assert!(
21622            matches!(
21623                via_method,
21624                crate::AplicacaoError::MembroIsSelfAplicacao { ref caixa } if caixa == "demo"
21625            ),
21626            "expected MembroIsSelfAplicacao carrying (caixa=\"demo\"), \
21627             got {via_method:?}",
21628        );
21629    }
21630
21631    #[test]
21632    fn validate_aplicacao_shape_view_arm_fires_before_self_membership_arm() {
21633        // Cross-arm ordering pin between the two arms of the fold: a
21634        // fixture carrying BOTH a typed-shape violation (a `:contratos`
21635        // edge whose `:para` is not a declared member — rejected by
21636        // [`crate::AplicacaoSpec::validate_contratos`] as
21637        // [`crate::AplicacaoError::ContratoMemberMissing`]) AND a
21638        // would-be self-edge violation (a `:membros` entry naming the
21639        // caixa's own `:nome`) surfaces the typed-shape diagnostic
21640        // first through the compound gate. Sanity assertion: the
21641        // self-referential `:membros` entry alone under the same
21642        // parent `:nome` trips the self-edge arm on its own via the
21643        // standalone [`crate::aplicacao::validate_no_self_membership`],
21644        // so the typed-shape-first surfacing is a real ordering
21645        // property, not a case where the self-edge arm silently
21646        // accepts the fixture. Pins the pre-fold layout wire-up's
21647        // canonical dispatch order (typed-shape cascade → cross-slot
21648        // self-edge) as a property of the substrate primitive rather
21649        // than a convention of the layout call site. Sibling in shape
21650        // to `validate_deps_per_entry_arm_fires_before_self_edge_arm`
21651        // (b5dd55e) on the sibling per-slot compound gate's per-arm
21652        // ordering property.
21653        use crate::aplicacao::{Membro, WitContract};
21654        let mut c = aplicacao_fixture("demo");
21655        c.membros = vec![Membro {
21656            caixa: "demo".into(),
21657            versao: "^0.1".into(),
21658        }];
21659        c.contratos = vec![WitContract {
21660            de: "demo".into(),
21661            para: "orphan".into(),
21662            wit: "wasi:http/proxy".into(),
21663            endpoint: Some("/x".into()),
21664            subject: None,
21665            slot: None,
21666        }];
21667        let err = c.validate_aplicacao_shape().unwrap_err();
21668        assert!(
21669            matches!(
21670                err,
21671                crate::AplicacaoError::ContratoMemberMissing { ref caixa }
21672                    if caixa == "orphan"
21673            ),
21674            "typed-shape arm must fire before self-edge arm — expected \
21675             ContratoMemberMissing on \"orphan\", got {err:?}",
21676        );
21677        // Sanity: the self-referential `:membros` entry alone under
21678        // the same parent `:nome` trips the self-edge arm on its own
21679        // — proves the typed-shape-first surfacing above is a real
21680        // ordering property, not a case where the self-edge arm
21681        // silently accepts the fixture.
21682        let sanity = crate::aplicacao::validate_no_self_membership(
21683            &[Membro {
21684                caixa: "demo".into(),
21685                versao: "^0.1".into(),
21686            }],
21687            "demo",
21688        )
21689        .unwrap_err();
21690        assert!(
21691            matches!(
21692                sanity,
21693                crate::AplicacaoError::MembroIsSelfAplicacao { ref caixa }
21694                    if caixa == "demo"
21695            ),
21696            "sanity: the self-referential :membros entry alone must \
21697             trip the self-edge arm — got {sanity:?}",
21698        );
21699    }
21700
21701    #[test]
21702    fn validate_aplicacao_shape_accepts_non_aplicacao_kind() {
21703        // Positive control on the identity-element arm: every non-
21704        // Aplicacao kind passes the compound gate trivially — the
21705        // paired [`Caixa::aplicacao_view`] accessor returns `None`
21706        // off the Aplicacao arm (by construction, keyed on
21707        // `caixa.kind().is_aplicacao()`), so the fold short-circuits
21708        // to `Ok(())` without touching the mesh slots. Pins the
21709        // identity element on every non-Aplicacao kind — a future
21710        // refactor that made the mesh-slot cascade fire on the wrong
21711        // kind (say, on a `Servico` whose mesh slots happen to be
21712        // populated in a mis-authored manifest, which the peer
21713        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
21714        // coherence gate would refuse upstream anyway) surfaces here
21715        // as a test failure first. Peer with the
21716        // `validate_limits_accepts_none` / `validate_behavior_accepts_none`
21717        // identity-element pins on the sibling M2 `Option`-shaped
21718        // per-Caixa compound gates.
21719        for kind in [
21720            CaixaKind::Biblioteca,
21721            CaixaKind::Binario,
21722            CaixaKind::Servico,
21723            CaixaKind::Supervisor,
21724            CaixaKind::Acao,
21725        ] {
21726            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21727            c.kind = kind;
21728            assert!(
21729                c.aplicacao_view().is_none(),
21730                "aplicacao_view must return None off the Aplicacao arm \
21731                 for kind {kind:?}",
21732            );
21733            c.validate_aplicacao_shape().expect(
21734                "non-Aplicacao kinds must pass the compound gate as the fold's identity element",
21735            );
21736        }
21737    }
21738
21739    #[test]
21740    fn validate_aplicacao_shape_accepts_clean_fixture() {
21741        // Positive control: a well-formed Aplicacao (two DNS-1123
21742        // members with valid semver constraints, no `:contratos` /
21743        // `:entrada` / `:placement` / `:politicas` set — every
21744        // per-slot gate accepts the vacuous / omitted arm) passes the
21745        // compound gate cleanly. A future tightening of either arm's
21746        // accepted set surfaces here as a test failure first. Mirrors
21747        // the peer `validate_deps_accepts_clean_fixture` (b5dd55e) /
21748        // `validate_upgrade_from_accepts_clean_fixture` (d6801df)
21749        // positive-control postures on the sibling per-Caixa
21750        // compound gates.
21751        let c = aplicacao_fixture("demo");
21752        c.validate_aplicacao_shape()
21753            .expect("clean Aplicacao fixture must pass the compound gate");
21754    }
21755
21756    // ── Caixa::validate_supervisor_shape — compound per-Caixa gate ───────
21757
21758    /// Build a minimal well-formed Supervisor fixture on top of the
21759    /// canonical template. Every arm of the compound gate then patches
21760    /// exactly one axis away from clean so its per-arm diagnostic
21761    /// surfaces without collateral noise from a peer slot. Peer of
21762    /// [`aplicacao_fixture`] on the sibling per-Aplicacao compound
21763    /// gate's pin family.
21764    fn supervisor_fixture(nome: &str) -> Caixa {
21765        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
21766        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
21767        c.kind = CaixaKind::Supervisor;
21768        // Supervisors don't run code — clear the biblioteca slot the
21769        // template seeds so the fold's per-arm diagnostics surface
21770        // without the peer `SupervisorOwnsCode` kind-coherence gate
21771        // firing upstream at the layout altitude.
21772        c.bibliotecas = vec![];
21773        // `:estrategia` defaults to `OneForOne` at the typed view level,
21774        // and `OneForOne` requires at least one `:children` entry — pin
21775        // a single-child `Permanent` worker so the typed-shape cascade
21776        // passes cleanly and the per-arm fixtures below can each patch
21777        // exactly one axis.
21778        c.estrategia = Some(RestartStrategy::OneForOne);
21779        c.children = vec![ChildSpec {
21780            caixa: "worker".into(),
21781            versao: "^0.1".into(),
21782            restart: RestartPolicy::Permanent,
21783        }];
21784        c
21785    }
21786
21787    #[test]
21788    fn validate_supervisor_shape_folds_view_arm_matches_gate() {
21789        // Fail-before-pass-after per-arm equivalence pin on the
21790        // typed-shape cascade arm: a fixture whose typed
21791        // [`crate::SupervisorSpec`] view fails
21792        // [`crate::SupervisorSpec::validate`] (here — a duplicate
21793        // `:children` `:caixa` entry, which
21794        // [`crate::SupervisorSpec::validate`]'s set-not-multiset gate
21795        // rejects as [`crate::SupervisorError::DuplicateChildCaixa`])
21796        // surfaces the same [`crate::SupervisorError`] diagnostic
21797        // through both the compound gate
21798        // [`Caixa::validate_supervisor_shape`] and the standalone
21799        // [`crate::SupervisorSpec::validate`] on the same folded view.
21800        // Pins the fold — a silent regression that de-folded the
21801        // typed-shape arm would surface here as a mismatch between the
21802        // two dispatches. Sibling in shape to the peer
21803        // `validate_aplicacao_shape_folds_view_arm_matches_gate`
21804        // (949a7a0) on the sibling per-Aplicacao compound gate.
21805        use crate::supervisor::{ChildSpec, RestartPolicy};
21806        let mut c = supervisor_fixture("demo");
21807        c.children = vec![
21808            ChildSpec {
21809                caixa: "worker".into(),
21810                versao: "^0.1".into(),
21811                restart: RestartPolicy::Permanent,
21812            },
21813            ChildSpec {
21814                caixa: "worker".into(),
21815                versao: "^0.1".into(),
21816                restart: RestartPolicy::Permanent,
21817            },
21818        ];
21819        let via_method = c.validate_supervisor_shape().unwrap_err();
21820        let via_standalone = c.supervisor_view().unwrap().validate().unwrap_err();
21821        assert_eq!(
21822            via_method, via_standalone,
21823            "Caixa::validate_supervisor_shape must surface the typed-\
21824             shape arm's diagnostic byte-equal to the standalone \
21825             `SupervisorSpec::validate` on the same folded view",
21826        );
21827        assert!(
21828            matches!(
21829                via_method,
21830                crate::SupervisorError::DuplicateChildCaixa { ref caixa }
21831                    if caixa == "worker"
21832            ),
21833            "expected DuplicateChildCaixa on the duplicate 'worker' \
21834             child, got {via_method:?}",
21835        );
21836    }
21837
21838    #[test]
21839    fn validate_supervisor_shape_folds_self_supervision_arm_matches_gate() {
21840        // Per-arm equivalence pin on the cross-slot self-edge axis: a
21841        // fixture whose `:children :caixa` names the Supervisor's own
21842        // `:nome` (which
21843        // [`crate::supervisor::validate_no_self_supervision`] rejects
21844        // as [`crate::SupervisorError::ChildSupervisesSelf`], a
21845        // one-node reconciliation cycle in the supervisor's
21846        // supervision-tree) surfaces the same
21847        // [`crate::SupervisorError::ChildSupervisesSelf`] through both
21848        // the compound gate and the standalone
21849        // [`crate::supervisor::validate_no_self_supervision`] keyed
21850        // off the same `(children, nome)` pair. Pins the fold's
21851        // second arm — reaching this arm through the compound gate
21852        // requires the typed-shape cascade to pass first, which itself
21853        // pins one cross-arm ordering step. Sibling in shape to the
21854        // peer
21855        // `validate_aplicacao_shape_folds_self_membership_arm_matches_gate`
21856        // (949a7a0) cross-slot equivalence pin on the sibling
21857        // per-Aplicacao compound gate.
21858        use crate::supervisor::{ChildSpec, RestartPolicy};
21859        let mut c = supervisor_fixture("demo");
21860        c.children = vec![ChildSpec {
21861            caixa: "demo".into(),
21862            versao: "^0.1".into(),
21863            restart: RestartPolicy::Permanent,
21864        }];
21865        let via_method = c.validate_supervisor_shape().unwrap_err();
21866        let via_standalone =
21867            crate::supervisor::validate_no_self_supervision(c.children(), c.nome()).unwrap_err();
21868        assert_eq!(
21869            via_method, via_standalone,
21870            "Caixa::validate_supervisor_shape must surface the cross-\
21871             slot self-edge diagnostic byte-equal to the standalone \
21872             `supervisor::validate_no_self_supervision` on the same \
21873             (children, nome) pair",
21874        );
21875        assert!(
21876            matches!(
21877                via_method,
21878                crate::SupervisorError::ChildSupervisesSelf { ref caixa } if caixa == "demo"
21879            ),
21880            "expected ChildSupervisesSelf carrying (caixa=\"demo\"), \
21881             got {via_method:?}",
21882        );
21883    }
21884
21885    #[test]
21886    fn validate_supervisor_shape_view_arm_fires_before_self_supervision_arm() {
21887        // Cross-arm ordering pin between the two arms of the fold: a
21888        // fixture carrying BOTH a typed-shape violation (a per-child
21889        // empty `:caixa` name — rejected by
21890        // [`crate::SupervisorSpec::validate`] as
21891        // [`crate::SupervisorError::EmptyChildName`]) AND a would-be
21892        // self-edge violation (a `:children` entry naming the
21893        // supervisor's own `:nome`) surfaces the typed-shape
21894        // diagnostic first through the compound gate. Sanity
21895        // assertion: the self-referential `:children` entry alone
21896        // under the same parent `:nome` trips the self-edge arm on
21897        // its own via the standalone
21898        // [`crate::supervisor::validate_no_self_supervision`], so the
21899        // typed-shape-first surfacing is a real ordering property, not
21900        // a case where the self-edge arm silently accepts the fixture.
21901        // Pins the pre-fold layout wire-up's canonical dispatch order
21902        // (typed-shape cascade → cross-slot self-edge) as a property
21903        // of the substrate primitive rather than a convention of the
21904        // layout call site. Sibling in shape to
21905        // `validate_aplicacao_shape_view_arm_fires_before_self_membership_arm`
21906        // (949a7a0) on the sibling per-Aplicacao compound gate.
21907        use crate::supervisor::{ChildSpec, RestartPolicy};
21908        let mut c = supervisor_fixture("demo");
21909        c.children = vec![
21910            ChildSpec {
21911                caixa: String::new(),
21912                versao: "^0.1".into(),
21913                restart: RestartPolicy::Permanent,
21914            },
21915            ChildSpec {
21916                caixa: "demo".into(),
21917                versao: "^0.1".into(),
21918                restart: RestartPolicy::Permanent,
21919            },
21920        ];
21921        let err = c.validate_supervisor_shape().unwrap_err();
21922        assert!(
21923            matches!(err, crate::SupervisorError::EmptyChildName),
21924            "typed-shape arm must fire before self-edge arm — expected \
21925             EmptyChildName on the empty :caixa child, got {err:?}",
21926        );
21927        // Sanity: the self-referential `:children` entry alone under
21928        // the same parent `:nome` trips the self-edge arm on its own
21929        // — proves the typed-shape-first surfacing above is a real
21930        // ordering property, not a case where the self-edge arm
21931        // silently accepts the fixture.
21932        let sanity = crate::supervisor::validate_no_self_supervision(
21933            &[ChildSpec {
21934                caixa: "demo".into(),
21935                versao: "^0.1".into(),
21936                restart: RestartPolicy::Permanent,
21937            }],
21938            "demo",
21939        )
21940        .unwrap_err();
21941        assert!(
21942            matches!(
21943                sanity,
21944                crate::SupervisorError::ChildSupervisesSelf { ref caixa } if caixa == "demo"
21945            ),
21946            "sanity: the self-referential :children entry alone must \
21947             trip the self-edge arm — got {sanity:?}",
21948        );
21949    }
21950
21951    #[test]
21952    fn validate_supervisor_shape_accepts_non_supervisor_kind() {
21953        // Positive control on the identity-element arm: every non-
21954        // Supervisor kind passes the compound gate trivially — the
21955        // paired [`Caixa::supervisor_view`] accessor returns `None`
21956        // off the Supervisor arm (by construction, keyed on
21957        // `caixa.kind().is_supervisor()`), so the fold short-circuits
21958        // to `Ok(())` without touching the supervision-tree slots.
21959        // Pins the identity element on every non-Supervisor kind — a
21960        // future refactor that made the supervision-tree cascade fire
21961        // on the wrong kind (say, on a `Servico` whose supervision
21962        // slots happen to be populated in a mis-authored manifest,
21963        // which the peer
21964        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
21965        // kind-coherence gate would refuse upstream anyway) surfaces
21966        // here as a test failure first. Peer with the
21967        // `validate_aplicacao_shape_accepts_non_aplicacao_kind`
21968        // (949a7a0) / `validate_limits_accepts_none` /
21969        // `validate_behavior_accepts_none` identity-element pins on
21970        // the sibling per-Caixa compound gates.
21971        for kind in [
21972            CaixaKind::Biblioteca,
21973            CaixaKind::Binario,
21974            CaixaKind::Servico,
21975            CaixaKind::Aplicacao,
21976            CaixaKind::Acao,
21977        ] {
21978            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21979            c.kind = kind;
21980            assert!(
21981                c.supervisor_view().is_none(),
21982                "supervisor_view must return None off the Supervisor \
21983                 arm for kind {kind:?}",
21984            );
21985            c.validate_supervisor_shape().expect(
21986                "non-Supervisor kinds must pass the compound gate as the fold's identity element",
21987            );
21988        }
21989    }
21990
21991    #[test]
21992    fn validate_supervisor_shape_accepts_clean_fixture() {
21993        // Positive control: a well-formed Supervisor (single
21994        // DNS-1123-valid `Permanent` worker child under the
21995        // `OneForOne` strategy — the OTP MaxIntensity/Period defaults
21996        // accept the vacuous `:max-restarts` / `:restart-window`
21997        // arms) passes the compound gate cleanly. A future tightening
21998        // of either arm's accepted set surfaces here as a test
21999        // failure first. Mirrors the peer
22000        // `validate_aplicacao_shape_accepts_clean_fixture` (949a7a0)
22001        // positive-control posture on the sibling per-Caixa compound
22002        // gate.
22003        let c = supervisor_fixture("demo");
22004        c.validate_supervisor_shape()
22005            .expect("clean Supervisor fixture must pass the compound gate");
22006    }
22007
22008    // ── Caixa::validate_acao_shape — compound per-Caixa gate ─────────────
22009
22010    /// Build a minimal well-formed `:kind Acao` fixture with a valid
22011    /// two-node acyclic `:ci` slot. Every arm of the compound gate
22012    /// then patches exactly one axis away from clean so its per-arm
22013    /// diagnostic surfaces without collateral noise from a peer slot.
22014    /// Peer of [`supervisor_fixture`] / [`aplicacao_fixture`] on the
22015    /// sibling per-kind compound gates' pin families.
22016    fn acao_fixture(nome: &str) -> Caixa {
22017        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
22018        c.kind = CaixaKind::Acao;
22019        // Acaos don't run code — clear the biblioteca slot the template
22020        // seeds so the compound gate's per-arm diagnostics surface
22021        // without the peer `AcaoOwnsCode` kind-coherence gate firing
22022        // upstream at the layout altitude.
22023        c.bibliotecas = vec![];
22024        c.ci = Some(canteiro_types::CiRun {
22025            workspace: "pleme-io".into(),
22026            repo: "caixa".into(),
22027            nodes: vec![
22028                canteiro_types::CiNode::new(
22029                    "build",
22030                    canteiro_types::EnvClass::None,
22031                    canteiro_types::ActionRef {
22032                        name: "build".into(),
22033                        command: "true".into(),
22034                        args: vec![],
22035                    },
22036                    vec![],
22037                ),
22038                canteiro_types::CiNode::new(
22039                    "test",
22040                    canteiro_types::EnvClass::None,
22041                    canteiro_types::ActionRef {
22042                        name: "test".into(),
22043                        command: "true".into(),
22044                        args: vec![],
22045                    },
22046                    vec!["build".into()],
22047                ),
22048            ],
22049        });
22050        c
22051    }
22052
22053    #[test]
22054    fn validate_acao_shape_folds_decompose_arm_matches_gate() {
22055        // Fail-before-pass-after per-arm equivalence pin on the
22056        // decompose axis: a fixture whose `:ci` slot fails
22057        // [`canteiro_types::decompose`] (here — a minimal two-node
22058        // cycle `a → b → a`, which the sibling
22059        // [`crate::render::decompose_ci`] wraps as
22060        // [`crate::CiDecomposeFailure`] carrying
22061        // [`canteiro_types::DecomposeError::Cycle`]) surfaces the same
22062        // [`crate::CiDecomposeFailure`] diagnostic through both the
22063        // compound gate [`Caixa::validate_acao_shape`] and the
22064        // standalone [`crate::render::decompose_ci`] on the same
22065        // `(caixa, ci)` fixture. Pins the fold — a silent regression
22066        // that de-folded the decompose arm would surface here as a
22067        // mismatch between the two dispatches. Sibling in shape to the
22068        // peer `validate_supervisor_shape_folds_view_arm_matches_gate`
22069        // / `validate_aplicacao_shape_folds_view_arm_matches_gate` on
22070        // the sibling per-kind compound gates.
22071        //
22072        // [`crate::CiDecomposeFailure`] does not derive `PartialEq`
22073        // (its `#[source]` carrier [`canteiro_types::DecomposeError`]
22074        // does, but the wrapper deliberately does not), so the two
22075        // dispatches are compared through their field pair
22076        // (`nome` + `source`) rather than through `assert_eq!` on the
22077        // wrapper itself — every field on the wrapper is thereby
22078        // pinned byte-equal without depending on an implementation
22079        // detail of `CiDecomposeFailure`'s derive set.
22080        let mut c = acao_fixture("demo");
22081        c.ci = Some(canteiro_types::CiRun {
22082            workspace: "pleme-io".into(),
22083            repo: "caixa".into(),
22084            nodes: vec![
22085                canteiro_types::CiNode::new(
22086                    "a",
22087                    canteiro_types::EnvClass::None,
22088                    canteiro_types::ActionRef {
22089                        name: "a".into(),
22090                        command: "true".into(),
22091                        args: vec![],
22092                    },
22093                    vec!["b".into()],
22094                ),
22095                canteiro_types::CiNode::new(
22096                    "b",
22097                    canteiro_types::EnvClass::None,
22098                    canteiro_types::ActionRef {
22099                        name: "b".into(),
22100                        command: "true".into(),
22101                        args: vec![],
22102                    },
22103                    vec!["a".into()],
22104                ),
22105            ],
22106        });
22107        let via_method = c.validate_acao_shape().unwrap_err();
22108        let via_standalone =
22109            crate::render::decompose_ci(&c, c.ci().expect("fixture has a :ci")).unwrap_err();
22110        assert_eq!(
22111            via_method.nome, via_standalone.nome,
22112            "Caixa::validate_acao_shape must surface the decompose \
22113             failure's `nome` byte-equal to the standalone \
22114             `decompose_ci` on the same (caixa, ci) fixture",
22115        );
22116        assert_eq!(
22117            via_method.source, via_standalone.source,
22118            "Caixa::validate_acao_shape must surface the decompose \
22119             failure's `source` byte-equal to the standalone \
22120             `decompose_ci` on the same (caixa, ci) fixture",
22121        );
22122        assert_eq!(
22123            via_method.source,
22124            canteiro_types::DecomposeError::Cycle,
22125            "expected the two-node cycle `a → b → a` to surface as \
22126             DecomposeError::Cycle, got {source:?}",
22127            source = via_method.source,
22128        );
22129    }
22130
22131    #[test]
22132    fn validate_acao_shape_folds_duplicate_node_arm_matches_gate() {
22133        // Per-arm equivalence pin on the `DuplicateNode` decompose
22134        // arm — the sibling of `Cycle` on the substrate's
22135        // `canteiro_types::DecomposeError` enumeration. A fixture
22136        // whose `:ci` slot carries two nodes sharing one name
22137        // surfaces the same [`crate::CiDecomposeFailure`] through
22138        // both dispatches, pinned by field pair. The three
22139        // decompose arms (`DuplicateNode` / `UnknownDep` / `Cycle`)
22140        // together enumerate every failure mode
22141        // [`canteiro_types::decompose`] refuses, so the per-arm
22142        // pins collectively cover the whole decompose axis.
22143        let mut c = acao_fixture("demo");
22144        c.ci = Some(canteiro_types::CiRun {
22145            workspace: "pleme-io".into(),
22146            repo: "caixa".into(),
22147            nodes: vec![
22148                canteiro_types::CiNode::new(
22149                    "twin",
22150                    canteiro_types::EnvClass::None,
22151                    canteiro_types::ActionRef {
22152                        name: "twin".into(),
22153                        command: "true".into(),
22154                        args: vec![],
22155                    },
22156                    vec![],
22157                ),
22158                canteiro_types::CiNode::new(
22159                    "twin",
22160                    canteiro_types::EnvClass::None,
22161                    canteiro_types::ActionRef {
22162                        name: "twin".into(),
22163                        command: "true".into(),
22164                        args: vec![],
22165                    },
22166                    vec![],
22167                ),
22168            ],
22169        });
22170        let via_method = c.validate_acao_shape().unwrap_err();
22171        assert_eq!(
22172            via_method.source,
22173            canteiro_types::DecomposeError::DuplicateNode("twin".into()),
22174            "expected DuplicateNode on the two-\"twin\"-name fixture, \
22175             got {source:?}",
22176            source = via_method.source,
22177        );
22178    }
22179
22180    #[test]
22181    fn validate_acao_shape_folds_unknown_dep_arm_matches_gate() {
22182        // Per-arm equivalence pin on the `UnknownDep` decompose arm —
22183        // the third and last arm on `canteiro_types::DecomposeError`
22184        // after `Cycle` and `DuplicateNode`. A fixture whose `:ci`
22185        // slot names a `deps` entry no declared node satisfies
22186        // surfaces the same [`crate::CiDecomposeFailure`] through
22187        // both dispatches. Pins the third decompose arm at the
22188        // compound gate.
22189        let mut c = acao_fixture("demo");
22190        c.ci = Some(canteiro_types::CiRun {
22191            workspace: "pleme-io".into(),
22192            repo: "caixa".into(),
22193            nodes: vec![canteiro_types::CiNode::new(
22194                "orphan",
22195                canteiro_types::EnvClass::None,
22196                canteiro_types::ActionRef {
22197                    name: "orphan".into(),
22198                    command: "true".into(),
22199                    args: vec![],
22200                },
22201                vec!["ghost".into()],
22202            )],
22203        });
22204        let via_method = c.validate_acao_shape().unwrap_err();
22205        assert_eq!(
22206            via_method.source,
22207            canteiro_types::DecomposeError::UnknownDep {
22208                node: "orphan".into(),
22209                dep: "ghost".into(),
22210            },
22211            "expected UnknownDep on the orphan-node-depends-on-ghost \
22212             fixture, got {source:?}",
22213            source = via_method.source,
22214        );
22215    }
22216
22217    #[test]
22218    fn validate_acao_shape_accepts_non_acao_kind() {
22219        // Positive control on the identity-element arm: every non-
22220        // Acao kind passes the compound gate trivially — the paired
22221        // `caixa.kind().is_acao()` guard short-circuits before the
22222        // decompose gate ever fires, so the fold returns `Ok(())`
22223        // without touching the `:ci` slot even when a non-Acao
22224        // fixture happens to declare one (the sibling
22225        // [`crate::LayoutError::CiOnNonAcao`] kind-coherence gate
22226        // catches that at the layout altitude anyway). Pins the
22227        // identity element on every non-Acao kind. Peer with the
22228        // `validate_supervisor_shape_accepts_non_supervisor_kind` /
22229        // `validate_aplicacao_shape_accepts_non_aplicacao_kind`
22230        // identity-element pins on the sibling per-Caixa compound
22231        // gates.
22232        for kind in [
22233            CaixaKind::Biblioteca,
22234            CaixaKind::Binario,
22235            CaixaKind::Servico,
22236            CaixaKind::Supervisor,
22237            CaixaKind::Aplicacao,
22238        ] {
22239            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22240            c.kind = kind;
22241            c.validate_acao_shape().expect(
22242                "non-Acao kinds must pass the compound gate as the fold's identity element",
22243            );
22244        }
22245    }
22246
22247    #[test]
22248    fn validate_acao_shape_accepts_absent_ci_slot() {
22249        // Positive control on the second identity-element arm: a
22250        // `:kind Acao` caixa with `ci = None` passes the compound
22251        // gate trivially — the presence gate is the sibling axis
22252        // owned by [`crate::LayoutError::MissingCi`] /
22253        // [`crate::require_ci`] / [`crate::MissingCiSlot`], not by
22254        // the decompose gate. A caixa that carries no `:ci` slot
22255        // has no run to decompose, so the fold's `let Some(ci) = …
22256        // else { return Ok(()) }` arm short-circuits before the
22257        // decompose gate fires. Pins that the two axes stay
22258        // separately diagnosable at the layout altitude — a future
22259        // regression that collapsed the presence gate onto the
22260        // shape gate here would land a
22261        // [`crate::CiDecomposeFailure`] on the wrong axis and
22262        // surface an off-target diagnostic at `feira build` time.
22263        let mut c = acao_fixture("demo");
22264        c.ci = None;
22265        c.validate_acao_shape().expect(
22266            "an :kind Acao caixa with absent :ci must pass the compound gate — \
22267             the presence gate is layout's MissingCi axis, not the decompose gate",
22268        );
22269    }
22270
22271    #[test]
22272    fn validate_acao_shape_accepts_clean_fixture() {
22273        // Positive control: a well-formed Acao (a two-node acyclic
22274        // `:ci` run with `test` depending on `build`) passes the
22275        // compound gate cleanly. A future tightening of the
22276        // decompose gate's accepted set surfaces here as a test
22277        // failure first. Mirrors the peer
22278        // `validate_supervisor_shape_accepts_clean_fixture` /
22279        // `validate_aplicacao_shape_accepts_clean_fixture`
22280        // positive-control posture on the sibling per-Caixa
22281        // compound gates.
22282        let c = acao_fixture("demo");
22283        c.validate_acao_shape()
22284            .expect("clean Acao fixture must pass the compound gate");
22285    }
22286
22287    fn bare_servico_fixture(nome: &str) -> Caixa {
22288        // A minimal Servico caixa with no code and no typed slots —
22289        // the cross-family fold's identity element on every arm.
22290        // Clears the biblioteca slot the template seeds so the
22291        // per-arm patches below can each add exactly one typed slot
22292        // without a peer `ServicoOwnsCode` / layout-side kind-gate
22293        // firing upstream.
22294        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
22295        c.kind = CaixaKind::Servico;
22296        c.bibliotecas = vec![];
22297        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
22298        c
22299    }
22300
22301    #[test]
22302    fn validate_kind_slot_coherence_folds_mesh_arm_matches_gate() {
22303        // Fail-before-pass-after per-arm equivalence pin on the M3
22304        // mesh-slot arm of the cross-family kind-coherence fold: a
22305        // non-Aplicacao caixa carrying a declared M3 mesh slot (here
22306        // a `:kind Servico` fixture with a single `:membros` entry —
22307        // the smallest possible M3 slot declaration on a foreign
22308        // kind) surfaces the same
22309        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] variant
22310        // through both the compound gate
22311        // [`Caixa::validate_kind_slot_coherence`] and the standalone
22312        // constructor [`crate::LayoutError::mesh_slots_on_non_aplicacao`]
22313        // dispatched on the same `declared_mesh_slots` list. Pins
22314        // the fold — a silent regression that de-folded the mesh
22315        // arm would surface here as a mismatch between the two
22316        // dispatches. Sibling in shape to the peer
22317        // `validate_aplicacao_shape_folds_view_arm_matches_gate` /
22318        // `validate_supervisor_shape_folds_view_arm_matches_gate` /
22319        // `validate_acao_shape_folds_decompose_arm_matches_gate`
22320        // per-arm equivalence pins on the sibling per-kind compound
22321        // gates.
22322        use crate::aplicacao::Membro;
22323        let mut c = bare_servico_fixture("demo");
22324        c.membros = vec![Membro {
22325            caixa: "cart".into(),
22326            versao: "^0.1".into(),
22327        }];
22328        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22329        let via_standalone =
22330            crate::LayoutError::mesh_slots_on_non_aplicacao(&c, c.declared_mesh_slots());
22331        assert_eq!(
22332            via_method, via_standalone,
22333            "Caixa::validate_kind_slot_coherence must surface the M3 \
22334             mesh-slot arm's diagnostic byte-equal to the standalone \
22335             LayoutError::mesh_slots_on_non_aplicacao ctor on the same \
22336             declared_mesh_slots list",
22337        );
22338    }
22339
22340    #[test]
22341    fn validate_kind_slot_coherence_folds_supervisor_arm_matches_gate() {
22342        // Per-arm equivalence pin on the supervisor-tree arm — the
22343        // sibling of the mesh arm on the cross-family fold. A
22344        // non-Supervisor caixa carrying a declared supervisor slot
22345        // (a `:kind Servico` fixture with `:estrategia` set — the
22346        // smallest possible supervisor slot declaration on a
22347        // foreign kind) surfaces the same
22348        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
22349        // variant through both dispatches, pinned by field pair
22350        // through `PartialEq`.
22351        use crate::supervisor::RestartStrategy;
22352        let mut c = bare_servico_fixture("demo");
22353        c.estrategia = Some(RestartStrategy::OneForOne);
22354        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22355        let via_standalone = crate::LayoutError::supervisor_slots_on_non_supervisor(
22356            &c,
22357            c.declared_supervisor_slots(),
22358        );
22359        assert_eq!(
22360            via_method, via_standalone,
22361            "Caixa::validate_kind_slot_coherence must surface the \
22362             supervisor-tree arm's diagnostic byte-equal to the \
22363             standalone LayoutError::supervisor_slots_on_non_supervisor \
22364             ctor on the same declared_supervisor_slots list",
22365        );
22366    }
22367
22368    #[test]
22369    fn validate_kind_slot_coherence_folds_servico_arm_matches_gate() {
22370        // Per-arm equivalence pin on the M2 Servico-runtime arm —
22371        // the third and last arm on the cross-family fold. A
22372        // non-Servico caixa carrying a declared M2 slot (a `:kind
22373        // Biblioteca` fixture with `:limits` set — the smallest
22374        // possible M2 slot declaration on a foreign kind) surfaces
22375        // the same [`crate::LayoutError::ServicoSlotsOnNonServico`]
22376        // variant through both dispatches. The three arms together
22377        // enumerate every typed-slot family the substrate carries
22378        // whose "declared but ignored" footgun is gated at the
22379        // layout altitude by a `{ caixa, kind, slots }` wrap variant,
22380        // so the per-arm pins collectively cover the whole
22381        // cross-family kind-coherence axis.
22382        use crate::limits::LimitsSpec;
22383        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22384        c.kind = CaixaKind::Biblioteca;
22385        c.limits = Some(LimitsSpec {
22386            memory: Some(64 * 1024 * 1024),
22387            fuel: None,
22388            wall_clock: None,
22389            cpu: None,
22390        });
22391        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22392        let via_standalone =
22393            crate::LayoutError::servico_slots_on_non_servico(&c, c.declared_servico_slots());
22394        assert_eq!(
22395            via_method, via_standalone,
22396            "Caixa::validate_kind_slot_coherence must surface the M2 \
22397             Servico-runtime arm's diagnostic byte-equal to the \
22398             standalone LayoutError::servico_slots_on_non_servico ctor \
22399             on the same declared_servico_slots list",
22400        );
22401    }
22402
22403    #[test]
22404    fn validate_kind_slot_coherence_mesh_arm_fires_before_supervisor_arm() {
22405        // Cross-arm ordering pin between the first two arms of the
22406        // fold: a fixture carrying BOTH a declared M3 mesh slot
22407        // (`:membros`) AND a declared supervisor-tree slot
22408        // (`:estrategia`) on a foreign kind (a `:kind Servico` here —
22409        // foreign to both the Aplicacao arm and the Supervisor arm)
22410        // surfaces the M3 mesh diagnostic first through the compound
22411        // gate. Pins the pre-fold layout wire-up's canonical
22412        // diagnostic sequence (mesh → supervisor → servico) as a
22413        // property of the substrate primitive rather than a
22414        // convention of the layout call site. A silent reordering
22415        // regression at the primitive would surface here as a
22416        // wrong-variant match before landing at a downstream
22417        // consumer's diagnostic-ordering expectation.
22418        use crate::aplicacao::Membro;
22419        use crate::supervisor::RestartStrategy;
22420        let mut c = bare_servico_fixture("demo");
22421        c.membros = vec![Membro {
22422            caixa: "cart".into(),
22423            versao: "^0.1".into(),
22424        }];
22425        c.estrategia = Some(RestartStrategy::OneForOne);
22426        let err = c.validate_kind_slot_coherence().unwrap_err();
22427        assert!(
22428            matches!(err, crate::LayoutError::MeshSlotsOnNonAplicacao { .. }),
22429            "expected MeshSlotsOnNonAplicacao to fire before \
22430             SupervisorSlotsOnNonSupervisor under the canonical \
22431             mesh → supervisor → servico order, got {err:?}",
22432        );
22433    }
22434
22435    #[test]
22436    fn validate_kind_slot_coherence_supervisor_arm_fires_before_servico_arm() {
22437        // Cross-arm ordering pin between the second and third arms
22438        // of the fold: a fixture carrying BOTH a declared
22439        // supervisor-tree slot (`:estrategia`) AND a declared M2 slot
22440        // (`:limits`) on a kind foreign to both (a `:kind Biblioteca`
22441        // here — foreign to both the Supervisor and the Servico
22442        // arms) surfaces the supervisor-tree diagnostic first
22443        // through the compound gate. Together with the peer
22444        // `_mesh_arm_fires_before_supervisor_arm` pin above this
22445        // pins the whole three-arm canonical order (mesh →
22446        // supervisor → servico) at the substrate primitive.
22447        use crate::limits::LimitsSpec;
22448        use crate::supervisor::RestartStrategy;
22449        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22450        c.kind = CaixaKind::Biblioteca;
22451        c.estrategia = Some(RestartStrategy::OneForOne);
22452        c.limits = Some(LimitsSpec {
22453            memory: Some(64 * 1024 * 1024),
22454            fuel: None,
22455            wall_clock: None,
22456            cpu: None,
22457        });
22458        let err = c.validate_kind_slot_coherence().unwrap_err();
22459        assert!(
22460            matches!(
22461                err,
22462                crate::LayoutError::SupervisorSlotsOnNonSupervisor { .. }
22463            ),
22464            "expected SupervisorSlotsOnNonSupervisor to fire before \
22465             ServicoSlotsOnNonServico under the canonical mesh → \
22466             supervisor → servico order, got {err:?}",
22467        );
22468    }
22469
22470    #[test]
22471    fn validate_kind_slot_coherence_accepts_owner_kind_on_every_arm() {
22472        // Positive control on the identity-element arm: the owner
22473        // kind of each typed-slot family passes the compound gate
22474        // even when it declares the full slot set that family owns.
22475        // Aplicacao with `:membros` populated passes the mesh arm;
22476        // Supervisor with `:estrategia` populated passes the
22477        // supervisor arm; Servico with `:limits` populated passes
22478        // the servico arm. Pins the fold's identity element on
22479        // every owner kind — a silent regression that dropped the
22480        // paired `!kind().is_<owner>()` short-circuit guard would
22481        // surface here as a false-positive rejection of every
22482        // native-slot declaration. Peer with the
22483        // `validate_<kind>_shape_accepts_non_<kind>_kind` identity-
22484        // element pins on the sibling per-Caixa compound gates.
22485        use crate::aplicacao::{Membro, Placement, PlacementStrategy};
22486        use crate::limits::LimitsSpec;
22487        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
22488
22489        let mut apli = Caixa::from_lisp(&Caixa::template("app")).unwrap();
22490        apli.kind = CaixaKind::Aplicacao;
22491        apli.bibliotecas = vec![];
22492        apli.membros = vec![Membro {
22493            caixa: "cart".into(),
22494            versao: "^0.1".into(),
22495        }];
22496        apli.placement = Some(Placement {
22497            estrategia: PlacementStrategy::SingleNode,
22498            clusters: vec!["rio".into()],
22499            shard_key: None,
22500            affinity: None,
22501        });
22502        apli.validate_kind_slot_coherence().expect(
22503            "an :kind Aplicacao caixa with declared M3 mesh slots must \
22504             pass the compound gate — Aplicacao is the mesh-slot family's \
22505             owner kind and the fold's identity element on that arm",
22506        );
22507
22508        let mut sup = Caixa::from_lisp(&Caixa::template("sup")).unwrap();
22509        sup.kind = CaixaKind::Supervisor;
22510        sup.bibliotecas = vec![];
22511        sup.estrategia = Some(RestartStrategy::OneForOne);
22512        sup.children = vec![ChildSpec {
22513            caixa: "worker".into(),
22514            versao: "^0.1".into(),
22515            restart: RestartPolicy::Permanent,
22516        }];
22517        sup.validate_kind_slot_coherence().expect(
22518            "an :kind Supervisor caixa with declared supervisor-tree slots \
22519             must pass the compound gate — Supervisor is the \
22520             supervisor-slot family's owner kind and the fold's identity \
22521             element on that arm",
22522        );
22523
22524        let mut svc = bare_servico_fixture("svc");
22525        svc.limits = Some(LimitsSpec {
22526            memory: Some(64 * 1024 * 1024),
22527            fuel: None,
22528            wall_clock: None,
22529            cpu: None,
22530        });
22531        svc.validate_kind_slot_coherence().expect(
22532            "an :kind Servico caixa with declared M2 slots must pass the \
22533             compound gate — Servico is the M2-slot family's owner kind \
22534             and the fold's identity element on that arm",
22535        );
22536    }
22537
22538    #[test]
22539    fn validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind() {
22540        // Positive control on the second identity-element arm: a
22541        // bare caixa (no declared typed slots) passes the compound
22542        // gate on every kind. Pins the fold's identity element on
22543        // the empty-slot axis — the paired `Vec::is_empty` short-
22544        // circuit guard fires before the wrap dispatch on all three
22545        // arms, so a bare caixa of any kind surfaces no diagnostic.
22546        // A silent regression that dropped the emptiness guard
22547        // would surface here as a false-positive rejection of every
22548        // no-slot caixa across the whole kind axis.
22549        for kind in CaixaKind::ALL {
22550            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22551            c.kind = *kind;
22552            c.bibliotecas = vec![];
22553            c.validate_kind_slot_coherence().unwrap_or_else(|err| {
22554                panic!(
22555                    "a bare :kind {kind:?} caixa (no declared typed slots) \
22556                     must pass the compound gate — the fold's identity \
22557                     element on the empty-slot axis is the paired \
22558                     Vec::is_empty short-circuit guard, got {err:?}",
22559                )
22560            });
22561        }
22562    }
22563
22564    #[test]
22565    fn run_kind_owned_slot_family_gate_owner_kind_short_circuits_before_accumulator() {
22566        // Fail-before-pass-after identity-element pin on the owner-kind
22567        // arm of the substrate primitive: on a caixa whose kind IS the
22568        // owner of the family named by `is_owner`, the primitive
22569        // short-circuits before dispatching `accumulator` — pinned here
22570        // by a poison-pill accumulator that panics on call. If a
22571        // regression drops the `is_owner` short-circuit and always
22572        // invokes the accumulator, the poison panic surfaces here
22573        // rather than a spurious pass. Byte-equal to the pre-lift
22574        // `if !self.kind().is_<owner>() { … }` outer guard's
22575        // short-circuit at the pre-fold layout call site.
22576        let c = bare_servico_fixture("demo");
22577        c.run_kind_owned_slot_family_gate(
22578            CaixaKind::is_servico,
22579            |_| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking accumulator on the owner kind"),
22580            |_, _| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking wrap on the owner kind"),
22581        )
22582        .expect(
22583            "the owner kind of a slot family must pass the substrate \
22584             primitive as the fold's identity element on the outer \
22585             is_owner guard, without invoking accumulator or wrap",
22586        );
22587    }
22588
22589    #[test]
22590    fn run_kind_owned_slot_family_gate_empty_accumulator_short_circuits_before_wrap() {
22591        // Fail-before-pass-after identity-element pin on the empty-
22592        // accumulator arm: on a non-owner kind whose per-family
22593        // accumulator yields no declared slot, the primitive short-
22594        // circuits before dispatching `wrap` — pinned here by a
22595        // poison-pill wrap that panics on call. Byte-equal to the
22596        // pre-lift `if !<slots>.is_empty() { … }` inner emptiness
22597        // guard's short-circuit at the pre-fold layout call site.
22598        let c = bare_servico_fixture("demo");
22599        c.run_kind_owned_slot_family_gate(
22600            CaixaKind::is_aplicacao,
22601            Caixa::declared_mesh_slots,
22602            |_, _| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking wrap on an empty accumulator"),
22603        )
22604        .expect(
22605            "a non-owner kind carrying no declared slot in the family \
22606             must pass the substrate primitive as the fold's identity \
22607             element on the inner emptiness guard, without invoking \
22608             wrap",
22609        );
22610    }
22611
22612    #[test]
22613    fn run_kind_owned_slot_family_gate_non_owner_non_empty_wraps_verbatim() {
22614        // Equivalence pin on the refusal arm: on a non-owner kind
22615        // whose accumulator yields a non-empty slot list, the primitive
22616        // returns the caller-supplied wrap byte-equal to the direct
22617        // ctor dispatch on the same `(caixa, slots)` pair. Pins the
22618        // three-argument route through — `is_owner` fires false, the
22619        // accumulator produces the slot list, and the wrap ctor
22620        // receives verbatim what a direct dispatch would receive.
22621        // Sibling of the peer per-arm equivalence pins on
22622        // [`Caixa::validate_kind_slot_coherence`].
22623        use crate::aplicacao::Membro;
22624        let mut c = bare_servico_fixture("demo");
22625        c.membros = vec![Membro {
22626            caixa: "cart".into(),
22627            versao: "^0.1".into(),
22628        }];
22629        let via_primitive = c
22630            .run_kind_owned_slot_family_gate(
22631                CaixaKind::is_aplicacao,
22632                Caixa::declared_mesh_slots,
22633                crate::LayoutError::mesh_slots_on_non_aplicacao,
22634            )
22635            .unwrap_err();
22636        let via_direct =
22637            crate::LayoutError::mesh_slots_on_non_aplicacao(&c, c.declared_mesh_slots());
22638        assert_eq!(
22639            via_primitive, via_direct,
22640            "Caixa::run_kind_owned_slot_family_gate must route the \
22641             non-owner-kind + non-empty-accumulator arm through the \
22642             caller-supplied wrap byte-equal to the direct ctor \
22643             dispatch on the same (caixa, slots) pair",
22644        );
22645    }
22646
22647    #[test]
22648    fn validate_kind_slot_coherence_routes_each_arm_through_run_kind_owned_slot_family_gate() {
22649        // Cross-primitive routing pin: every arm of the compound gate
22650        // [`Caixa::validate_kind_slot_coherence`] routes through the
22651        // substrate primitive [`Caixa::run_kind_owned_slot_family_gate`]
22652        // on its `(is_owner, accumulator, wrap)` triple. A silent
22653        // regression that de-folded one arm and re-inlined the four-
22654        // line block would surface here as a mismatch between the
22655        // compound-gate error and the direct-primitive-dispatch error
22656        // on the same fixture. Sibling of the peer
22657        // `probe_declared_entries_routes_miss_arm_through_probe_declared_entry`
22658        // cross-primitive routing pin on the layout-pipeline
22659        // existence-probe axis.
22660        use crate::aplicacao::Membro;
22661        use crate::limits::LimitsSpec;
22662        use crate::supervisor::RestartStrategy;
22663
22664        // Mesh arm — non-Aplicacao carrying a declared M3 slot.
22665        let mut mesh = bare_servico_fixture("demo");
22666        mesh.membros = vec![Membro {
22667            caixa: "cart".into(),
22668            versao: "^0.1".into(),
22669        }];
22670        let via_compound = mesh.validate_kind_slot_coherence().unwrap_err();
22671        let via_primitive = mesh
22672            .run_kind_owned_slot_family_gate(
22673                CaixaKind::is_aplicacao,
22674                Caixa::declared_mesh_slots,
22675                crate::LayoutError::mesh_slots_on_non_aplicacao,
22676            )
22677            .unwrap_err();
22678        assert_eq!(
22679            via_compound, via_primitive,
22680            "validate_kind_slot_coherence's mesh arm must route \
22681             byte-equal through the run_kind_owned_slot_family_gate \
22682             substrate primitive",
22683        );
22684
22685        // Supervisor arm — non-Supervisor carrying a declared
22686        // supervisor-tree slot on a kind foreign to both the Aplicacao
22687        // arm and this one.
22688        let mut sup = bare_servico_fixture("demo");
22689        sup.estrategia = Some(RestartStrategy::OneForOne);
22690        let via_compound = sup.validate_kind_slot_coherence().unwrap_err();
22691        let via_primitive = sup
22692            .run_kind_owned_slot_family_gate(
22693                CaixaKind::is_supervisor,
22694                Caixa::declared_supervisor_slots,
22695                crate::LayoutError::supervisor_slots_on_non_supervisor,
22696            )
22697            .unwrap_err();
22698        assert_eq!(
22699            via_compound, via_primitive,
22700            "validate_kind_slot_coherence's supervisor arm must route \
22701             byte-equal through the run_kind_owned_slot_family_gate \
22702             substrate primitive",
22703        );
22704
22705        // Servico arm — non-Servico carrying a declared M2 slot on a
22706        // kind foreign to every prior arm (Biblioteca — foreign to
22707        // both the Aplicacao mesh arm and the Supervisor supervisor
22708        // arm and the Servico M2 arm).
22709        let mut svc = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22710        svc.kind = CaixaKind::Biblioteca;
22711        svc.limits = Some(LimitsSpec {
22712            memory: Some(64 * 1024 * 1024),
22713            fuel: None,
22714            wall_clock: None,
22715            cpu: None,
22716        });
22717        let via_compound = svc.validate_kind_slot_coherence().unwrap_err();
22718        let via_primitive = svc
22719            .run_kind_owned_slot_family_gate(
22720                CaixaKind::is_servico,
22721                Caixa::declared_servico_slots,
22722                crate::LayoutError::servico_slots_on_non_servico,
22723            )
22724            .unwrap_err();
22725        assert_eq!(
22726            via_compound, via_primitive,
22727            "validate_kind_slot_coherence's servico arm must route \
22728             byte-equal through the run_kind_owned_slot_family_gate \
22729             substrate primitive",
22730        );
22731    }
22732
22733    #[test]
22734    fn validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate() {
22735        // Fail-before-pass-after per-arm equivalence pin on the
22736        // Supervisor no-code arm of the reciprocal code-surface
22737        // fold: a `:kind Supervisor` caixa carrying a declared
22738        // `:bibliotecas` entry (the smallest possible code-surface
22739        // declaration on a no-code kind) surfaces the same
22740        // [`crate::LayoutError::SupervisorOwnsCode`] variant
22741        // through both the compound gate
22742        // [`Caixa::validate_no_code_kind_coherence`] and the
22743        // standalone constructor
22744        // [`crate::LayoutError::supervisor_owns_code`]. Pins the
22745        // fold — a silent regression that de-folded the Supervisor
22746        // arm would surface here as a mismatch between the two
22747        // dispatches. Sibling in shape to the peer
22748        // `validate_kind_slot_coherence_folds_supervisor_arm_matches_gate`
22749        // per-arm equivalence pin on the cross-family
22750        // typed-slot-coherence fold.
22751        let mut c = Caixa::from_lisp(&Caixa::template("sup")).unwrap();
22752        c.kind = CaixaKind::Supervisor;
22753        c.bibliotecas = vec!["lib/sup.lisp".into()];
22754        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22755        let via_standalone = crate::LayoutError::supervisor_owns_code(&c);
22756        assert_eq!(
22757            via_method, via_standalone,
22758            "Caixa::validate_no_code_kind_coherence must surface the \
22759             Supervisor arm's diagnostic byte-equal to the standalone \
22760             LayoutError::supervisor_owns_code ctor",
22761        );
22762    }
22763
22764    #[test]
22765    fn validate_no_code_kind_coherence_folds_aplicacao_arm_matches_gate() {
22766        // Per-arm equivalence pin on the Aplicacao no-code arm —
22767        // the sibling of the Supervisor arm on the code-surface
22768        // fold. A `:kind Aplicacao` caixa carrying a declared
22769        // `:exe` entry surfaces the same
22770        // [`crate::LayoutError::AplicacaoOwnsCode`] variant through
22771        // both dispatches. Uses the `:exe` code-surface axis (a
22772        // second axis distinct from the Supervisor arm's
22773        // `:bibliotecas` fixture) so the three per-arm pins
22774        // collectively exercise every arm of the `has_code`
22775        // disjunction (`:bibliotecas || :exe || :servicos`).
22776        let mut c = Caixa::from_lisp(&Caixa::template("app")).unwrap();
22777        c.kind = CaixaKind::Aplicacao;
22778        c.bibliotecas = vec![];
22779        c.exe = vec!["exe/app".into()];
22780        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22781        let via_standalone = crate::LayoutError::aplicacao_owns_code(&c);
22782        assert_eq!(
22783            via_method, via_standalone,
22784            "Caixa::validate_no_code_kind_coherence must surface the \
22785             Aplicacao arm's diagnostic byte-equal to the standalone \
22786             LayoutError::aplicacao_owns_code ctor",
22787        );
22788    }
22789
22790    #[test]
22791    fn validate_no_code_kind_coherence_folds_acao_arm_matches_gate() {
22792        // Per-arm equivalence pin on the Acao no-code arm — the
22793        // third and last arm on the code-surface fold. A `:kind
22794        // Acao` caixa carrying a declared `:servicos` entry
22795        // surfaces the same [`crate::LayoutError::AcaoOwnsCode`]
22796        // variant through both dispatches. Uses the `:servicos`
22797        // code-surface axis (the third distinct axis of the
22798        // `has_code` disjunction) so the three per-arm pins
22799        // collectively cover every arm of the code-surface
22800        // disjunction plus every no-code kind of the arm
22801        // dispatch.
22802        let mut c = Caixa::from_lisp(&Caixa::template("acao")).unwrap();
22803        c.kind = CaixaKind::Acao;
22804        c.bibliotecas = vec![];
22805        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
22806        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22807        let via_standalone = crate::LayoutError::acao_owns_code(&c);
22808        assert_eq!(
22809            via_method, via_standalone,
22810            "Caixa::validate_no_code_kind_coherence must surface the \
22811             Acao arm's diagnostic byte-equal to the standalone \
22812             LayoutError::acao_owns_code ctor",
22813        );
22814    }
22815
22816    #[test]
22817    fn validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis() {
22818        // Positive control on the code-owning-kind identity
22819        // element: each of the three code-owning kinds
22820        // (`Biblioteca` owning `:bibliotecas`, `Binario` owning
22821        // `:exe`, `Servico` owning `:servicos`) passes the
22822        // compound gate cleanly when it declares its native code
22823        // surface. Pins the fold's second identity element — the
22824        // paired per-arm `is_<no-code-kind>()` short-circuit
22825        // fires on every code-owning kind, so a caixa with any
22826        // native code declaration on its owner kind surfaces no
22827        // diagnostic. A silent regression that dropped the paired
22828        // `is_<no-code-kind>()` short-circuit guard on any arm
22829        // would surface here as a false-positive rejection of the
22830        // corresponding owner kind. Peer with the
22831        // `validate_kind_slot_coherence_accepts_owner_kind_on_every_arm`
22832        // identity-element pin on the sibling cross-family fold.
22833        let mut bib = Caixa::from_lisp(&Caixa::template("bib")).unwrap();
22834        bib.kind = CaixaKind::Biblioteca;
22835        bib.bibliotecas = vec!["lib/bib.lisp".into()];
22836        bib.validate_no_code_kind_coherence().expect(
22837            "a :kind Biblioteca caixa with declared :bibliotecas must pass \
22838             the compound gate — Biblioteca owns the :bibliotecas code surface",
22839        );
22840
22841        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
22842        bin.kind = CaixaKind::Binario;
22843        bin.bibliotecas = vec![];
22844        bin.exe = vec!["exe/bin".into()];
22845        bin.validate_no_code_kind_coherence().expect(
22846            "a :kind Binario caixa with declared :exe must pass the compound \
22847             gate — Binario owns the :exe code surface",
22848        );
22849
22850        let svc = bare_servico_fixture("svc");
22851        svc.validate_no_code_kind_coherence().expect(
22852            "a :kind Servico caixa with declared :servicos must pass the \
22853             compound gate — Servico owns the :servicos code surface",
22854        );
22855    }
22856
22857    #[test]
22858    fn validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind() {
22859        // Positive control on the has-no-code identity element:
22860        // a bare caixa (no declared code) passes the compound
22861        // gate on every kind — including the three no-code kinds
22862        // that would otherwise fire an OwnsCode diagnostic. Pins
22863        // the fold's first identity element — the paired
22864        // `!has_code` short-circuit fires before every per-arm
22865        // wrap dispatch, so a bare caixa of any kind surfaces no
22866        // diagnostic. A silent regression that dropped the
22867        // has_code guard would surface here as a false-positive
22868        // rejection of every no-code kind that declares no code.
22869        // Peer with the
22870        // `validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind`
22871        // identity-element pin on the sibling cross-family fold.
22872        for kind in CaixaKind::ALL {
22873            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22874            c.kind = *kind;
22875            c.bibliotecas = vec![];
22876            c.exe = vec![];
22877            c.servicos = vec![];
22878            c.validate_no_code_kind_coherence().unwrap_or_else(|err| {
22879                panic!(
22880                    "a bare :kind {kind:?} caixa (no declared code) must pass \
22881                     the compound gate — the fold's first identity element is \
22882                     the paired !has_code short-circuit, got {err:?}",
22883                )
22884            });
22885        }
22886    }
22887
22888    #[test]
22889    fn validate_ci_kind_coherence_folds_arm_matches_gate() {
22890        // Fail-before-pass-after per-arm equivalence pin on the
22891        // `:ci`-on-non-`Acao` arm: a `:kind Biblioteca` caixa
22892        // (the smallest non-`Acao` kind) carrying a declared
22893        // `:ci` slot surfaces the same
22894        // [`crate::LayoutError::CiOnNonAcao`] variant through the
22895        // compound gate [`Caixa::validate_ci_kind_coherence`] and
22896        // an inlined struct-literal wrap carrying `caixa.nome()`
22897        // + `caixa.kind()` verbatim. Pins the fold — a silent
22898        // regression that de-folded the arm would surface here as
22899        // a mismatch between the two dispatches. Sibling in shape
22900        // to the peer
22901        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
22902        // per-arm equivalence pin on the reciprocal
22903        // code-surface fold.
22904        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22905        c.kind = CaixaKind::Biblioteca;
22906        c.ci = Some(canteiro_types::CiRun {
22907            workspace: "pleme-io".into(),
22908            repo: "caixa".into(),
22909            nodes: vec![],
22910        });
22911        let via_method = c.validate_ci_kind_coherence().unwrap_err();
22912        let via_standalone = crate::LayoutError::CiOnNonAcao {
22913            caixa: c.nome().to_string(),
22914            kind: c.kind(),
22915        };
22916        assert_eq!(
22917            via_method, via_standalone,
22918            "Caixa::validate_ci_kind_coherence must surface the \
22919             :ci-on-non-Acao arm's diagnostic byte-equal to a \
22920             LayoutError::CiOnNonAcao struct literal carrying the \
22921             caixa's nome + kind",
22922        );
22923    }
22924
22925    #[test]
22926    fn validate_ci_kind_coherence_fold_names_offending_kind_on_every_non_acao_kind() {
22927        // Exhaustive per-kind sweep on the non-`Acao` arm: for each
22928        // of the five non-`Acao` kinds
22929        // (`Biblioteca` / `Binario` / `Servico` / `Supervisor` /
22930        // `Aplicacao`), a caixa carrying a declared `:ci` slot
22931        // surfaces the [`crate::LayoutError::CiOnNonAcao`]
22932        // variant naming the offending kind verbatim. A silent
22933        // regression that mistyped one arm's kind-projection
22934        // (e.g. always threading `CaixaKind::Biblioteca` regardless
22935        // of the caixa's actual kind) would surface here as a
22936        // mismatch on every kind past the first. Peer of the
22937        // `validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind`
22938        // exhaustive-sweep pin on the sibling code-surface fold.
22939        for kind in CaixaKind::ALL {
22940            if kind.is_acao() {
22941                continue;
22942            }
22943            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22944            c.kind = *kind;
22945            c.ci = Some(canteiro_types::CiRun {
22946                workspace: "pleme-io".into(),
22947                repo: "caixa".into(),
22948                nodes: vec![],
22949            });
22950            let err = c.validate_ci_kind_coherence().unwrap_err();
22951            match err {
22952                crate::LayoutError::CiOnNonAcao {
22953                    caixa: got_caixa,
22954                    kind: got_kind,
22955                } => {
22956                    assert_eq!(
22957                        got_caixa,
22958                        c.nome(),
22959                        "CiOnNonAcao must name the offending caixa's nome verbatim on kind {kind:?}",
22960                    );
22961                    assert_eq!(
22962                        got_kind, *kind,
22963                        "CiOnNonAcao must name the offending kind verbatim on kind {kind:?}",
22964                    );
22965                }
22966                other => panic!(
22967                    "expected CiOnNonAcao on :kind {kind:?} with declared :ci, got {other:?}",
22968                ),
22969            }
22970        }
22971    }
22972
22973    #[test]
22974    fn validate_ci_kind_coherence_accepts_acao_on_every_ci_shape() {
22975        // Positive control on the owner-kind identity element: an
22976        // `:kind Acao` caixa passes the coherence gate cleanly on
22977        // every `:ci` shape — the arm's paired
22978        // `!kind().is_acao()` short-circuit fires before the
22979        // dispatch, so the fold surfaces no diagnostic even on
22980        // fixtures whose `:ci` would fail the peer
22981        // [`Self::validate_acao_shape`] decompose gate (a
22982        // duplicate-node fixture, an unknown-dep fixture, a
22983        // cyclic fixture). Pins the fold's first identity element
22984        // — a silent regression that dropped the paired
22985        // `!kind().is_acao()` short-circuit guard would surface
22986        // here as a false-positive rejection of every `Acao`
22987        // caixa. Peer with the
22988        // `validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis`
22989        // identity-element pin on the sibling code-surface fold.
22990        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22991        c.kind = CaixaKind::Acao;
22992        c.bibliotecas = vec![];
22993        c.ci = Some(canteiro_types::CiRun {
22994            workspace: "pleme-io".into(),
22995            repo: "caixa".into(),
22996            nodes: vec![],
22997        });
22998        c.validate_ci_kind_coherence().expect(
22999            "a :kind Acao caixa with declared :ci must pass the compound \
23000             coherence gate — Acao is the :ci-owning kind (a malformed \
23001             :ci on Acao surfaces via validate_acao_shape's decompose gate, \
23002             not via this kind-coherence gate)",
23003        );
23004    }
23005
23006    #[test]
23007    fn validate_ci_kind_coherence_accepts_absent_ci_on_every_kind() {
23008        // Positive control on the absent-`:ci` identity element:
23009        // a caixa with `ci = None` passes the coherence gate on
23010        // every kind — including `Acao`, whose absent `:ci`
23011        // fails a separate presence gate ([`crate::LayoutError::MissingCi`])
23012        // downstream at the layout altitude, not this coherence
23013        // gate. Pins the fold's second identity element — the
23014        // paired `ci().is_some()` short-circuit fires before every
23015        // per-arm dispatch, so a caixa with no declared `:ci`
23016        // surfaces no coherence diagnostic. A silent regression
23017        // that dropped the paired `ci().is_some()` short-circuit
23018        // would surface here as a false-positive rejection on
23019        // every non-`Acao` kind. Peer with the
23020        // `validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind`
23021        // identity-element pin on the sibling code-surface fold.
23022        for kind in CaixaKind::ALL {
23023            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23024            c.kind = *kind;
23025            c.ci = None;
23026            c.validate_ci_kind_coherence().unwrap_or_else(|err| {
23027                panic!(
23028                    "a :kind {kind:?} caixa with no declared :ci must pass \
23029                     the compound coherence gate — the fold's second identity \
23030                     element is the paired ci().is_some() short-circuit, got \
23031                     {err:?}",
23032                )
23033            });
23034        }
23035    }
23036
23037    #[test]
23038    fn validate_foreign_code_kind_coherence_folds_arm_matches_gate() {
23039        // Fail-before-pass-after equivalence pin on the compound
23040        // foreign-code-slot coherence fold: a `:kind Servico` caixa
23041        // carrying a declared `:exe` entry (the smallest possible
23042        // foreign-code-slot declaration on a code-running kind that
23043        // is not its owner — Servico owns `:servicos`, not `:exe`)
23044        // surfaces the same [`crate::LayoutError::ForeignCodeSlot`]
23045        // variant through both the compound gate
23046        // [`Caixa::validate_foreign_code_kind_coherence`] and the
23047        // standalone constructor
23048        // [`crate::LayoutError::foreign_code_slot`] dispatched on the
23049        // same `declared_foreign_code_slots` list. Pins the fold — a
23050        // silent regression that de-folded the arm would surface here
23051        // as a mismatch between the two dispatches. Sibling in shape
23052        // to the peer
23053        // `validate_kind_slot_coherence_folds_mesh_arm_matches_gate`
23054        // / `validate_ci_kind_coherence_folds_arm_matches_gate` /
23055        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
23056        // per-arm equivalence pins on the sibling kind-coherence folds.
23057        let mut c = bare_servico_fixture("demo");
23058        c.exe = vec!["exe/foreign".into()];
23059        let via_method = c.validate_foreign_code_kind_coherence().unwrap_err();
23060        let via_standalone =
23061            crate::LayoutError::foreign_code_slot(&c, c.declared_foreign_code_slots());
23062        assert_eq!(
23063            via_method, via_standalone,
23064            "Caixa::validate_foreign_code_kind_coherence must surface the \
23065             foreign-code-slot diagnostic byte-equal to the standalone \
23066             LayoutError::foreign_code_slot ctor on the same \
23067             declared_foreign_code_slots list",
23068        );
23069    }
23070
23071    #[test]
23072    fn validate_foreign_code_kind_coherence_exe_arm_precedes_servicos_arm() {
23073        // Cross-arm ordering pin on the fold's accumulator: a fixture
23074        // carrying BOTH a declared `:exe` AND a declared `:servicos`
23075        // on a kind foreign to both (a `:kind Biblioteca` here —
23076        // foreign to both the Binario arm and the Servico arm)
23077        // surfaces `:exe` first in the `ForeignCodeSlot`'s slots
23078        // list. Pins the canonical `:exe` → `:servicos` diagnostic
23079        // order [`Caixa::declared_foreign_code_slots`] establishes,
23080        // as a property of the substrate primitive rather than an
23081        // implicit accumulator convention. A silent reordering
23082        // regression at the accumulator would surface here as a
23083        // wrong-first-slot list before landing at a downstream
23084        // consumer's diagnostic-ordering expectation.
23085        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23086        c.kind = CaixaKind::Biblioteca;
23087        c.exe = vec!["exe/demo".into()];
23088        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
23089        let err = c.validate_foreign_code_kind_coherence().unwrap_err();
23090        let crate::LayoutError::ForeignCodeSlot { slots, .. } = &err else {
23091            panic!("expected ForeignCodeSlot variant, got {err:?}");
23092        };
23093        assert!(
23094            slots.starts_with(":exe"),
23095            "expected the :exe arm to precede the :servicos arm in the \
23096             ForeignCodeSlot slots list under the canonical :exe → :servicos \
23097             order, got slots = {slots:?}",
23098        );
23099        assert!(
23100            slots.contains(":servicos"),
23101            "expected the :servicos arm to also fire in the ForeignCodeSlot \
23102             slots list on a fixture carrying both foreign code surfaces, \
23103             got slots = {slots:?}",
23104        );
23105    }
23106
23107    #[test]
23108    fn validate_foreign_code_kind_coherence_accepts_native_slot_on_owner_kind() {
23109        // Positive control on the native-slot identity element: each
23110        // code-surface slot's owner kind passes the fold trivially
23111        // when it declares only its native code surface. `:kind
23112        // Binario` with a declared `:exe` and no `:servicos` passes
23113        // (the `!requires_exe()` guard short-circuits the arm inside
23114        // [`Caixa::declared_foreign_code_slots`], so the accumulator
23115        // returns empty); `:kind Servico` with a declared `:servicos`
23116        // and no `:exe` passes for the mirror reason. Pins the fold's
23117        // native-slot identity element on both arms — a silent
23118        // regression that dropped either per-arm `!requires_<slot>()`
23119        // predicate would surface here as a false-positive rejection
23120        // of every native-slot declaration on its owner kind. Peer
23121        // with the
23122        // `validate_kind_slot_coherence_accepts_owner_kind_on_every_arm`
23123        // identity-element pin on the sibling cross-family fold.
23124        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23125        bin.kind = CaixaKind::Binario;
23126        bin.bibliotecas = vec![];
23127        bin.exe = vec!["exe/bin".into()];
23128        bin.servicos = vec![];
23129        bin.validate_foreign_code_kind_coherence().expect(
23130            "a :kind Binario caixa with a declared native :exe and no \
23131             :servicos must pass the compound coherence gate — Binario is \
23132             the :exe slot's owner kind and the fold's native-slot identity \
23133             element on that arm",
23134        );
23135
23136        let mut svc = bare_servico_fixture("svc");
23137        svc.exe = vec![];
23138        svc.validate_foreign_code_kind_coherence().expect(
23139            "a :kind Servico caixa with a declared native :servicos and no \
23140             :exe must pass the compound coherence gate — Servico is the \
23141             :servicos slot's owner kind and the fold's native-slot identity \
23142             element on that arm",
23143        );
23144    }
23145
23146    #[test]
23147    fn validate_foreign_code_kind_coherence_accepts_bare_caixa_on_every_kind() {
23148        // Positive control on the empty-slot identity element: a
23149        // bare caixa (no declared `:exe` and no declared `:servicos`)
23150        // passes the compound gate on every kind. Pins the fold's
23151        // identity element on the empty-accumulator axis — the outer
23152        // `is_empty` short-circuit fires before the wrap dispatch on
23153        // every kind, so a bare caixa of any kind surfaces no
23154        // foreign-code-slot diagnostic. A silent regression that
23155        // dropped the emptiness guard would surface here as a
23156        // false-positive rejection of every no-code-slot caixa
23157        // across the whole kind axis. Peer with the
23158        // `validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind`
23159        // identity-element pin on the sibling cross-family fold.
23160        for kind in CaixaKind::ALL {
23161            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23162            c.kind = *kind;
23163            c.bibliotecas = vec![];
23164            c.exe = vec![];
23165            c.servicos = vec![];
23166            c.validate_foreign_code_kind_coherence()
23167                .unwrap_or_else(|err| {
23168                    panic!(
23169                        "a bare :kind {kind:?} caixa (no declared :exe / \
23170                         :servicos) must pass the compound coherence gate — \
23171                         the fold's identity element on the empty-accumulator \
23172                         axis is the outer Vec::is_empty short-circuit, got \
23173                         {err:?}",
23174                    )
23175                });
23176        }
23177    }
23178
23179    #[test]
23180    fn validate_required_kind_slot_folds_binario_arm_matches_gate() {
23181        // Fail-before-pass-after per-arm equivalence pin on the
23182        // `Binario` required-`:exe` arm of the required-slot fold:
23183        // a `:kind Binario` caixa carrying no declared `:exe` entry
23184        // surfaces the same
23185        // [`crate::LayoutError::BinarioWithoutExe`] variant through
23186        // both the compound gate
23187        // [`Caixa::validate_required_kind_slot`] and the standalone
23188        // constructor [`crate::LayoutError::binario_without_exe`].
23189        // Pins the fold — a silent regression that de-folded the
23190        // `Binario` arm would surface here as a mismatch between
23191        // the two dispatches. Sibling in shape to the peer
23192        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
23193        // per-arm equivalence pin on the reciprocal code-surface
23194        // fold.
23195        let mut c = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23196        c.kind = CaixaKind::Binario;
23197        c.bibliotecas = vec![];
23198        c.exe = vec![];
23199        let via_method = c.validate_required_kind_slot().unwrap_err();
23200        let via_standalone = crate::LayoutError::binario_without_exe(&c);
23201        assert_eq!(
23202            via_method, via_standalone,
23203            "Caixa::validate_required_kind_slot must surface the \
23204             Binario arm's diagnostic byte-equal to the standalone \
23205             LayoutError::binario_without_exe ctor",
23206        );
23207    }
23208
23209    #[test]
23210    fn validate_required_kind_slot_folds_servico_arm_matches_gate() {
23211        // Per-arm equivalence pin on the `Servico` required-
23212        // `:servicos` arm — the sibling of the Binario arm on the
23213        // required-slot fold. A `:kind Servico` caixa carrying no
23214        // declared `:servicos` entry surfaces the same
23215        // [`crate::LayoutError::ServicoWithoutServicos`] variant
23216        // through both dispatches.
23217        let mut c = Caixa::from_lisp(&Caixa::template("svc")).unwrap();
23218        c.kind = CaixaKind::Servico;
23219        c.bibliotecas = vec![];
23220        c.servicos = vec![];
23221        let via_method = c.validate_required_kind_slot().unwrap_err();
23222        let via_standalone = crate::LayoutError::servico_without_servicos(&c);
23223        assert_eq!(
23224            via_method, via_standalone,
23225            "Caixa::validate_required_kind_slot must surface the \
23226             Servico arm's diagnostic byte-equal to the standalone \
23227             LayoutError::servico_without_servicos ctor",
23228        );
23229    }
23230
23231    #[test]
23232    fn validate_required_kind_slot_folds_acao_arm_matches_gate() {
23233        // Per-arm equivalence pin on the `Acao` required-`:ci` arm
23234        // — the third and last arm on the required-slot fold. A
23235        // `:kind Acao` caixa carrying no declared `:ci` slot
23236        // surfaces the same [`crate::LayoutError::MissingCi`]
23237        // variant through both dispatches. The three per-arm pins
23238        // collectively cover every required-slot axis and every
23239        // owner kind of the arm dispatch.
23240        let mut c = Caixa::from_lisp(&Caixa::template("acao")).unwrap();
23241        c.kind = CaixaKind::Acao;
23242        c.bibliotecas = vec![];
23243        c.ci = None;
23244        let via_method = c.validate_required_kind_slot().unwrap_err();
23245        let via_standalone = crate::LayoutError::missing_ci(&c);
23246        assert_eq!(
23247            via_method, via_standalone,
23248            "Caixa::validate_required_kind_slot must surface the \
23249             Acao arm's diagnostic byte-equal to the standalone \
23250             LayoutError::missing_ci ctor",
23251        );
23252    }
23253
23254    #[test]
23255    fn validate_required_kind_slot_accepts_owner_kind_with_required_slot_present() {
23256        // Positive control on the owner-kind-with-slot-present
23257        // identity element: each of the three owner kinds
23258        // (`Binario` with a non-empty `:exe`, `Servico` with a
23259        // non-empty `:servicos`, `Acao` with `ci = Some(_)`)
23260        // passes the compound gate cleanly when it declares its
23261        // required slot. Pins the fold's second identity element
23262        // — the paired `is_empty` / `is_none` short-circuit fires
23263        // on every owner kind whose required slot is present, so
23264        // a caixa with its native required slot surfaces no
23265        // diagnostic. A silent regression that dropped the paired
23266        // `is_empty` / `is_none` short-circuit guard on any arm
23267        // would surface here as a false-positive rejection of the
23268        // corresponding owner kind. Peer with the
23269        // `validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis`
23270        // identity-element pin on the sibling code-surface fold.
23271        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23272        bin.kind = CaixaKind::Binario;
23273        bin.bibliotecas = vec![];
23274        bin.exe = vec!["exe/bin".into()];
23275        bin.validate_required_kind_slot().expect(
23276            "a :kind Binario caixa with declared :exe must pass the \
23277             required-slot gate — Binario's required slot is present",
23278        );
23279
23280        let svc = bare_servico_fixture("svc");
23281        svc.validate_required_kind_slot().expect(
23282            "a :kind Servico caixa with declared :servicos must pass \
23283             the required-slot gate — Servico's required slot is present",
23284        );
23285
23286        let acao = acao_fixture("acao");
23287        acao.validate_required_kind_slot().expect(
23288            "a :kind Acao caixa with declared :ci must pass the \
23289             required-slot gate — Acao's required slot is present",
23290        );
23291    }
23292
23293    #[test]
23294    fn validate_required_kind_slot_accepts_non_owner_kinds() {
23295        // Positive control on the non-owner-kind identity element:
23296        // every kind that is not one of the three owner kinds
23297        // (`Binario` / `Servico` / `Acao`) passes the compound gate
23298        // trivially — each per-arm predicate is
23299        // `self.kind().requires_<slot>()`, which returns `true`
23300        // only for the owner kind of that arm, so a non-owner kind
23301        // short-circuits every per-arm dispatch. Bibliotheca,
23302        // Supervisor, and Aplicacao are the three non-owner kinds
23303        // this pin exercises — none of them owns a required slot in
23304        // this fold (`Biblioteca`'s `:bibliotecas` default-file
23305        // fallback stays on the layout-side `MissingLib` fs-oracle
23306        // gate outside this fold; `Supervisor`'s `:children` and
23307        // `Aplicacao`'s `:membros` are carried by
23308        // [`CaixaKind::requires_children`] /
23309        // [`CaixaKind::requires_membros`] without a paired
23310        // layout-side wire-up). A silent regression that swapped a
23311        // per-arm predicate for a non-`requires_*` guard would
23312        // surface here as a false-positive rejection of the
23313        // corresponding non-owner kind. Peer with the
23314        // `validate_ci_kind_coherence_accepts_absent_ci_on_every_kind`
23315        // identity-element pin on the sibling `:ci` fold.
23316        for kind in CaixaKind::ALL {
23317            if kind.requires_exe() || kind.requires_servicos() || kind.requires_ci() {
23318                continue;
23319            }
23320            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23321            c.kind = *kind;
23322            c.bibliotecas = vec![];
23323            c.exe = vec![];
23324            c.servicos = vec![];
23325            c.ci = None;
23326            c.validate_required_kind_slot().unwrap_or_else(|err| {
23327                panic!(
23328                    "a :kind {kind:?} caixa (a non-owner kind on every \
23329                     required-slot arm) must pass the compound gate — the \
23330                     fold's identity element is the paired \
23331                     `self.kind().requires_<slot>()` short-circuit, got \
23332                     {err:?}",
23333                )
23334            });
23335        }
23336    }
23337
23338    // ── `manifest_code_path_slot_path_ctors!` — the paired `{ slot:
23339    //    &'static str, path: PathBuf }` two-slot envelope on
23340    //    `ManifestError`, strict sibling of the peer
23341    //    [`crate::behavior::behavior_slot_path_ctors!`] (67c31ec) on the
23342    //    sibling `BehaviorError` envelope's identical
23343    //    `{ slot: &'static str, path: PathBuf }` two-slot shape.
23344    //    Five-variant lift closing the five open-coded ctor sites
23345    //    remaining on the `:bibliotecas` / `:exe` / `:servicos`
23346    //    code-path-list value-shape trajectory this envelope carries.
23347
23348    #[test]
23349    fn code_path_absolute_ctor_matches_struct_literal_wrap() {
23350        let path = Path::new("/abs/lib/x.lisp");
23351        assert_eq!(
23352            ManifestError::code_path_absolute(":bibliotecas", path),
23353            ManifestError::CodePathAbsolute {
23354                slot: ":bibliotecas",
23355                path: path.to_path_buf(),
23356            },
23357            "generated code_path_absolute ctor must produce byte-equal \
23358             `ManifestError::CodePathAbsolute` to the pre-lift \
23359             struct-literal wrap on the same `(&'static str, &Path)` \
23360             fixture",
23361        );
23362    }
23363
23364    #[test]
23365    fn code_path_parent_escape_ctor_matches_struct_literal_wrap() {
23366        let path = Path::new("lib/../../etc/x.lisp");
23367        assert_eq!(
23368            ManifestError::code_path_parent_escape(":bibliotecas", path),
23369            ManifestError::CodePathParentEscape {
23370                slot: ":bibliotecas",
23371                path: path.to_path_buf(),
23372            },
23373            "generated code_path_parent_escape ctor must produce \
23374             byte-equal `ManifestError::CodePathParentEscape` to the \
23375             pre-lift struct-literal wrap on the same `(&'static str, \
23376             &Path)` fixture",
23377        );
23378    }
23379
23380    #[test]
23381    fn code_path_non_lisp_extension_ctor_matches_struct_literal_wrap() {
23382        let path = Path::new("lib/x.txt");
23383        assert_eq!(
23384            ManifestError::code_path_non_lisp_extension(":bibliotecas", path),
23385            ManifestError::CodePathNonLispExtension {
23386                slot: ":bibliotecas",
23387                path: path.to_path_buf(),
23388            },
23389            "generated code_path_non_lisp_extension ctor must produce \
23390             byte-equal `ManifestError::CodePathNonLispExtension` to \
23391             the pre-lift struct-literal wrap on the same \
23392             `(&'static str, &Path)` fixture",
23393        );
23394    }
23395
23396    #[test]
23397    fn code_path_non_computeunit_yaml_extension_ctor_matches_struct_literal_wrap() {
23398        let path = Path::new("servicos/x.yaml");
23399        assert_eq!(
23400            ManifestError::code_path_non_computeunit_yaml_extension(":servicos", path),
23401            ManifestError::CodePathNonComputeUnitYamlExtension {
23402                slot: ":servicos",
23403                path: path.to_path_buf(),
23404            },
23405            "generated code_path_non_computeunit_yaml_extension ctor \
23406             must produce byte-equal \
23407             `ManifestError::CodePathNonComputeUnitYamlExtension` to \
23408             the pre-lift struct-literal wrap on the same \
23409             `(&'static str, &Path)` fixture",
23410        );
23411    }
23412
23413    #[test]
23414    fn code_path_duplicate_ctor_matches_struct_literal_wrap() {
23415        let path = Path::new("lib/x.lisp");
23416        assert_eq!(
23417            ManifestError::code_path_duplicate(":bibliotecas", path),
23418            ManifestError::CodePathDuplicate {
23419                slot: ":bibliotecas",
23420                path: path.to_path_buf(),
23421            },
23422            "generated code_path_duplicate ctor must produce byte-equal \
23423             `ManifestError::CodePathDuplicate` to the pre-lift \
23424             struct-literal wrap on the same `(&'static str, &Path)` \
23425             fixture",
23426        );
23427    }
23428
23429    #[test]
23430    fn manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly() {
23431        // Cross-axis routing pin: sweep the two constructor input axes
23432        // (`slot: &'static str`, `path: &Path`) through non-default
23433        // fixtures against every generated arm in the
23434        // [`manifest_code_path_slot_path_ctors!`] macro, so any
23435        // wrapper-side lowercase / trim / truncate / canonicalization at
23436        // codegen time — or a silent field re-name away from the
23437        // canonical `slot` / `path` axes on any one variant, or a `slot`
23438        // axis silently rerouted through `.to_string()` instead of
23439        // passed as `&'static str` verbatim, or a `path` axis silently
23440        // rerouted through `.canonicalize()` / `PathBuf::from(<lossy
23441        // string>)` instead of `.to_path_buf()` — surfaces here rather
23442        // than at a downstream diagnostic-shape mismatch. Peer of the
23443        // sibling
23444        // [`crate::behavior::tests::behavior_slot_path_ctors_route_slot_and_path_through_uniformly`]
23445        // pin (67c31ec) on the sibling `BehaviorError` envelope's
23446        // identical two-slot family.
23447        //
23448        // The `path` fixture carries three distinguishing traits at
23449        // once: a non-`root/`-relative leading segment (`weird/`), a
23450        // `..` component (a canonicalization trap that would collapse
23451        // to `weird/x.lisp` under `.canonicalize()`), and a mixed-case
23452        // extension (a lowercase-normalization trap that would collapse
23453        // `.LISP` to `.lisp` under any `to_ascii_lowercase()` codegen)
23454        // so a routing regression on any one of the three trap axes
23455        // surfaces at assert time. Similarly the `slot` fixture
23456        // sweeps the three canonical code-path author-key literals
23457        // (`:bibliotecas` / `:exe` / `:servicos`) so a silent lookup
23458        // against a per-variant const roster would surface here.
23459        let path = Path::new("weird/../nested/x.LISP");
23460        let cases: [(ManifestError, ManifestError); 5] = [
23461            (
23462                ManifestError::code_path_absolute(":bibliotecas", path),
23463                ManifestError::CodePathAbsolute {
23464                    slot: ":bibliotecas",
23465                    path: path.to_path_buf(),
23466                },
23467            ),
23468            (
23469                ManifestError::code_path_parent_escape(":exe", path),
23470                ManifestError::CodePathParentEscape {
23471                    slot: ":exe",
23472                    path: path.to_path_buf(),
23473                },
23474            ),
23475            (
23476                ManifestError::code_path_non_lisp_extension(":servicos", path),
23477                ManifestError::CodePathNonLispExtension {
23478                    slot: ":servicos",
23479                    path: path.to_path_buf(),
23480                },
23481            ),
23482            (
23483                ManifestError::code_path_non_computeunit_yaml_extension(":bibliotecas", path),
23484                ManifestError::CodePathNonComputeUnitYamlExtension {
23485                    slot: ":bibliotecas",
23486                    path: path.to_path_buf(),
23487                },
23488            ),
23489            (
23490                ManifestError::code_path_duplicate(":exe", path),
23491                ManifestError::CodePathDuplicate {
23492                    slot: ":exe",
23493                    path: path.to_path_buf(),
23494                },
23495            ),
23496        ];
23497        for (via_ctor, via_struct_literal) in cases {
23498            assert_eq!(
23499                via_ctor, via_struct_literal,
23500                "manifest_code_path_slot_path_ctors!-generated ctor \
23501                 must pass `slot` verbatim onto the canonical \
23502                 `&'static str` `slot` field and route `path` through \
23503                 `.to_path_buf()` onto the canonical `PathBuf` `path` \
23504                 field — a field-rename, silent-conversion, or \
23505                 axis-swap regression surfaces here rather than at a \
23506                 downstream diagnostic-shape mismatch",
23507            );
23508        }
23509    }
23510
23511    // Per-variant equivalence pin for the [`ManifestError::code_path_empty`]
23512    // one-slot inherent constructor (see the paired doc-block above the impl
23513    // definition) — the constructor folds the uniform
23514    // `Self::CodePathEmpty { slot }` one-field struct-literal onto one
23515    // substrate primitive. The equivalence pin below (fail-before-pass-after
23516    // by construction — a byte-mismatched constructor body would trip this pin
23517    // first) locks the generated constructor to its struct-literal peer under
23518    // `PartialEq`, so the wire-up at
23519    // [`Caixa::validate_code_path_lists`]'s per-slot
23520    // [`PathShapeViolation::Empty`] arm on this variant produces a byte-equal
23521    // `ManifestError` to the pre-lift open-coded struct-literal. The
23522    // cross-axis pin that follows (`slot: &'static str` sweep over every
23523    // canonical `:bibliotecas` / `:exe` / `:servicos` code-path author-key
23524    // label) routes the constructor input axis verbatim (`slot` as
23525    // `&'static str` without conversion), so the fold does not silently
23526    // collapse onto a fixed `slot` value.
23527    //
23528    // Peer of the sibling `code_path_absolute_ctor_matches_struct_literal_wrap`
23529    // / `code_path_parent_escape_ctor_matches_struct_literal_wrap` /
23530    // `code_path_non_lisp_extension_ctor_matches_struct_literal_wrap` /
23531    // `code_path_non_computeunit_yaml_extension_ctor_matches_struct_literal_wrap`
23532    // / `code_path_duplicate_ctor_matches_struct_literal_wrap` /
23533    // `manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly`
23534    // equivalence + cross-axis pins the peer
23535    // [`manifest_code_path_slot_path_ctors!`] family (de11917) established on
23536    // the paired `{ slot: &'static str, path: PathBuf }` two-slot envelope of
23537    // the same `ManifestError` — the per-slot [`PathShapeViolation`] cascade
23538    // at [`Caixa::validate_code_path_lists`] now carries a substrate-primitive
23539    // equivalence pin at every arm rather than five pinned arms plus a
23540    // hand-written open-coded sixth. Mirror-symmetric sibling of the peer
23541    // [`crate::behavior::tests::empty_path_ctor_matches_struct_literal_wrap`]
23542    // / `empty_path_ctor_routes_slot_verbatim_across_every_on_star_key` pins
23543    // on the sibling M2 `:behavior` envelope's identical one-slot shape.
23544
23545    #[test]
23546    fn code_path_empty_ctor_matches_struct_literal_wrap() {
23547        let slot = ":bibliotecas";
23548        assert_eq!(
23549            ManifestError::code_path_empty(slot),
23550            ManifestError::CodePathEmpty { slot },
23551            "generated code_path_empty ctor must produce byte-equal \
23552             `ManifestError::CodePathEmpty` to the open-coded struct-literal \
23553             wrap on the same `&'static str` fixture",
23554        );
23555    }
23556
23557    #[test]
23558    fn code_path_empty_ctor_routes_slot_verbatim_across_every_code_path_key() {
23559        // Cross-axis pin: sweep the constructor's single input axis
23560        // (`slot: &'static str`) through every canonical code-path
23561        // author-key label the outer per-slot iterator at
23562        // [`Caixa::validate_code_path_lists`] threads through so any
23563        // wrapper-side lowercase / trim / truncate / fixed-slot substitution
23564        // on the one-field construction surfaces here rather than at a
23565        // downstream diagnostic-shape mismatch. Peer of the sibling
23566        // [`manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly`]
23567        // cross-axis pin on the two-slot envelope of the same
23568        // `ManifestError` — extended here onto the one-slot envelope so
23569        // both slot-only and slot+path constructor input axes carry a
23570        // per-code-path-label sweep. Mirror-symmetric sibling of the peer
23571        // [`crate::behavior::tests::empty_path_ctor_routes_slot_verbatim_across_every_on_star_key`]
23572        // sweep on the sibling M2 `:behavior` envelope's identical one-slot
23573        // shape.
23574        for slot in [":bibliotecas", ":exe", ":servicos"] {
23575            assert_eq!(
23576                ManifestError::code_path_empty(slot),
23577                ManifestError::CodePathEmpty { slot },
23578            );
23579        }
23580    }
23581
23582    // ── `manifest_field_reason_ctors!` — the paired `{ <field>: String,
23583    //    reason: String }` two-slot envelope on `ManifestError`, direct
23584    //    sibling of the peer
23585    //    [`crate::aplicacao::aplicacao_field_reason_ctors!`] (981060b)
23586    //    on the M3 mesh `AplicacaoError` envelope's identical two-slot
23587    //    shape and of the peer [`crate::dep::dep_nome_axis_reason_ctors!`]
23588    //    (5621f8a) on the sibling `:deps` envelope's mirror-symmetric
23589    //    three-slot shape (the `nome` axis added at the per-dep-owned
23590    //    altitude). Ten-variant lift closing the ten open-coded ctor
23591    //    sites at the per-axis [`Caixa::validate_*`] cascade — the tenth
23592    //    (`restart_window_malformed => RestartWindowMalformed
23593    //    { restart_window }`) closes the last open-coded four-line
23594    //    `.map_err(|reason| ManifestError::RestartWindowMalformed
23595    //    { restart_window: s.to_string(), reason })` block at
23596    //    [`Caixa::validate_restart_window`] onto the same substrate
23597    //    primitive per typed variant.
23598
23599    #[test]
23600    fn nome_invalid_ctor_matches_struct_literal_wrap() {
23601        let nome = "cart-svc";
23602        let reason = "sample reason text";
23603        assert_eq!(
23604            ManifestError::nome_invalid(nome, reason),
23605            ManifestError::NomeInvalid {
23606                nome: nome.to_string(),
23607                reason: reason.to_string(),
23608            },
23609            "generated nome_invalid ctor must produce byte-equal \
23610             `ManifestError::NomeInvalid` to the pre-lift struct-literal \
23611             wrap on the same `(&str, &str)` fixture",
23612        );
23613    }
23614
23615    #[test]
23616    fn nome_chart_name_budget_exceeded_ctor_matches_struct_literal_wrap() {
23617        let nome = "a-very-long-cart-service-name";
23618        let reason = "sample reason text";
23619        assert_eq!(
23620            ManifestError::nome_chart_name_budget_exceeded(nome, reason),
23621            ManifestError::NomeChartNameBudgetExceeded {
23622                nome: nome.to_string(),
23623                reason: reason.to_string(),
23624            },
23625            "generated nome_chart_name_budget_exceeded ctor must produce \
23626             byte-equal `ManifestError::NomeChartNameBudgetExceeded` to \
23627             the pre-lift struct-literal wrap on the same `(&str, &str)` \
23628             fixture",
23629        );
23630    }
23631
23632    #[test]
23633    fn versao_invalid_ctor_matches_struct_literal_wrap() {
23634        let versao = "0.1";
23635        let reason = "sample reason text";
23636        assert_eq!(
23637            ManifestError::versao_invalid(versao, reason),
23638            ManifestError::VersaoInvalid {
23639                versao: versao.to_string(),
23640                reason: reason.to_string(),
23641            },
23642            "generated versao_invalid ctor must produce byte-equal \
23643             `ManifestError::VersaoInvalid` to the pre-lift \
23644             struct-literal wrap on the same `(&str, &str)` fixture",
23645        );
23646    }
23647
23648    #[test]
23649    fn etiqueta_invalid_ctor_matches_struct_literal_wrap() {
23650        let etiqueta = "MyKeyword";
23651        let reason = "sample reason text";
23652        assert_eq!(
23653            ManifestError::etiqueta_invalid(etiqueta, reason),
23654            ManifestError::EtiquetaInvalid {
23655                etiqueta: etiqueta.to_string(),
23656                reason: reason.to_string(),
23657            },
23658            "generated etiqueta_invalid ctor must produce byte-equal \
23659             `ManifestError::EtiquetaInvalid` to the pre-lift \
23660             struct-literal wrap on the same `(&str, &str)` fixture",
23661        );
23662    }
23663
23664    #[test]
23665    fn autor_invalid_ctor_matches_struct_literal_wrap() {
23666        let autor = "Ada Lovelace";
23667        let reason = "sample reason text";
23668        assert_eq!(
23669            ManifestError::autor_invalid(autor, reason),
23670            ManifestError::AutorInvalid {
23671                autor: autor.to_string(),
23672                reason: reason.to_string(),
23673            },
23674            "generated autor_invalid ctor must produce byte-equal \
23675             `ManifestError::AutorInvalid` to the pre-lift struct-literal \
23676             wrap on the same `(&str, &str)` fixture",
23677        );
23678    }
23679
23680    #[test]
23681    fn repositorio_invalid_ctor_matches_struct_literal_wrap() {
23682        let repositorio = "https://example.com/no-dot-git";
23683        let reason = "sample reason text";
23684        assert_eq!(
23685            ManifestError::repositorio_invalid(repositorio, reason),
23686            ManifestError::RepositorioInvalid {
23687                repositorio: repositorio.to_string(),
23688                reason: reason.to_string(),
23689            },
23690            "generated repositorio_invalid ctor must produce byte-equal \
23691             `ManifestError::RepositorioInvalid` to the pre-lift \
23692             struct-literal wrap on the same `(&str, &str)` fixture",
23693        );
23694    }
23695
23696    #[test]
23697    fn descricao_invalid_ctor_matches_struct_literal_wrap() {
23698        let descricao = "some description";
23699        let reason = "sample reason text";
23700        assert_eq!(
23701            ManifestError::descricao_invalid(descricao, reason),
23702            ManifestError::DescricaoInvalid {
23703                descricao: descricao.to_string(),
23704                reason: reason.to_string(),
23705            },
23706            "generated descricao_invalid ctor must produce byte-equal \
23707             `ManifestError::DescricaoInvalid` to the pre-lift \
23708             struct-literal wrap on the same `(&str, &str)` fixture",
23709        );
23710    }
23711
23712    #[test]
23713    fn licenca_invalid_ctor_matches_struct_literal_wrap() {
23714        let licenca = "not-an-spdx";
23715        let reason = "sample reason text";
23716        assert_eq!(
23717            ManifestError::licenca_invalid(licenca, reason),
23718            ManifestError::LicencaInvalid {
23719                licenca: licenca.to_string(),
23720                reason: reason.to_string(),
23721            },
23722            "generated licenca_invalid ctor must produce byte-equal \
23723             `ManifestError::LicencaInvalid` to the pre-lift \
23724             struct-literal wrap on the same `(&str, &str)` fixture",
23725        );
23726    }
23727
23728    #[test]
23729    fn edicao_invalid_ctor_matches_struct_literal_wrap() {
23730        let edicao = "26";
23731        let reason = "sample reason text";
23732        assert_eq!(
23733            ManifestError::edicao_invalid(edicao, reason),
23734            ManifestError::EdicaoInvalid {
23735                edicao: edicao.to_string(),
23736                reason: reason.to_string(),
23737            },
23738            "generated edicao_invalid ctor must produce byte-equal \
23739             `ManifestError::EdicaoInvalid` to the pre-lift \
23740             struct-literal wrap on the same `(&str, &str)` fixture",
23741        );
23742    }
23743
23744    #[test]
23745    fn restart_window_malformed_ctor_matches_struct_literal_wrap() {
23746        let restart_window = "1.5s";
23747        let reason = "sample reason text";
23748        assert_eq!(
23749            ManifestError::restart_window_malformed(restart_window, reason),
23750            ManifestError::RestartWindowMalformed {
23751                restart_window: restart_window.to_string(),
23752                reason: reason.to_string(),
23753            },
23754            "generated restart_window_malformed ctor must produce byte-equal \
23755             `ManifestError::RestartWindowMalformed` to the pre-lift \
23756             struct-literal wrap on the same `(&str, &str)` fixture",
23757        );
23758    }
23759
23760    // Routing pin against the actual [`Caixa::validate_restart_window`]
23761    // wire-up: the codec surfaces its parse error as `Result<Duration, String>`,
23762    // and the pre-lift `.map_err(|reason| ManifestError::RestartWindowMalformed
23763    // { restart_window: s.to_string(), reason })` closure passed the owned
23764    // `String` verbatim onto the `reason: String` slot. The lifted
23765    // `restart_window_malformed(&str, impl Into<String>)` ctor must produce
23766    // byte-equal output on the same `(offending_value, owned_reason)` pair a
23767    // real parse-failure fixture surfaces, so a silent regression on the
23768    // owned-`String` axis (a future `reason` bound change dropping the
23769    // `Into<String>` route the owned reason threads through) surfaces here
23770    // rather than at a downstream diagnostic-shape drift.
23771    #[test]
23772    fn restart_window_malformed_ctor_matches_wire_up_owned_reason_shape() {
23773        let raw = "1.5s";
23774        let reason: String = crate::supervisor::duration_codec::parse(raw)
23775            .expect_err("fractional-seconds `1.5s` must fail the shared codec");
23776        assert_eq!(
23777            ManifestError::restart_window_malformed(raw, reason.clone()),
23778            ManifestError::RestartWindowMalformed {
23779                restart_window: raw.to_string(),
23780                reason: reason.clone(),
23781            },
23782            "generated restart_window_malformed ctor must accept the owned \
23783             `String` the [`crate::supervisor::duration_codec::parse`] parse-\
23784             error carrier surfaces (the exact shape the \
23785             [`Caixa::validate_restart_window`] `.map_err(|reason| ...)` \
23786             closure passes into it) and produce byte-equal \
23787             `ManifestError::RestartWindowMalformed` to the pre-lift \
23788             struct-literal wrap on the same `(offending_value, owned_reason)` \
23789             pair",
23790        );
23791    }
23792
23793    // Cross-family invariance pin — the ten sibling ctors all route
23794    // `reason: impl Into<String>` + `<field>: &str` verbatim onto their
23795    // respective typed variants through the shared
23796    // [`manifest_field_reason_ctors!`] macro. Sweeps three fixture
23797    // shapes for `reason` (`&str` literal, owned `String`, `format!(…)`
23798    // output — the three shapes every in-crate wire-up threads through:
23799    // the parser-shaped `String` every `Result<(), String>` predicate
23800    // returns, the `e.to_string()` owned `String` the
23801    // `semver::Version::parse` arm passes, and the literal-shape reason
23802    // the `EdicaoInvalid` direct arm passes) against every generated arm
23803    // so any per-arm wrapper transformation drift surfaces here rather
23804    // than at a downstream diagnostic-shape mismatch. Peer of the
23805    // sibling
23806    // [`crate::aplicacao::tests::aplicacao_field_reason_ctors_route_reason_through_into_uniformly`]
23807    // pin (981060b) on the sibling `AplicacaoError` envelope's identical
23808    // two-slot family.
23809    #[test]
23810    fn manifest_field_reason_ctors_route_reason_through_into_uniformly() {
23811        let via_literal = "literal reason text";
23812        let via_owned: String = String::from("literal reason text");
23813        let via_format = format!("{} reason text", "literal");
23814        assert_eq!(
23815            ManifestError::nome_invalid("n", via_literal),
23816            ManifestError::nome_invalid("n", via_owned.clone()),
23817        );
23818        assert_eq!(
23819            ManifestError::nome_invalid("n", via_literal),
23820            ManifestError::nome_invalid("n", via_format.clone()),
23821        );
23822        assert_eq!(
23823            ManifestError::nome_chart_name_budget_exceeded("n", via_literal),
23824            ManifestError::nome_chart_name_budget_exceeded("n", via_owned.clone()),
23825        );
23826        assert_eq!(
23827            ManifestError::versao_invalid("0.1", via_literal),
23828            ManifestError::versao_invalid("0.1", via_owned.clone()),
23829        );
23830        assert_eq!(
23831            ManifestError::etiqueta_invalid("k", via_literal),
23832            ManifestError::etiqueta_invalid("k", via_owned.clone()),
23833        );
23834        assert_eq!(
23835            ManifestError::autor_invalid("a", via_literal),
23836            ManifestError::autor_invalid("a", via_owned.clone()),
23837        );
23838        assert_eq!(
23839            ManifestError::repositorio_invalid("r", via_literal),
23840            ManifestError::repositorio_invalid("r", via_owned.clone()),
23841        );
23842        assert_eq!(
23843            ManifestError::descricao_invalid("d", via_literal),
23844            ManifestError::descricao_invalid("d", via_owned.clone()),
23845        );
23846        assert_eq!(
23847            ManifestError::licenca_invalid("l", via_literal),
23848            ManifestError::licenca_invalid("l", via_owned.clone()),
23849        );
23850        assert_eq!(
23851            ManifestError::edicao_invalid("26", via_literal),
23852            ManifestError::edicao_invalid("26", via_owned.clone()),
23853        );
23854        assert_eq!(
23855            ManifestError::edicao_invalid("26", via_literal),
23856            ManifestError::edicao_invalid("26", via_format.clone()),
23857        );
23858        assert_eq!(
23859            ManifestError::restart_window_malformed("1.5s", via_literal),
23860            ManifestError::restart_window_malformed("1.5s", via_owned),
23861        );
23862        assert_eq!(
23863            ManifestError::restart_window_malformed("1.5s", via_literal),
23864            ManifestError::restart_window_malformed("1.5s", via_format),
23865        );
23866    }
23867
23868    // Cross-arm routing pin — the ten sibling ctors accept both `&str`
23869    // (from the [`Caixa::nome`] / [`Caixa::versao`] / [`Caixa::repositorio`]
23870    // / [`Caixa::descricao`] / [`Caixa::licenca`] / [`Caixa::edicao`]
23871    // accessors that return `&str`) and `&String` (from the
23872    // [`Caixa::etiquetas`] / [`Caixa::autores`] slice iterators that yield
23873    // `&String`) at the `<field>: &str` parameter via Deref coercion. This
23874    // pin sweeps both call shapes against the two accessors' actual
23875    // wire-up postures so a future rebrand of the etiquetas / autores
23876    // slice-iterator type (a lift from `&[String]` to `&[Cow<'_, str>]`,
23877    // a `smol_str::SmolStr` per-entry swap) that silently broke the
23878    // Deref-coercion path surfaces at this pin rather than at a
23879    // recompile-time type-mismatch far from the ctor family.
23880    #[test]
23881    fn manifest_field_reason_ctors_accept_both_str_and_string_slice_iters() {
23882        let owned: String = String::from("MyKeyword");
23883        // `&str` literal — the canonical accessor-return shape
23884        // ([`Caixa::nome`] etc. yield `&str`).
23885        assert_eq!(
23886            ManifestError::etiqueta_invalid("MyKeyword", "r"),
23887            ManifestError::EtiquetaInvalid {
23888                etiqueta: "MyKeyword".to_string(),
23889                reason: "r".to_string(),
23890            },
23891        );
23892        // `&String` — the canonical slice-iterator-yield shape
23893        // ([`Caixa::etiquetas`] / [`Caixa::autores`] yield `&String`).
23894        assert_eq!(
23895            ManifestError::etiqueta_invalid(&owned, "r"),
23896            ManifestError::EtiquetaInvalid {
23897                etiqueta: owned.clone(),
23898                reason: "r".to_string(),
23899            },
23900        );
23901        // Both call shapes must produce byte-equal
23902        // [`ManifestError::EtiquetaInvalid`] values on the same
23903        // underlying `String`, so a wire-up threading `etiqueta: &String`
23904        // through the same ctor as a peer wire-up threading `nome: &str`
23905        // through it collapses onto one canonical shape.
23906        assert_eq!(
23907            ManifestError::etiqueta_invalid("MyKeyword", "r"),
23908            ManifestError::etiqueta_invalid(&owned, "r"),
23909        );
23910    }
23911
23912    // ── `manifest_field_only_ctors!` — the paired `{ <field>: String }`
23913    //    single-slot envelope on `ManifestError`, direct sibling of the
23914    //    peer [`crate::aplicacao::aplicacao_caixa_only_ctors!`] (d9f6867,
23915    //    `{ caixa: String }` on `AplicacaoError`) and
23916    //    [`crate::aplicacao::aplicacao_path_only_ctors!`] (3ba8de6,
23917    //    `{ path: String }` on `AplicacaoError`) on the M3 mesh envelope,
23918    //    of the peer [`crate::supervisor::supervisor_caixa_only_ctors!`]
23919    //    (db09650, `{ caixa: String }` on `SupervisorError`), and of the
23920    //    peer [`crate::dep::dep_nome_only_ctors!`] (792aa92,
23921    //    `{ nome: String }` on `DepError`) folds on their sibling
23922    //    envelopes. Two-variant lift closing the last two open-coded
23923    //    single-`String`-slot ctor sites at
23924    //    [`Caixa::validate_etiquetas`] and [`Caixa::validate_autores`].
23925
23926    #[test]
23927    fn etiqueta_duplicate_ctor_matches_struct_literal_wrap() {
23928        assert_eq!(
23929            ManifestError::etiqueta_duplicate("mesh"),
23930            ManifestError::EtiquetaDuplicate {
23931                etiqueta: "mesh".to_string(),
23932            },
23933            "generated etiqueta_duplicate ctor must produce byte-equal \
23934             `ManifestError::EtiquetaDuplicate` to the pre-lift \
23935             struct-literal wrap on the same `&str` fixture",
23936        );
23937    }
23938
23939    #[test]
23940    fn autor_duplicate_ctor_matches_struct_literal_wrap() {
23941        assert_eq!(
23942            ManifestError::autor_duplicate("pleme-io"),
23943            ManifestError::AutorDuplicate {
23944                autor: "pleme-io".to_string(),
23945            },
23946            "generated autor_duplicate ctor must produce byte-equal \
23947             `ManifestError::AutorDuplicate` to the pre-lift \
23948             struct-literal wrap on the same `&str` fixture",
23949        );
23950    }
23951
23952    #[test]
23953    fn manifest_field_only_ctors_route_field_through_to_string() {
23954        // Cross-axis pin: sweep the sole constructor input axis
23955        // (`<field>: &str`) through a non-default fixture value against
23956        // every generated arm in the [`manifest_field_only_ctors!`]
23957        // macro, so any wrapper-side lowercase / trim / truncate / silent
23958        // constant-substitution on the `<field>.to_string()` sole-field
23959        // construction surfaces here rather than at a downstream
23960        // diagnostic-shape mismatch. Peer of the sibling
23961        // [`crate::aplicacao::tests::aplicacao_caixa_only_ctors_route_caixa_through_to_string`]
23962        // (d9f6867) and
23963        // [`crate::aplicacao::tests::aplicacao_path_only_ctors_route_path_through_to_string`]
23964        // (3ba8de6) cross-axis pins on the peer `AplicacaoError`
23965        // single-`String`-slot envelopes.
23966        let value = "cache-v2";
23967        assert_eq!(
23968            ManifestError::etiqueta_duplicate(value),
23969            ManifestError::EtiquetaDuplicate {
23970                etiqueta: value.to_string(),
23971            },
23972        );
23973        assert_eq!(
23974            ManifestError::autor_duplicate(value),
23975            ManifestError::AutorDuplicate {
23976                autor: value.to_string(),
23977            },
23978        );
23979    }
23980
23981    #[test]
23982    fn manifest_field_only_ctors_accept_both_str_and_string_slice_iters() {
23983        // The two wire-up sites at [`Caixa::validate_etiquetas`] and
23984        // [`Caixa::validate_autores`] each thread a `&String` loop head
23985        // through the ctor via Deref coercion at the `<field>: &str`
23986        // parameter — this pin locks that call shape's byte-equality
23987        // against the direct `&str` shape so a future rebrand of the
23988        // `:etiquetas` / `:autores` slice-iterator type that silently
23989        // broke the Deref-coercion path surfaces here rather than at a
23990        // recompile-time type-mismatch far from the ctor family. Peer of
23991        // the sibling
23992        // [`manifest_field_reason_ctors_accept_both_str_and_string_slice_iters`]
23993        // pin on the peer two-slot `{ <field>: String, reason: String }`
23994        // envelope.
23995        let etiqueta: String = String::from("mesh");
23996        assert_eq!(
23997            ManifestError::etiqueta_duplicate("mesh"),
23998            ManifestError::etiqueta_duplicate(&etiqueta),
23999        );
24000        let autor: String = String::from("pleme-io");
24001        assert_eq!(
24002            ManifestError::autor_duplicate("pleme-io"),
24003            ManifestError::autor_duplicate(&autor),
24004        );
24005    }
24006
24007    #[test]
24008    fn dialeto_estrangeiro_ctor_matches_struct_literal_wrap() {
24009        // Byte-identity pin against the pre-lift open-coded
24010        // `Self::DialetoEstrangeiro { dialeto }` one-field struct-literal —
24011        // a future silent de-lift of [`Caixa::from_lisp`]'s foreign-dialect
24012        // wire-up back to an inline struct-literal (or a divergence between
24013        // the ctor's stored-field wrapping and the struct-literal shape
24014        // downstream consumers still read through `matches!`
24015        // destructuring) trips at caixa-core test time rather than at a
24016        // downstream `LeituraError::to_string()` diagnostic-shape drift on
24017        // a consumer far from the wire-up commit. Peer of the sibling
24018        // [`crate::dialeto::tests::cabeca_errada_ctor_matches_struct_literal_wrap`]
24019        // (38d5159) byte-identity pin the peer single-slot
24020        // [`crate::dialeto::DialetoError::cabeca_errada`] ctor carries.
24021        for dialeto in [
24022            crate::dialeto::CaixaDialeto::Molde,
24023            crate::dialeto::CaixaDialeto::MoldePosicional,
24024        ] {
24025            let via_ctor = LeituraError::dialeto_estrangeiro(dialeto);
24026            let via_struct_literal = LeituraError::DialetoEstrangeiro { dialeto };
24027            assert!(
24028                matches!(
24029                    (&via_ctor, &via_struct_literal),
24030                    (
24031                        LeituraError::DialetoEstrangeiro { dialeto: a },
24032                        LeituraError::DialetoEstrangeiro { dialeto: b },
24033                    ) if a == b && *a == dialeto
24034                ),
24035                "LeituraError::dialeto_estrangeiro({dialeto:?}) must \
24036                 byte-match the open-coded `LeituraError::DialetoEstrangeiro \
24037                 {{ dialeto: {dialeto:?} }}` struct-literal — a future \
24038                 silent de-lift back to the struct-literal, or a divergence \
24039                 in the field's stored shape, would surface here",
24040            );
24041            assert_eq!(
24042                via_ctor.to_string(),
24043                via_struct_literal.to_string(),
24044                "Display byte-string must be identical between the ctor \
24045                 and struct-literal forms — a divergence would mean the \
24046                 ctor wired the field through a different projection than \
24047                 the struct-literal, silently splitting the two paths' \
24048                 diagnostic shape. dialect: {dialeto:?}",
24049            );
24050        }
24051    }
24052
24053    #[test]
24054    fn dialeto_estrangeiro_routes_dialeto_verbatim_across_every_caixa_dialeto_arm() {
24055        // Boundary-covering fixture sweep on the sole
24056        // [`crate::dialeto::CaixaDialeto`] axis the variant carries —
24057        // every arm in [`crate::dialeto::CaixaDialeto::ALL`] (including the
24058        // non-[`crate::dialeto::CaixaDialeto::is_molde_family`] arms the
24059        // [`Caixa::from_lisp`] wire-up never reaches today, since the ctor
24060        // is a substrate primitive independent of any single caller's
24061        // dispatch gate) round-trips through the ctor byte-equal to the
24062        // input and byte-equal to the open-coded struct-literal wrap. Any
24063        // wrapper-side silent transformation (a `dialeto.normalize()`
24064        // rewrite, a `dialeto.into()` divergence, an accidental field
24065        // rebrand on the ctor body) surfaces at assert time rather than
24066        // at a downstream consumer that reads `err.dialeto` back and
24067        // gets a different arm than the one it stored. Peer of the sibling
24068        // [`crate::dialeto::tests::cabeca_errada_routes_encontrado_verbatim_across_boundary_inputs`]
24069        // (38d5159) boundary-sweep pin on the peer single-slot ctor.
24070        for &dialeto in crate::dialeto::CaixaDialeto::ALL {
24071            let via_ctor = LeituraError::dialeto_estrangeiro(dialeto);
24072            match via_ctor {
24073                LeituraError::DialetoEstrangeiro { dialeto: stored } => {
24074                    assert_eq!(
24075                        stored, dialeto,
24076                        "LeituraError::dialeto_estrangeiro({dialeto:?}) \
24077                         must route the input arm verbatim into the \
24078                         stored `dialeto:` field — any silent \
24079                         normalization on the ctor path would surface \
24080                         here rather than at a downstream consumer that \
24081                         branches on `err.dialeto`",
24082                    );
24083                }
24084                other => panic!(
24085                    "dialeto_estrangeiro({dialeto:?}) must construct the \
24086                     DialetoEstrangeiro variant; got: {other:?}"
24087                ),
24088            }
24089        }
24090    }
24091
24092    #[test]
24093    fn from_lisp_foreign_dialect_gate_routes_through_dialeto_estrangeiro_ctor() {
24094        // End-to-end pin refusing a silent regression that de-folds the
24095        // [`Caixa::from_lisp`] production wire-up back to
24096        // `Err(LeituraError::DialetoEstrangeiro { dialeto })` at the
24097        // foreign-dialect classification arm — for every arm in
24098        // [`crate::dialeto::CaixaDialeto::ALL`] the
24099        // [`crate::dialeto::CaixaDialeto::is_molde_family`] partition
24100        // returns `true` for (the [`crate::dialeto::CaixaDialeto::Molde`]
24101        // and [`crate::dialeto::CaixaDialeto::MoldePosicional`]
24102        // canonical two-arity closure), the observed
24103        // [`Caixa::from_lisp`] `Err` byte-equals the value returned by
24104        // `LeituraError::dialeto_estrangeiro(dialeto)`. Peer of the sibling
24105        // [`crate::dialeto::tests::classify_form_wrong_head_routes_through_cabeca_errada_ctor`]
24106        // (38d5159) end-to-end wire-up pin on the sibling
24107        // [`crate::dialeto::classify_form`] wrong-head gate.
24108        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
24109            (
24110                crate::dialeto::CaixaDialeto::Molde,
24111                r#"
24112                  (defcaixa
24113                    :name "base64"
24114                    :kind :Biblioteca
24115                    :ecosystem :rust-single-crate
24116                    :package {:name "base64" :version "0.22.1"})
24117                "#,
24118            ),
24119            (
24120                crate::dialeto::CaixaDialeto::MoldePosicional,
24121                r#"
24122                  (defcaixa todoku-go
24123                    :kind :Biblioteca
24124                    :ecosystem :go
24125                    :package {:name "todoku-go" :version "0.3.0"})
24126                "#,
24127            ),
24128        ];
24129
24130        for &(expected, src) in fixtures {
24131            let observed = Caixa::from_lisp(src.trim())
24132                .expect_err("foreign-dialect source must not parse as Pacote");
24133            let via_ctor = LeituraError::dialeto_estrangeiro(expected);
24134            assert!(
24135                matches!(
24136                    (&observed, &via_ctor),
24137                    (
24138                        LeituraError::DialetoEstrangeiro { dialeto: a },
24139                        LeituraError::DialetoEstrangeiro { dialeto: b },
24140                    ) if a == b && *a == expected
24141                ),
24142                "Caixa::from_lisp on {expected:?} source must byte-equal \
24143                 LeituraError::dialeto_estrangeiro({expected:?}) — a silent \
24144                 de-lift of the production wire-up back to the open-coded \
24145                 struct-literal, or a divergence between the ctor and the \
24146                 gate's construction shape, would surface here rather than \
24147                 at a downstream diagnostic consumer",
24148            );
24149            assert_eq!(
24150                observed.to_string(),
24151                via_ctor.to_string(),
24152                "from_lisp's observed `Err` and \
24153                 `dialeto_estrangeiro({expected:?})` must render the same \
24154                 Display byte-string — any drift means the two \
24155                 construction paths projected the same axis through \
24156                 different display shapes",
24157            );
24158        }
24159    }
24160}