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 six variants `Biblioteca` /
1380    /// `Binario` / `Servico` / `Supervisor` / `Aplicacao` / `Acao`
1381    /// partition the caixa surface into disjoint runtime contracts) —
1382    /// the typed
1383    /// slot's [`CaixaKind`] accept-set (parse-time-rejected non-symbol
1384    /// values through the derive-macro's symbol-arm gate, exhaustively
1385    /// matched at every downstream dispatch site) maps onto every
1386    /// load-bearing downstream consumer the substrate carries:
1387    ///
1388    ///   - [`crate::render::require_kind`]'s per-renderer entry-gate
1389    ///     predicate — the canonical two-line
1390    ///     `require_kind(caixa, Servico)?` prelude every per-Servico
1391    ///     renderer (`caixa-helm`, `caixa-flux`, the future `caixa-otel`
1392    ///     / per-Servico OCI packager / M4 `wasm.pleme.io/v1alpha1/
1393    ///     ComputeUnit` CR materializer) runs at its entry-point,
1394    ///     alongside the [`crate::render::KindMismatch`] error carrier's
1395    ///     `actual:` field the diagnostic surfaces to name the offending
1396    ///     caixa's variant.
1397    ///   - [`Self::aplicacao_view`]'s + [`Self::supervisor_view`]'s
1398    ///     per-view kind-gate binding — the two `Option<TypedSpec>`
1399    ///     `_view` composers that fold the flat mesh-slot / supervisor-
1400    ///     slot columns into their typed sub-spec only when the kind
1401    ///     matches (returns `None` otherwise); the future per-Servico
1402    ///     M2-view composer (`servico_view`) will follow the same shape.
1403    ///   - [`Self::declared_foreign_code_slots`]'s per-slot kind-
1404    ///     coherence gate — the `!self.kind.requires_exe()` /
1405    ///     `!self.kind.requires_servicos()` predicates that fence
1406    ///     each code-surface slot from the wrong owning kind.
1407    ///   - [`crate::LayoutInvariants::verify`]'s kind ↔ code-surface
1408    ///     coherence gates — the six `caixa.kind == CaixaKind::X` /
1409    ///     `caixa.kind != CaixaKind::X` predicates and the four kind-
1410    ///     coherence error carriers (`SupervisorOwnsCode` /
1411    ///     `AplicacaoOwnsCode` / `MeshSlotsOnNonAplicacao` /
1412    ///     `SupervisorSlotsOnNonSupervisor` / `ServicoSlotsOnNonServico`
1413    ///     / `ForeignCodeSlot`) which each name the offending caixa's
1414    ///     variant in their `kind:` field.
1415    ///
1416    /// Prior to this lift the `.kind` field was accessed inline at
1417    /// twenty-plus production sites across `caixa-core` (the
1418    /// [`crate::render::require_kind`] entry-gate predicate + the
1419    /// [`crate::render::KindMismatch`] `actual:` field, the two `_view`
1420    /// composers, the `declared_foreign_code_slots` per-slot kind-
1421    /// coherence gate, and the six [`crate::LayoutInvariants::verify`]
1422    /// kind ↔ code-surface predicates + four error carriers) — a score
1423    /// of open-coded field-accesses that expressed no compile-time link
1424    /// back to the typed slot. A future extension of the `:kind` axis
1425    /// to a richer author surface — a per-`:kind` sub-variant discriminant
1426    /// (e.g. `Servico(ServicoRuntime)` splitting the current single
1427    /// variant across the wasm-component / legacy-container / native-
1428    /// binary runtime axes the M5 roadmap acknowledges), a per-cluster
1429    /// kind-overlay the M4 CR materializer resolves per-CR (the
1430    /// "cluster policy demotes `Aplicacao` to `Servico` on a single-
1431    /// tenant cluster" arm), a promotion of the plain [`CaixaKind`]
1432    /// enum to a richer `KindWithRuntime` discriminated on the
1433    /// component-model world axis — would have had to be threaded
1434    /// through every open-coded copy in lockstep or the entry gate,
1435    /// the view composers, and the layout invariants would silently
1436    /// disagree on which kind a given [`Caixa`] resolves to. Lifting
1437    /// the resolution to a typed method on the substrate primitive
1438    /// means every downstream consumer of the caixa's per-`Caixa`
1439    /// kind surface reaches for exactly one typed dispatch — the
1440    /// resolver's accept-set migrates as a unit on any future axis
1441    /// addition.
1442    ///
1443    /// First outer top-level [`Caixa`] `Copy`-return required-enum-
1444    /// discriminant accessor — opens the "outer [`Caixa`] `Copy`-return
1445    /// required-discriminant" projection pattern. Sibling in shape to
1446    /// the peer per-`:supervisor` [`crate::supervisor::SupervisorSpec::estrategia`]
1447    /// (eafb619), per-`:placement` [`crate::aplicacao::Placement::estrategia`]
1448    /// (921fe1b), and per-`:children` [`crate::supervisor::ChildSpec::restart`]
1449    /// (dfb4a81) `Copy`-return closed-set-enum discriminant accessors
1450    /// on the sibling nested-spec typed-slot discriminator axes,
1451    /// extended here to the outer top-level [`Caixa`] universal-axis
1452    /// surface. Named `kind()` to match the storage field's name;
1453    /// the accessor's identity maps onto the canonical CAIXA-SDLC §I
1454    /// vocabulary the slot's docstring already carries.
1455    #[must_use]
1456    pub const fn kind(&self) -> CaixaKind {
1457        self.kind
1458    }
1459
1460    /// Substrate-canonical per-`Caixa` `:autores` universal-axis
1461    /// maintainer-name-list slice-accessor every consumer of the top-
1462    /// level manifest's maintainer axis keys off — returns the author-
1463    /// declared `:autores` list verbatim as a `&[String]` slice-view over
1464    /// the same backing buffer the raw `self.autores.as_slice()` field
1465    /// access borrows from. Empty-list-carrying (`:autores` is a default-
1466    /// empty axis every `defcaixa` form supplies with an empty `()` when
1467    /// unset; the [`Self::from_lisp`] derive folds an omitted `:autores`
1468    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1469    /// parse definitionally carries a `Vec<String>` slot — possibly
1470    /// empty — and the returned `&[String]` degenerates to an empty
1471    /// slice on that arm without any silent `None` collapse).
1472    ///
1473    /// The `:autores` slot carries the universal-axis maintainer-name
1474    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
1475    /// facing surface every `defcaixa` form supplies alongside `:nome` /
1476    /// `:versao` / `:kind`; the substrate-wide contact-carrying axis
1477    /// every downstream registry-facing artifact emits under) — the
1478    /// typed slot's `Vec<String>` accept-set (empty-per-entry rejected
1479    /// through [`ManifestError::AutorEmpty`], non-chart-maintainer-shape
1480    /// rejected through [`ManifestError::AutorInvalid`], cross-entry
1481    /// duplicate rejected through [`ManifestError::AutorDuplicate`]) maps
1482    /// onto every load-bearing downstream consumer the substrate carries
1483    /// — the [`Self::validate_autores`] universal-axis empty-per-entry +
1484    /// shape + duplicate gate at caixa-core/src/manifest.rs, the
1485    /// caixa-helm `build_chart_yaml` `maintainers:` fold at
1486    /// caixa-helm/src/lib.rs that walks each entry into a `Maintainer {
1487    /// name, email: None }` record, every future per-`Caixa` registry-
1488    /// facing renderer the CAIXA-SDLC §I roadmap acknowledges (the
1489    /// future `artifacthub.io/maintainers` `Chart.yaml` annotation the
1490    /// caixa-helm docstring alludes to at [`Self::validate_licenca`],
1491    /// the future per-cluster author-notification overlay the M4 CR
1492    /// materializer resolves per-CR).
1493    ///
1494    /// Prior to this lift the `.autores` field was accessed inline at
1495    /// two production sites — [`Self::validate_autores`]'s `for autor
1496    /// in &self.autores` walk that gates every entry through
1497    /// [`ManifestError::AutorEmpty`] / `AutorInvalid` / `AutorDuplicate`,
1498    /// and the caixa-helm `build_chart_yaml` `caixa.autores.iter().map(|a|
1499    /// Maintainer { name: a.clone(), email: None }).collect()` fold that
1500    /// materializes every entry into a `Chart.yaml` `maintainers:` row —
1501    /// two open-coded field-accesses that expressed no compile-time link
1502    /// back to the typed slot. A future extension of the `:autores` axis
1503    /// to a richer author surface — a per-`:autores` structured
1504    /// `Maintainer { name, email, url }` at the storage layer once the
1505    /// substrate absorbs `artifacthub.io/maintainers`' name+email+url
1506    /// tuple, a per-registry `:autores` allowlist the M4 CR materializer
1507    /// enforces per-CR (the "cluster policy demands every author declare
1508    /// an on-file `mailto:` contact" arm), a promotion of the plain
1509    /// `Vec<String>` byte-string list to a richer
1510    /// `Vec<ChartMaintainer>` newtype discriminated on the RFC-5322
1511    /// `<name> [<email>]` grammar the `is_chart_maintainer_name_shape`
1512    /// predicate already resolves through — would have had to be
1513    /// threaded through both open-coded copies in lockstep or the
1514    /// validate gate and the caixa-helm emit path would silently
1515    /// disagree on which authors a given [`Caixa`] resolves to (an
1516    /// author's `:autores ("alice" "bob")` would satisfy validate while
1517    /// the caixa-helm emit path silently rendered a drifted other
1518    /// maintainer list, or vice versa). Lifting the resolution to a
1519    /// typed method on the substrate primitive means every downstream
1520    /// consumer of the caixa's per-`Caixa` maintainer surface reaches
1521    /// for exactly one typed dispatch — the resolver's accept-set
1522    /// migrates as a unit on any future axis addition.
1523    ///
1524    /// First outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1525    /// opens the "outer [`Caixa`] `&[T]` slice" projection pattern the
1526    /// sibling per-`Caixa` `:etiquetas` / `:deps` / `:deps-dev` / `:exe`
1527    /// / `:bibliotecas` / `:servicos` / `:upgrade-from` / `:children`
1528    /// future lifts fold on. Sibling in shape to the peer per-`:supervisor`
1529    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce), per-`:placement`
1530    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7), per-`:membros`
1531    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36), per-`:contratos`
1532    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1533    /// per-`:upgrade-from :instructions` [`crate::upgrade::UpgradeFromEntry::instructions`]
1534    /// (0137e5a) `&[T]`-return slice accessors on the sibling per-M2 /
1535    /// per-M3 typed-slot list axes, extended here to the outer top-level
1536    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1537    /// `&Vec<String>`) because every downstream consumer of the author
1538    /// list treats it as a read-only sequence — the slice-view is the
1539    /// narrowest borrow that supports every present + roadmapped consumer
1540    /// (`.iter()`, `.len()`, `.is_empty()`) without leaking the backing
1541    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
1542    /// reaches for (the storage-side `Vec` remains reachable through the
1543    /// `pub autores` field for the mutation-carrying serde round-trip and
1544    /// per-test fixture-mutation paths). Named `autores()` to match the
1545    /// storage field's name; the accessor's identity maps onto the
1546    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1547    /// carries.
1548    #[must_use]
1549    pub const fn autores(&self) -> &[String] {
1550        self.autores.as_slice()
1551    }
1552
1553    /// Substrate-canonical per-`Caixa` `:etiquetas` universal-axis
1554    /// registry-search-tag-list slice-accessor every consumer of the
1555    /// top-level manifest's topical-tag axis keys off — returns the
1556    /// author-declared `:etiquetas` list verbatim as a `&[String]`
1557    /// slice-view over the same backing buffer the raw
1558    /// `self.etiquetas.as_slice()` field access borrows from. Empty-
1559    /// list-carrying (`:etiquetas` is a default-empty axis every
1560    /// `defcaixa` form supplies with an empty `()` when unset; the
1561    /// [`Self::from_lisp`] derive folds an omitted `:etiquetas` through
1562    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1563    /// definitionally carries a `Vec<String>` slot — possibly empty —
1564    /// and the returned `&[String]` degenerates to an empty slice on
1565    /// that arm without any silent `None` collapse).
1566    ///
1567    /// The `:etiquetas` slot carries the universal-axis topical-tag
1568    /// list every kind of caixa emits under (CAIXA-SDLC §I — the
1569    /// author-facing surface every `defcaixa` form supplies alongside
1570    /// `:nome` / `:versao` / `:kind`; the substrate-wide registry-
1571    /// search-facing axis every downstream registry-facing artifact
1572    /// emits under) — the typed slot's `Vec<String>` accept-set
1573    /// (empty-per-entry rejected through [`ManifestError::EtiquetaEmpty`],
1574    /// non-chart-keyword-shape rejected through
1575    /// [`ManifestError::EtiquetaInvalid`], cross-entry duplicate
1576    /// rejected through [`ManifestError::EtiquetaDuplicate`]) maps onto
1577    /// every load-bearing downstream consumer the substrate carries —
1578    /// the [`Self::validate_etiquetas`] universal-axis empty-per-entry
1579    /// + shape + duplicate gate at caixa-core/src/manifest.rs, the
1580    /// caixa-helm `build_chart_yaml` `keywords:` fold at
1581    /// caixa-helm/src/lib.rs that walks each entry into the rendered
1582    /// `Chart.yaml` `keywords:` array (chained with the
1583    /// [`crate::LAREIRA_CHART_KEYWORDS`] substrate-wide floor set and
1584    /// dedup'd through a `BTreeSet` at emit time), every future per-
1585    /// `Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
1586    /// acknowledges (the future `artifacthub.io/keywords` `Chart.yaml`
1587    /// annotation, the future per-cluster tag-notification overlay the
1588    /// M4 CR materializer resolves per-CR).
1589    ///
1590    /// Prior to this lift the `.etiquetas` field was accessed inline at
1591    /// two production sites — [`Self::validate_etiquetas`]'s `for
1592    /// etiqueta in &self.etiquetas` walk that gates every entry through
1593    /// [`ManifestError::EtiquetaEmpty`] / `EtiquetaInvalid` /
1594    /// `EtiquetaDuplicate`, and the caixa-helm `build_chart_yaml`
1595    /// `caixa.etiquetas.iter().cloned().chain(...)` fold that
1596    /// materializes every entry into a `Chart.yaml` `keywords:` row —
1597    /// two open-coded field-accesses that expressed no compile-time
1598    /// link back to the typed slot. A future extension of the
1599    /// `:etiquetas` axis to a richer tag surface — a per-`:etiquetas`
1600    /// structured `ChartKeyword { name, uri, category }` at the storage
1601    /// layer once the substrate absorbs `artifacthub.io/keywords`
1602    /// richer tag tuple, a per-registry `:etiquetas` allowlist the M4
1603    /// CR materializer enforces per-CR (the "cluster policy demands
1604    /// every tag come from a substrate-approved taxonomy" arm), a
1605    /// promotion of the plain `Vec<String>` byte-string list to a
1606    /// richer `Vec<ChartKeyword>` newtype discriminated on the DNS-
1607    /// 1123-label-shaped grammar the `is_chart_keyword_shape` predicate
1608    /// already resolves through — would have had to be threaded through
1609    /// both open-coded copies in lockstep or the validate gate and the
1610    /// caixa-helm emit path would silently disagree on which tags a
1611    /// given [`Caixa`] resolves to (an author's `:etiquetas ("demo"
1612    /// "aplicacao")` would satisfy validate while the caixa-helm emit
1613    /// path silently rendered a drifted other keyword list, or vice
1614    /// versa). Lifting the resolution to a typed method on the
1615    /// substrate primitive means every downstream consumer of the
1616    /// caixa's per-`Caixa` topical-tag surface reaches for exactly one
1617    /// typed dispatch — the resolver's accept-set migrates as a unit
1618    /// on any future axis addition.
1619    ///
1620    /// Second outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1621    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1622    /// [`Self::autores`] (b5d813f) opened, sibling in shape and
1623    /// idiom. The remaining unlifted outer-`Caixa` slice-carrying axes
1624    /// (`:deps` / `:deps-dev` / `:exe` / `:bibliotecas` / `:servicos`
1625    /// / `:upgrade-from` / `:children` / `:membros` / `:contratos`)
1626    /// fold onto the same pattern in future lifts. Sibling in shape to
1627    /// the peer per-`:supervisor`
1628    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1629    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1630    /// (a6e18d7), per-`:membros`
1631    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1632    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1633    /// (0dcc926), and per-`:upgrade-from :instructions`
1634    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1635    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1636    /// typed-slot list axes, extended here to the outer top-level
1637    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1638    /// `&Vec<String>`) because every downstream consumer of the tag
1639    /// list treats it as a read-only sequence — the slice-view is the
1640    /// narrowest borrow that supports every present + roadmapped
1641    /// consumer (`.iter()`, `.len()`, `.is_empty()`) without leaking
1642    /// the backing `Vec`'s grow/push/reserve surface no consumer of
1643    /// the typed view reaches for (the storage-side `Vec` remains
1644    /// reachable through the `pub etiquetas` field for the mutation-
1645    /// carrying serde round-trip and per-test fixture-mutation paths).
1646    /// Named `etiquetas()` to match the storage field's name; the
1647    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1648    /// vocabulary the slot's docstring already carries.
1649    #[must_use]
1650    pub const fn etiquetas(&self) -> &[String] {
1651        self.etiquetas.as_slice()
1652    }
1653
1654    /// Substrate-canonical per-`Caixa` `:bibliotecas` universal-axis
1655    /// library-source-path-list slice-accessor every consumer of the
1656    /// top-level manifest's Biblioteca-source axis keys off — returns
1657    /// the author-declared `:bibliotecas` list verbatim as a
1658    /// `&[String]` slice-view over the same backing buffer the raw
1659    /// `self.bibliotecas.as_slice()` field access borrows from. Empty-
1660    /// list-carrying (`:bibliotecas` is a default-empty axis every
1661    /// `defcaixa` form supplies with an empty `()` when unset; the
1662    /// [`Self::from_lisp`] derive folds an omitted `:bibliotecas`
1663    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1664    /// parse definitionally carries a `Vec<String>` slot — possibly
1665    /// empty — and the returned `&[String]` degenerates to an empty
1666    /// slice on that arm without any silent `None` collapse).
1667    ///
1668    /// The `:bibliotecas` slot carries the universal-axis lisp-library
1669    /// entry-path list every `:kind Biblioteca` caixa emits under
1670    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1671    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1672    /// substrate-wide library-carrier axis every downstream
1673    /// authoring-facing consumer keys off) — the typed slot's
1674    /// `Vec<String>` accept-set (empty-per-entry rejected through
1675    /// [`ManifestError::CodePathEmpty { slot: ":bibliotecas" }`],
1676    /// non-sandboxed-relative-shape rejected through
1677    /// [`ManifestError::CodePathShape`], non-`.lisp`-extension rejected
1678    /// through [`ManifestError::CodePathNonLispExtension`], cross-entry
1679    /// duplicate rejected through [`ManifestError::CodePathDuplicate`])
1680    /// maps onto every load-bearing downstream consumer the substrate
1681    /// carries — the [`crate::LayoutInvariants`] Biblioteca-arm
1682    /// empty-check + per-entry file-exists loop at
1683    /// caixa-core/src/layout.rs that gates each entry through
1684    /// [`crate::LayoutError::MissingLib`] / `MissingEntry`, the
1685    /// [`Self::validate_code_paths`] per-slot shape gate at
1686    /// caixa-core/src/manifest.rs that walks each entry through the
1687    /// sandbox-relative / `.lisp`-extension / cross-entry duplicate
1688    /// gates, the `feira build` per-entry `tatara_lisp::read` parse
1689    /// walk at caixa-feira/src/cmd/build.rs that phase-1-checks each
1690    /// declared library file for lexical / structural errors before
1691    /// downstream `importar` resolution, every future per-`Caixa`
1692    /// library-facing renderer the CAIXA-SDLC §I roadmap acknowledges
1693    /// (the future `tatara-lispc` compilation entry the docstring at
1694    /// caixa-feira/src/cmd/build.rs alludes to, the future per-cluster
1695    /// bytecode-caching overlay the M4 CR materializer resolves per-CR,
1696    /// the future `caixa-lsp` per-library semantic-token stream the
1697    /// caixa-lsp docstring roadmaps).
1698    ///
1699    /// Prior to this lift the `.bibliotecas` field was accessed inline
1700    /// at three production sites — [`crate::LayoutInvariants`]'s
1701    /// `caixa.bibliotecas.is_empty()` `MissingLib`-arm gate + `for p
1702    /// in &caixa.bibliotecas` `MissingEntry` walk that gates each
1703    /// declared library path through the on-disk-existence check,
1704    /// the compound-code-path `has_code = !caixa.bibliotecas.is_empty()
1705    /// || !caixa.exe.is_empty() || !caixa.servicos.is_empty()` OR-fold
1706    /// on the [`crate::LayoutError::SupervisorOwnsCode`] /
1707    /// `AplicacaoOwnsCode` kind-coherence gate, and the `feira build`
1708    /// per-entry `for entry in &caixa.bibliotecas` + `caixa.bibliotecas.
1709    /// len()` phase-1 tatara-lispc-precursor parse walk — three open-
1710    /// coded field-accesses that expressed no compile-time link back
1711    /// to the typed slot. A future extension of the `:bibliotecas`
1712    /// axis to a richer library surface — a per-`:bibliotecas`
1713    /// structured `BibliotecaEntry { path, edition, exports }` at the
1714    /// storage layer once the substrate absorbs the per-library
1715    /// language-edition + explicit-exports tuple the tatara-lisp
1716    /// module-system roadmap acknowledges, a per-registry
1717    /// `:bibliotecas` allowlist the M4 CR materializer enforces
1718    /// per-CR (the "cluster policy demands every biblioteca declare
1719    /// its own :edicao" arm), a promotion of the plain `Vec<String>`
1720    /// byte-string list to a richer `Vec<LibraryPath>` newtype
1721    /// discriminated on the `lib/<nome>.lisp`-shape grammar the
1722    /// [`crate::render::is_sandboxed_relative_path`] +
1723    /// [`crate::render::is_lisp_extension`] predicates already resolve
1724    /// through — would have had to be threaded through all three
1725    /// open-coded copies in lockstep or the layout gate, the shape
1726    /// validator, and the `feira build` phase-1 parse walk would
1727    /// silently disagree on which library paths a given [`Caixa`]
1728    /// resolves to (an author's `:bibliotecas ("lib/foo.lisp"
1729    /// "lib/bar.lisp")` would satisfy layout while `feira build`
1730    /// silently parsed a drifted other list, or vice versa). Lifting
1731    /// the resolution to a typed method on the substrate primitive
1732    /// means every downstream consumer of the caixa's per-`Caixa`
1733    /// library-source surface reaches for exactly one typed dispatch
1734    /// — the resolver's accept-set migrates as a unit on any future
1735    /// axis addition.
1736    ///
1737    /// Third outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1738    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1739    /// [`Self::autores`] (b5d813f) opened and [`Self::etiquetas`]
1740    /// (78c7d3c) folded on, sibling in shape and idiom. The remaining
1741    /// unlifted outer-`Caixa` slice-carrying axes (`:deps` /
1742    /// `:deps-dev` / `:exe` / `:servicos` / `:upgrade-from` /
1743    /// `:children` / `:membros` / `:contratos`) fold onto the same
1744    /// pattern in future lifts. Sibling in shape to the peer
1745    /// per-`:supervisor`
1746    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1747    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1748    /// (a6e18d7), per-`:membros`
1749    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1750    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1751    /// (0dcc926), and per-`:upgrade-from :instructions`
1752    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1753    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1754    /// typed-slot list axes, extended here to the outer top-level
1755    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1756    /// `&Vec<String>`) because every downstream consumer of the
1757    /// library-source list treats it as a read-only sequence — the
1758    /// slice-view is the narrowest borrow that supports every
1759    /// present + roadmapped consumer (`.iter()`, `.len()`,
1760    /// `.is_empty()`) without leaking the backing `Vec`'s
1761    /// grow/push/reserve surface no consumer of the typed view
1762    /// reaches for (the storage-side `Vec` remains reachable through
1763    /// the `pub bibliotecas` field for the mutation-carrying serde
1764    /// round-trip and per-test fixture-mutation paths). Named
1765    /// `bibliotecas()` to match the storage field's name; the
1766    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1767    /// vocabulary the slot's docstring already carries.
1768    #[must_use]
1769    pub const fn bibliotecas(&self) -> &[String] {
1770        self.bibliotecas.as_slice()
1771    }
1772
1773    /// Substrate-canonical per-`Caixa` `:exe` universal-axis
1774    /// nix-built-executable-entry-path-list slice-accessor every consumer
1775    /// of the top-level manifest's Binario-executable axis keys off —
1776    /// returns the author-declared `:exe` list verbatim as a `&[String]`
1777    /// slice-view over the same backing buffer the raw
1778    /// `self.exe.as_slice()` field access borrows from. Empty-list-
1779    /// carrying (`:exe` is a default-empty axis every `defcaixa` form
1780    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
1781    /// derive folds an omitted `:exe` through `#[serde(default)]` to
1782    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
1783    /// `Vec<String>` slot — possibly empty — and the returned `&[String]`
1784    /// degenerates to an empty slice on that arm without any silent
1785    /// `None` collapse).
1786    ///
1787    /// The `:exe` slot carries the universal-axis nix-built executable
1788    /// entry-path list every `:kind Binario` caixa emits under
1789    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1790    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1791    /// substrate-wide `exe/`-directory-fenced entry-carrier axis every
1792    /// downstream flake-build-facing consumer keys off) — the typed
1793    /// slot's `Vec<String>` accept-set (empty-per-entry rejected
1794    /// through [`ManifestError::CodePathEmpty { slot: ":exe" }`],
1795    /// non-sandboxed-relative-shape rejected through
1796    /// [`ManifestError::CodePathShape`], cross-entry duplicate rejected
1797    /// through [`ManifestError::CodePathDuplicate`], out-of-`exe/`-
1798    /// directory paths rejected past the layout's
1799    /// [`crate::LayoutError::ExeOutsideDir`] `starts_with` fence) maps
1800    /// onto every load-bearing downstream consumer the substrate carries
1801    /// — the [`crate::LayoutInvariants`] Binario-arm empty-check +
1802    /// per-entry file-exists + `exe/`-directory-fence loop at
1803    /// caixa-core/src/layout.rs that gates each entry through
1804    /// [`crate::LayoutError::BinarioWithoutExe`] / `MissingEntry` /
1805    /// `ExeOutsideDir`, the compound `has_code` OR-fold on the
1806    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1807    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1808    /// that fences code-surface slots off from the two no-code kinds,
1809    /// [`Self::declared_foreign_code_slots`]'s `!self.exe.is_empty()`
1810    /// arm on the [`crate::LayoutError::ForeignCodeSlot`] gate that
1811    /// fences the `:exe` code surface off from every non-Binario code-
1812    /// running kind, [`Self::validate_code_paths`]'s per-slot shape gate
1813    /// that walks each entry through the sandbox-relative / cross-entry
1814    /// duplicate gates, every future per-`Caixa` executable-facing
1815    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1816    /// `caixa-flake` per-Binario `packages.<system>.<nome>` derivation
1817    /// entry the caixa-flake docstring roadmaps, the future per-cluster
1818    /// `nix-store` overlay the M4 CR materializer resolves per-CR, the
1819    /// future `feira nix` per-executable Binario-target emit path).
1820    ///
1821    /// Prior to this lift the `.exe` field was accessed inline at three
1822    /// production sites — the compound-code-path `has_code =
1823    /// !caixa.bibliotecas().is_empty() || !caixa.exe.is_empty() ||
1824    /// !caixa.servicos.is_empty()` OR-fold on the
1825    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1826    /// `AplicacaoOwnsCode` kind-coherence gate, the Binario-arm
1827    /// `caixa.exe.is_empty()` [`crate::LayoutError::BinarioWithoutExe`]
1828    /// gate, the per-entry `for p in &caixa.exe`
1829    /// `MissingEntry`/`ExeOutsideDir` walk, and the
1830    /// [`Self::declared_foreign_code_slots`]'s
1831    /// `!self.exe.is_empty()` arm on the `ForeignCodeSlot` gate — four
1832    /// open-coded field-accesses that expressed no compile-time link
1833    /// back to the typed slot. A future extension of the `:exe` axis
1834    /// to a richer executable surface — a per-`:exe` structured
1835    /// `BinarioEntry { path, wrapper, capabilities }` at the storage
1836    /// layer once the substrate absorbs the per-executable
1837    /// nix-wrapper + linux-capabilities tuple the CAIXA-SDLC §I
1838    /// executable roadmap acknowledges, a per-registry `:exe` allowlist
1839    /// the M4 CR materializer enforces per-CR (the "cluster policy
1840    /// demands every Binario declare an explicit `:wrapper`" arm), a
1841    /// promotion of the plain `Vec<String>` byte-string list to a
1842    /// richer `Vec<ExecutablePath>` newtype discriminated on the
1843    /// `exe/<nome>`-shape grammar the layout's `starts_with(exe_dir)`
1844    /// fence already resolves through — would have had to be threaded
1845    /// through all four open-coded copies in lockstep or the layout
1846    /// gate, the shape validator, and the `feira nix` emit path would
1847    /// silently disagree on which executable paths a given [`Caixa`]
1848    /// resolves to (an author's `:exe ("exe/cli" "exe/serve")` would
1849    /// satisfy layout while `feira nix` silently packaged a drifted
1850    /// other list, or vice versa). Lifting the resolution to a typed
1851    /// method on the substrate primitive means every downstream
1852    /// consumer of the caixa's per-`Caixa` executable-source surface
1853    /// reaches for exactly one typed dispatch — the resolver's accept-
1854    /// set migrates as a unit on any future axis addition.
1855    ///
1856    /// Fourth outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1857    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1858    /// [`Self::autores`] (b5d813f) opened, [`Self::etiquetas`]
1859    /// (78c7d3c) folded on, and [`Self::bibliotecas`] (8a36c23) closed
1860    /// the universal-axis text-tag family of. Opens the outer-`Caixa`
1861    /// foreign-code-slot `&[T]` sub-family the sibling `:servicos`
1862    /// future lift closes onto (per the trio of code-surface list slots
1863    /// the [`Self::validate_code_paths`] per-slot dispatch tuple
1864    /// already carries — `:bibliotecas` + `:exe` + `:servicos`, of which
1865    /// `:bibliotecas` landed at 8a36c23 and `:servicos` remains as the
1866    /// last unlifted code-surface slot). Sibling in shape to the peer
1867    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
1868    /// (bc92bce), per-`:placement`
1869    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
1870    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
1871    /// (6c77e36), per-`:contratos`
1872    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1873    /// per-`:upgrade-from :instructions`
1874    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1875    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1876    /// typed-slot list axes, extended here to the outer top-level
1877    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1878    /// `&Vec<String>`) because every downstream consumer of the
1879    /// executable-source list treats it as a read-only sequence — the
1880    /// slice-view is the narrowest borrow that supports every
1881    /// present + roadmapped consumer (`.iter()`, `.len()`,
1882    /// `.is_empty()`) without leaking the backing `Vec`'s
1883    /// grow/push/reserve surface no consumer of the typed view
1884    /// reaches for (the storage-side `Vec` remains reachable through
1885    /// the `pub exe` field for the mutation-carrying serde
1886    /// round-trip and per-test fixture-mutation paths). Named `exe()`
1887    /// to match the storage field's name; the accessor's identity
1888    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
1889    /// docstring already carries.
1890    #[must_use]
1891    pub const fn exe(&self) -> &[String] {
1892        self.exe.as_slice()
1893    }
1894
1895    /// Substrate-canonical per-`Caixa` `:servicos` universal-axis
1896    /// ComputeUnit-CR-YAML-entry-path-list slice-accessor every consumer
1897    /// of the top-level manifest's Servico-component axis keys off —
1898    /// returns the author-declared `:servicos` list verbatim as a
1899    /// `&[String]` slice-view over the same backing buffer the raw
1900    /// `self.servicos.as_slice()` field access borrows from. Empty-list-
1901    /// carrying (`:servicos` is a default-empty axis every `defcaixa`
1902    /// form supplies with an empty `()` when unset; the
1903    /// [`Self::from_lisp`] derive folds an omitted `:servicos` through
1904    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1905    /// definitionally carries a `Vec<String>` slot — possibly empty —
1906    /// and the returned `&[String]` degenerates to an empty slice on
1907    /// that arm without any silent `None` collapse).
1908    ///
1909    /// The `:servicos` slot carries the universal-axis
1910    /// `.computeunit.yaml` ComputeUnit-CR entry-path list every
1911    /// `:kind Servico` caixa emits under (CAIXA-SDLC §I — the
1912    /// author-facing surface every `defcaixa` form supplies alongside
1913    /// `:nome` / `:versao` / `:kind`; the substrate-wide
1914    /// `servicos/`-directory-fenced entry-carrier axis every downstream
1915    /// Servico-facing renderer keys off) — the typed slot's
1916    /// `Vec<String>` accept-set (empty-per-entry rejected through
1917    /// [`ManifestError::CodePathEmpty { slot: ":servicos" }`],
1918    /// non-sandboxed-relative-shape rejected through
1919    /// [`ManifestError::CodePathShape`], non-`.computeunit.yaml`
1920    /// extension rejected through
1921    /// [`ManifestError::CodePathNonComputeUnitYamlExtension`], cross-
1922    /// entry duplicate rejected through
1923    /// [`ManifestError::CodePathDuplicate`], `len != 1` rejected by the
1924    /// V0 [`crate::ServicoCountMismatch`] gate on the per-Servico
1925    /// renderer entry-points, out-of-`servicos/`-directory paths
1926    /// rejected past the layout's [`crate::LayoutError::ServicoOutsideDir`]
1927    /// `starts_with` fence) maps onto every load-bearing downstream
1928    /// consumer the substrate carries — the [`crate::LayoutInvariants`]
1929    /// Servico-arm empty-check + per-entry file-exists + `servicos/`-
1930    /// directory-fence loop at caixa-core/src/layout.rs that gates each
1931    /// entry through [`crate::LayoutError::ServicoWithoutServicos`] /
1932    /// `MissingEntry` / `ServicoOutsideDir`, the compound `has_code`
1933    /// OR-fold on the [`crate::LayoutError::SupervisorOwnsCode`] /
1934    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1935    /// that fences code-surface slots off from the two no-code kinds,
1936    /// [`Self::declared_foreign_code_slots`]'s
1937    /// `!self.servicos.is_empty()` arm on the
1938    /// [`crate::LayoutError::ForeignCodeSlot`] gate that fences the
1939    /// `:servicos` code surface off from every non-Servico code-running
1940    /// kind, [`Self::validate_code_paths`]'s per-slot shape gate that
1941    /// walks each entry through the sandbox-relative / `.computeunit.
1942    /// yaml`-extension / cross-entry duplicate gates, the
1943    /// [`crate::require_single_servico`] V0 singularity gate every
1944    /// per-Servico renderer entry-point runs through
1945    /// [`crate::require_v0_servico_shape`], the `feira chart` /
1946    /// `feira deploy` per-verb `first_servico_path` walk at
1947    /// caixa-feira/src/cmd/chart.rs that resolves the singleton
1948    /// ComputeUnit-CR file, every future per-`Caixa` Servico-facing
1949    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1950    /// per-Servico OCI packager, the future M4
1951    /// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer, the future
1952    /// per-Servico OTel collector-config emit).
1953    ///
1954    /// Prior to this lift the `.servicos` field was accessed inline at
1955    /// five production sites — the compound-code-path `has_code =
1956    /// !caixa.bibliotecas().is_empty() || !caixa.exe().is_empty() ||
1957    /// !caixa.servicos.is_empty()` OR-fold on the
1958    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1959    /// `AplicacaoOwnsCode` kind-coherence gate, the Servico-arm
1960    /// `caixa.servicos.is_empty()`
1961    /// [`crate::LayoutError::ServicoWithoutServicos`] gate, the
1962    /// per-entry `for p in &caixa.servicos`
1963    /// `MissingEntry`/`ServicoOutsideDir` walk, the
1964    /// [`Self::declared_foreign_code_slots`]'s
1965    /// `!self.servicos.is_empty()` arm on the `ForeignCodeSlot` gate,
1966    /// and the [`crate::require_single_servico`] V0 count gate's
1967    /// `caixa.servicos.len() == 1` / `caixa.servicos.len()` count
1968    /// projection (both the accept-arm predicate and the
1969    /// diagnostic-carrying `ServicoCountMismatch { count }`
1970    /// projection) — five open-coded field-accesses across three
1971    /// crates that expressed no compile-time link back to the typed
1972    /// slot. A future extension of the `:servicos` axis to a richer
1973    /// component surface — a per-`:servicos` structured
1974    /// `ServicoEntry { path, world, capabilities }` at the storage
1975    /// layer once the substrate absorbs the per-component WIT-world +
1976    /// capability-set tuple the CAIXA-SDLC §I Servico roadmap
1977    /// acknowledges, a per-registry `:servicos` allowlist the M4 CR
1978    /// materializer enforces per-CR (the "cluster policy demands every
1979    /// Servico declare an explicit `:world`" arm), a promotion of the
1980    /// plain `Vec<String>` byte-string list to a richer
1981    /// `Vec<ComputeUnitPath>` newtype discriminated on the
1982    /// `servicos/<nome>.computeunit.yaml`-shape grammar the layout's
1983    /// `starts_with(servicos_dir)` fence and the
1984    /// [`crate::render::is_computeunit_yaml_extension`] predicate
1985    /// already resolve through, a promotion of the V0 singleton
1986    /// contract to a multi-component `Vec<ComputeUnitPath>` past the M5
1987    /// component-model multi-world boundary — would have had to be
1988    /// threaded through all five open-coded copies in lockstep or the
1989    /// layout gate, the shape validator, the V0 count gate, and the
1990    /// `feira chart` / `feira deploy` entry-point walks would silently
1991    /// disagree on which ComputeUnit-CR paths a given [`Caixa`]
1992    /// resolves to (an author's `:servicos ("servicos/foo.computeunit.
1993    /// yaml")` would satisfy layout while `feira chart` silently
1994    /// packaged a drifted other list, or vice versa). Lifting the
1995    /// resolution to a typed method on the substrate primitive means
1996    /// every downstream consumer of the caixa's per-`Caixa`
1997    /// ComputeUnit-CR-source surface reaches for exactly one typed
1998    /// dispatch — the resolver's accept-set migrates as a unit on any
1999    /// future axis addition.
2000    ///
2001    /// Fifth and final outer top-level [`Caixa`] `&[T]`-return slice-
2002    /// accessor — folds on the "outer [`Caixa`] `&[T]` slice"
2003    /// projection pattern [`Self::autores`] (b5d813f) opened,
2004    /// [`Self::etiquetas`] (78c7d3c) folded on, [`Self::bibliotecas`]
2005    /// (8a36c23) closed the universal-axis text-tag family of, and
2006    /// [`Self::exe`] (65d9527) opened the foreign-code-slot sub-family
2007    /// of. Closes the outer-`Caixa` foreign-code-slot `&[T]` sub-family
2008    /// — with `:bibliotecas`, `:exe`, and `:servicos` now each carrying
2009    /// a substrate-canonical slice accessor, the trio of code-surface
2010    /// list slots the [`Self::validate_code_paths`] per-slot dispatch
2011    /// tuple carries is complete on the typed dispatch surface (the
2012    /// internal `[(":bibliotecas", &self.bibliotecas, ..), (":exe",
2013    /// &self.exe, ..), (":servicos", &self.servicos, ..)]` per-slot
2014    /// dispatch tuple's homogeneous `&Vec<String>`-typed shape blocks a
2015    /// per-element accessor swap in isolation — a future companion lift
2016    /// promotes the tuple's element type to `&[String]` and threads the
2017    /// triple of typed dispatches through as a unit). Sibling in shape
2018    /// to the peer per-`:supervisor`
2019    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2020    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2021    /// (a6e18d7), per-`:membros`
2022    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2023    /// per-`:contratos`
2024    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2025    /// per-`:upgrade-from :instructions`
2026    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2027    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2028    /// typed-slot list axes, extended here to the outer top-level
2029    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
2030    /// `&Vec<String>`) because every downstream consumer of the
2031    /// ComputeUnit-CR-source list treats it as a read-only sequence —
2032    /// the slice-view is the narrowest borrow that supports every
2033    /// present + roadmapped consumer (`.iter()`, `.len()`,
2034    /// `.is_empty()`, `.first()`) without leaking the backing `Vec`'s
2035    /// grow/push/reserve surface no consumer of the typed view reaches
2036    /// for (the storage-side `Vec` remains reachable through the
2037    /// `pub servicos` field for the mutation-carrying serde round-trip
2038    /// and per-test fixture-mutation paths, and for the
2039    /// [`Self::validate_code_paths`] per-slot dispatch tuple whose
2040    /// homogeneous-element-type shape carries the raw field access
2041    /// until the trio-closure lift promotes the tuple as a unit).
2042    /// Named `servicos()` to match the storage field's name; the
2043    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
2044    /// vocabulary the slot's docstring already carries.
2045    #[must_use]
2046    pub const fn servicos(&self) -> &[String] {
2047        self.servicos.as_slice()
2048    }
2049
2050    /// Substrate-canonical per-`Caixa` `:deps` universal-axis
2051    /// runtime-dependency-declaration-list slice-accessor every consumer
2052    /// of the top-level manifest's runtime-dep-graph axis keys off —
2053    /// returns the author-declared `:deps` list verbatim as a `&[Dep]`
2054    /// slice-view over the same backing buffer the raw
2055    /// `self.deps.as_slice()` field access borrows from. Empty-list-
2056    /// carrying (`:deps` is a default-empty axis every `defcaixa` form
2057    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
2058    /// derive folds an omitted `:deps` through `#[serde(default)]` to
2059    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
2060    /// `Vec<Dep>` slot — possibly empty — and the returned `&[Dep]`
2061    /// degenerates to an empty slice on that arm without any silent
2062    /// `None` collapse).
2063    ///
2064    /// The `:deps` slot carries the universal-axis runtime dependency
2065    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
2066    /// facing surface every `defcaixa` form supplies alongside `:nome` /
2067    /// `:versao` / `:kind`; the substrate-wide runtime-closure-input axis
2068    /// every downstream resolver-facing artifact emits under) — the
2069    /// typed slot's `Vec<Dep>` accept-set (empty-`:nome` rejected through
2070    /// [`DepError::NomeEmpty`], non-DNS-1123-label `:nome` rejected
2071    /// through [`DepError::NomeInvalid`], malformed `:versao` rejected
2072    /// through [`DepError::VersaoInvalid`], empty `:fonte.repo` rejected
2073    /// through [`DepError::FonteRepoEmpty`], within-list duplicate `:nome`
2074    /// rejected through [`DepError::DuplicateNome { list: ":deps" }`])
2075    /// maps onto every load-bearing downstream consumer the substrate
2076    /// carries — the [`Self::validate_deps`] per-entry
2077    /// [`Dep::validate`] + within-list dedup walk at
2078    /// caixa-core/src/manifest.rs, the [`crate::dep::validate_no_self_dep`]
2079    /// cross-list self-reference gate at caixa-core/src/layout.rs that
2080    /// checks each entry against the caixa's own `:nome`, the
2081    /// caixa-resolver `for dep in &root.deps` closure walk at
2082    /// caixa-resolver/src/resolve.rs that seeds every git-clone target
2083    /// through the resolver's [`crate::Dep`]-keyed pipeline, the
2084    /// caixa-crd `caixa.deps.iter().map(dep_into_ref).collect()` fold at
2085    /// caixa-crd/src/conversion.rs that materializes each entry into the
2086    /// K8s `Caixa` CR's `spec.deps` field, every future per-`Caixa`
2087    /// resolver-facing renderer the CAIXA-SDLC §I roadmap acknowledges
2088    /// (the future per-cluster runtime-closure-audit overlay the M4 CR
2089    /// materializer resolves per-CR, the future `lacre.lisp` BLAKE3-
2090    /// closure emit walk the caixa-resolver docstring roadmaps).
2091    ///
2092    /// First outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2093    /// opens the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2094    /// sibling `:deps-dev` future lift closes on. Peer of the closed
2095    /// outer-`Caixa` foreign-code-slot `&[String]` sub-family
2096    /// ([`Self::bibliotecas`] 8a36c23, [`Self::exe`] 65d9527,
2097    /// [`Self::servicos`] 611f78b) and the outer-`Caixa` universal-axis
2098    /// text-tag family ([`Self::autores`] b5d813f, [`Self::etiquetas`]
2099    /// 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice" projection
2100    /// pattern onto a novel element-type axis (`Dep` composite vs the
2101    /// prior sibling family's `String` scalar). Sibling in shape to the
2102    /// peer per-`:supervisor`
2103    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2104    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2105    /// (a6e18d7), per-`:membros`
2106    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2107    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
2108    /// (0dcc926), and per-`:upgrade-from :instructions`
2109    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2110    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2111    /// typed-slot list axes, extended here to the outer top-level
2112    /// [`Caixa`] universal-axis dep-graph surface. Returns `&[Dep]`
2113    /// (not `&Vec<Dep>`) because every downstream consumer of the
2114    /// runtime-dep list treats it as a read-only sequence — the slice-
2115    /// view is the narrowest borrow that supports every present +
2116    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2117    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2118    /// of the typed view reaches for (the storage-side `Vec` remains
2119    /// reachable through the `pub deps` field for the mutation-carrying
2120    /// serde round-trip and per-test fixture-mutation paths). Named
2121    /// `deps()` to match the storage field's name; the accessor's
2122    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
2123    /// slot's docstring already carries.
2124    #[must_use]
2125    pub const fn deps(&self) -> &[Dep] {
2126        self.deps.as_slice()
2127    }
2128
2129    /// Substrate-canonical per-`Caixa` `:deps-dev` universal-axis
2130    /// development-only-dependency-declaration-list slice-accessor every
2131    /// consumer of the top-level manifest's dev-dep-graph axis keys off —
2132    /// returns the author-declared `:deps-dev` list verbatim as a `&[Dep]`
2133    /// slice-view over the same backing buffer the raw
2134    /// `self.deps_dev.as_slice()` field access borrows from. Empty-list-
2135    /// carrying (`:deps-dev` is a default-empty axis every `defcaixa`
2136    /// form supplies with an empty `()` when unset; the
2137    /// [`Self::from_lisp`] derive folds an omitted `:deps-dev` through
2138    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
2139    /// definitionally carries a `Vec<Dep>` slot — possibly empty — and
2140    /// the returned `&[Dep]` degenerates to an empty slice on that arm
2141    /// without any silent `None` collapse).
2142    ///
2143    /// The `:deps-dev` slot carries the universal-axis dev-only
2144    /// dependency list every kind of caixa emits under (CAIXA-SDLC §I —
2145    /// the author-facing sibling of `:deps` that every `defcaixa` form
2146    /// supplies to declare tests / lint / bench closures the runtime
2147    /// `:deps` axis does not carry; the substrate-wide dev-closure-input
2148    /// axis every downstream test-facing artifact emits under, matching
2149    /// Cargo's `[dev-dependencies]` table's dev-time-only visibility
2150    /// contract) — the typed slot's `Vec<Dep>` accept-set (empty-`:nome`
2151    /// rejected through [`DepError::NomeEmpty`], non-DNS-1123-label
2152    /// `:nome` rejected through [`DepError::NomeInvalid`], malformed
2153    /// `:versao` rejected through [`DepError::VersaoInvalid`], empty
2154    /// `:fonte.repo` rejected through [`DepError::FonteRepoEmpty`],
2155    /// within-list duplicate `:nome` rejected through
2156    /// [`DepError::DuplicateNome { list: ":deps-dev" }`]) maps onto every
2157    /// load-bearing downstream consumer the substrate carries — the
2158    /// [`Self::validate_deps`] per-entry [`Dep::validate`] + within-list
2159    /// dedup walk at caixa-core/src/manifest.rs, the
2160    /// [`crate::dep::validate_no_self_dep`] cross-list self-reference
2161    /// gate at caixa-core/src/layout.rs that checks each entry against
2162    /// the caixa's own `:nome`, the caixa-resolver
2163    /// `for dep in &root.deps_dev` closure walk at
2164    /// caixa-resolver/src/resolve.rs that seeds every dev-only git-clone
2165    /// target through the resolver's [`crate::Dep`]-keyed pipeline, and
2166    /// every future per-`Caixa` resolver-facing renderer the CAIXA-SDLC
2167    /// §I roadmap acknowledges (the future per-cluster dev-closure-audit
2168    /// overlay the M4 CR materializer resolves per-CR, the future
2169    /// `lacre.lisp` BLAKE3-closure emit walk the caixa-resolver docstring
2170    /// roadmaps).
2171    ///
2172    /// Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2173    /// closes the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2174    /// sibling [`Self::deps`] (ad34b4e) opened on. The two accessors
2175    /// jointly close the two-list dep-graph surface every downstream
2176    /// resolver-facing consumer keys off (runtime `:deps` +
2177    /// dev-only `:deps-dev`, the canonical Cargo-shaped dependency-table
2178    /// pair the [`Self::validate_deps`] gate already walks in canonical
2179    /// order). Peer of the closed outer-`Caixa` foreign-code-slot
2180    /// `&[String]` sub-family ([`Self::bibliotecas`] 8a36c23,
2181    /// [`Self::exe`] 65d9527, [`Self::servicos`] 611f78b) and the outer-
2182    /// `Caixa` universal-axis text-tag family ([`Self::autores`]
2183    /// b5d813f, [`Self::etiquetas`] 78c7d3c) — folds the "outer
2184    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
2185    /// dev-dep composite-element axis (`Dep` composite, matching the
2186    /// [`Self::deps`] element type). Sibling in shape to the peer
2187    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
2188    /// (bc92bce), per-`:placement`
2189    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
2190    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
2191    /// (6c77e36), per-`:contratos`
2192    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2193    /// per-`:upgrade-from :instructions`
2194    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2195    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2196    /// typed-slot list axes, folded here to the outer top-level
2197    /// [`Caixa`] universal-axis dev-dep-graph surface. Returns `&[Dep]`
2198    /// (not `&Vec<Dep>`) because every downstream consumer of the
2199    /// dev-dep list treats it as a read-only sequence — the slice-view
2200    /// is the narrowest borrow that supports every present +
2201    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2202    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2203    /// of the typed view reaches for (the storage-side `Vec` remains
2204    /// reachable through the `pub deps_dev` field for the mutation-
2205    /// carrying serde round-trip and per-test fixture-mutation paths).
2206    /// Named `deps_dev()` to match the storage field's `snake_case` name;
2207    /// the kebab-case author-surface tag `:deps-dev` is the same axis
2208    /// after tatara-lisp's kebab↔snake fold and the accessor's identity
2209    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
2210    /// docstring already carries.
2211    #[must_use]
2212    pub const fn deps_dev(&self) -> &[Dep] {
2213        self.deps_dev.as_slice()
2214    }
2215
2216    /// Substrate-canonical per-[`Caixa`] typed-dispatch read accessor
2217    /// every consumer that walks one of the two dep-list axes keyed on a
2218    /// [`crate::dep::DepList`] discriminant reaches for — routes the
2219    /// `(list: DepList) -> &[Dep]` projection through one typed method on
2220    /// the substrate primitive rather than the prior open-coded
2221    /// `match list { Prod => caixa.deps(), Dev => caixa.deps_dev() }`
2222    /// inline dispatch every per-axis walker would otherwise carry.
2223    /// Returns the author-declared per-list `Vec<Dep>` verbatim as a
2224    /// `&[Dep]` slice-view over the same backing buffer the sibling
2225    /// [`Self::deps`] (`Prod`) / [`Self::deps_dev`] (`Dev`) per-slot
2226    /// accessors borrow from, preserving the empty-list-carrying invariant
2227    /// each per-slot accessor already establishes (`:deps` / `:deps-dev`
2228    /// are default-empty axes every `defcaixa` form supplies with an empty
2229    /// `()` when unset; the [`Self::from_lisp`] derive folds an omitted
2230    /// list through `#[serde(default)]` to `Vec::new()`, so both arms
2231    /// definitionally carry a `Vec<Dep>` slot — possibly empty — and the
2232    /// returned `&[Dep]` degenerates to an empty slice on either arm
2233    /// without any silent `None` collapse).
2234    ///
2235    /// The [`crate::dep::DepList`] closed-set typed enum is the
2236    /// substrate's canonical discriminator for the "runtime-closure
2237    /// `:deps` vs dev-only-closure `:deps-dev`" axis every dep-list
2238    /// consumer dispatches on — the compiler-checked exhaustiveness on
2239    /// the enum's `match` arms is the build-time guarantee that no future
2240    /// per-list read-site regresses to a bare-`bool`-flag inline dispatch
2241    /// that a future third dep-list axis (a `:deps-build` build-only
2242    /// closure once the substrate grows cross-artifact heterogeneous
2243    /// dep-graphs, per CAIXA-SDLC §I) would silently split at every
2244    /// consumer. Prior to this the read side carried two per-slot
2245    /// accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`]) and no
2246    /// typed dispatch that a per-axis walker could parametrise on, so
2247    /// every per-list walker (the [`Self::validate_deps`] per-list
2248    /// [`crate::render::insert_first_seen`] dedup walk, a future
2249    /// `feira app graph` per-list dep summary, a future M4 per-cluster
2250    /// dev-closure-audit overlay the CR materializer resolves per-CR)
2251    /// open-coded the same two-block "run over `:deps`, then run over
2252    /// `:deps-dev`" pattern — a silent duplication that a future third
2253    /// dep-list axis would have had to grow a third block at every site.
2254    ///
2255    /// Peer of the sibling [`Self::push_dep`] typed-mutation dispatch
2256    /// (359fba5) — closes the two-side dispatch symmetry on the outer
2257    /// [`Caixa`] two-list dep-graph surface: `push_dep` on the mutation
2258    /// side, `deps_of` on the read side, both keyed on the same
2259    /// [`crate::dep::DepList`] discriminator. Same "one typed dispatch on
2260    /// the substrate primitive, thin projections at each consumer"
2261    /// discipline the sibling per-slot read accessors ([`Self::nome`]
2262    /// e6b7d97, [`Self::versao`], [`Self::kind`]) carry — extended onto
2263    /// the outer-[`Caixa`] typed-dispatch read surface.
2264    ///
2265    /// Declared `pub const fn` — every operator in the body is already
2266    /// `const`-callable (the [`crate::dep::DepList`] enum is a plain
2267    /// closed-set `#[derive(Copy)]` discriminator so the `match` arms
2268    /// are const-evaluable, and each arm forwards through the sibling
2269    /// `pub const fn` [`Self::deps`] / [`Self::deps_dev`] per-slot
2270    /// slice accessor). Pinned load-bearing by the paired
2271    /// [`caixa_deps_of_is_const_fn`][pin] wrapper test (a
2272    /// `const fn deps_of_via_const_fn(c: &Caixa, l: DepList) -> &[Dep]`
2273    /// that forwards through this accessor) — any future accidental
2274    /// downgrade to non-`const` fails the wrapper at caixa-core build
2275    /// time with E0015 (`cannot call non-const method`), strictly
2276    /// stronger than a runtime `assert!` and side-stepping the
2277    /// destructor-in-const restriction the `Caixa` fixture's owning
2278    /// carriers rule out on the direct-`const _: () = assert!(…)`
2279    /// residence. Peer of the sibling per-`Dep` outer-accessor
2280    /// family's parallel `const`-eval-surface pass and of the outer-
2281    /// `Caixa` slice-return accessor family's earlier pass (231a968)
2282    /// — same "one canonical dispatch per axis, `const`-eval posture
2283    /// pinned at the substrate primitive, thin projections at each
2284    /// consumer" discipline extended onto the outer-`Caixa`
2285    /// typed-dispatch read surface on the [`DepList`]-keyed dep-list
2286    /// axis.
2287    ///
2288    /// [DepList]: crate::dep::DepList
2289    /// [pin]: tests::caixa_deps_of_is_const_fn
2290    #[must_use]
2291    pub const fn deps_of(&self, list: crate::dep::DepList) -> &[Dep] {
2292        match list {
2293            crate::dep::DepList::Prod => self.deps(),
2294            crate::dep::DepList::Dev => self.deps_dev(),
2295        }
2296    }
2297
2298    /// Substrate-canonical per-[`Caixa`] typed-mutation dispatch every
2299    /// consumer that appends to one of the two dep-list axes keys off
2300    /// — routes the `(list: DepList, dep: Dep)` tuple through one typed
2301    /// method on the substrate primitive rather than the prior
2302    /// `feira add`-side open-coded `if self.dev { &mut caixa.deps_dev }
2303    /// else { &mut caixa.deps }` inline dispatch + open-coded
2304    /// `.iter().any(|d| d.nome == …)` dup-check cascade. Refuses the
2305    /// mutation with the canonical typed [`DepError::DuplicateNome`] on
2306    /// a within-list name collision — the same `list: &'static str`
2307    /// diagnostic shape [`Self::validate_deps`]'s per-list
2308    /// [`crate::render::insert_first_seen`] walk raises on the peer
2309    /// parse-time within-list dedup axis, so a future author reading a
2310    /// `feira add` refusal and a `feira build` refusal reaches for the
2311    /// same corrective surface without switching diagnostic idioms.
2312    ///
2313    /// The two-arm [`crate::dep::DepList`] enum is the substrate's
2314    /// closed-set typed carrier for the "runtime-closure `:deps` vs
2315    /// dev-only-closure `:deps-dev`" axis every dep-list consumer
2316    /// dispatches on — the compiler-checked exhaustiveness on the
2317    /// enum's `match` arms is the build-time guarantee that no future
2318    /// per-list mutation-site regresses to a bare-`bool`-flag
2319    /// (`is_dev: bool`) inline dispatch that a future third
2320    /// dep-list axis (a `:deps-build` build-only closure once the
2321    /// substrate grows cross-artifact heterogeneous dep-graphs, per
2322    /// CAIXA-SDLC §I) would silently split at every consumer.
2323    ///
2324    /// Same "one typed dispatch on the substrate primitive, thin
2325    /// projections at each consumer" discipline the sibling per-slot
2326    /// read accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`],
2327    /// [`Self::nome`] e6b7d97, [`Self::versao`], [`Self::kind`])
2328    /// carry — extended onto the outer-[`Caixa`] typed-mutation surface,
2329    /// the substrate's first typed-mutation dispatch on the top-level
2330    /// manifest. The prior `feira add` open-coded `&mut caixa.deps` /
2331    /// `&mut caixa.deps_dev` inline field-access + `bail!` string-
2332    /// diagnostic path routed no through-line back to the typed slot,
2333    /// so a future extension of either dep-list axis to a richer author
2334    /// surface (a per-cluster override the operator pins through a
2335    /// future `:placement`-scoped dep-list slot the CAIXA-SDLC §I
2336    /// roadmap acknowledges, an M4
2337    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
2338    /// admission-webhook that normalized the list at admission time)
2339    /// would have had to be threaded through the `feira add` mutation
2340    /// site in lockstep with every read consumer or one path would
2341    /// silently disagree with the other on which list a given dep lands
2342    /// in. Lifting the resolution rule to a typed method on the
2343    /// substrate primitive means every downstream dep-list-mutating
2344    /// consumer of the top-level manifest reaches for exactly one typed
2345    /// dispatch — the resolver's accept-set migrates as a unit on any
2346    /// future axis addition.
2347    ///
2348    /// # Errors
2349    ///
2350    /// Returns [`DepError::DuplicateNome`] with `list = list.as_str()`
2351    /// when another entry in the same list already carries the same
2352    /// `:nome` — the mutation is refused and the caller can surface the
2353    /// typed diagnostic to the author (the `feira add` verb routes the
2354    /// error through `anyhow::Error::from`, which preserves the
2355    /// canonical `#[error(...)]`-templated diagnostic body).
2356    pub fn push_dep(&mut self, list: crate::dep::DepList, dep: Dep) -> Result<(), DepError> {
2357        let target = match list {
2358            crate::dep::DepList::Prod => &mut self.deps,
2359            crate::dep::DepList::Dev => &mut self.deps_dev,
2360        };
2361        if target.iter().any(|d| d.nome() == dep.nome()) {
2362            return Err(DepError::duplicate_nome(dep.nome(), list.as_str()));
2363        }
2364        target.push(dep);
2365        Ok(())
2366    }
2367
2368    /// Substrate-canonical per-`Caixa` `:limits` M2 typed-slot outer-
2369    /// composite Lunatic-per-process wasm32-sandboxing-composite optional-
2370    /// composite-reference accessor every consumer of the top-level
2371    /// manifest's per-Servico [`LimitsSpec`] outer-composite reader keys
2372    /// off — returns the author-declared `:limits` typed composite
2373    /// verbatim as an `Option<&LimitsSpec>` reference over the same
2374    /// backing storage the raw `self.limits.as_ref()` field access
2375    /// borrows from, with `None` naming the "no `:limits` block
2376    /// authored — every per-axis Lunatic-sandbox cap defers to the
2377    /// wasm-engine-default arm named on the per-axis
2378    /// [`LimitsSpec::memory`] / [`LimitsSpec::fuel`] /
2379    /// [`LimitsSpec::wall_clock`] / [`LimitsSpec::cpu`] scalar-accessor
2380    /// docstrings" partition every downstream Servico-M2-overlay
2381    /// emitter treats as "emit nothing" and the sibling
2382    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate
2383    /// treats as "skip the per-axis
2384    /// [`crate::LimitsError::MemoryZero`] / `MemoryBelowWasm32Page` /
2385    /// `FuelZero` / `WallClockZero` / `CpuZero` refusal cascade".
2386    ///
2387    /// The outer `:limits` slot carries the M2 Servico-runtime typed
2388    /// composite — the load-bearing container of every Lunatic-shaped
2389    /// per-process wasm32-sandbox cap axis every long-running wasm
2390    /// component's runtime dispatches on (INSPIRATIONS §III.1 —
2391    /// Lunatic per-process linear-memory / fuel / wall-clock /
2392    /// millicore cap primitives translated onto pleme-io's typed
2393    /// `:limits :memory` / `:limits :fuel` / `:limits :wall-clock` /
2394    /// `:limits :cpu` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2395    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2396    /// chart both fan on). Every per-`:limits` axis threads through a
2397    /// lifted per-slot accessor on the [`LimitsSpec`] type: the
2398    /// [`LimitsSpec::memory`] wasm32 linear-memory byte-cap scalar
2399    /// accessor, the [`LimitsSpec::fuel`] wasmtime fuel-cap scalar
2400    /// accessor, the [`LimitsSpec::wall_clock`] per-call wall-clock
2401    /// deadline scalar accessor, and the [`LimitsSpec::cpu`]
2402    /// K8s-millicore soft-CPU-share scalar accessor. Every downstream
2403    /// consumer that reaches for a limits axis first passes through
2404    /// this outer accessor onto the composite and then dispatches
2405    /// onto the per-axis accessor — the two-level dispatch means
2406    /// every per-`:limits` reader now routes through a typed dispatch
2407    /// on the substrate primitive at both altitudes.
2408    ///
2409    /// Prior to this lift the `.limits` `Option<LimitsSpec>` composite
2410    /// was accessed inline at three production sites — the
2411    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate's
2412    /// `if let Some(l) = &caixa.limits { … }` traversal head
2413    /// (caixa-core/src/layout.rs:882, which drives the per-axis
2414    /// refusal cascade on the composite: the `LimitsError::MemoryZero`
2415    /// / `MemoryBelowWasm32Page` / `MemoryExceedsWasm32Max` /
2416    /// `FuelZero` / `FuelExceedsMax` / `WallClockZero` /
2417    /// `WallClockExceedsMax` / `CpuZero` / `CpuExceedsMax` refusals
2418    /// [`LimitsSpec::validate`] fans onto), the
2419    /// [`crate::render::servico_m2_overlay`] per-Servico M2 overlay
2420    /// emitter's `if let Some(limits) = &caixa.limits { … }` traversal
2421    /// head (caixa-core/src/render.rs:18504, which drives the
2422    /// `M2_KEY_LIMITS`-keyed `limits.is_empty()`-gated `serde_yaml`
2423    /// projection every `caixa-helm` / `caixa-flux` Servico values-
2424    /// block emitter fans on), and the
2425    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2426    /// set enumerator's `self.limits.is_some()` presence probe
2427    /// (caixa-core/src/manifest.rs:1788, which drives the
2428    /// `M2_AUTHOR_KEY_LIMITS` kebab-case author-label push every
2429    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2430    /// gate reads) — three open-coded outer-field accesses that
2431    /// expressed no compile-time link back to the typed slot at the
2432    /// [`Caixa`] altitude. A future extension of the `:limits` outer
2433    /// axis to a richer author surface (a multi-`:limits` list the M4
2434    /// CR materializer resolves per-CR at admission time so a Servico
2435    /// can expose a compute-heavy + IO-heavy limits pair, a per-
2436    /// cluster `:limits-overrides` slot the operator pins so a
2437    /// cluster-specific policy can tighten a caixa-declared cap
2438    /// without re-authoring the `caixa.lisp`, a promotion of the
2439    /// plain `Option<LimitsSpec>` to a richer
2440    /// `{static, dynamic}` partition once the wasm-engine's runtime-
2441    /// resolved dynamic-cap surface lands) would have had to be
2442    /// threaded through all three open-coded copies in lockstep or
2443    /// one consumer would silently disagree with the peers on which
2444    /// limits composite a given Caixa resolves to — the layout gate's
2445    /// per-axis bracket-dispatch seed reading the raw slot while the
2446    /// peer `servico_m2_overlay` emitter read an operator-resolved
2447    /// slot would silently split the build-time sandbox-shape gate
2448    /// from the runtime `ComputeUnit` CR emission gate, a three-
2449    /// consumer split at the layout gate, the M2 overlay emitter, and
2450    /// the declared-slot enumerator far from the source `caixa.lisp`
2451    /// with no field naming the limits-drift root cause. Lifting the
2452    /// resolution rule to a typed method on the substrate primitive
2453    /// means every downstream consumer of the caixa's per-`Caixa`
2454    /// Lunatic-sandboxing outer-composite surface reaches for exactly
2455    /// one typed dispatch — the resolver's accept-set migrates as a
2456    /// unit on any future axis addition.
2457    ///
2458    /// First outer top-level [`Caixa`] `Option<&Composite>`-return
2459    /// composite-reference accessor — opens the outer-`Caixa`
2460    /// `Option<&Composite>` composite-reference projection pattern the
2461    /// sibling per-`Caixa` `:behavior` [`crate::BehaviorSpec`] /
2462    /// `:politicas` [`crate::aplicacao::MeshPolicy`] / `:placement`
2463    /// [`crate::aplicacao::Placement`] / `:entrada`
2464    /// [`crate::aplicacao::Entrada`] future outer-composite lifts
2465    /// fold on. Peer of the M3 mesh-slot outer-composite family the
2466    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2467    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2468    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2469    /// accessors already close on the outer [`crate::AplicacaoSpec`]
2470    /// altitude — extends that "one typed dispatch on the substrate
2471    /// primitive, thin projections at each consumer" discipline onto
2472    /// the outer top-level [`Caixa`] altitude, opening the M2 Servico-
2473    /// runtime slot family's outer-composite axis. Returns
2474    /// `Option<&LimitsSpec>` (not the owning composite by copy or
2475    /// clone) because every downstream consumer of the limits
2476    /// composite treats it as a read-only per-axis dispatch source —
2477    /// the reference-view is the narrowest borrow that supports every
2478    /// present + roadmapped consumer (per-axis accessor dispatch,
2479    /// `.is_empty()`-gated overlay projection, presence-probe early
2480    /// return on the "author-omitted `:limits` ⇒ engine-default
2481    /// applies" partition) without cloning the composite through
2482    /// every consumer's fast path. The `Option` half of the return-
2483    /// type preserves the load-bearing "author-omitted `:limits` ⇒
2484    /// engine-default applies" partition (not a default composite the
2485    /// downstream must reject on emptiness) — the accessor projects
2486    /// the raw `Option<LimitsSpec>` slot's presence bit through the
2487    /// reference-return unchanged. Named `limits()` to match the
2488    /// storage field's name verbatim and the tatara-lisp author-
2489    /// surface term (`:limits`) the field's own docstring already
2490    /// carries.
2491    #[must_use]
2492    pub const fn limits(&self) -> Option<&LimitsSpec> {
2493        self.limits.as_ref()
2494    }
2495
2496    /// Substrate-canonical per-`Caixa` `:behavior` M2 typed-slot outer-
2497    /// composite OTP-`gen_server`-shaped callback-table optional-
2498    /// composite-reference accessor every consumer of the top-level
2499    /// manifest's per-Servico [`BehaviorSpec`] outer-composite reader
2500    /// keys off — returns the author-declared `:behavior` typed
2501    /// composite verbatim as an `Option<&BehaviorSpec>` reference over
2502    /// the same backing storage the raw `self.behavior.as_ref()` field
2503    /// access borrows from, with `None` naming the "no `:behavior`
2504    /// block authored — every per-callback OTP-shaped hook defers to
2505    /// the wasm-engine's runtime default arm named on the per-axis
2506    /// [`BehaviorSpec::on_init`] / [`BehaviorSpec::on_call`] /
2507    /// [`BehaviorSpec::on_cast`] / [`BehaviorSpec::on_info`] /
2508    /// [`BehaviorSpec::on_state_change`] /
2509    /// [`BehaviorSpec::on_terminate`] scalar-accessor docstrings"
2510    /// partition every downstream Servico-M2-overlay emitter treats as
2511    /// "emit nothing" and the sibling [`crate::StandardLayout::verify`]
2512    /// per-`:behavior` shape gate treats as "skip the per-arm
2513    /// [`crate::behavior::BehaviorError`] refusal cascade + the
2514    /// per-callback on-disk `MissingEntry` existence check".
2515    ///
2516    /// The outer `:behavior` slot carries the M2 Servico-runtime typed
2517    /// composite — the load-bearing container of every OTP-shaped
2518    /// per-Servico lifecycle-callback path axis every long-running wasm
2519    /// component's runtime dispatches on (INSPIRATIONS §II.3 — Erlang/
2520    /// OTP `gen_server:init/1` / `handle_call/3` / `handle_cast/2` /
2521    /// `handle_info/2` / `code_change/3` / `terminate/2` primitives
2522    /// translated onto pleme-io's typed `:behavior :on-init` /
2523    /// `:on-call` / `:on-cast` / `:on-info` / `:on-state-change` /
2524    /// `:on-terminate` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2525    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2526    /// chart both fan on). Every per-`:behavior` axis threads through a
2527    /// lifted per-callback accessor on the [`BehaviorSpec`] type
2528    /// (9b4ecde / d66c702 / 156ddbe / 99616ac / 4846cef / 701add7).
2529    /// Every downstream consumer that reaches for a behavior axis
2530    /// first passes through this outer accessor onto the composite
2531    /// and then dispatches onto the per-callback accessor — the
2532    /// two-level dispatch means every per-`:behavior` reader now
2533    /// routes through a typed dispatch on the substrate primitive at
2534    /// both altitudes.
2535    ///
2536    /// Composes cross-slot with the M2 `:upgrade-from` gate: the
2537    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
2538    /// cross-slot composition gate at [`crate::StandardLayout::verify`]
2539    /// keys the "per-version `:state-change` instruction must have a
2540    /// `:on-state-change` callback" precondition off this accessor's
2541    /// composite (the callback-side counterpart to the
2542    /// `:upgrade-from :instructions :state-change :script` refusal at
2543    /// the appup-side). Threading that gate's traversal input through
2544    /// this accessor closes the cross-slot invariant on the substrate
2545    /// primitive, not on the raw field.
2546    ///
2547    /// Prior to this lift the `.behavior` `Option<BehaviorSpec>`
2548    /// composite was accessed inline at four production sites — the
2549    /// [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
2550    /// `if let Some(b) = &caixa.behavior { … }` traversal head
2551    /// (caixa-core/src/layout.rs:896, which drives the per-arm
2552    /// `BehaviorError` refusal cascade + the per-callback on-disk
2553    /// [`crate::LayoutError::MissingEntry`] existence check under
2554    /// [`crate::render::LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`]),
2555    /// the [`crate::upgrade::validate_upgrade_from_against_behavior`]
2556    /// cross-slot composition gate's `caixa.behavior.as_ref()`
2557    /// traversal-input feed (caixa-core/src/layout.rs:1008, which
2558    /// drives the `:state-change` ↔ `:on-state-change` precondition
2559    /// refusal), the [`crate::render::servico_m2_overlay`] per-Servico
2560    /// M2 overlay emitter's `if let Some(behavior) = &caixa.behavior
2561    /// { … }` traversal head (caixa-core/src/render.rs:18513, which
2562    /// drives the `M2_KEY_BEHAVIOR`-keyed `behavior.is_empty()`-gated
2563    /// `serde_yaml` projection every `caixa-helm` / `caixa-flux`
2564    /// Servico values-block emitter fans on), and the
2565    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2566    /// set enumerator's `self.behavior.is_some()` presence probe
2567    /// (caixa-core/src/manifest.rs:1919, which drives the
2568    /// `M2_AUTHOR_KEY_BEHAVIOR` kebab-case author-label push every
2569    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2570    /// gate reads) — four open-coded outer-field accesses that
2571    /// expressed no compile-time link back to the typed slot at the
2572    /// [`Caixa`] altitude. A future extension of the `:behavior`
2573    /// outer axis to a richer author surface (a per-callback overlay
2574    /// resolver the operator materializes at admission time so a
2575    /// cluster-specific policy can inject a per-callback tracing
2576    /// interceptor without re-authoring the `caixa.lisp`, a promotion
2577    /// of the plain `Option<BehaviorSpec>` to a richer `{static,
2578    /// dynamic}` partition once a runtime-resolved behavior-swap
2579    /// surface lands, the M4 per-callback middleware chain the
2580    /// caixa-operator's per-Servico admission webhook keys off) would
2581    /// have had to be threaded through all four open-coded copies in
2582    /// lockstep or one consumer would silently disagree with the
2583    /// peers on which behavior composite a given Caixa resolves to —
2584    /// the layout gate's per-callback existence-check seed reading
2585    /// the raw slot while the peer `servico_m2_overlay` emitter read
2586    /// an operator-resolved slot would silently split the build-time
2587    /// callback-shape gate from the runtime `ComputeUnit` CR emission
2588    /// gate from the cross-slot `:state-change` composition gate from
2589    /// the M2 declared-slot enumerator, a four-consumer split far
2590    /// from the source `caixa.lisp` with no field naming the
2591    /// behavior-drift root cause. Lifting the resolution rule to a
2592    /// typed method on the substrate primitive means every downstream
2593    /// consumer of the caixa's per-`Caixa` OTP-callback-table outer-
2594    /// composite surface reaches for exactly one typed dispatch — the
2595    /// resolver's accept-set migrates as a unit on any future axis
2596    /// addition.
2597    ///
2598    /// Second outer top-level [`Caixa`] `Option<&Composite>`-return
2599    /// composite-reference accessor — sibling to the opening
2600    /// [`Self::limits`] (b2bd9d7) accessor on the outer-`Caixa`
2601    /// `Option<&Composite>` composite-reference sub-family, extends
2602    /// the "one typed dispatch on the substrate primitive, thin
2603    /// projections at each consumer" discipline onto the second of
2604    /// the three M2 Servico-runtime slots. The remaining
2605    /// `Option<&Composite>` axes at the outer top-level [`Caixa`]
2606    /// altitude — the M3 mesh-slot family (`:politicas`,
2607    /// `:placement`, `:entrada` — already closed on the inner
2608    /// [`crate::AplicacaoSpec`] altitude via 534dc21 / 9abb8f0 /
2609    /// d32111c) — remain the future sibling lifts on the outer
2610    /// top-level projection. Returns `Option<&BehaviorSpec>` (not
2611    /// the owning composite by copy or clone) because every
2612    /// downstream consumer of the behavior composite treats it as a
2613    /// read-only per-callback dispatch source — the reference-view is
2614    /// the narrowest borrow that supports every present + roadmapped
2615    /// consumer (per-callback accessor dispatch, `.is_empty()`-gated
2616    /// overlay projection, presence-probe early return on the
2617    /// "author-omitted `:behavior` ⇒ runtime-default applies"
2618    /// partition, cross-slot `:state-change` composition input)
2619    /// without cloning the composite through every consumer's fast
2620    /// path. The `Option` half of the return-type preserves the
2621    /// load-bearing "author-omitted `:behavior` ⇒ runtime-default
2622    /// applies" partition (not a default composite the downstream
2623    /// must reject on emptiness) — the accessor projects the raw
2624    /// `Option<BehaviorSpec>` slot's presence bit through the
2625    /// reference-return unchanged. Named `behavior()` to match the
2626    /// storage field's name verbatim and the tatara-lisp author-
2627    /// surface term (`:behavior`) the field's own docstring already
2628    /// carries.
2629    #[must_use]
2630    pub const fn behavior(&self) -> Option<&crate::BehaviorSpec> {
2631        self.behavior.as_ref()
2632    }
2633
2634    /// Substrate-canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
2635    /// composite MESH-COMPOSITION-shaped mesh-policy optional-composite-
2636    /// reference accessor every consumer of the top-level manifest's
2637    /// per-Aplicacao [`crate::aplicacao::MeshPolicy`] outer-composite
2638    /// reader keys off — returns the author-declared `:politicas` typed
2639    /// composite verbatim as an `Option<&MeshPolicy>` reference over the
2640    /// same backing storage the raw `self.politicas.as_ref()` field
2641    /// access borrows from, with `None` naming the "no `:politicas`
2642    /// block authored — every per-axis mesh-policy scalar defers to the
2643    /// cluster-default arm named on the per-axis
2644    /// [`crate::aplicacao::MeshPolicy::timeout`] /
2645    /// [`crate::aplicacao::MeshPolicy::retries`] /
2646    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] /
2647    /// [`crate::aplicacao::MeshPolicy::mtls_required`] /
2648    /// [`crate::aplicacao::MeshPolicy::rate_limit`] scalar-accessor
2649    /// docstrings" partition every downstream caixa-mesh /
2650    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2651    /// "emit no per-`:politicas` overlay" and the sibling
2652    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2653    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2654    /// arm.
2655    ///
2656    /// The outer `:politicas` slot carries the M3 mesh-slot per-
2657    /// Aplicacao typed composite — the load-bearing container of every
2658    /// mesh-level policy axis every Cilium NetworkPolicy / Gateway API
2659    /// v1.x HTTPRoute / future M4 per-edge policy overlay emitter fans
2660    /// on (MESH-COMPOSITION §III.2 — the Aplicacao's typed mesh-policy
2661    /// composite; §V — the "no infinite blocking" per-call deadline +
2662    /// "sandboxing-by-default" mTLS-enforcement CSE invariants; §III.3
2663    /// — the typed inter-Servico contrato-edge overlay the per-`(:de,
2664    /// :para)` mesh renderer keys off). Every per-`:politicas` axis
2665    /// threads through a lifted per-slot accessor on the
2666    /// [`crate::aplicacao::MeshPolicy`] type: the
2667    /// [`crate::aplicacao::MeshPolicy::mtls_required`] (c0110f1) Cilium
2668    /// mTLS-enforcement toggle, the
2669    /// [`crate::aplicacao::MeshPolicy::retries`] (bdfb399) transient-
2670    /// failure retry budget, the [`crate::aplicacao::MeshPolicy::timeout`]
2671    /// (7073d0f) Gateway-API per-call deadline, the
2672    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] (b0e741a)
2673    /// Envoy-outlier-detection composite. Every downstream consumer
2674    /// that reaches for a mesh-policy axis first passes through this
2675    /// outer accessor onto the composite and then dispatches onto the
2676    /// per-axis accessor — the two-level dispatch means every per-
2677    /// `:politicas` reader now routes through a typed dispatch on the
2678    /// substrate primitive at both altitudes.
2679    ///
2680    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2681    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2682    /// author-omitted arm onto the [`crate::aplicacao::MeshPolicy::default`]
2683    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::politicas`]
2684    /// (534dc21) `&MeshPolicy`-return accessor observes a typed
2685    /// composite whether or not the author declared the outer slot.
2686    /// The outer accessor preserves the "author-omitted vs authored-
2687    /// empty" partition the inner accessor's `is_empty()`-gated
2688    /// renderer overlay collapses — routing the presence bit through
2689    /// this accessor keeps the [`Self::declared_mesh_slots`] M3 kind-
2690    /// coherence enumerator's `M3_AUTHOR_KEY_POLITICAS` push separate
2691    /// from the inner `MeshPolicy::is_empty()`-gated overlay elision.
2692    ///
2693    /// Prior to this lift the `.politicas` `Option<MeshPolicy>`
2694    /// composite was accessed inline at two production sites — the
2695    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2696    /// `self.politicas.clone().unwrap_or_default()` traversal head
2697    /// (caixa-core/src/manifest.rs:1899, which drives the fold onto
2698    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2699    /// arm the inner [`crate::AplicacaoSpec::politicas`] accessor
2700    /// then observes), and the [`Self::declared_mesh_slots`] M3
2701    /// declared-slot-set enumerator's `self.politicas.is_some()`
2702    /// presence probe (caixa-core/src/manifest.rs:1961, which drives
2703    /// the `M3_AUTHOR_KEY_POLITICAS` kebab-case author-label push
2704    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2705    /// coherence gate reads) — two open-coded outer-field accesses
2706    /// that expressed no compile-time link back to the typed slot at
2707    /// the [`Caixa`] altitude. A future extension of the `:politicas`
2708    /// outer axis to a richer author surface (a per-cluster
2709    /// `:politicas-overrides` slot the operator materializes at
2710    /// admission time so a cluster-specific policy can tighten the
2711    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2712    /// promotion of the plain `Option<MeshPolicy>` to a richer
2713    /// `{static, dynamic}` partition once the M4 per-edge
2714    /// contrato-scoped policy-override surface lands, the M5 traffic-
2715    /// shaping composition the caixa-operator's per-Aplicacao mesh
2716    /// admission webhook keys off) would have had to be threaded
2717    /// through both open-coded copies in lockstep or the Aplicacao-
2718    /// composition seed's default-fold arm would silently disagree
2719    /// with the M3 declared-slot enumerator on which policy composite
2720    /// a given Caixa resolves to — the seed reading an operator-
2721    /// resolved slot while the enumerator's presence probe read the
2722    /// raw slot would silently split the build-time mesh-artifact
2723    /// emission gate from the M3 declared-slot enumerator's kind-
2724    /// coherence gate, a two-consumer split far from the source
2725    /// `caixa.lisp` with no field naming the policy-drift root cause.
2726    /// Lifting the resolution rule to a typed method on the substrate
2727    /// primitive means every downstream consumer of the caixa's per-
2728    /// `Caixa` MESH-COMPOSITION mesh-policy outer-composite surface
2729    /// reaches for exactly one typed dispatch — the resolver's
2730    /// accept-set migrates as a unit on any future axis addition.
2731    ///
2732    /// Third outer top-level [`Caixa`] `Option<&Composite>`-return
2733    /// composite-reference accessor — sibling to the opening
2734    /// [`Self::limits`] (b2bd9d7) and [`Self::behavior`] (35d8b52)
2735    /// accessors on the outer-`Caixa` `Option<&Composite>` composite-
2736    /// reference sub-family, extends the "one typed dispatch on the
2737    /// substrate primitive, thin projections at each consumer"
2738    /// discipline onto the first of the three M3 mesh-slot axes.
2739    /// Peer of the closed inner mesh-slot outer-composite family the
2740    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2741    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2742    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2743    /// accessor pins already close on the inner [`crate::AplicacaoSpec`]
2744    /// altitude — opens the outer top-level [`Caixa`] altitude's M3
2745    /// mesh-slot arm of the composite-reference family the remaining
2746    /// two axes (`:placement`, `:entrada`) fold onto in future
2747    /// sibling lifts. Returns `Option<&MeshPolicy>` (not the owning
2748    /// composite by copy or clone) because every downstream consumer
2749    /// of the mesh-policy composite treats it as a read-only per-axis
2750    /// dispatch source — the reference-view is the narrowest borrow
2751    /// that supports every present + roadmapped consumer (per-axis
2752    /// accessor dispatch, `.is_empty()`-gated overlay projection,
2753    /// presence-probe early return on the "author-omitted `:politicas`
2754    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2755    /// seed's default-fold arm) without cloning the composite through
2756    /// every consumer's fast path. The `Option` half of the return-
2757    /// type preserves the load-bearing "author-omitted `:politicas` ⇒
2758    /// cluster-default applies" partition (not a default composite
2759    /// the downstream must reject on emptiness) — the accessor
2760    /// projects the raw `Option<MeshPolicy>` slot's presence bit
2761    /// through the reference-return unchanged. Named `politicas()` to
2762    /// match the storage field's name verbatim and the tatara-lisp
2763    /// author-surface term (`:politicas`) the field's own docstring
2764    /// already carries.
2765    #[must_use]
2766    pub const fn politicas(&self) -> Option<&crate::aplicacao::MeshPolicy> {
2767        self.politicas.as_ref()
2768    }
2769
2770    /// Substrate-canonical per-`Caixa` `:placement` M3 mesh-slot outer-
2771    /// composite MESH-COMPOSITION-shaped distribution optional-composite-
2772    /// reference accessor every consumer of the top-level manifest's
2773    /// per-Aplicacao [`crate::aplicacao::Placement`] outer-composite
2774    /// reader keys off — returns the author-declared `:placement` typed
2775    /// composite verbatim as an `Option<&Placement>` reference over the
2776    /// same backing storage the raw `self.placement.as_ref()` field
2777    /// access borrows from, with `None` naming the "no `:placement`
2778    /// block authored — every per-axis placement scalar defers to the
2779    /// cluster-default arm named on the per-axis
2780    /// [`crate::aplicacao::Placement::estrategia`] /
2781    /// [`crate::aplicacao::Placement::clusters`] /
2782    /// [`crate::aplicacao::Placement::affinity`] /
2783    /// [`crate::aplicacao::Placement::shard_key`] scalar-accessor
2784    /// docstrings" partition every downstream caixa-mesh /
2785    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2786    /// "emit no per-`:placement` overlay" and the sibling
2787    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2788    /// the [`crate::aplicacao::Placement::default`] cluster-default arm.
2789    ///
2790    /// The outer `:placement` slot carries the M3 mesh-slot per-
2791    /// Aplicacao typed distribution composite — the load-bearing
2792    /// container of every where-does-this-Aplicacao-run axis every
2793    /// caixa-mesh programs.yaml per-cluster distribution overlay /
2794    /// caixa-flux per-Aplicacao GitRepository/HelmRelease fan-out /
2795    /// future M4 per-Aplicacao Akka-style cluster-sharding entity-id
2796    /// resolver emitter fans on (MESH-COMPOSITION §II.4 — the
2797    /// Aplicacao's typed distribution composite; §V CSE invariants —
2798    /// "distribution is a first-class typed composite, not a runtime
2799    /// scheduler hint" the per-axis scalars enforce; §III.3 — the
2800    /// typed inter-Servico contrato-edge overlay the per-cluster
2801    /// mesh renderer keys off). Every per-`:placement` axis threads
2802    /// through a lifted per-slot accessor on the
2803    /// [`crate::aplicacao::Placement`] type: the
2804    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
2805    /// MESH-COMPOSITION distribution-strategy scalar, the
2806    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7) per-cluster
2807    /// distribution-target slice, the [`crate::aplicacao::Placement::affinity`]
2808    /// M3-Adaptive-compression-hint optional-scalar, and the
2809    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) Akka-cluster-
2810    /// sharding extractor-expression optional-scalar. Every downstream
2811    /// consumer that reaches for a placement axis first passes through
2812    /// this outer accessor onto the composite and then dispatches onto
2813    /// the per-axis accessor — the two-level dispatch means every per-
2814    /// `:placement` reader now routes through a typed dispatch on the
2815    /// substrate primitive at both altitudes.
2816    ///
2817    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2818    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2819    /// author-omitted arm onto the [`crate::aplicacao::Placement::default`]
2820    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::placement`]
2821    /// (9abb8f0) `&Placement`-return accessor observes a typed composite
2822    /// whether or not the author declared the outer slot. The outer
2823    /// accessor preserves the "author-omitted vs authored-empty" partition
2824    /// the inner accessor collapses at the cluster-default fold —
2825    /// routing the presence bit through this accessor keeps the
2826    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2827    /// `M3_AUTHOR_KEY_PLACEMENT` push separate from the inner
2828    /// [`crate::AplicacaoSpec::validate_placement`]-gated overlay
2829    /// dispatch.
2830    ///
2831    /// Prior to this lift the `.placement` `Option<Placement>`
2832    /// composite was accessed inline at two production sites — the
2833    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2834    /// `self.placement.clone().unwrap_or_default()` traversal head
2835    /// (caixa-core/src/manifest.rs:2036, which drives the fold onto
2836    /// the [`crate::aplicacao::Placement::default`] cluster-default
2837    /// arm the inner [`crate::AplicacaoSpec::placement`] accessor
2838    /// then observes), and the [`Self::declared_mesh_slots`] M3
2839    /// declared-slot-set enumerator's `self.placement.is_some()`
2840    /// presence probe (caixa-core/src/manifest.rs:2100, which drives
2841    /// the `M3_AUTHOR_KEY_PLACEMENT` kebab-case author-label push
2842    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2843    /// coherence gate reads) — two open-coded outer-field accesses
2844    /// that expressed no compile-time link back to the typed slot at
2845    /// the [`Caixa`] altitude. A future extension of the `:placement`
2846    /// outer axis to a richer author surface (a per-cluster
2847    /// `:placement-overrides` slot the operator materializes at
2848    /// admission time so a cluster-specific placement can tighten the
2849    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2850    /// per-tenant placement-alias table the M4
2851    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer resolves
2852    /// per-CR at admission time, a promotion of the plain
2853    /// `Option<Placement>` to a richer `{static, dynamic}` partition
2854    /// once Orleans-style virtual-actor dynamic placement comes into
2855    /// typed scope) would have had to be threaded through both open-
2856    /// coded copies in lockstep or the Aplicacao-composition seed's
2857    /// default-fold arm would silently disagree with the M3 declared-
2858    /// slot enumerator on which distribution composite a given Caixa
2859    /// resolves to — the seed reading an operator-resolved slot while
2860    /// the enumerator's presence probe read the raw slot would
2861    /// silently split the build-time distribution-artifact emission
2862    /// gate from the M3 declared-slot enumerator's kind-coherence
2863    /// gate, a two-consumer split far from the source `caixa.lisp`
2864    /// with no field naming the distribution-drift root cause.
2865    /// Lifting the resolution rule to a typed method on the substrate
2866    /// primitive means every downstream consumer of the caixa's per-
2867    /// `Caixa` MESH-COMPOSITION distribution outer-composite surface
2868    /// reaches for exactly one typed dispatch — the resolver's
2869    /// accept-set migrates as a unit on any future axis addition.
2870    ///
2871    /// Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
2872    /// composite-reference accessor — sibling to the opening
2873    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) M2-
2874    /// Servico-runtime pair and the peer [`Self::politicas`] (5d23d29)
2875    /// M3-mesh-slot arm on the outer-`Caixa` `Option<&Composite>`
2876    /// composite-reference sub-family, folds on the "one typed
2877    /// dispatch on the substrate primitive, thin projections at each
2878    /// consumer" discipline extended onto the second of the three M3
2879    /// mesh-slot axes. Peer of the closed inner mesh-slot outer-
2880    /// composite family the sibling
2881    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2882    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2883    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2884    /// accessor pins already close on the inner
2885    /// [`crate::AplicacaoSpec`] altitude — folds on the outer top-
2886    /// level [`Caixa`] altitude's M3 mesh-slot arm the sibling
2887    /// [`Self::politicas`] opened, extending the discipline onto the
2888    /// second of the three M3 mesh-slot axes. The remaining M3
2889    /// mesh-slot axis (`:entrada`) folds onto this accessor's
2890    /// discipline in the final sibling lift, closing the outer top-
2891    /// level [`Caixa`] `Option<&Composite>` M3 mesh-slot sub-family.
2892    /// Returns `Option<&Placement>` (not the owning composite by copy
2893    /// or clone) because every downstream consumer of the placement
2894    /// composite treats it as a read-only per-axis dispatch source —
2895    /// the reference-view is the narrowest borrow that supports every
2896    /// present + roadmapped consumer (per-axis accessor dispatch,
2897    /// serde composite-serialization on the programs.yaml overlay,
2898    /// presence-probe early return on the "author-omitted `:placement`
2899    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2900    /// seed's default-fold arm) without cloning the composite through
2901    /// every consumer's fast path. The `Option` half of the return-
2902    /// type preserves the load-bearing "author-omitted `:placement` ⇒
2903    /// cluster-default applies" partition (not a default composite
2904    /// the downstream must reject on emptiness) — the accessor
2905    /// projects the raw `Option<Placement>` slot's presence bit
2906    /// through the reference-return unchanged. Named `placement()` to
2907    /// match the storage field's name verbatim and the tatara-lisp
2908    /// author-surface term (`:placement`) the field's own docstring
2909    /// already carries.
2910    #[must_use]
2911    pub const fn placement(&self) -> Option<&crate::aplicacao::Placement> {
2912        self.placement.as_ref()
2913    }
2914
2915    /// Substrate-canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
2916    /// composite MESH-COMPOSITION-shaped external-gateway optional-
2917    /// composite-reference accessor every consumer of the top-level
2918    /// manifest's per-Aplicacao [`crate::aplicacao::Entrada`] outer-
2919    /// composite reader keys off — returns the author-declared
2920    /// `:entrada` typed composite verbatim as an `Option<&Entrada>`
2921    /// reference over the same backing storage the raw
2922    /// `self.entrada.as_ref()` field access borrows from, with `None`
2923    /// naming the "no `:entrada` block authored — this Aplicacao is
2924    /// cluster-internal, no `Gateway`/`HTTPRoute` fan-out emitted"
2925    /// partition every downstream caixa-mesh Gateway-API artifact
2926    /// emitter treats as "emit no gateway-listener + no `HTTPRoute`
2927    /// backend for this Aplicacao" and the sibling
2928    /// [`Self::aplicacao_view`] Aplicacao-composition seed forwards
2929    /// verbatim (unlike the peer `:politicas` / `:placement` arms,
2930    /// `:entrada` has no cluster-default fold — an omitted `:entrada`
2931    /// stays `None` on the projected [`crate::AplicacaoSpec`] and the
2932    /// peer inner [`crate::AplicacaoSpec::entrada`] accessor observes
2933    /// the same `Option<&Entrada>` presence bit unchanged).
2934    ///
2935    /// The outer `:entrada` slot carries the M3 mesh-slot per-
2936    /// Aplicacao typed external-gateway composite — the load-bearing
2937    /// container of every how-does-the-outside-world-reach-this-
2938    /// Aplicacao axis every caixa-mesh `Gateway`/`HTTPRoute` fan-out
2939    /// emitter fans on (MESH-COMPOSITION §II.5 — the Aplicacao's typed
2940    /// external-entry composite; §V CSE invariants — "the external
2941    /// gateway is a first-class typed composite, not a per-Servico
2942    /// ingress annotation" the per-axis scalars enforce; §III.4 — the
2943    /// typed hostname + backend-Servico pair the per-cluster Gateway-
2944    /// API renderer keys off). Every per-`:entrada` axis threads
2945    /// through a lifted per-slot accessor on the
2946    /// [`crate::aplicacao::Entrada`] type: the
2947    /// [`crate::aplicacao::Entrada::host`] Gateway-API `Listener.hostname`
2948    /// scalar, the [`crate::aplicacao::Entrada::para`] backend-Servico
2949    /// caixa-name scalar, the [`crate::aplicacao::Entrada::paths`]
2950    /// per-rule `HTTPPathMatch` list, the [`crate::aplicacao::Entrada::port`]
2951    /// backend `trigger.service.port` scalar, and the
2952    /// [`crate::aplicacao::Entrada::resolved_paths`] URL-path fallback
2953    /// resolver every HTTPRoute-aware renderer consumes. Every
2954    /// downstream consumer that reaches for an entry axis first passes
2955    /// through this outer accessor onto the composite and then
2956    /// dispatches onto the per-axis accessor — the two-level dispatch
2957    /// means every per-`:entrada` reader now routes through a typed
2958    /// dispatch on the substrate primitive at both altitudes.
2959    ///
2960    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2961    /// seed: the Aplicacao-view builder forwards the outer `Option`
2962    /// arm verbatim (no default fold — `:entrada` is inherently
2963    /// optional; a cluster-internal Aplicacao has no external gateway
2964    /// at all, not "an external gateway that defaults to nothing"), so
2965    /// the peer inner [`crate::AplicacaoSpec::entrada`] (d32111c)
2966    /// `Option<&Entrada>`-return accessor observes the same presence
2967    /// bit whether or not the author declared the outer slot. Routing
2968    /// the presence bit through this accessor keeps the
2969    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2970    /// `M3_AUTHOR_KEY_ENTRADA` push separate from the inner
2971    /// [`crate::AplicacaoSpec::validate_entrada`]-gated
2972    /// hostname/backend/path emission dispatch.
2973    ///
2974    /// Prior to this lift the `.entrada` `Option<Entrada>` composite
2975    /// was accessed inline at two production sites — the
2976    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2977    /// `self.entrada.clone()` traversal head (caixa-core/src/manifest.rs:2182,
2978    /// which drives the forward onto the peer inner
2979    /// [`crate::AplicacaoSpec::entrada`] accessor the caixa-mesh
2980    /// Gateway-API fan-out then observes), and the
2981    /// [`Self::declared_mesh_slots`] M3 declared-slot-set enumerator's
2982    /// `self.entrada.is_some()` presence probe (caixa-core/src/manifest.rs:2248,
2983    /// which drives the `M3_AUTHOR_KEY_ENTRADA` kebab-case author-
2984    /// label push every [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
2985    /// kind-coherence gate reads) — two open-coded outer-field
2986    /// accesses that expressed no compile-time link back to the typed
2987    /// slot at the [`Caixa`] altitude. A future extension of the
2988    /// `:entrada` outer axis to a richer author surface (a per-cluster
2989    /// `:entrada-overrides` slot the operator materializes at admission
2990    /// time so a cluster-specific hostname can pin the caixa-declared
2991    /// bound without re-authoring the `caixa.lisp`, a per-tenant
2992    /// gateway-alias table the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
2993    /// CR materializer resolves per-CR at admission time, a promotion
2994    /// of the plain `Option<Entrada>` to a richer
2995    /// `{public, private, internal}` partition once Cilium-identity-
2996    /// scoped internal gateways come into typed scope) would have had
2997    /// to be threaded through both open-coded copies in lockstep or the
2998    /// Aplicacao-composition seed's forward arm would silently
2999    /// disagree with the M3 declared-slot enumerator on which external-
3000    /// gateway composite a given Caixa resolves to — the seed reading
3001    /// an operator-resolved slot while the enumerator's presence probe
3002    /// read the raw slot would silently split the build-time gateway-
3003    /// artifact emission gate from the M3 declared-slot enumerator's
3004    /// kind-coherence gate, a two-consumer split far from the source
3005    /// `caixa.lisp` with no field naming the entry-drift root cause.
3006    /// Lifting the resolution rule to a typed method on the substrate
3007    /// primitive means every downstream consumer of the caixa's per-
3008    /// `Caixa` MESH-COMPOSITION external-gateway outer-composite
3009    /// surface reaches for exactly one typed dispatch — the resolver's
3010    /// accept-set migrates as a unit on any future axis addition.
3011    ///
3012    /// Fifth and final outer top-level [`Caixa`] `Option<&Composite>`-
3013    /// return composite-reference accessor — closes the outer-`Caixa`
3014    /// `Option<&Composite>` composite-reference sub-family opened by
3015    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) on the
3016    /// M2 Servico-runtime arm and extended onto the M3 mesh-slot arm
3017    /// by [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074),
3018    /// folds on the "one typed dispatch on the substrate primitive,
3019    /// thin projections at each consumer" discipline extended onto the
3020    /// third and final M3 mesh-slot axis. Peer of the closed inner
3021    /// mesh-slot outer-composite family the sibling
3022    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
3023    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
3024    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
3025    /// accessor pins already close on the inner
3026    /// [`crate::AplicacaoSpec`] altitude — this lift closes the mirror
3027    /// sub-family on the outer top-level [`Caixa`] altitude, so both
3028    /// altitudes of the outer-composite reference-return discipline
3029    /// (per-`Caixa` outer-slot presence + per-`AplicacaoSpec` inner-
3030    /// slot presence) now carry the full five-arm accept-set behind a
3031    /// typed dispatch on the substrate primitive. Returns
3032    /// `Option<&Entrada>` (not the owning composite by copy or clone)
3033    /// because every downstream consumer of the entrada composite
3034    /// treats it as a read-only per-axis dispatch source — the
3035    /// reference-view is the narrowest borrow that supports every
3036    /// present + roadmapped consumer (per-axis accessor dispatch,
3037    /// serde composite-serialization on the programs.yaml overlay,
3038    /// presence-probe early return on the "author-omitted `:entrada`
3039    /// ⇒ cluster-internal Aplicacao" partition, `Aplicacao`-composition
3040    /// seed's forward arm) without cloning the composite through every
3041    /// consumer's fast path. The `Option` half of the return-type
3042    /// preserves the load-bearing "author-omitted `:entrada` ⇒
3043    /// cluster-internal Aplicacao" partition (not a default composite
3044    /// the downstream must reject on emptiness — a cluster-internal
3045    /// Aplicacao has no external gateway at all, not "a default gateway
3046    /// that emits nothing"); the accessor projects the raw
3047    /// `Option<Entrada>` slot's presence bit through the reference-
3048    /// return unchanged. Named `entrada()` to match the storage field's
3049    /// name verbatim and the tatara-lisp author-surface term
3050    /// (`:entrada`) the field's own docstring already carries.
3051    #[must_use]
3052    pub const fn entrada(&self) -> Option<&crate::aplicacao::Entrada> {
3053        self.entrada.as_ref()
3054    }
3055
3056    /// Substrate-canonical per-`Caixa` `:ci` slot accessor — returns the
3057    /// author-declared typed CI run (`canteiro_types::CiRun`) verbatim as
3058    /// an `Option<&CiRun>`, borrowed from the typed slot's own
3059    /// `Option<CiRun>` storage. `None` when the slot is absent (every
3060    /// non-`Acao` kind, and an `Acao` caixa that hasn't declared `:ci`
3061    /// yet — the latter is caught by [`crate::LayoutError::MissingCi`],
3062    /// not silently accepted).
3063    ///
3064    /// Named `ci()` to match the storage field's name and the
3065    /// tatara-lisp author surface (`:ci`); mirrors the sibling
3066    /// `Option<&Composite>` accessors on this same `Caixa` altitude
3067    /// ([`Self::limits`], [`Self::behavior`], [`Self::politicas`],
3068    /// [`Self::placement`], [`Self::entrada`]) — one typed dispatch on
3069    /// the substrate primitive rather than an open-coded `self.ci.as_ref()`
3070    /// at every consumer.
3071    #[must_use]
3072    pub const fn ci(&self) -> Option<&canteiro_types::CiRun> {
3073        self.ci.as_ref()
3074    }
3075
3076    /// Substrate-canonical per-`Caixa` `:estrategia` M2 supervisor-tree-
3077    /// slot flat-spread OTP-shaped sibling-restart-strategy discriminant
3078    /// accessor every consumer of the top-level manifest's per-Supervisor
3079    /// restart-strategy axis keys off — returns the author-declared
3080    /// `:estrategia` variant verbatim as an `Option<RestartStrategy>`,
3081    /// `Copy`-projected from the typed slot's own
3082    /// `Option<crate::supervisor::RestartStrategy>` storage. Optional
3083    /// (`:estrategia` is a flat-spread supervisor-only slot every
3084    /// non-`Supervisor`-kind `defcaixa` carries as `None` by
3085    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3086    /// still omit to defer to [`RestartStrategy::default`] —
3087    /// [`RestartStrategy::OneForOne`] — through the [`Self::supervisor_view`]
3088    /// `unwrap_or_default()` fold; a returned `None` degenerates to the
3089    /// [`SupervisorSpec::default`]-inherited strategy without any silent
3090    /// promotion to a fresh explicit variant at the accessor boundary).
3091    ///
3092    /// The `:estrategia` slot carries the M2 typed OTP-shaped sibling-
3093    /// restart-strategy discriminant every substrate-side per-Supervisor
3094    /// dispatch fans on (INSPIRATIONS §II.2 — OTP `supervisor:strategy`
3095    /// closed-set `one_for_one | one_for_all | rest_for_one |
3096    /// simple_one_for_one` algebra translated onto pleme-io's typed
3097    /// [`RestartStrategy`] enum; CAIXA-SDLC §II — the M2 supervisor-tree
3098    /// slot algebra the operator's hierarchical reconciliation scheduler
3099    /// fans on). The slot is *flat-spread* on the outer top-level `Caixa`
3100    /// (per the field-shape docstring at caixa-core/src/manifest.rs — "The
3101    /// supervisor slots are flat on Caixa (vs nested under a
3102    /// `SupervisorSpec` sub-form) to keep tatara-lisp authoring at one
3103    /// level of nesting"), so the accessor's altitude is the outer
3104    /// [`Caixa`] surface rather than the composed [`SupervisorSpec`]
3105    /// altitude the sibling [`crate::supervisor::SupervisorSpec::estrategia`]
3106    /// (eafb619) accessor keys off. The two typed axes — the outer
3107    /// author-surface `Option<RestartStrategy>` on the [`Caixa`] altitude
3108    /// (author-omitted arm carried as `None`) and the inner post-
3109    /// composition `RestartStrategy` on the [`SupervisorSpec`] altitude
3110    /// (`Option` collapsed through the [`Self::supervisor_view`]
3111    /// `unwrap_or_default()` fold) — now share one accessor discipline for
3112    /// the shared substrate concept "the author-declared OTP-shaped
3113    /// sibling-restart-strategy variant that partitions the downstream
3114    /// per-Supervisor renderer's per-arm fan-out"; the outer-altitude
3115    /// `None` arm is the pre-composition presence bit every declared-slot
3116    /// enumerator ([`Self::declared_supervisor_slots`]) reads, and the
3117    /// inner-altitude non-`Option` `RestartStrategy` is the post-
3118    /// composition partition-dispatch input every strategy-arm consumer
3119    /// ([`SupervisorSpec::validate`], the future wasm-operator's per-
3120    /// Supervisor sibling-restart branch, the future M4
3121    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
3122    /// webhook) fans on.
3123    ///
3124    /// Prior to this lift the `.estrategia` field was accessed inline at
3125    /// two production sites in `caixa-core/src/manifest.rs` — the
3126    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`
3127    /// presence-probe arm at `if self.estrategia.is_some()` (which drives
3128    /// the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3129    /// coherence gate's per-slot label push) and the [`Self::supervisor_view`]
3130    /// `SupervisorSpec` construction site at `estrategia:
3131    /// self.estrategia.unwrap_or_default()` (which composes the flat-
3132    /// spread outer author-surface `Option<RestartStrategy>` onto the
3133    /// inner post-composition [`SupervisorSpec`] `RestartStrategy` field
3134    /// the [`SupervisorSpec::estrategia`] accessor keys off) — two open-
3135    /// coded field-accesses that expressed no compile-time link back to
3136    /// the typed slot. A future extension of the outer `:estrategia` axis
3137    /// to a richer author surface (a per-cluster strategy override the
3138    /// operator pins through a future `:estrategia-overrides` overlay the
3139    /// MESH-COMPOSITION §III.2 supervision-canary roadmap acknowledges,
3140    /// a per-tenant strategy-alias table the M4 CR materializer resolves
3141    /// per-CR, a per-Supervisor dynamic strategy derivation the future
3142    /// adaptive-supervision engine computes from child-failure-history
3143    /// topology, a per-child-cohort strategy split the future
3144    /// `RestForCohort` extension the INSPIRATIONS.md §II.2 Erlang/OTP
3145    /// absorption roadmap acknowledges, a promotion of the plain
3146    /// `Option<RestartStrategy>` to a richer
3147    /// `AuthorDeclaredStrategy { declared, overlay }` newtype once the
3148    /// operator-resolved overlay lands) would have had to be threaded
3149    /// through both open-coded copies in lockstep or the enumerator's
3150    /// presence probe and the composition site's `unwrap_or_default()`
3151    /// fold would silently disagree on which strategy a given [`Caixa`]
3152    /// resolves to (an author's `:estrategia OneForAll` would satisfy
3153    /// the enumerator's presence probe while the composition site
3154    /// silently rendered a stale `OneForOne`, or vice versa). Lifting
3155    /// the resolution rule to a typed method on the substrate primitive
3156    /// means every downstream consumer of the caixa's per-`Caixa` outer-
3157    /// altitude sibling-restart-strategy surface reaches for exactly one
3158    /// typed dispatch — the resolver's accept-set migrates as a unit on
3159    /// any future axis addition.
3160    ///
3161    /// First outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3162    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3163    /// axes — opens the outer-`Caixa` `Option<Copy>` flat-spread
3164    /// projection pattern the sibling per-`Caixa` `:max-restarts`
3165    /// `Option<u32>` and (through the future duration-newtype landing)
3166    /// `:restart-window` `Option<Duration>` future outer-scalar lifts
3167    /// fold on. Peer of the inner-altitude [`crate::supervisor::SupervisorSpec::estrategia`]
3168    /// (eafb619) `Copy`-return sibling-restart-strategy scalar accessor on
3169    /// the post-composition [`SupervisorSpec`] altitude — same "one
3170    /// typed dispatch on the substrate primitive, thin projections at
3171    /// each consumer" discipline extended onto the pre-composition outer
3172    /// author-surface [`Caixa`] altitude for the same OTP-shaped
3173    /// sibling-restart-strategy axis. Peer of the closed outer-`Caixa`
3174    /// `Option<&Composite>` composite-reference family the sibling
3175    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3176    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3177    /// [`Self::entrada`] (e4128e4) accessor pins already carry on the
3178    /// outer `Option<&Composite>` altitude — extends the outer-`Caixa`
3179    /// typed-slot accessor discipline onto the flat-spread M2 supervisor-
3180    /// tree `Option<Copy>`-discriminant sub-family the sibling M3
3181    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
3182    /// `PlacementStrategy` `Copy`-composite-enum scalar accessor already
3183    /// pins on the inner-altitude per-`:placement` composite. Named
3184    /// `estrategia()` to match the storage field's name and the
3185    /// per-[`SupervisorSpec`] peer [`crate::supervisor::SupervisorSpec::estrategia`]
3186    /// / per-[`crate::aplicacao::Placement`] peer
3187    /// [`crate::aplicacao::Placement::estrategia`] method-name discipline
3188    /// verbatim; the accessor's identity name maps onto the canonical
3189    /// OTP-shape supervision vocabulary the [`RestartStrategy`] enum's
3190    /// docstring already carries.
3191    #[must_use]
3192    pub const fn estrategia(&self) -> Option<crate::supervisor::RestartStrategy> {
3193        self.estrategia
3194    }
3195
3196    /// Substrate-canonical per-`Caixa` `:max-restarts` M2 supervisor-tree-
3197    /// slot flat-spread OTP-`MaxIntensity`-shaped restart-budget-count
3198    /// scalar accessor every consumer of the top-level manifest's per-
3199    /// Supervisor `:max-restarts` restart-budget-count axis keys off —
3200    /// returns the author-declared `:max-restarts` typed `Option<u32>`
3201    /// verbatim, `Copy`-projected from the typed slot's own `Option<u32>`
3202    /// storage (`u32` is `Copy`, so `Option<u32>` is `Copy` and the
3203    /// accessor returns by value; no borrow of `&self` past the call).
3204    /// Optional (`:max-restarts` is a flat-spread supervisor-only slot
3205    /// every non-`Supervisor`-kind `defcaixa` carries as `None` by
3206    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3207    /// still omit to defer to the [`Self::supervisor_view`]
3208    /// `unwrap_or(5)` fold's OTP-canonical `{intensity, 5, 60}` default).
3209    ///
3210    /// The `:max-restarts` slot carries the M2 typed Erlang/OTP-shaped
3211    /// `MaxIntensity` restart-budget count that pairs with the sibling
3212    /// `:restart-window` `Period` to form the `MaxIntensity / Period`
3213    /// restart-intensity ratio the supervisor trips its own escalation on
3214    /// (INSPIRATIONS §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}`
3215    /// worker-supervisor default; RUNTIME-PATTERNS §II.2; CAIXA-SDLC §II
3216    /// — the M2 supervisor-tree slot algebra the operator's hierarchical
3217    /// reconciliation scheduler fans on). The slot is *flat-spread* on
3218    /// the outer top-level `Caixa` (per the field-shape docstring at
3219    /// caixa-core/src/manifest.rs — "The supervisor slots are flat on
3220    /// Caixa (vs nested under a `SupervisorSpec` sub-form)"), so the
3221    /// accessor's altitude is the outer [`Caixa`] surface rather than the
3222    /// composed [`SupervisorSpec`] altitude the sibling
3223    /// [`crate::supervisor::SupervisorSpec::max_restarts`] accessor keys
3224    /// off. The two typed axes — the outer author-surface `Option<u32>`
3225    /// on the [`Caixa`] altitude (author-omitted arm carried as `None`)
3226    /// and the inner post-composition `u32` on the [`SupervisorSpec`]
3227    /// altitude (`Option` collapsed through the [`Self::supervisor_view`]
3228    /// `unwrap_or(5)` fold) — now share one accessor discipline for the
3229    /// shared substrate concept "the author-declared OTP-shaped
3230    /// restart-budget count every downstream per-Supervisor consumer's
3231    /// restart-intensity budget-vs-count comparator fans on".
3232    ///
3233    /// Prior to this lift the `.max_restarts` field was accessed inline
3234    /// at two production sites in `caixa-core/src/manifest.rs` — the
3235    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`
3236    /// presence-probe arm at `if self.max_restarts.is_some()` (which
3237    /// drives the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3238    /// kind-coherence gate's per-slot label push) and the
3239    /// [`Self::supervisor_view`] `SupervisorSpec` construction site at
3240    /// `max_restarts: self.max_restarts.unwrap_or(5)` (which composes the
3241    /// flat-spread outer author-surface `Option<u32>` onto the inner
3242    /// post-composition [`SupervisorSpec`] `u32` field the
3243    /// [`SupervisorSpec::max_restarts`] accessor keys off) — two open-
3244    /// coded field-accesses that expressed no compile-time link back to
3245    /// the typed slot. A future extension of the outer `:max-restarts`
3246    /// axis to a richer author surface (a per-cluster restart-budget
3247    /// override the operator pins through a future `:max-restarts-overrides`
3248    /// overlay the MESH-COMPOSITION §III.2 supervision-canary roadmap
3249    /// acknowledges, a per-tenant restart-budget-alias table the M4 CR
3250    /// materializer resolves per-CR, a per-Supervisor dynamic restart-
3251    /// budget derivation the future adaptive-supervision engine computes
3252    /// from child-failure-history topology, a promotion of the plain
3253    /// `Option<u32>` count to a richer `{MaxR, MaxT}` per-child-cohort
3254    /// restart-budget-partition once the INSPIRATIONS §II.2 Erlang/OTP
3255    /// per-child-cohort roadmap lands) would have had to be threaded
3256    /// through both open-coded copies in lockstep or the enumerator's
3257    /// presence probe and the composition site's `unwrap_or(5)` fold
3258    /// would silently disagree on which restart-budget a given [`Caixa`]
3259    /// resolves to (an author's `:max-restarts 10` would satisfy the
3260    /// enumerator's presence probe while the composition site silently
3261    /// composed the OTP-canonical `5`, or vice versa). Lifting the
3262    /// resolution rule to a typed method on the substrate primitive means
3263    /// every downstream consumer of the caixa's per-`Caixa` outer-altitude
3264    /// restart-budget-count surface reaches for exactly one typed dispatch
3265    /// — the resolver's accept-set migrates as a unit on any future axis
3266    /// addition.
3267    ///
3268    /// Second outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3269    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3270    /// axes — folds on the outer-`Caixa` `Option<Copy>` flat-spread
3271    /// projection pattern the sibling per-`Caixa`
3272    /// [`Self::estrategia`] (ed04d3c) accessor opened, extends the
3273    /// sub-family onto the sibling `Option<u32>` restart-budget-count arm.
3274    /// Peer of the inner-altitude
3275    /// [`crate::supervisor::SupervisorSpec::max_restarts`] `u32` accessor
3276    /// on the post-composition [`SupervisorSpec`] altitude — same "one
3277    /// typed dispatch on the substrate primitive, thin projections at
3278    /// each consumer" discipline extended onto the pre-composition outer
3279    /// author-surface [`Caixa`] altitude for the same OTP-`MaxIntensity`-
3280    /// shaped restart-budget-count axis. Named `max_restarts()` to match
3281    /// the storage field's name and the per-[`SupervisorSpec`] peer
3282    /// [`crate::supervisor::SupervisorSpec::max_restarts`] method-name
3283    /// discipline verbatim; the accessor's identity maps onto the
3284    /// canonical OTP-shape supervision vocabulary the `:max-restarts`
3285    /// field's docstring already carries.
3286    #[must_use]
3287    pub const fn max_restarts(&self) -> Option<u32> {
3288        self.max_restarts
3289    }
3290
3291    /// Substrate-canonical per-`Caixa` `:restart-window` M2 supervisor-
3292    /// tree-slot flat-spread OTP-`Period`-shaped restart-intensity-
3293    /// denominator raw-duration-string scalar accessor every consumer of
3294    /// the top-level manifest's per-Supervisor `:restart-window` sliding-
3295    /// window axis keys off — returns the author-declared `:restart-window`
3296    /// typed `Option<String>` verbatim as an `Option<&str>`, borrowed
3297    /// from the typed slot's own `Option<String>` storage. `None` when
3298    /// the slot is absent (the canonical "never reset — every restart
3299    /// across the supervisor's lifetime counts against the sibling
3300    /// `:max-restarts` budget" sentinel every non-`Supervisor`-kind
3301    /// `defcaixa` carries by `#[serde(default)]` and every
3302    /// `Supervisor`-kind `defcaixa` may still omit to defer to the
3303    /// [`Self::supervisor_view`] `restart_window: None` composition
3304    /// through the [`crate::supervisor::duration_codec::parse`] soft-
3305    /// swallow `.and_then(|s| … .ok())` fold).
3306    ///
3307    /// The `:restart-window` slot carries the raw M2 typed Erlang/OTP-
3308    /// shaped `Period` sliding-observation-interval duration string that
3309    /// pairs with the sibling `:max-restarts` `MaxIntensity` restart-
3310    /// budget count to form the `MaxIntensity / Period` restart-intensity
3311    /// ratio the supervisor trips its own escalation on (INSPIRATIONS
3312    /// §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}` worker-
3313    /// supervisor default; RUNTIME-PATTERNS §II.2). The outer-`Caixa`
3314    /// slot stores the raw duration string (`"60s"`, `"5m"`, `"500ms"`)
3315    /// authored under `:restart-window` — the typed [`SupervisorSpec`]
3316    /// holds an `Option<Duration>` routed through the shared
3317    /// [`crate::supervisor::duration_codec`] via `with = "duration_codec"`
3318    /// — so the outer altitude's accessor returns `Option<&str>` (raw
3319    /// authoring surface) while the inner altitude's
3320    /// [`crate::supervisor::SupervisorSpec::restart_window`] returns
3321    /// `Option<Duration>` (parsed typed surface). The parse-refusal arm
3322    /// is closed by the sibling [`Self::validate_restart_window`] gate
3323    /// that surfaces [`ManifestError::RestartWindowMalformed`] naming
3324    /// the offending value; the view-construction path
3325    /// [`Self::supervisor_view`] soft-swallows the same parse error to
3326    /// `None` to keep the view best-effort.
3327    ///
3328    /// Prior to this lift the `.restart_window` field was accessed inline
3329    /// at three production sites in `caixa-core/src/manifest.rs` — the
3330    /// [`Self::declared_supervisor_slots`]
3331    /// `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` presence-probe arm at
3332    /// `if self.restart_window.is_some()` (which drives the
3333    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3334    /// coherence gate's per-slot label push), the
3335    /// [`Self::validate_restart_window`] `let Some(s) =
3336    /// self.restart_window.as_deref()` empty-and-shape gate binding
3337    /// (which folds the raw string through the shared
3338    /// [`crate::supervisor::duration_codec::parse`] to surface
3339    /// [`ManifestError::RestartWindowMalformed`] naming the offending
3340    /// value), and the [`Self::supervisor_view`] `self.restart_window
3341    /// .as_deref().and_then(…)` view-construction fold (which composes
3342    /// the flat-spread outer author-surface `Option<String>` onto the
3343    /// inner post-composition [`SupervisorSpec`] `Option<Duration>`
3344    /// field the [`SupervisorSpec::restart_window`] accessor keys off) —
3345    /// three open-coded field-accesses that expressed no compile-time
3346    /// link back to the typed slot. A future extension of the outer
3347    /// `:restart-window` axis to a richer author surface (a per-cluster
3348    /// window override, a per-tenant window-alias table, a per-Supervisor
3349    /// dynamic window derivation the future adaptive-supervision engine
3350    /// computes from child-failure-history topology, a promotion of the
3351    /// plain `Option<String>` raw duration to a typed `Option<Duration>`
3352    /// once the future author-surface parser lands at the [`Caixa`]
3353    /// altitude and the raw-string form is retired) would have had to be
3354    /// threaded through every open-coded copy in lockstep or the three
3355    /// consumers would silently disagree on which raw string a given
3356    /// [`Caixa`] resolves to. Lifting the resolution rule to a typed
3357    /// method on the substrate primitive means every downstream consumer
3358    /// of the caixa's per-`Caixa` outer-altitude restart-window raw-
3359    /// string surface reaches for exactly one typed dispatch — the
3360    /// resolver's accept-set migrates as a unit on any future axis
3361    /// addition.
3362    ///
3363    /// Third outer top-level [`Caixa`] supervisor-tree-slot flat-spread
3364    /// accessor — folds on the outer-`Caixa` M2 supervisor-tree flat-
3365    /// spread projection pattern the sibling per-`Caixa`
3366    /// [`Self::estrategia`] (ed04d3c) `Option<Copy>` and
3367    /// [`Self::max_restarts`] `Option<Copy>` accessors opened, extends
3368    /// the sub-family onto the sibling `Option<&str>` raw-duration-
3369    /// string arm (the outer altitude's raw-string form; the inner
3370    /// altitude's parsed [`Duration`] form is the peer
3371    /// [`crate::supervisor::SupervisorSpec::restart_window`] accessor).
3372    /// Peer of the sibling per-`Caixa` `Option<&str>`-return scalar
3373    /// accessors ([`Self::licenca`] / [`Self::repositorio`] /
3374    /// [`Self::descricao`] / [`Self::edicao`]) on the universal-axis
3375    /// outer scalar-projection family the outer-`Caixa` `Option<&str>`
3376    /// sub-family already carries — same "one typed dispatch on the
3377    /// substrate primitive, thin projections at each consumer"
3378    /// discipline extended onto the M2 supervisor-tree flat-spread
3379    /// `Option<&str>` raw-duration-string arm. Named `restart_window()`
3380    /// to match the storage field's name and the per-[`SupervisorSpec`]
3381    /// peer [`crate::supervisor::SupervisorSpec::restart_window`]
3382    /// method-name discipline verbatim; the accessor's identity maps
3383    /// onto the canonical OTP-shape supervision vocabulary the
3384    /// `:restart-window` field's docstring already carries.
3385    #[must_use]
3386    pub const fn restart_window(&self) -> Option<&str> {
3387        match &self.restart_window {
3388            Some(s) => Some(s.as_str()),
3389            None => None,
3390        }
3391    }
3392
3393    /// Substrate-canonical per-`Caixa` `:upgrade-from` M2 typed-slot
3394    /// outer-composite OTP-appup-shaped per-prior-version migration-
3395    /// entry-list slice accessor every consumer of the top-level
3396    /// manifest's per-Servico hot-upgrade-block `&[UpgradeFromEntry]`
3397    /// slice-view keys off — returns the author-declared `:upgrade-from`
3398    /// typed `Vec<UpgradeFromEntry>` verbatim as a
3399    /// `&[UpgradeFromEntry]` slice-view over the same backing buffer
3400    /// the raw `self.upgrade_from.as_slice()` field access borrows
3401    /// from. Empty-slice-carrying (the "no hot-upgrade path declared"
3402    /// arm every `defcaixa` without an `:upgrade-from` block carries;
3403    /// the [`Self::from_lisp`] derive folds an omitted `:upgrade-from`
3404    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
3405    /// parse definitionally carries a `Vec<UpgradeFromEntry>` slot —
3406    /// possibly empty — and the returned `&[UpgradeFromEntry]`
3407    /// degenerates to an empty slice on that arm without any silent
3408    /// `None` collapse).
3409    ///
3410    /// The outer `:upgrade-from` slot carries the M2 typed OTP-appup
3411    /// migration block — the load-bearing container of every per-
3412    /// prior-`:versao` migration-instruction list the wasm-operator
3413    /// dispatches on at hot-upgrade time (INSPIRATIONS §II.4 — OTP
3414    /// `.appup` per-prior-version `LoadModule | StateChange |
3415    /// SoftPurge | Purge | Restart` instruction algebra translated
3416    /// onto pleme-io's typed `:upgrade-from :from` + `:instructions`
3417    /// entry list; CAIXA-SDLC §II — the typed-M2 slot algebra the
3418    /// operator's hot-upgrade dispatch fans on). Every per-entry axis
3419    /// threads through a lifted per-entry accessor on the
3420    /// [`UpgradeFromEntry`] type: the
3421    /// [`UpgradeFromEntry::prior_versao`] SemVer-shaped previous-
3422    /// version scalar accessor and the
3423    /// [`UpgradeFromEntry::instructions`] `&[UpgradeInstruction]`-
3424    /// return per-entry instruction-list accessor (0137e5a). Every
3425    /// downstream consumer of the hot-upgrade path first passes
3426    /// through this outer accessor onto the slice and then dispatches
3427    /// per-entry through the inner accessors — the two-level dispatch
3428    /// means every per-`:upgrade-from` reader now routes through a
3429    /// typed dispatch on the substrate primitive at both altitudes.
3430    ///
3431    /// Prior to this lift the `.upgrade_from` `Vec<UpgradeFromEntry>`
3432    /// slot was accessed inline at production sites across three
3433    /// files — the [`Self::declared_servico_slots`] M2 declared-slot
3434    /// enumerator's `self.upgrade_from.is_empty()` presence probe
3435    /// (caixa-core/src/manifest.rs, which drives the
3436    /// `M2_AUTHOR_KEY_UPGRADE_FROM` kebab-case author-label push every
3437    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
3438    /// gate reads), the [`crate::StandardLayout::verify`] per-
3439    /// `:upgrade-from` three-stage validation pass (caixa-core/src/
3440    /// layout.rs, which fans onto the
3441    /// [`crate::upgrade::validate_upgrade_from`] per-entry shape +
3442    /// cross-entry duplicate gate, the
3443    /// [`crate::upgrade::validate_upgrade_from_against_versao`]
3444    /// SemVer-precedence cross-slot gate, the
3445    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
3446    /// `:state-change` ↔ `:on-state-change` cross-slot composition
3447    /// gate, and the per-instruction script-path existence-probe walk
3448    /// that reads each entry's [`UpgradeFromEntry::instructions`] to
3449    /// resolve every declared migration script against the layout
3450    /// root), and the [`crate::render::servico_m2_overlay`] per-
3451    /// Servico M2 overlay emitter's `!caixa.upgrade_from.is_empty()`
3452    /// presence gate + `serde_yaml::to_value(&caixa.upgrade_from)`
3453    /// projection (caixa-core/src/render.rs, which drives the
3454    /// `M2_KEY_UPGRADE_FROM`-keyed `serde_yaml` projection every
3455    /// `caixa-helm` / `caixa-flux` Servico values-block emitter fans
3456    /// on and lands as the ComputeUnit CR's `spec.upgradeFrom` field).
3457    /// A future extension of the outer `:upgrade-from` axis (a per-
3458    /// cluster `:upgrade-overrides` overlay the wasm-engine operator
3459    /// resolves at admission time so a cluster-specific migration
3460    /// policy can tighten a caixa-declared step without re-authoring
3461    /// the `caixa.lisp`, promotion of the plain
3462    /// `Vec<UpgradeFromEntry>` to a richer `{static, dynamic}`
3463    /// partition once runtime-resolved hot-upgrade instructions land,
3464    /// per-entry priority annotation once multi-strategy fan-out
3465    /// lands) would have had to be threaded through all six open-
3466    /// coded copies in lockstep or one consumer would silently
3467    /// disagree with the peers on which upgrade slice a given Caixa
3468    /// resolves to — a six-consumer split at the enumerator, the
3469    /// three-stage validate pass, the script-path probe walk, and the
3470    /// M2 overlay emitter, far from the source `caixa.lisp` with no
3471    /// field naming the upgrade-drift root cause. Lifting the
3472    /// resolution rule to a typed method on the substrate primitive
3473    /// means every downstream consumer of the caixa's per-`Caixa`
3474    /// OTP-appup outer-slice surface reaches for exactly one typed
3475    /// dispatch — the resolver's accept-set migrates as a unit on any
3476    /// future axis addition.
3477    ///
3478    /// First outer top-level [`Caixa`] `&[Composite]`-return slice
3479    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the
3480    /// outer-`Caixa` `&[Composite]` composite-slice projection
3481    /// pattern the sibling `:children`
3482    /// [`crate::supervisor::ChildSpec`] / `:membros`
3483    /// [`crate::aplicacao::Membro`] / `:contratos`
3484    /// [`crate::aplicacao::WitContract`] future outer-composite-slice
3485    /// lifts fold on. Peer of the closed outer-`Caixa` scalar
3486    /// `Option<&Composite>` composite-reference family the sibling
3487    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3488    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3489    /// [`Self::entrada`] (e4128e4) accessors closed on the outer
3490    /// `Option<&Composite>` altitude, extended here to the outer-
3491    /// `Caixa` `&[Composite]` vec-carry altitude. Peer at the inner
3492    /// altitude of [`crate::upgrade::UpgradeFromEntry::instructions`]
3493    /// (0137e5a) — same "one typed dispatch on the substrate
3494    /// primitive, thin projections at each consumer" discipline
3495    /// folded onto the outer top-level [`Caixa`] altitude, opening the
3496    /// M2 vec-carry slot family's outer-composite-slice axis. Sibling
3497    /// in shape to the peer outer-`Caixa` `&[Dep]`-return
3498    /// [`Self::deps`] (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and
3499    /// `&[String]`-return [`Self::autores`] (b5d813f) /
3500    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`]
3501    /// (8a36c23) / [`Self::exe`] (65d9527) / [`Self::servicos`]
3502    /// (611f78b) slice-accessors on the sibling outer-`Caixa` scalar-
3503    /// element vec-carry axes — folds the "outer [`Caixa`] `&[T]`
3504    /// slice" projection pattern onto the sibling M2 typed-composite-
3505    /// element axis (`UpgradeFromEntry` composite, matching the
3506    /// per-inner [`UpgradeFromEntry::instructions`] element type at a
3507    /// different altitude).
3508    ///
3509    /// Returns `&[UpgradeFromEntry]` (not `&Vec<UpgradeFromEntry>`)
3510    /// because every downstream consumer of the hot-upgrade list
3511    /// treats it as a read-only sequence — the slice-view is the
3512    /// narrowest borrow that supports every present + roadmapped
3513    /// consumer (`.iter()`, `.len()`, `.is_empty()`, `serde` slice-
3514    /// serialization through
3515    /// `serde_yaml::to_value(&[UpgradeFromEntry])`) without leaking
3516    /// the backing `Vec`'s grow/push/reserve surface no consumer of
3517    /// the typed view reaches for (the storage-side `Vec` remains
3518    /// reachable through the `pub upgrade_from` field for the
3519    /// mutation-carrying serde round-trip and per-test fixture-
3520    /// mutation paths). Named `upgrade_from()` to match the storage
3521    /// field's `snake_case` name; the kebab-case author-surface tag
3522    /// `:upgrade-from` is the same axis after tatara-lisp's
3523    /// kebab↔snake fold and the accessor's identity maps onto the
3524    /// canonical CAIXA-SDLC §II vocabulary the slot's docstring
3525    /// already carries.
3526    #[must_use]
3527    pub const fn upgrade_from(&self) -> &[UpgradeFromEntry] {
3528        self.upgrade_from.as_slice()
3529    }
3530
3531    /// Substrate-canonical per-`Caixa` `:children` M2 supervisor-tree-
3532    /// slot outer-composite OTP-shaped per-supervisor static-child-list
3533    /// slice accessor every consumer of the top-level manifest's per-
3534    /// Supervisor `&[ChildSpec]` slice-view keys off — returns the
3535    /// author-declared `:children` typed `Vec<crate::supervisor::ChildSpec>`
3536    /// verbatim as a `&[crate::supervisor::ChildSpec]` slice-view over
3537    /// the same backing buffer the raw `self.children.as_slice()` field
3538    /// access borrows from. Empty-slice-carrying (the "no static children
3539    /// declared" arm every non-`Supervisor`-kind `defcaixa` carries by
3540    /// #[serde(default)] and every `SimpleOneForOne` supervisor carries
3541    /// by [`crate::supervisor::SupervisorError::SimpleOneForOneWithStaticChildren`]
3542    /// gate; the returned `&[ChildSpec]` degenerates to an empty slice
3543    /// on those arms without any silent `None` collapse).
3544    ///
3545    /// The outer `:children` slot carries the M2 typed OTP-supervisor
3546    /// static-child list — the load-bearing container of every per-
3547    /// child `{caixa, versao, restart}` triple the wasm-operator's
3548    /// hierarchical reconciler dispatches on at supervisor-tree
3549    /// materialization time (INSPIRATIONS §II.2 — OTP `supervisor:init/1`
3550    /// static-child list translated onto pleme-io's typed
3551    /// [`crate::supervisor::ChildSpec`] entry list; CAIXA-SDLC §II —
3552    /// the typed-M2 slot algebra the operator's per-supervisor fan-out
3553    /// dispatch fans on). Every per-child axis threads through a lifted
3554    /// per-entry accessor on the [`crate::supervisor::ChildSpec`] type:
3555    /// the [`crate::supervisor::ChildSpec::nome`] DNS-1123-label
3556    /// child-caixa-identity scalar accessor, the peer versao SemVer-2
3557    /// version-requirement scalar accessor, and the
3558    /// [`crate::supervisor::ChildSpec::restart`] `Copy`-composite-enum
3559    /// per-child post-exit restart-decision-policy discriminant
3560    /// accessor (dfb4a81). Every downstream consumer of the supervisor-
3561    /// tree path first passes through this outer accessor onto the
3562    /// slice and then dispatches per-child through the inner accessors
3563    /// — the two-level dispatch means every per-`:children` reader now
3564    /// routes through a typed dispatch on the substrate primitive at
3565    /// both altitudes.
3566    ///
3567    /// Prior to this lift the `.children` `Vec<ChildSpec>` slot was
3568    /// accessed inline at three production sites across two files —
3569    /// the [`Self::declared_supervisor_slots`] supervisor-tree
3570    /// declared-slot enumerator's `!self.children.is_empty()` presence
3571    /// probe (caixa-core/src/manifest.rs, which drives the
3572    /// `SUPERVISOR_AUTHOR_KEY_CHILDREN` kebab-case author-label push
3573    /// every [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3574    /// kind-coherence gate reads), the [`Self::supervisor_view`]
3575    /// per-supervisor typed-view composer's `self.children.clone()`
3576    /// per-child fold-in path (caixa-core/src/manifest.rs, which
3577    /// materializes the typed [`crate::supervisor::SupervisorSpec`]
3578    /// view every [`crate::StandardLayout::verify`] Supervisor-arm gate
3579    /// dispatches on), and the [`crate::StandardLayout::verify`] per-
3580    /// `:children :caixa` self-parent refusal probe's
3581    /// `&caixa.children`-borrowed
3582    /// [`crate::supervisor::validate_no_self_supervision`] input
3583    /// (caixa-core/src/layout.rs, which pins the "no child names the
3584    /// supervisor's own `:nome`" cross-slot coherence gate). A future
3585    /// extension of the outer `:children` axis (a per-cluster
3586    /// `:children-overrides` overlay the wasm-engine operator resolves
3587    /// at admission time so a cluster-specific child-set can tighten
3588    /// a caixa-declared list without re-authoring the `caixa.lisp`,
3589    /// promotion of the plain `Vec<ChildSpec>` to a richer
3590    /// `{static, dynamic}` partition once Erlang/OTP's
3591    /// `simple_one_for_one`-shaped dynamic-child slot lands as a typed
3592    /// axis, per-child priority annotation once multi-strategy fan-out
3593    /// lands) would have had to be threaded through all three open-
3594    /// coded copies in lockstep or one consumer would silently
3595    /// disagree with the peers on which child slice a given Caixa
3596    /// resolves to — the enumerator's presence probe reading the raw
3597    /// slot while the peer view-composer's fold-in path read an
3598    /// operator-resolved slot would silently split the paired
3599    /// declared-slot enumerator and typed-view composition, and the
3600    /// [`crate::supervisor::validate_no_self_supervision`] self-parent
3601    /// refusal probe reading a third borrow would silently drift the
3602    /// cross-slot coherence gate's traversal input from the two peers,
3603    /// a three-consumer split at the enumerator, the view composer,
3604    /// and the self-parent gate far from the source `caixa.lisp` with
3605    /// no field naming the child-set-drift root cause. Lifting the
3606    /// resolution rule to a typed method on the substrate primitive
3607    /// means every downstream consumer of the caixa's per-`Caixa`
3608    /// OTP-supervisor outer-slice surface reaches for exactly one
3609    /// typed dispatch — the resolver's accept-set migrates as a unit
3610    /// on any future axis addition.
3611    ///
3612    /// Second outer top-level [`Caixa`] `&[Composite]`-return slice
3613    /// accessor for M2 / M3 typed-slot vec-carry axes — folds on the
3614    /// outer-`Caixa` `&[Composite]` composite-slice sub-family the
3615    /// sibling [`Self::upgrade_from`] (2a1f907) accessor opened, peer
3616    /// at the outer altitude of the closed inner-`SupervisorSpec`
3617    /// [`crate::SupervisorSpec::children`] (bc92bce) accessor on the
3618    /// same OTP-supervisor static-child-list axis — same "byte-equal,
3619    /// borrow-shared" outer-accessor discipline extended onto the
3620    /// second outer-`Caixa` `&[Composite]` vec-carry axis. Sibling in
3621    /// shape to the peer outer-`Caixa` `&[Dep]`-return [`Self::deps`]
3622    /// (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and `&[String]`-return
3623    /// [`Self::autores`] (b5d813f) / [`Self::etiquetas`] (78c7d3c) /
3624    /// [`Self::bibliotecas`] (8a36c23) / [`Self::exe`] (65d9527) /
3625    /// [`Self::servicos`] (611f78b) slice-accessors on the sibling
3626    /// outer-`Caixa` scalar-element vec-carry axes — folds the "outer
3627    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
3628    /// M2 typed-composite-element axis
3629    /// ([`crate::supervisor::ChildSpec`] composite, matching the
3630    /// per-inner [`crate::SupervisorSpec::children`] element type at a
3631    /// different altitude).
3632    ///
3633    /// Returns `&[crate::supervisor::ChildSpec]` (not
3634    /// `&Vec<ChildSpec>`) because every downstream consumer of the
3635    /// child list treats it as a read-only sequence — the slice-view
3636    /// is the narrowest borrow that supports every present +
3637    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`, the
3638    /// [`crate::supervisor::validate_no_self_supervision`] `&[ChildSpec]`
3639    /// input, `serde` slice-serialization) without leaking the backing
3640    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3641    /// reaches for (the storage-side `Vec` remains reachable through
3642    /// the `pub children` field for the mutation-carrying serde round-
3643    /// trip and per-test fixture-mutation paths, including the
3644    /// [`Self::supervisor_view`] fold-in path that clones the slot
3645    /// into the typed view). Named `children()` to match the storage
3646    /// field's name verbatim and the tatara-lisp author-surface term
3647    /// (`:children`) the field's own docstring already carries; the
3648    /// accessor's identity maps onto the canonical OTP supervision
3649    /// vocabulary the [`Caixa::children`] field's docstring already
3650    /// reaches for ("Static children of a supervisor").
3651    #[must_use]
3652    pub const fn children(&self) -> &[crate::supervisor::ChildSpec] {
3653        self.children.as_slice()
3654    }
3655
3656    /// Substrate-canonical per-`Caixa` `:membros` M3 mesh-slot outer-
3657    /// composite MESH-COMPOSITION-shaped per-Aplicacao member-list slice
3658    /// accessor every consumer of the top-level manifest's per-Aplicacao
3659    /// `&[crate::aplicacao::Membro]` slice-view keys off — returns the
3660    /// author-declared `:membros` typed `Vec<crate::aplicacao::Membro>`
3661    /// verbatim as a `&[crate::aplicacao::Membro]` slice-view over the
3662    /// same backing buffer the raw `self.membros.as_slice()` field access
3663    /// borrows from. Empty-slice-carrying (the "no members declared" arm
3664    /// every non-`Aplicacao`-kind `defcaixa` carries by `#[serde(default)]`
3665    /// and every partially-authored Aplicacao carries before the
3666    /// [`crate::AplicacaoError::MembrosEmpty`] gate fires; the returned
3667    /// `&[Membro]` degenerates to an empty slice on those arms without any
3668    /// silent `None` collapse).
3669    ///
3670    /// The outer `:membros` slot carries the M3 typed MESH-COMPOSITION
3671    /// per-Aplicacao member list — the load-bearing container of every
3672    /// per-member `{caixa, versao}` pair the caixa-mesh renderer's
3673    /// per-Aplicacao program-emission dispatch fans on at mesh-artifact
3674    /// materialization time (MESH-COMPOSITION §III.1 — the typed graph's
3675    /// vertex set the `:contratos` `:de`/`:para` edges resolve against and
3676    /// the `:entrada :para` external-gateway destination validates
3677    /// against; CAIXA-SDLC §II — the typed-M3 slot algebra the operator's
3678    /// per-Aplicacao fan-out dispatch fans on). Every per-member axis
3679    /// threads through a lifted per-entry accessor on the
3680    /// [`crate::aplicacao::Membro`] type: the
3681    /// [`crate::aplicacao::Membro::nome`] DNS-1123-label member-caixa-
3682    /// identity scalar accessor (4a32abf) and the peer
3683    /// [`crate::aplicacao::Membro::versao_requirement`] SemVer-2
3684    /// version-requirement scalar accessor (a40b0e3). Every downstream
3685    /// consumer of the mesh-graph path first passes through this outer
3686    /// accessor onto the slice and then dispatches per-member through
3687    /// the inner accessors — the two-level dispatch means every per-
3688    /// `:membros` reader now routes through a typed dispatch on the
3689    /// substrate primitive at both altitudes.
3690    ///
3691    /// Prior to this lift the `.membros` `Vec<Membro>` slot was accessed
3692    /// inline at three production sites across two files — the
3693    /// [`Self::declared_mesh_slots`] mesh-slot declared-slot
3694    /// enumerator's `!self.membros.is_empty()` presence probe
3695    /// (caixa-core/src/manifest.rs, which drives the
3696    /// `M3_AUTHOR_KEY_MEMBROS` kebab-case author-label push every
3697    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3698    /// gate reads), the [`Self::aplicacao_view`] per-Aplicacao typed-view
3699    /// composer's `self.membros.clone()` per-member fold-in path
3700    /// (caixa-core/src/manifest.rs, which materializes the typed
3701    /// [`crate::aplicacao::AplicacaoSpec`] view every
3702    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate dispatches
3703    /// on), and the [`crate::StandardLayout::verify`] per-`:membros
3704    /// :caixa` self-membership refusal probe's `&caixa.membros`-borrowed
3705    /// [`crate::aplicacao::validate_no_self_membership`] input
3706    /// (caixa-core/src/layout.rs, which pins the "no member names the
3707    /// Aplicacao's own `:nome`" cross-slot coherence gate). A future
3708    /// extension of the outer `:membros` axis (a per-cluster
3709    /// `:membros-overrides` overlay the wasm-engine operator resolves at
3710    /// admission time so a cluster-specific member-set can tighten a
3711    /// caixa-declared list without re-authoring the `caixa.lisp`,
3712    /// promotion of the plain `Vec<Membro>` to a richer
3713    /// `{static, dynamic}` partition once runtime-resolved Aplicacao
3714    /// members land as a typed axis, per-member priority annotation once
3715    /// multi-strategy fan-out lands) would have had to be threaded
3716    /// through all three open-coded copies in lockstep or one consumer
3717    /// would silently disagree with the peers on which member slice a
3718    /// given Caixa resolves to — the enumerator's presence probe reading
3719    /// the raw slot while the peer view-composer's fold-in path read an
3720    /// operator-resolved slot would silently split the paired
3721    /// declared-slot enumerator and typed-view composition, and the
3722    /// [`crate::aplicacao::validate_no_self_membership`] self-membership
3723    /// refusal probe reading a third borrow would silently drift the
3724    /// cross-slot coherence gate's traversal input from the two peers, a
3725    /// three-consumer split at the enumerator, the view composer, and
3726    /// the self-membership gate far from the source `caixa.lisp` with no
3727    /// field naming the member-set-drift root cause. Lifting the
3728    /// resolution rule to a typed method on the substrate primitive
3729    /// means every downstream consumer of the caixa's per-`Caixa`
3730    /// MESH-COMPOSITION outer-slice surface reaches for exactly one
3731    /// typed dispatch — the resolver's accept-set migrates as a unit on
3732    /// any future axis addition.
3733    ///
3734    /// Third outer top-level [`Caixa`] `&[Composite]`-return slice
3735    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the outer-
3736    /// `Caixa` M3 mesh-slot arm of the `&[Composite]` composite-slice
3737    /// sub-family the sibling M2 [`Self::upgrade_from`] (2a1f907) /
3738    /// [`Self::children`] (c17b51e) accessors opened for the M2 vec-carry
3739    /// altitude. Peer at the outer altitude of the closed inner-
3740    /// [`crate::AplicacaoSpec::membros`] (6c77e36) accessor on the same
3741    /// MESH-COMPOSITION per-Aplicacao member-list axis — the two
3742    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3743    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3744    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3745    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3746    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3747    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3748    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3749    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3750    /// pattern onto the sibling M3 typed-composite-element axis
3751    /// ([`crate::aplicacao::Membro`] composite, matching the per-inner
3752    /// [`crate::AplicacaoSpec::membros`] element type at a different
3753    /// altitude).
3754    ///
3755    /// Returns `&[crate::aplicacao::Membro]` (not `&Vec<Membro>`)
3756    /// because every downstream consumer of the member list treats it
3757    /// as a read-only sequence — the slice-view is the narrowest borrow
3758    /// that supports every present + roadmapped consumer (`.iter()`,
3759    /// `.len()`, `.is_empty()`, the
3760    /// [`crate::aplicacao::validate_no_self_membership`] `&[Membro]`
3761    /// input, `serde` slice-serialization) without leaking the backing
3762    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3763    /// reaches for (the storage-side `Vec` remains reachable through the
3764    /// `pub membros` field for the mutation-carrying serde round-trip
3765    /// and per-test fixture-mutation paths, including the
3766    /// [`Self::aplicacao_view`] fold-in path that clones the slot into
3767    /// the typed view). Named `membros()` to match the storage field's
3768    /// name verbatim and the tatara-lisp author-surface term
3769    /// (`:membros`) the field's own docstring already carries; the
3770    /// accessor's identity maps onto the canonical MESH-COMPOSITION
3771    /// vocabulary the [`Caixa::membros`] field's docstring already
3772    /// reaches for ("Member Servicos that make up this Aplicacao").
3773    #[must_use]
3774    pub const fn membros(&self) -> &[crate::aplicacao::Membro] {
3775        self.membros.as_slice()
3776    }
3777
3778    /// Substrate-canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
3779    /// composite MESH-COMPOSITION-shaped per-Aplicacao WIT-typed
3780    /// inter-Servico contract-list slice accessor every consumer of the
3781    /// top-level manifest's per-Aplicacao `&[crate::aplicacao::WitContract]`
3782    /// slice-view keys off — returns the author-declared `:contratos`
3783    /// typed `Vec<crate::aplicacao::WitContract>` verbatim as a
3784    /// `&[crate::aplicacao::WitContract]` slice-view over the same
3785    /// backing buffer the raw `self.contratos.as_slice()` field access
3786    /// borrows from. Empty-slice-carrying (the "no contracts declared"
3787    /// arm every non-`Aplicacao`-kind `defcaixa` carries by
3788    /// `#[serde(default)]` and every leaf Aplicacao carrying only a
3789    /// single member with no inter-Servico edge carries; the returned
3790    /// `&[WitContract]` degenerates to an empty slice on those arms
3791    /// without any silent `None` collapse).
3792    ///
3793    /// The outer `:contratos` slot carries the M3 typed MESH-COMPOSITION
3794    /// per-Aplicacao WIT-typed inter-Servico edge list — the load-bearing
3795    /// container of every per-edge `{de, para, wit, endpoint | subject |
3796    /// slot}` quadruple the caixa-mesh renderer's per-Aplicacao
3797    /// `CiliumNetworkPolicy` fan-out (one L7 policy per edge —
3798    /// MESH-COMPOSITION §III.2 point 2) and per-`(:de, :para)`
3799    /// adjacency-list seed dispatch on at mesh-artifact materialization
3800    /// time (MESH-COMPOSITION §III.1 — the typed graph's edge set the
3801    /// `:membros` vertex set resolves against, closed by the
3802    /// [`crate::AplicacaoError::ContractoUnknownMember`] / cycle-refusal
3803    /// gates in §III.3; CAIXA-SDLC §II — the typed-M3 slot algebra the
3804    /// operator's per-Aplicacao fan-out dispatch fans on). Every
3805    /// per-edge axis threads through a lifted per-entry accessor on the
3806    /// [`crate::aplicacao::WitContract`] type: the peer `de` / `para`
3807    /// DNS-1123-label member-caixa-name endpoint scalar accessors, the
3808    /// [`crate::aplicacao::WitContract::endpoint`] (7020470) HTTP-shape
3809    /// / [`crate::aplicacao::WitContract::subject`] (90de675)
3810    /// NATS-pub-sub-shape / [`crate::aplicacao::WitContract::slot`]
3811    /// (ed22b66) `wasi:keyvalue/store`-shape payload-carrier accessors,
3812    /// and the WIT-world discriminant. Every downstream consumer of the
3813    /// mesh-graph edge path first passes through this outer accessor
3814    /// onto the slice and then dispatches per-contract through the
3815    /// inner accessors — the two-level dispatch means every
3816    /// per-`:contratos` reader now routes through a typed dispatch on
3817    /// the substrate primitive at both altitudes.
3818    ///
3819    /// Prior to this lift the `.contratos` `Vec<WitContract>` slot was
3820    /// accessed inline at two production sites in
3821    /// caixa-core/src/manifest.rs — the [`Self::declared_mesh_slots`]
3822    /// mesh-slot declared-slot enumerator's
3823    /// `!self.contratos.is_empty()` presence probe (which drives the
3824    /// `M3_AUTHOR_KEY_CONTRATOS` kebab-case author-label push every
3825    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3826    /// gate reads) and the [`Self::aplicacao_view`] per-Aplicacao
3827    /// typed-view composer's `self.contratos.clone()` per-contract
3828    /// fold-in path (which materializes the typed
3829    /// [`crate::aplicacao::AplicacaoSpec`] view every
3830    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate and every
3831    /// downstream `caixa-mesh` renderer dispatches on). A future
3832    /// extension of the outer `:contratos` axis (a per-cluster
3833    /// `:contratos-overrides` overlay the wasm-engine operator resolves
3834    /// at admission time so a cluster-specific edge-set can tighten a
3835    /// caixa-declared list without re-authoring the `caixa.lisp`,
3836    /// promotion of the plain `Vec<WitContract>` to a richer
3837    /// `{static, dynamic}` partition once runtime-resolved contract
3838    /// edges land, per-edge policy annotation once the M4 per-edge
3839    /// policy overlay axis lands) would have had to be threaded through
3840    /// both open-coded copies in lockstep or one consumer would
3841    /// silently disagree with the peer on which edge slice a given
3842    /// Caixa resolves to — the enumerator's presence probe reading the
3843    /// raw slot while the peer view-composer's fold-in path read an
3844    /// operator-resolved slot would silently split the paired
3845    /// declared-slot enumerator and typed-view composition, a
3846    /// two-consumer split at the enumerator and the view composer far
3847    /// from the source `caixa.lisp` with no field naming the edge-set-
3848    /// drift root cause. Lifting the resolution rule to a typed method
3849    /// on the substrate primitive means every downstream consumer of
3850    /// the caixa's per-`Caixa` MESH-COMPOSITION outer-slice surface
3851    /// reaches for exactly one typed dispatch — the resolver's
3852    /// accept-set migrates as a unit on any future axis addition.
3853    ///
3854    /// Fourth and final outer top-level [`Caixa`] `&[Composite]`-return
3855    /// slice accessor for M2 / M3 typed-slot vec-carry axes — closes
3856    /// the outer-`Caixa` `&[Composite]` composite-slice sub-family the
3857    /// sibling M2 [`Self::upgrade_from`] (2a1f907) / [`Self::children`]
3858    /// (c17b51e) accessors opened and the M3 [`Self::membros`]
3859    /// (0f26987) accessor folded on, and closes the outer-`Caixa` M3
3860    /// mesh-slot arm of the composite-slice sub-family the sibling
3861    /// [`Self::membros`] accessor opened for the M3 vec-carry altitude.
3862    /// Peer at the outer altitude of the closed inner-
3863    /// [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
3864    /// same MESH-COMPOSITION per-Aplicacao contract-list axis — the two
3865    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3866    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3867    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3868    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3869    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3870    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3871    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3872    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3873    /// pattern onto the sibling M3 typed-composite-element axis
3874    /// ([`crate::aplicacao::WitContract`] composite, matching the
3875    /// per-inner [`crate::AplicacaoSpec::contratos`] element type at a
3876    /// different altitude).
3877    ///
3878    /// Returns `&[crate::aplicacao::WitContract]` (not
3879    /// `&Vec<WitContract>`) because every downstream consumer of the
3880    /// contract list treats it as a read-only sequence — the slice-view
3881    /// is the narrowest borrow that supports every present + roadmapped
3882    /// consumer (`.iter()`, `.len()`, `.is_empty()`, per-edge WIT-world
3883    /// discriminant dispatch, `serde` slice-serialization) without
3884    /// leaking the backing `Vec`'s grow/push/reserve surface no
3885    /// consumer of the typed view reaches for (the storage-side `Vec`
3886    /// remains reachable through the `pub contratos` field for the
3887    /// mutation-carrying serde round-trip and per-test fixture-mutation
3888    /// paths, including the [`Self::aplicacao_view`] fold-in path that
3889    /// clones the slot into the typed view). Named `contratos()` to
3890    /// match the storage field's name verbatim and the tatara-lisp
3891    /// author-surface term (`:contratos`) the field's own docstring
3892    /// already carries; the accessor's identity maps onto the canonical
3893    /// MESH-COMPOSITION vocabulary the [`Caixa::contratos`] field's
3894    /// docstring already reaches for ("WIT-typed inter-Servico
3895    /// contracts").
3896    #[must_use]
3897    pub const fn contratos(&self) -> &[crate::aplicacao::WitContract] {
3898        self.contratos.as_slice()
3899    }
3900
3901    /// Compose the Aplicacao-related flat slots into a single typed
3902    /// [`crate::aplicacao::AplicacaoSpec`] for validation +
3903    /// downstream renderer consumption. Returns `None` when the
3904    /// caixa isn't a `:kind Aplicacao`.
3905    #[must_use]
3906    pub fn aplicacao_view(&self) -> Option<crate::aplicacao::AplicacaoSpec> {
3907        if !self.kind().is_aplicacao() {
3908            return None;
3909        }
3910        Some(crate::aplicacao::AplicacaoSpec {
3911            membros: self.membros().to_vec(),
3912            contratos: self.contratos().to_vec(),
3913            politicas: self.politicas().cloned().unwrap_or_default(),
3914            placement: self.placement().cloned().unwrap_or_default(),
3915            entrada: self.entrada().cloned(),
3916        })
3917    }
3918
3919    /// The kebab-case `:slot` tags of every M3 mesh slot this caixa
3920    /// *declares* a value on, in canonical declaration order
3921    /// (`:membros` → `:contratos` → `:politicas` → `:placement` →
3922    /// `:entrada`). A slot counts as declared when its backing field
3923    /// carries a value — a non-empty `Vec`, or a `Some(...)`.
3924    ///
3925    /// The M3 mesh slots compose the typed graph of a `:kind Aplicacao`
3926    /// (MESH-COMPOSITION §III.1). [`Self::aplicacao_view`] only folds
3927    /// them into a validatable [`crate::aplicacao::AplicacaoSpec`] when
3928    /// the kind matches (returns `None` otherwise), and the caixa-mesh /
3929    /// caixa-flux / caixa-helm renderers only emit them for an
3930    /// Aplicacao. On any *other* kind a declared mesh slot is the
3931    /// manifest field's documented "ignored otherwise" (see the
3932    /// `:membros` … `:entrada` field docs): it silently passes
3933    /// [`Caixa::from_lisp`] and then vanishes — never validated, never
3934    /// rendered — far from the source caixa.lisp.
3935    /// [`crate::StandardLayout::verify`] consults this to reject that
3936    /// silent-drop at caixa-build time
3937    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]), mirroring the
3938    /// `SupervisorOwnsCode` / `AplicacaoOwnsCode` kind-coherence gates:
3939    /// a slot foreign to the kind is a build error, not a silent drop.
3940    ///
3941    /// Lifted as a typed method (rather than an inline disjunction at
3942    /// the verify call site) so the mesh-slot set lives in one place —
3943    /// a future M4 axis added to the Aplicacao surface (per-edge policy
3944    /// overlay, distributed-app takeover config) is one push here, and
3945    /// every consumer reaching for "which mesh slots are set" (the
3946    /// verify gate, a future `feira lint` kind-coherence advisory)
3947    /// inherits the canonical order without rolling its own.
3948    ///
3949    /// Each per-arm kebab-case label is routed through the peer
3950    /// [`crate::M3_AUTHOR_KEY_MEMBROS`] /
3951    /// [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
3952    /// [`crate::M3_AUTHOR_KEY_POLITICAS`] /
3953    /// [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
3954    /// [`crate::M3_AUTHOR_KEY_ENTRADA`] consts declared next to the
3955    /// [`crate::M3_KEY_PLACEMENT`] renderer-side wire-key peer, so both
3956    /// halves of every M3 top-level mesh slot's dual axis (author-facing
3957    /// kebab-case label + renderer-side artifact key) route through one
3958    /// canonical declaration per arm — same discipline the peer
3959    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`]
3960    /// / [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot consts
3961    /// (f49c8b0) establish on the sibling per-Servico M2 top-level slot
3962    /// axis, extended here to close the M3 mesh-slot author-facing-label
3963    /// axis so both altitudes of the typed-slot algebra
3964    /// (per-Servico M2 + per-Aplicacao M3) share the same
3965    /// "one canonical byte-string per arm, next to the axis" discipline.
3966    #[must_use]
3967    pub fn declared_mesh_slots(&self) -> Vec<&'static str> {
3968        let mut slots = Vec::new();
3969        if !self.membros().is_empty() {
3970            slots.push(crate::render::M3_AUTHOR_KEY_MEMBROS);
3971        }
3972        if !self.contratos().is_empty() {
3973            slots.push(crate::render::M3_AUTHOR_KEY_CONTRATOS);
3974        }
3975        if self.politicas().is_some() {
3976            slots.push(crate::render::M3_AUTHOR_KEY_POLITICAS);
3977        }
3978        if self.placement().is_some() {
3979            slots.push(crate::render::M3_AUTHOR_KEY_PLACEMENT);
3980        }
3981        if self.entrada().is_some() {
3982            slots.push(crate::render::M3_AUTHOR_KEY_ENTRADA);
3983        }
3984        slots
3985    }
3986
3987    /// The kebab-case `:slot` tags of every supervisor-tree slot this
3988    /// caixa *declares* a value on, in canonical declaration order
3989    /// (`:estrategia` → `:max-restarts` → `:restart-window` →
3990    /// `:children`). A slot counts as declared when its backing field
3991    /// carries a value — a `Some(...)`, or a non-empty `Vec`.
3992    ///
3993    /// The supervisor-tree slots compose the typed OTP supervisor of a
3994    /// `:kind Supervisor` (INSPIRATIONS §II.2; the `:estrategia` +
3995    /// `:children` field docs above). [`Self::supervisor_view`] only
3996    /// folds them into a validatable [`SupervisorSpec`] when the kind
3997    /// matches (returns `None` otherwise), and the wasm-operator's
3998    /// hierarchical reconciler only consumes them for a Supervisor. On
3999    /// any *other* kind a declared supervisor slot is the manifest
4000    /// field's documented "ignored otherwise" (see the `:estrategia` …
4001    /// `:children` field docs): it silently passes [`Caixa::from_lisp`]
4002    /// and then vanishes — never validated, never reconciled — far from
4003    /// the source caixa.lisp. [`crate::StandardLayout::verify`] consults
4004    /// this to reject that silent-drop at caixa-build time
4005    /// ([`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]), the
4006    /// exact mirror of the [`Self::declared_mesh_slots`] /
4007    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] gate on the
4008    /// Aplicacao-only slot set: a slot foreign to the kind is a build
4009    /// error, not a silent drop.
4010    #[must_use]
4011    pub fn declared_supervisor_slots(&self) -> Vec<&'static str> {
4012        let mut slots = Vec::new();
4013        if self.estrategia().is_some() {
4014            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA);
4015        }
4016        if self.max_restarts().is_some() {
4017            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS);
4018        }
4019        if self.restart_window().is_some() {
4020            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW);
4021        }
4022        if !self.children().is_empty() {
4023            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN);
4024        }
4025        slots
4026    }
4027
4028    /// The kebab-case `:slot` tags of every M2 Servico-runtime slot this
4029    /// caixa *declares* a value on, in canonical declaration order
4030    /// (`:limits` → `:behavior` → `:upgrade-from`). A slot counts as
4031    /// declared when its backing field carries a value — a `Some(...)`,
4032    /// or a non-empty `Vec`.
4033    ///
4034    /// The M2 slots configure the runtime of a long-running wasm
4035    /// component, i.e. a `:kind Servico`: `:limits` is Lunatic
4036    /// per-process sandboxing (INSPIRATIONS §III.1), `:behavior` is the
4037    /// OTP `gen_server` callback set (§II.3), `:upgrade-from` is the OTP
4038    /// appup hot-code-reload table (§II.4). The caixa-helm / caixa-flux
4039    /// renderers gate on [`crate::require_kind`]`(_, Servico)` and only
4040    /// emit these slots for a Servico; on any *other* kind a declared M2
4041    /// slot is the manifest field's documented "ignored otherwise": its
4042    /// well-formedness is checked by [`crate::StandardLayout::verify`]
4043    /// but the value is never rendered into a chart / programs.yaml entry
4044    /// — it silently passes [`Caixa::from_lisp`] + `feira build` and then
4045    /// vanishes, far from the source caixa.lisp.
4046    /// [`crate::StandardLayout::verify`] consults this to reject that
4047    /// silent-drop at caixa-build time
4048    /// ([`crate::LayoutError::ServicoSlotsOnNonServico`]), the exact
4049    /// mirror of the [`Self::declared_mesh_slots`] /
4050    /// [`Self::declared_supervisor_slots`] gates on the peer
4051    /// kind-exclusive slot sets: a slot foreign to the kind is a build
4052    /// error, not a silent drop.
4053    ///
4054    /// Each per-arm kebab-case label is routed through the peer
4055    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
4056    /// [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts declared next to the
4057    /// [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
4058    /// [`crate::M2_KEY_UPGRADE_FROM`] renderer-side wire-key peers, so
4059    /// both halves of the M2 top-level slot's dual axis (author-facing
4060    /// kebab-case label + renderer-side camelCase overlay-container wire
4061    /// key) route through one canonical declaration per arm — same
4062    /// discipline the peer [`crate::M2_BEHAVIOR_AUTHOR_KEY_ON_*`] sub-slot
4063    /// author-label consts (889dc18) establish on the sibling
4064    /// per-callback axis inside the `:behavior` overlay block.
4065    #[must_use]
4066    pub fn declared_servico_slots(&self) -> Vec<&'static str> {
4067        let mut slots = Vec::new();
4068        if self.limits().is_some() {
4069            slots.push(crate::render::M2_AUTHOR_KEY_LIMITS);
4070        }
4071        if self.behavior().is_some() {
4072            slots.push(crate::render::M2_AUTHOR_KEY_BEHAVIOR);
4073        }
4074        if !self.upgrade_from().is_empty() {
4075            slots.push(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM);
4076        }
4077        slots
4078    }
4079
4080    /// The kebab-case `:slot` tags of every code-surface slot this caixa
4081    /// declares a value on that its [`CaixaKind`] doesn't natively own,
4082    /// in canonical declaration order (`:exe` → `:servicos`). A
4083    /// code-surface slot is owned by exactly one kind: `:exe` by
4084    /// [`CaixaKind::Binario`] (the nix-built executable surface), and
4085    /// `:servicos` by [`CaixaKind::Servico`] (the wasm component +
4086    /// `ComputeUnit` daemon surface).
4087    ///
4088    /// Each is silently ignored when declared on the wrong kind: the
4089    /// caixa-helm / caixa-flux / caixa-flake renderers gate on
4090    /// [`crate::require_kind`]`(_, <owning-kind>)`, so on any *other*
4091    /// code-running kind a declared `:exe` / `:servicos` is the manifest
4092    /// field's documented "ignored otherwise" — its path is checked for
4093    /// existence by the layout's `bibliotecas`/`exe`/`servicos` loops
4094    /// (which run after [`Caixa::from_lisp`]), but the value is never
4095    /// rendered into a build target or programs.yaml entry. It silently
4096    /// passes [`Caixa::from_lisp`] + `feira build`, far from the source
4097    /// caixa.lisp, with no field naming which slot is foreign.
4098    ///
4099    /// [`crate::StandardLayout::verify`] consults this to reject that
4100    /// silent-drop at caixa-build time
4101    /// ([`crate::LayoutError::ForeignCodeSlot`]), beside the M2
4102    /// servico-runtime, supervisor-tree, and M3 mesh kind-coherence
4103    /// gates ([`Self::declared_servico_slots`] /
4104    /// [`Self::declared_supervisor_slots`] /
4105    /// [`Self::declared_mesh_slots`]): the fourth kind ↔ slot algebra
4106    /// axis to be closed on the typed surface. The Supervisor /
4107    /// Aplicacao "no code at all" cases ([`crate::LayoutError::SupervisorOwnsCode`]
4108    /// / [`crate::LayoutError::AplicacaoOwnsCode`]) keep their dedicated
4109    /// diagnostics — they fire ahead of this gate on the same `verify`
4110    /// pass, so for Supervisor / Aplicacao the `OwnCode` arm always wins
4111    /// and this method is moot. For Biblioteca / Binario / Servico, this
4112    /// gate fires when a code-running kind declares another code-running
4113    /// kind's exclusive code surface.
4114    ///
4115    /// `:bibliotecas` is deliberately excluded — a Binario or Servico
4116    /// may legitimately ship a `lib/` helper that the underlying
4117    /// substrate (the nix flake for Binario, the wasm component build
4118    /// for Servico) bundles into its build, so the slot's
4119    /// declared-on-wrong-kind cardinality isn't a structural error on
4120    /// either code-running kind. A Biblioteca declaring `:bibliotecas`
4121    /// is the native case (the slot's owning kind). Supervisor /
4122    /// Aplicacao declaring `:bibliotecas` is gated upstream by
4123    /// [`crate::LayoutError::SupervisorOwnsCode`] /
4124    /// [`crate::LayoutError::AplicacaoOwnsCode`].
4125    ///
4126    /// Lifted as a typed method (rather than an inline disjunction at
4127    /// the verify call site) so the foreign-code-slot set lives in one
4128    /// place — a future kind that gains its own code-surface slot is
4129    /// one push here, and every consumer reaching for "which code
4130    /// surfaces are foreign to this kind" (the verify gate, a future
4131    /// `feira lint` kind-coherence advisory, the future `app-operator`'s
4132    /// per-caixa build-target classifier) inherits the canonical order
4133    /// without rolling its own.
4134    #[must_use]
4135    pub fn declared_foreign_code_slots(&self) -> Vec<&'static str> {
4136        let mut slots = Vec::new();
4137        if !self.exe().is_empty() && !self.kind().requires_exe() {
4138            slots.push(":exe");
4139        }
4140        if !self.servicos().is_empty() && !self.kind().requires_servicos() {
4141            slots.push(":servicos");
4142        }
4143        slots
4144    }
4145
4146    /// Validate every entry of `:deps` and `:deps-dev` through
4147    /// [`Dep::validate`] — closing the parity loop with the per-axis
4148    /// `:versao` gates already wired into the typed-graph
4149    /// ([`crate::AplicacaoSpec::validate_membros`] for `:membros`,
4150    /// 9888b13) and typed supervisor tree
4151    /// ([`crate::SupervisorSpec::validate`] for `:children`, b38ff3a).
4152    ///
4153    /// Until this gate landed `:deps :versao` and `:deps-dev :versao`
4154    /// were the only `:versao` axes still untyped past
4155    /// [`Caixa::from_lisp`]: the derive macro stored the requirement
4156    /// as a String without parsing it, so a malformed-but-non-empty
4157    /// requirement (`"^bad-version"`, `"^^0.1"`, `"v0.1"`, `"not-a-req"`)
4158    /// silently passed parse and the `semver::Error` surfaced at
4159    /// lacre-resolve time, far from the source caixa.lisp, with no
4160    /// field naming which `:deps` entry carried the typo. Lifting the
4161    /// gate here makes the four `:versao` typed surfaces (`:deps`,
4162    /// `:deps-dev`, `:membros`, `:children`) structurally equivalent —
4163    /// every requirement string past `validate_deps` is round-trippable
4164    /// through [`crate::parse_requirement`] without re-checking at the
4165    /// resolver layer.
4166    ///
4167    /// Both lists run through the same per-entry validator so a typo
4168    /// in `:deps-dev` surfaces with the same diagnostic as one in
4169    /// `:deps` — neither axis is a second-class citizen of the typed
4170    /// surface.
4171    ///
4172    /// Within each list, [`DepError::DuplicateNome`] closes the
4173    /// set-not-multiset discipline on the `:nome` axis: two entries
4174    /// naming the same caixa carry two `:versao` / `:fonte` / feature
4175    /// triples that the caixa-resolver's lacre pipeline collapses to one
4176    /// via its `HashMap`-keyed-by-`:nome` consumption — the second entry
4177    /// silently overwrites the first at `concrete_versao`-resolve time
4178    /// (the same "second wins / one silently overwrites the other"
4179    /// shape the peer typed-graph duplicate gates already close on every
4180    /// other Vec-shaped authoring surface that keys by name). The
4181    /// duplicate check fires per-list and runs *after* each per-entry
4182    /// [`Dep::validate`] call so a malformed-and-duplicated entry
4183    /// surfaces its narrower per-entry diagnostic
4184    /// ([`DepError::NomeInvalid`], [`DepError::VersaoInvalid`],
4185    /// [`DepError::FonteRepoEmpty`], …) before the cross-entry duplicate
4186    /// diagnostic — the canonical "per-entry shape before cross-entry
4187    /// uniqueness" precedence the peer `:children :caixa`
4188    /// ([`crate::SupervisorSpec::validate`]), `:membros :caixa`
4189    /// ([`crate::AplicacaoSpec::validate_membros`]), `:contratos`
4190    /// ([`crate::AplicacaoSpec::validate`]), `:placement :clusters`
4191    /// ([`crate::AplicacaoSpec::validate_placement`]),
4192    /// `:entrada :paths` ([`crate::AplicacaoSpec::validate`]),
4193    /// `:upgrade-from :from` ([`crate::upgrade::validate_upgrade_from`]),
4194    /// and the within-`:upgrade-from`-entry per-instruction-class
4195    /// singularity gates ([`crate::UpgradeError::DuplicateLoadModule`],
4196    /// [`crate::UpgradeError::DuplicateStateChange`],
4197    /// [`crate::UpgradeError::DuplicateCleanup`]) all establish.
4198    ///
4199    /// Cross-list (`:deps` ↔ `:deps-dev`) coincidence is *not* gated
4200    /// here: Cargo's `[dependencies]` + `[dev-dependencies]` accept the
4201    /// same name in both tables (the dev table's pin overrides the
4202    /// runtime table's pin in test/dev contexts), and caixa's surface
4203    /// mirrors that convention until a deliberate choice retires the
4204    /// override pattern. Only within-list duplicates are structurally
4205    /// incoherent — those are what this gate closes.
4206    ///
4207    /// Compound per-`Caixa` entry gate on the dep-graph axis: folds the
4208    /// two standalone dep-list validators — the per-entry + within-list
4209    /// duplicate-`:nome` walk (the [`Dep::validate`] +
4210    /// [`crate::render::insert_first_seen`] cascade this method opened
4211    /// on) and the cross-slot self-edge gate
4212    /// ([`crate::dep::validate_no_self_dep`]) — onto one substrate
4213    /// primitive on [`Caixa`]. The two arms run in the same canonical
4214    /// order the layout pipeline
4215    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4216    /// author-time gate) has always sequenced them (per-entry +
4217    /// cross-entry duplicate → cross-slot self-edge), so the fold is
4218    /// byte-for-byte equivalent to the pre-fold two-block cascade at
4219    /// that call site (pinned by the paired
4220    /// `validate_deps_folds_per_entry_arm_matches_gate` /
4221    /// `validate_deps_folds_self_edge_arm_matches_gate` equivalence
4222    /// pins and the `validate_deps_per_entry_arm_fires_before_self_edge_arm`
4223    /// ordering pin). Self-contained on `&self` — resolves its three
4224    /// inputs ([`Self::deps`], [`Self::deps_dev`], [`Self::nome`])
4225    /// through the substrate primitives' own accessor family, the same
4226    /// posture every peer per-slot compound gate
4227    /// ([`crate::AplicacaoSpec::validate_contratos`],
4228    /// [`crate::MeshPolicy::validate`],
4229    /// [`crate::SupervisorSpec::validate_children`],
4230    /// [`Self::validate_upgrade_from`]) already carries.
4231    ///
4232    /// Prior to this lift [`crate::dep::validate_no_self_dep`] lived
4233    /// only open-coded at the layout wire-up site
4234    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs)
4235    /// as a standalone two-arg dispatch immediately after this method's
4236    /// per-entry + cross-entry walk, both wrapped through the same
4237    /// [`crate::LayoutError::DepsViolation`] envelope: every future
4238    /// consumer that wanted to gate the dep-graph as a whole — the
4239    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4240    /// per-CR admission webhook re-checking `:deps` / `:deps-dev` after
4241    /// a per-entry patch, a future `feira validate --deps` per-caixa
4242    /// admission verb, a per-`:deps` overlay resolver a per-cluster
4243    /// overlay lift would materialize (each the deferred consumer this
4244    /// method's peer [`Self::deps`] / [`Self::deps_dev`] accessors'
4245    /// docstrings already name) — was structurally forced to either
4246    /// re-inline the two-dispatch cascade in lockstep with the layout
4247    /// wire-up (the duplication the PRIME DIRECTIVE names as a bug) or
4248    /// call the whole [`crate::layout::StandardLayout::verify`] pipeline
4249    /// and pay every peer per-Caixa gate to re-check one slot. Post-fold
4250    /// each such consumer reaches the two-arm compound gate through one
4251    /// call on the substrate primitive.
4252    pub fn validate_deps(&self) -> Result<(), DepError> {
4253        for &list in crate::dep::DepList::ALL {
4254            let mut seen = std::collections::HashSet::new();
4255            for dep in self.deps_of(list) {
4256                dep.validate()?;
4257                crate::render::insert_first_seen(&mut seen, dep.nome(), || {
4258                    DepError::duplicate_nome(dep.nome(), list.as_str())
4259                })?;
4260            }
4261        }
4262        crate::dep::validate_no_self_dep(self.deps(), self.deps_dev(), self.nome())?;
4263        Ok(())
4264    }
4265
4266    /// Run a per-slot typed validator on `self` and, on the per-arm
4267    /// parser-side error arm, thread the error into a paired
4268    /// [`crate::LayoutError`] wrap under `self.nome()`. Substrate
4269    /// primitive folding the 18 self-similar layout-pipeline wire-up
4270    /// sites at [`crate::layout::StandardLayout::verify`] that carry
4271    /// the identical
4272    /// `caixa.validate_<slot>().map_err(|err| crate::LayoutError::<slot>_violation(caixa, err))?;`
4273    /// cascade onto one dispatch. Each of the eighteen sites (`:nome`,
4274    /// `:nome`-chart-name-budget, `:versao`, `:deps`, `:etiquetas`,
4275    /// `:autores`, `:repositorio`, `:descricao`, `:licenca`, `:edicao`,
4276    /// `:bibliotecas`/`:exe`/`:servicos` code-path shape, `:limits`,
4277    /// `:behavior`, `:upgrade-from`, `:restart-window`, per-Supervisor
4278    /// shape, per-Aplicacao shape, per-Acao shape) carried the same
4279    /// four-line "run a per-slot typed validator on `caixa` and, on the
4280    /// per-arm parser-side error arm, thread it into the paired
4281    /// [`crate::LayoutError`] one-slot envelope through the substrate-
4282    /// canonical `layout_violation_ctors!` family (131ca0d)" cascade,
4283    /// differing only in the two names bound at each site — the
4284    /// validator (`Caixa::validate_deps` / `validate_nome` / ...) and
4285    /// the paired ctor (`LayoutError::deps_violation` / ...). Eighteen
4286    /// consumers, one identical shape, one substrate primitive on
4287    /// [`Caixa`] closing the duplication the PRIME DIRECTIVE names as
4288    /// a bug — on the second half of the per-slot cascade the peer
4289    /// substrate primitives on the [`crate::LayoutError`]-wrap side
4290    /// (the `layout_violation_ctors!` macro 131ca0d, the
4291    /// `layout_slot_kind_ctors!` macro 0419438, the `layout_nome_only_ctors!`
4292    /// macro 3fe3dd7, the [`crate::LayoutError::missing_entry`] ctor
4293    /// 1b09f9d, the [`crate::layout::StandardLayout::probe_declared_entry`]
4294    /// primitive fda1e35) each closed on their sibling envelopes; the
4295    /// first half of the cascade (the per-slot compound gates
4296    /// [`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
4297    /// baa4688, [`Self::validate_behavior`] 0d2877a,
4298    /// [`Self::validate_upgrade_from`] d6801df,
4299    /// [`Self::validate_aplicacao_shape`] 949a7a0,
4300    /// [`Self::validate_supervisor_shape`] 4c70105,
4301    /// [`Self::validate_acao_shape`] 5d6df54,
4302    /// [`Self::validate_kind_slot_coherence`] f0d286e,
4303    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
4304    /// [`Self::validate_ci_kind_coherence`] 9b55beb,
4305    /// [`Self::validate_required_kind_slot`] 9c385d8) each closed on
4306    /// their per-slot compound gates.
4307    ///
4308    /// Composes the [`crate::layout::LayoutError`] wrap and the per-slot
4309    /// typed validator through two typed callables: `gate` runs on
4310    /// `self` and yields a per-slot error `E`; on the `Err(E)` arm
4311    /// `wrap` re-wraps that error under `self` into a
4312    /// [`crate::layout::LayoutError`]. The `Ok(())` arm passes through
4313    /// verbatim as the fold's identity element — byte-equal to the
4314    /// pre-lift `Result::map_err` short-circuit at the `?;` marker
4315    /// every wire-up site formerly carried. Every future consumer that
4316    /// wants to run one of the per-slot gates and thread its error
4317    /// through the layout wrap (the deferred
4318    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission-
4319    /// webhook per-slot re-check, a future `feira validate --<slot>`
4320    /// per-caixa admission verb, an overlay resolver re-running one
4321    /// gate after a per-slot patch) reaches the two-callable dispatch
4322    /// through one call rather than re-inlining the four-line cascade
4323    /// in lockstep with the pre-existing 18 wire-ups. The two callables
4324    /// reach the primitive as first-class type-checked references
4325    /// rather than the pre-lift `.map_err(|err| CTOR(caixa, err))`
4326    /// closure body — so a mismatch between the validator's `E` type
4327    /// and the ctor's `E` bound trips at the wire-up site (compile-
4328    /// time) rather than at the closure body (also compile-time, but
4329    /// with a diagnostic pointing at the closure expression rather
4330    /// than the two named callables).
4331    pub fn run_layout_gate<E, W>(
4332        &self,
4333        gate: impl FnOnce(&Caixa) -> Result<(), E>,
4334        wrap: W,
4335    ) -> Result<(), crate::LayoutError>
4336    where
4337        W: FnOnce(&Caixa, E) -> crate::LayoutError,
4338    {
4339        gate(self).map_err(|err| wrap(self, err))
4340    }
4341
4342    /// Run one arm of the cross-family kind ↔ owned-slot-family
4343    /// coherence cascade on `self`: on a caixa whose [`Self::kind`] does
4344    /// not own the typed-slot family named by `is_owner`, refuse when
4345    /// the paired `accumulator` reports any declared slot in that
4346    /// family; otherwise pass. Substrate primitive folding the three
4347    /// self-similar four-line
4348    /// `if !self.kind().is_<owner>() { let slots = self.declared_<family>_slots();
4349    /// if !slots.is_empty() { return Err(<wrap>(self, slots)); } }`
4350    /// arms at [`Self::validate_kind_slot_coherence`] onto one dispatch.
4351    /// Three consumers (M3 mesh — Aplicacao-owner, supervisor-tree —
4352    /// Supervisor-owner, M2 Servico-runtime — Servico-owner), one
4353    /// identical shape, one substrate primitive on [`Caixa`] closing
4354    /// the duplication the PRIME DIRECTIVE names as a bug on the
4355    /// outer kind-coherence arm shape — peer with the substrate
4356    /// primitives on the two adjacent halves of the same three-arm
4357    /// cascade the sibling [`Self::declared_mesh_slots`] /
4358    /// [`Self::declared_supervisor_slots`] /
4359    /// [`Self::declared_servico_slots`] accumulator family closes on
4360    /// the inner slot-set enumerator axis and the sibling
4361    /// [`crate::layout::layout_slot_kind_ctors!`] macro (0419438)
4362    /// closes on the inner wrap-envelope ctor axis. Each of the three
4363    /// [`Self::validate_kind_slot_coherence`] arms now reads through
4364    /// one call across every altitude of the per-arm cascade:
4365    /// one dispatch on this primitive for the outer guard shape, one
4366    /// dispatch on `Self::declared_<family>_slots` for the accumulator,
4367    /// one dispatch on `crate::LayoutError::<family>_on_non_<owner>`
4368    /// for the wrap ctor.
4369    ///
4370    /// Composes the outer owner-kind guard, the per-family accumulator,
4371    /// and the per-family wrap ctor through three typed callables:
4372    /// `is_owner` runs on `&self.kind()` (a `&CaixaKind` borrow so the
4373    /// `gen_platform::IsVariant`-derived `fn(&CaixaKind) -> bool`
4374    /// per-arm predicates — [`crate::CaixaKind::is_aplicacao`] /
4375    /// [`crate::CaixaKind::is_supervisor`] / [`crate::CaixaKind::is_servico`]
4376    /// — pass verbatim as function references), `accumulator` runs on
4377    /// `&self` and yields the
4378    /// per-family declared-slot list, and `wrap` runs on `(&self,
4379    /// Vec<&'static str>)` and yields the per-family
4380    /// [`crate::LayoutError`] wrap. The `is_owner` short-circuit fires
4381    /// before the accumulator dispatch (so the owner kind of each
4382    /// family passes without invoking `accumulator`, byte-equal to the
4383    /// pre-lift `if !self.kind().is_<owner>() { … }` outer guard's
4384    /// short-circuit — pinned by
4385    /// `run_kind_owned_slot_family_gate_owner_kind_short_circuits_before_accumulator`),
4386    /// and the accumulator's `is_empty` short-circuit fires before the
4387    /// wrap dispatch (so a non-owner kind with no declared slot in that
4388    /// family passes without invoking `wrap`, byte-equal to the pre-lift
4389    /// `if !<slots>.is_empty() { … }` inner guard's short-circuit —
4390    /// pinned by
4391    /// `run_kind_owned_slot_family_gate_empty_accumulator_short_circuits_before_wrap`).
4392    /// The wrap ctor is `FnOnce(&Caixa, Vec<&'static str>) ->
4393    /// crate::LayoutError` — matching the [`crate::layout::layout_slot_kind_ctors!`]
4394    /// macro's per-variant `fn(&Caixa, Vec<&'static str>) -> LayoutError`
4395    /// substrate-canonical ctor shape verbatim, so
4396    /// [`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
4397    /// [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
4398    /// [`crate::LayoutError::servico_slots_on_non_servico`] pass as
4399    /// function references without a closure wrap. A mismatch between
4400    /// the ctor's signature and this bound trips at the wire-up site
4401    /// (compile-time) rather than at a closure body.
4402    ///
4403    /// The sibling [`crate::LayoutError::ForeignCodeSlot`] gate on the
4404    /// code-surface family sits outside this primitive because
4405    /// [`Self::declared_foreign_code_slots`] bakes the per-arm kind-
4406    /// check into the accumulator itself (each arm's
4407    /// `!self.kind().requires_<slot>()` guard fires inside the
4408    /// accumulator, not around it), so the code-surface arm carries no
4409    /// outer `is_owner`-shaped guard and its dispatch reads through
4410    /// [`Self::validate_foreign_code_kind_coherence`] verbatim without
4411    /// this primitive — the same posture the `_no_code_` /
4412    /// `_ci_kind_` coherence axes take on their respective per-arm
4413    /// shapes. The primitive here is specific to the "outer
4414    /// non-owner-kind guard + inner accumulator + inner emptiness
4415    /// guard + wrap" arm shape that fires three times in
4416    /// [`Self::validate_kind_slot_coherence`].
4417    ///
4418    /// Every future consumer that wants to gate one kind-owned slot
4419    /// family as a unit outside the composed cascade (the deferred
4420    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission-
4421    /// webhook per-family re-check after a per-slot patch, a future
4422    /// `feira validate --<family>-coherence` per-caixa admission verb,
4423    /// a per-`Caixa` overlay resolver rejecting a kind-foreign patch
4424    /// on one family) reaches the four-line arm through one call
4425    /// rather than re-inlining the outer-guard + accumulator +
4426    /// emptiness-guard + wrap cascade in lockstep with the pre-existing
4427    /// three arms. Every future kind-owned typed-slot family (an
4428    /// `Actor`-owned per-virtual-actor grain slot the M5 Orleans-
4429    /// inspired kind reaches through, a per-Aplicacao overlay slot the
4430    /// M4 CR materializer consults) folds onto
4431    /// [`Self::validate_kind_slot_coherence`] as one additional
4432    /// dispatch on this primitive rather than a fourth open-coded
4433    /// four-line block.
4434    pub fn run_kind_owned_slot_family_gate<F, A, W>(
4435        &self,
4436        is_owner: F,
4437        accumulator: A,
4438        wrap: W,
4439    ) -> Result<(), crate::LayoutError>
4440    where
4441        F: FnOnce(&crate::CaixaKind) -> bool,
4442        A: FnOnce(&Caixa) -> Vec<&'static str>,
4443        W: FnOnce(&Caixa, Vec<&'static str>) -> crate::LayoutError,
4444    {
4445        if is_owner(&self.kind()) {
4446            return Ok(());
4447        }
4448        let slots = accumulator(self);
4449        if slots.is_empty() {
4450            return Ok(());
4451        }
4452        Err(wrap(self, slots))
4453    }
4454
4455    /// Reject `:nome` values the K8s apiserver would refuse at admission
4456    /// time. The top-level Caixa identity flows directly into every
4457    /// substrate-side artifact's `metadata.name` axis: the
4458    /// `lareira-<nome>` Helm chart name ([`caixa-helm::lib::chart_name`]),
4459    /// the programs.yaml `name:` entry the `lareira-fleet-programs`
4460    /// aggregator keys ComputeUnit derivation off
4461    /// ([`caixa-flux::lib::programs_yaml_entry`]), the
4462    /// `LABEL_APLICACAO` label value carried on every Aplicacao-owned
4463    /// pod and the per-`:contratos` CiliumNetworkPolicy `metadata.name`
4464    /// (`<aplicacao>-<de>-to-<para>`) and the per-`:entrada`
4465    /// `<aplicacao>-<para>` HTTPRoute `metadata.name`
4466    /// ([`caixa-mesh::lib::cilium_network_policies`],
4467    /// [`caixa-mesh::lib::gateway_routes`]), and the default
4468    /// `lib/<nome>.lisp` / `exe/<nome>` layout paths
4469    /// ([`crate::StandardLayout::verify`]). Each K8s apiserver-side
4470    /// schema enforces the DNS-1123 label rule on admission; a
4471    /// structurally invalid `:nome` (`"MyApp"` — the canonical
4472    /// "I copied the display name verbatim" footgun, `"my_app"` — the
4473    /// Python-/Postgres-leak, `"team.app"` — `:nome` is a single label
4474    /// not a subdomain, `"-app"` / `"app-"` — DNS-1123 boundary
4475    /// violations, `"my app"` — the paste-from-doc footgun, `"café"` —
4476    /// IDN must be pre-encoded as Punycode, the 64-byte UUID-shaped
4477    /// over-cap slug) silently passed [`Caixa::from_lisp`] and the
4478    /// failure surfaced at `kubectl apply` time as a `metadata.name:
4479    /// Invalid value` rejection on whichever derived artifact admitted
4480    /// first, far from the source `caixa.lisp` and without any field
4481    /// naming the offending `:nome`.
4482    ///
4483    /// Thin wrapper around [`crate::render::is_dns_1123_label`] (the
4484    /// substrate-side predicate the per-axis name gates already share:
4485    /// `:membros :caixa` 3f9d7a0, `:placement :clusters` 6cbb900,
4486    /// `:children :caixa` 31bfa43) that maps the shared parser-shaped
4487    /// reason into the [`ManifestError::NomeInvalid`] variant, so the
4488    /// diagnostic is self-locating (the offending `:nome` is named
4489    /// verbatim) and the author can grep their `caixa.lisp` for
4490    /// `:nome "<value>"` and fix it in one edit. Same diagnostic shape
4491    /// every per-axis sibling gate already exposes
4492    /// ([`crate::AplicacaoError::MembroCaixaInvalid`],
4493    /// [`crate::AplicacaoError::PlacementClusterInvalid`],
4494    /// [`crate::SupervisorError::ChildCaixaInvalid`]).
4495    ///
4496    /// Empty `:nome` (which [`Caixa::from_lisp`] does not reject — the
4497    /// derive macro stores the raw String) is gated by the narrower
4498    /// [`ManifestError::NomeEmpty`] arm before the predicate is
4499    /// consulted, mirroring the empty-first cascade every per-axis
4500    /// name gate already uses (e.g. `MembroCaixaEmpty` before
4501    /// `MembroCaixaInvalid`, `EmptyChildName` before `ChildCaixaInvalid`).
4502    pub fn validate_nome(&self) -> Result<(), ManifestError> {
4503        // Routes through the shared
4504        // [`crate::render::require_valid_dns_1123_label`] gate the peer
4505        // name axes each land on so drift between the eight axes'
4506        // accepted DNS-1123-label sets is structurally impossible.
4507        let nome = self.nome();
4508        crate::render::require_valid_dns_1123_label(
4509            nome,
4510            || ManifestError::NomeEmpty,
4511            |reason| ManifestError::nome_invalid(nome, reason),
4512        )
4513    }
4514
4515    /// Reject `:nome` values whose joint length with the canonical
4516    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] (`"lareira-"`) overflows
4517    /// the K8s DNS-1123 label cap [`crate::DNS_1123_LABEL_MAX_LEN`]
4518    /// (63 bytes). Every per-Servico / per-Aplicacao renderer the
4519    /// substrate carries materializes the caixa's `:nome` through the
4520    /// canonical [`crate::lareira_chart_name`] helper (f7320d7) into a
4521    /// `lareira-<nome>` artifact that lands as a K8s `metadata.name` /
4522    /// Helm chart name / `HelmRelease` `release_name`: `caixa-helm`'s
4523    /// `ChartDir.name` + `Chart.yaml::name`
4524    /// (caixa-helm/src/lib.rs:207), `caixa-flux`'s `cluster_bundle`
4525    /// `HelmRelease` `chart:` slot (caixa-flux/src/lib.rs:329),
4526    /// `caixa-tatara`'s `process_for_aplicacao` `release_name` +
4527    /// `oci://<registry>/lareira-<nome>` chart ref
4528    /// (caixa-tatara/src/lib.rs:124,178). Helm's own `Chart.yaml::name`
4529    /// admission rule strict-parses against DNS-1123-label, the Helm
4530    /// operator's tracking-secret name is derived from `release_name`
4531    /// and is itself DNS-1123-label-bounded, and the rendered chart's
4532    /// K8s object `metadata.name` axes embed the chart name as a
4533    /// prefix — every one fails admission on a > 63-byte chart name.
4534    ///
4535    /// The per-axis [`Self::validate_nome`] gate (6c992f8) already
4536    /// caps `:nome` itself at 63 bytes via [`is_dns_1123_label`], so a
4537    /// `:nome` of 56–63 bytes silently passed validate (the inner
4538    /// DNS-1123 check accepts the bare `:nome`) but produced a
4539    /// `lareira-<nome>` of 64–71 bytes that the apiserver / `helm lint`
4540    /// rejected at admission — far from the source `caixa.lisp`, with
4541    /// no field naming the overflow root cause. The
4542    /// [`lareira_chart_name`] helper's own doc comment
4543    /// (caixa-core/src/render.rs:3198) explicitly deferred the fix:
4544    /// "the M4 admission webhook will pin the joint-length invariant
4545    /// when it lands". This gate lands the invariant at the
4546    /// manifest-validate layer rather than waiting for the apiserver
4547    /// — the same fail-at-the-source posture every peer per-axis
4548    /// value-shape gate (DNS-1123 on `:nome`, SemVer-2 on `:versao`,
4549    /// SPDX-expression-shape on `:licenca`, 4-digit decimal year on
4550    /// `:edicao`, etc.) takes.
4551    ///
4552    /// Thin wrapper around
4553    /// [`crate::render::is_lareira_chart_name_shape`] (the
4554    /// substrate-side predicate that composes [`lareira_chart_name`] +
4555    /// [`is_dns_1123_label`] via the lifted
4556    /// [`crate::LAREIRA_CHART_NAME_NOME_MAX_LEN`] budget); maps the
4557    /// shared parser-shaped reason into the
4558    /// [`ManifestError::NomeChartNameBudgetExceeded`] variant so the
4559    /// diagnostic is self-locating (the offending `:nome` is named
4560    /// verbatim alongside the rendered chart name and the budget) and
4561    /// the author can shorten in one edit. The gate runs across every
4562    /// `:kind` — `:nome` is the substrate-wide identity axis any
4563    /// future renderer the substrate adds can derive a
4564    /// `lareira-<nome>` artifact from, and uniform enforcement closes
4565    /// the drift footgun where a future kind grows a chart-emitting
4566    /// render path while the validate cascade doesn't catch it.
4567    ///
4568    /// Runs *after* [`Self::validate_nome`] so the narrower
4569    /// `NomeEmpty` / `NomeInvalid` shape diagnostics fire first — a
4570    /// structurally-malformed `:nome` (empty, uppercase, underscore,
4571    /// dot, leading/trailing hyphen, Unicode, > 63 bytes) surfaces its
4572    /// specific shape error rather than the chart-name-budget error,
4573    /// preserving the legitimate "well-shaped `:nome` that happens to
4574    /// overflow the joint cap" arm for this gate.
4575    pub fn validate_nome_chart_name_budget(&self) -> Result<(), ManifestError> {
4576        let nome = self.nome();
4577        crate::render::is_lareira_chart_name_shape(nome)
4578            .map_err(|reason| ManifestError::nome_chart_name_budget_exceeded(nome, reason))
4579    }
4580
4581    /// Reject `:versao` values that don't parse as [`semver::Version`].
4582    /// The top-level Caixa version flows directly into every
4583    /// substrate-side artifact that carries a "this is which version of
4584    /// the caixa" axis: the `lareira-<nome>` Helm chart's `Chart.yaml`
4585    /// `version:` + `appVersion:` axes ([`caixa-helm::lib`] —
4586    /// SemVer-2-strict at `helm template` / `helm install` time per
4587    /// https://helm.sh/docs/topics/charts/#charts-and-versioning), the
4588    /// `feira publish` Zig-style `v<versao>` git tag
4589    /// ([`caixa-flux::lib::programs_yaml_entry`] / the
4590    /// `caixa-publish.yml` reusable workflow), the programs.yaml entry's
4591    /// `versao:` value the `lareira-fleet-programs` aggregator carries
4592    /// onto each rendered ComputeUnit, the OCI image's `:v<versao>` /
4593    /// `:latest` tags the substrate's `wasi-service-flake` builds with
4594    /// `skopeo push`, the lacre closure's pinned versions
4595    /// ([`caixa-resolver`] keys `concrete_versao`), and the
4596    /// `:upgrade-from :from` references peers in this exact `versao`
4597    /// shape (`semver::Version`, not `VersionReq`). Each consumer
4598    /// expects a strict three-part `MAJOR.MINOR.PATCH` (optionally
4599    /// `-prerelease` and/or `+build`); a structurally invalid `:versao`
4600    /// (`"0.1"` — missing patch, the canonical "I shortened it" footgun;
4601    /// `"v0.1.0"` — the git-tag-shape-leaking-into-versao typo;
4602    /// `"latest"` / `"main"` — the "I confused it with a docker tag"
4603    /// footgun; `"^0.1"` / `"~0.1.2"` — the requirement-shape leaking
4604    /// into the version field a peer `:deps :versao` accepts;
4605    /// `"0.1.0.0"` — the four-part Java/Microsoft convention DNS
4606    /// SemVer-2 forbids) silently passed [`Caixa::from_lisp`] (the
4607    /// derive macro stores the raw String) and the failure surfaced at
4608    /// the *first* downstream consumer that strict-parses it: at
4609    /// `helm install` time as a chart-version rejection, at
4610    /// `feira publish` time as a malformed git tag, at lacre-resolve
4611    /// time as a `semver::Error` not naming the offending caixa, at
4612    /// `feira upgrade --to <versao>` time as an unresolvable
4613    /// `:upgrade-from :from` match — far from the source `caixa.lisp`
4614    /// and without any field naming the offending `:versao`.
4615    ///
4616    /// Thin wrapper around [`semver::Version::parse`] — the same parser
4617    /// [`crate::CaixaVersion::parse`] (the typed `:versao` accessor)
4618    /// and [`crate::UpgradeFromEntry::validate`] (the peer
4619    /// `:upgrade-from :from` axis, 26da2c7) consume. Maps the
4620    /// `semver::Error` reason into the [`ManifestError::VersaoInvalid`]
4621    /// variant, carrying the offending `:versao` verbatim + a
4622    /// parser-shaped reason naming the specific violation, so the
4623    /// diagnostic is self-locating (the author can grep their
4624    /// `caixa.lisp` for `:versao "<value>"` and fix it in one edit).
4625    /// Same diagnostic shape as [`ManifestError::NomeInvalid`]
4626    /// (6c992f8) and [`crate::UpgradeError::FromInvalid`]
4627    /// (b0c8389) on the peer axes. With this gate, the typed `:versao`
4628    /// surfaces — top-level `:versao`, `:upgrade-from :from` — are
4629    /// now structurally equivalent (every value past validate is
4630    /// round-trippable through [`semver::Version::parse`] without
4631    /// re-checking at the renderer, resolver, or operator hot-upgrade
4632    /// layer), peer with the four `:versao` requirement axes (`:deps`,
4633    /// `:deps-dev`, `:membros`, `:children`) the prior commits
4634    /// (2420c44, 9888b13, b38ff3a) wired through `parse_requirement`.
4635    ///
4636    /// Empty `:versao` (which [`Caixa::from_lisp`] does not reject —
4637    /// the derive macro stores the raw String) is gated by the
4638    /// narrower [`ManifestError::VersaoEmpty`] arm before the parser is
4639    /// consulted, mirroring the empty-first cascade every per-axis
4640    /// version gate already uses (e.g. `MembroVersaoEmpty` before
4641    /// `MembroVersaoInvalid`, `EmptyChildVersion` before
4642    /// `ChildVersaoInvalid`, `NomeEmpty` before `NomeInvalid`).
4643    pub fn validate_versao(&self) -> Result<(), ManifestError> {
4644        let versao = self.versao();
4645        if versao.is_empty() {
4646            return Err(ManifestError::VersaoEmpty);
4647        }
4648        semver::Version::parse(versao)
4649            .map_err(|e| ManifestError::versao_invalid(versao, e.to_string()))?;
4650        Ok(())
4651    }
4652
4653    /// Compound per-`Caixa` entry gate on the M2 `:upgrade-from` slot:
4654    /// folds the three [`crate::upgrade`] top-level validators — the
4655    /// per-entry shape + cross-entry duplicate-`:from` gate
4656    /// ([`crate::upgrade::validate_upgrade_from`]), the cross-slot
4657    /// `:from < :versao` SemVer-2 precedence gate
4658    /// ([`crate::upgrade::validate_upgrade_from_against_versao`]), and the
4659    /// cross-slot `:state-change` ↔ `:on-state-change` composition gate
4660    /// ([`crate::upgrade::validate_upgrade_from_against_behavior`]) — onto
4661    /// one substrate primitive on [`Caixa`]. The three dispatches run in
4662    /// the same order the layout pipeline
4663    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4664    /// author-time gate) has always sequenced them, so the fold is
4665    /// byte-for-byte equivalent to the pre-fold three-block cascade at
4666    /// that call site (pinned by the per-arm
4667    /// `validate_upgrade_from_folds_per_entry_arm_matches_gate` /
4668    /// `_folds_versao_arm_matches_gate` / `_folds_behavior_arm_matches_gate`
4669    /// equivalence pins and by the cross-arm
4670    /// `validate_upgrade_from_per_entry_arm_fires_before_versao_arm` /
4671    /// `_versao_arm_fires_before_behavior_arm` ordering pins).
4672    ///
4673    /// Prior to this lift the three [`crate::upgrade`] top-level validators
4674    /// lived only open-coded at the layout wire-up site
4675    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4676    /// each threaded through the same `self.upgrade_from()` slice and each
4677    /// paired with the same [`crate::LayoutError::UpgradeViolation`]-wrap
4678    /// envelope: every future consumer that wanted to gate `:upgrade-from`
4679    /// as a whole — the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
4680    /// materializer's per-CR admission webhook re-checking `:upgrade-from`
4681    /// after a per-`(:from … :instructions …)` patch, a future `feira
4682    /// validate --upgrade` per-caixa admission verb, a per-`:upgrade-from`
4683    /// overlay resolver a per-cluster overlay lift would materialize —
4684    /// was structurally forced to either re-inline the three-dispatch
4685    /// cascade in lockstep with the layout wire-up (the duplication the
4686    /// PRIME DIRECTIVE names as a bug) or call the whole
4687    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4688    /// peer per-Caixa gate to re-check one slot. Post-fold each such
4689    /// consumer reaches the three-arm compound gate through one call on
4690    /// the substrate primitive.
4691    ///
4692    /// The three arms together name one contract with three axes:
4693    ///
4694    ///   - **per-entry + cross-entry graph-edge invariant** — every entry's
4695    ///     `:from` parses as SemVer-2 and every per-instruction / within-
4696    ///     entry ordering / singularity gate on each entry's
4697    ///     `:instructions` list passes, and no two entries share the same
4698    ///     parsed `:from` (the wasm-operator's OTP appup
4699    ///     `release_handler:install_release/1` analog picks at most one
4700    ///     matching block per running version — two entries with the same
4701    ///     parsed semver are an ambiguous edge in the typed upgrade graph).
4702    ///   - **cross-slot reachability invariant** — every entry's `:from`
4703    ///     is strictly less than the caixa's own `:versao` under SemVer-2
4704    ///     precedence. An entry whose `:from >= :versao` is structurally
4705    ///     unreachable by the operator's `:from`-match dispatch (the
4706    ///     operator loads the current `:versao` and matches the *running*
4707    ///     version against each entry's `:from`; an entry whose `:from >=
4708    ///     :versao` is never reached because the operator never runs a
4709    ///     version >= the current one that it could then upgrade *to* the
4710    ///     current one).
4711    ///   - **cross-slot composition invariant** — every entry carrying a
4712    ///     `(:state-change …)` instruction has a `:behavior
4713    ///     :on-state-change` callback declared on the same caixa. The
4714    ///     per-version migration script is the `gen_server:code_change/3`
4715    ///     analog and the runtime hook it is delivered through during hot
4716    ///     upgrade is the `:on-state-change` callback (the upgrade.rs
4717    ///     module doc pins the composition verbatim: "Composes with the
4718    ///     `:behavior :on-state-change` callback to deliver state migration
4719    ///     during hot upgrades").
4720    ///
4721    /// All three axes must hold together — every consumer's
4722    /// `:upgrade-from` accept-set past this compound gate is the same
4723    /// set the `feira build` author-time gate admits.
4724    ///
4725    /// The per-slot compound entry gate discipline lifted here onto the
4726    /// M2 `:upgrade-from` axis is the sibling of the peer per-kind
4727    /// compound entry gates ([`crate::render::require_supervisor_view`]
4728    /// / [`crate::render::require_aplicacao_view`] /
4729    /// [`crate::render::require_v0_servico_shape`]) that fold every
4730    /// per-kind cascade at the per-kind altitude, and of the peer
4731    /// per-slot compound gates ([`crate::AplicacaoSpec::validate_contratos`],
4732    /// [`crate::MeshPolicy::validate`],
4733    /// [`crate::SupervisorSpec::validate_children`]) that fold every
4734    /// structural axis on their slot onto one substrate primitive.
4735    /// Extended here to the last unlifted compound-cascade wire-up at
4736    /// the layout-pipeline altitude — the three-dispatch M2
4737    /// `:upgrade-from` cascade that lived only open-coded at the layout
4738    /// wire-up site.
4739    ///
4740    /// The per-instruction script-path on-disk existence-probe walk that
4741    /// [`crate::layout::StandardLayout::verify`] runs immediately after
4742    /// this gate (which resolves each entry's `:instructions
4743    /// (:state-change :script)` against the layout root) stays open-coded
4744    /// at the layout wire-up site — that arm needs the filesystem oracle
4745    /// on the [`crate::LayoutInvariants`] trait, not the pure per-Caixa
4746    /// typed-shape surface this compound gate folds. Same posture the
4747    /// peer [`Self::validate_code_paths`] takes on the sibling code-path
4748    /// axes: the typed-shape gate fires on the per-Caixa surface, the
4749    /// on-disk existence check fires on the [`crate::StandardLayout`]
4750    /// surface.
4751    ///
4752    /// # Errors
4753    ///
4754    /// Returns [`crate::UpgradeError::FromInvalid`] /
4755    /// [`crate::UpgradeError::ModuleEmpty`] /
4756    /// [`crate::UpgradeError::ModuleInvalid`] /
4757    /// [`crate::UpgradeError::EmptyScript`] /
4758    /// [`crate::UpgradeError::AbsoluteScript`] /
4759    /// [`crate::UpgradeError::ParentEscapeScript`] /
4760    /// [`crate::UpgradeError::NonLispExtensionScript`] /
4761    /// [`crate::UpgradeError::RestartNotExclusive`] /
4762    /// [`crate::UpgradeError::StateChangeWithoutPriorLoad`] /
4763    /// [`crate::UpgradeError::PurgeWithoutPriorLoad`] /
4764    /// [`crate::UpgradeError::StateChangeAfterCleanup`] /
4765    /// [`crate::UpgradeError::DuplicateLoadModule`] /
4766    /// [`crate::UpgradeError::DuplicateStateChange`] /
4767    /// [`crate::UpgradeError::DuplicateCleanup`] /
4768    /// [`crate::UpgradeError::DuplicateFrom`] on the per-entry +
4769    /// cross-entry axis; [`crate::UpgradeError::FromNotBeforeVersao`] on
4770    /// the cross-slot `:from ↔ :versao` axis;
4771    /// [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
4772    /// on the cross-slot `:state-change ↔ :on-state-change` axis.
4773    pub fn validate_upgrade_from(&self) -> Result<(), crate::UpgradeError> {
4774        crate::upgrade::validate_upgrade_from(self.upgrade_from())?;
4775        crate::upgrade::validate_upgrade_from_against_versao(self.upgrade_from(), self.versao())?;
4776        crate::upgrade::validate_upgrade_from_against_behavior(
4777            self.upgrade_from(),
4778            self.behavior(),
4779        )?;
4780        Ok(())
4781    }
4782
4783    /// Compound per-`Caixa` entry gate on the M2 `:limits` slot — folds
4784    /// the [`crate::LimitsSpec::validate`] four-axis cascade (`:memory`
4785    /// wasm32 zero-floor / below-page / above-cap / non-page-multiple;
4786    /// `:fuel` zero-floor / cap; `:wall-clock` zero-floor / cap; `:cpu`
4787    /// zero-floor / cap) onto one substrate primitive on [`Caixa`]. The
4788    /// `#[serde(default)]` absent-slot arm (`limits: None`, the
4789    /// canonical "no bound declared — engine-default applies" author
4790    /// shape [`crate::LimitsSpec::is_empty`]'s per-axis `None` cascade
4791    /// reads) is the fold's identity element and passes trivially; the
4792    /// present-slot arm (`limits: Some(l)`) dispatches to
4793    /// [`crate::LimitsSpec::validate`] verbatim, threading its per-axis
4794    /// [`crate::LimitsError`] Display through untouched.
4795    ///
4796    /// Prior to this lift the M2 `:limits` slot lived only wired
4797    /// open-coded at the layout wire-up site
4798    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4799    /// through the `if let Some(l) = caixa.limits() { l.validate() … }`
4800    /// three-line `Option::None → Ok(()) | Some(_) → …` unwrap-and-
4801    /// dispatch pattern paired with the same
4802    /// [`crate::LayoutError::LimitsViolation`]-wrap envelope: every
4803    /// future consumer that wanted to gate `:limits` as a whole — the
4804    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4805    /// per-CR admission webhook re-checking `:limits` after a per-
4806    /// `{:memory, :fuel, :wall-clock, :cpu}` patch (the exact case the
4807    /// [`Self::limits`] accessor docstring names as the second
4808    /// consumer of the slot), a future `feira validate --limits` per-
4809    /// caixa admission verb, a per-`:limits` overlay resolver a per-
4810    /// cluster `:limits-overrides` overlay lift would materialize — was
4811    /// structurally forced to either re-inline the two-line
4812    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4813    /// pattern in lockstep with the layout wire-up (the duplication the
4814    /// PRIME DIRECTIVE names as a bug) or call the whole
4815    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4816    /// peer per-Caixa gate ([`Self::validate_nome`],
4817    /// [`Self::validate_versao`], [`Self::validate_deps`],
4818    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4819    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4820    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4821    /// [`Self::validate_upgrade_from`], [`Self::validate_code_paths`],
4822    /// plus the per-kind `require_supervisor_view` /
4823    /// `require_aplicacao_view` gates, plus the on-disk existence
4824    /// walks) to re-check one slot. Post-lift each such consumer
4825    /// reaches the [`crate::LimitsSpec::validate`] four-axis cascade
4826    /// (and its identity-element on the absent slot) through one call
4827    /// on the substrate primitive.
4828    ///
4829    /// The per-slot compound entry-gate discipline lifted here onto the
4830    /// M2 `:limits` axis is the sibling of the peer per-slot compound
4831    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4832    /// [`crate::MeshPolicy::validate`],
4833    /// [`crate::SupervisorSpec::validate_children`],
4834    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`]) that
4835    /// fold every structural + cross-slot axis on their slot onto one
4836    /// substrate primitive. Extended here to the M2 `:limits` slot, the
4837    /// first of the two M2 typed slots (`:limits`, `:behavior`) whose
4838    /// per-Caixa compound-gate wire-up still lived open-coded at the
4839    /// layout altitude after the [`Self::validate_upgrade_from`] lift
4840    /// (d6801df) closed the sibling M2 slot's cascade.
4841    ///
4842    /// # Errors
4843    ///
4844    /// Returns every [`crate::LimitsError`] variant on the present-slot
4845    /// arm — verbatim from [`crate::LimitsSpec::validate`]. Passes
4846    /// trivially on the absent-slot arm (`limits: None`, the fold's
4847    /// identity element).
4848    pub fn validate_limits(&self) -> Result<(), crate::LimitsError> {
4849        match self.limits() {
4850            Some(l) => l.validate(),
4851            None => Ok(()),
4852        }
4853    }
4854
4855    /// Compound per-`Caixa` entry gate on the M2 `:behavior` slot's
4856    /// pure typed-shape surface — folds the
4857    /// [`crate::BehaviorSpec::validate`] six-slot value-shape cascade
4858    /// (each declared `:on-init` / `:on-call` / `:on-cast` / `:on-info`
4859    /// / `:on-state-change` / `:on-terminate` callback-path is
4860    /// non-empty / relative / no-`..`-parent-escape / terminating-
4861    /// `.lisp`-extension, routed through the shared
4862    /// [`crate::render::require_sandboxed_lisp_path`] arm-set) onto one
4863    /// substrate primitive on [`Caixa`]. The `#[serde(default)]`
4864    /// absent-slot arm (`behavior: None`, the canonical "no callback
4865    /// declared — the runtime falls back to the wasm-engine's default
4866    /// callback per arm" author shape [`crate::BehaviorSpec::is_empty`]'s
4867    /// per-slot `None` cascade reads) is the fold's identity element
4868    /// and passes trivially; the present-slot arm (`behavior: Some(b)`)
4869    /// dispatches to [`crate::BehaviorSpec::validate`] verbatim,
4870    /// threading its per-slot [`crate::BehaviorError`] Display through
4871    /// untouched.
4872    ///
4873    /// Scope note — the on-disk callback-path existence walk paired
4874    /// with the value-shape gate at
4875    /// [`crate::layout::StandardLayout::verify`] stays open-coded at
4876    /// the layout altitude, because it needs the
4877    /// [`crate::layout::LayoutInvariants`] filesystem oracle
4878    /// ([`crate::layout::LayoutInvariants::exists`]) that the pure
4879    /// per-Caixa typed-shape surface this compound gate folds onto has
4880    /// no reference to. Same posture the peer M2 `:upgrade-from`
4881    /// per-Caixa compound gate ([`Self::validate_upgrade_from`]
4882    /// d6801df) already carries: the pure typed-shape surface folds
4883    /// onto the substrate primitive; the per-instruction script-path
4884    /// existence probe on the paired axis (there `:state-change
4885    /// :script`; here `:on-*`) stays at the layout altitude.
4886    ///
4887    /// Prior to this lift the pure value-shape surface of the M2
4888    /// `:behavior` slot lived only wired open-coded at the layout
4889    /// wire-up site ([`crate::layout::StandardLayout::verify`],
4890    /// caixa-core/src/layout.rs), through the
4891    /// `if let Some(b) = caixa.behavior() { b.validate() … }`
4892    /// unwrap-and-dispatch pattern paired with the same
4893    /// [`crate::LayoutError::BehaviorViolation`]-wrap envelope: every
4894    /// future consumer that wanted to gate the `:behavior` slot's
4895    /// value-shape as a whole — the deferred
4896    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
4897    /// admission webhook re-checking `:behavior` after a per-`{:on-init,
4898    /// :on-call, :on-cast, :on-info, :on-state-change, :on-terminate}`
4899    /// patch (the exact case the peer `:on-*` accessor docstrings on
4900    /// [`crate::BehaviorSpec`] already name as deferred consumers of
4901    /// the slot), a future `feira validate --behavior` per-caixa
4902    /// admission verb, a per-`:behavior` overlay resolver a future
4903    /// per-cluster callback-overlay lift would materialize — was
4904    /// structurally forced to either re-inline the two-line
4905    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4906    /// pattern in lockstep with the layout wire-up (the duplication the
4907    /// PRIME DIRECTIVE names as a bug) or call the whole
4908    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4909    /// peer per-Caixa gate ([`Self::validate_nome`],
4910    /// [`Self::validate_versao`], [`Self::validate_deps`],
4911    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4912    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4913    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4914    /// [`Self::validate_limits`], [`Self::validate_upgrade_from`],
4915    /// [`Self::validate_code_paths`], plus the per-kind
4916    /// `require_supervisor_view` / `require_aplicacao_view` gates, plus
4917    /// the on-disk existence walks) to re-check one slot. Post-lift
4918    /// each such consumer reaches the [`crate::BehaviorSpec::validate`]
4919    /// six-slot cascade (and its identity-element on the absent slot)
4920    /// through one call on the substrate primitive.
4921    ///
4922    /// The per-slot compound entry-gate discipline lifted here onto the
4923    /// M2 `:behavior` axis is the sibling of the peer per-slot compound
4924    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4925    /// [`crate::MeshPolicy::validate`],
4926    /// [`crate::SupervisorSpec::validate_children`],
4927    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`],
4928    /// [`Self::validate_limits`]) that fold every structural + cross-
4929    /// slot axis on their slot onto one substrate primitive. Extended
4930    /// here to the M2 `:behavior` slot, the last of the four M2 typed
4931    /// slots (`:limits`, `:behavior`, `:upgrade-from`, plus the
4932    /// supervisor-only `:children` peer) whose per-Caixa compound-gate
4933    /// wire-up still lived open-coded at the layout altitude after the
4934    /// [`Self::validate_limits`] lift (baa4688) closed the sibling M2
4935    /// `:limits` slot's cascade. With this lift the "one named per-slot
4936    /// / per-Caixa compound gate per typed slot folding every structural
4937    /// axis on that slot (plus the `Option::None` identity element for
4938    /// the `Option`-shaped slots) onto one substrate primitive"
4939    /// discipline spans every M2 typed slot uniformly, so a reader who
4940    /// has learned any peer M2 gate reads `:behavior` without a per-
4941    /// slot exception carve-out.
4942    ///
4943    /// # Errors
4944    ///
4945    /// Returns every [`crate::BehaviorError`] variant on the present-
4946    /// slot arm — verbatim from [`crate::BehaviorSpec::validate`].
4947    /// Passes trivially on the absent-slot arm (`behavior: None`, the
4948    /// fold's identity element).
4949    pub fn validate_behavior(&self) -> Result<(), crate::BehaviorError> {
4950        match self.behavior() {
4951            Some(b) => b.validate(),
4952            None => Ok(()),
4953        }
4954    }
4955
4956    /// Reject `:restart-window` values the shared
4957    /// [`crate::supervisor::duration_codec::parse`] refuses. The flat
4958    /// `restart_window: Option<String>` slot on [`Caixa`] is stored
4959    /// raw by the derive macro (the typed [`SupervisorSpec`] holds an
4960    /// `Option<Duration>` routed through the shared codec via `with =
4961    /// "duration_codec"`); the inline `Caixa → SupervisorSpec`
4962    /// view-construction path ([`Self::supervisor_view`]) folds the
4963    /// raw string through the same shared codec and soft-swallows the
4964    /// parse error as `None` to keep the view best-effort. Without
4965    /// this gate a malformed `:restart-window` (`"1.5s"` — the
4966    /// fractional-seconds drift class; `"1.0s"` — the decimal-shaped
4967    /// integer drift; `"0.5m"` — the unit-fraction drift; `"+30s"` /
4968    /// `"-30s"` — the leading-sign drift; `"30x"` — the unknown-unit
4969    /// footgun; `"abc"` — pure garbage; `""` — the empty-after-trim
4970    /// edge case) silently produced a `SupervisorSpec` with
4971    /// `restart_window: None`, indistinguishable from the canonical
4972    /// "omit the slot to express no reset" authoring shape — Erlang/OTP's
4973    /// `MaxIntensity / Period` invariant turns into a never-reset
4974    /// supervisor far from the source `caixa.lisp`, with no field
4975    /// naming the offending `:restart-window`. Lifting the gate to a
4976    /// Caixa-level validator mirrors the trajectory of the peer
4977    /// per-axis identity gates ([`Self::validate_nome`] 6c992f8,
4978    /// [`Self::validate_versao`] 1fdaa02, [`Self::validate_deps`]
4979    /// a7f0d8c) and the ABSORPTION-ROADMAP.md M2.2 test pin
4980    /// (line 196: "reject invalid `:restart-window` (non-duration)").
4981    ///
4982    /// Thin wrapper around [`crate::supervisor::duration_codec::parse`]
4983    /// (the shared codec backing `:supervisor :restart-window` as
4984    /// serde-routed on [`SupervisorSpec`], `:politicas :timeout`, and
4985    /// `:politicas :circuit-breaker :window` — all three covered by
4986    /// the integer-magnitude gate 1c55a2a). Maps the codec's parse
4987    /// error verbatim into the [`ManifestError::RestartWindowMalformed`]
4988    /// variant, carrying the offending raw string + a parser-shaped
4989    /// reason naming the canonical authoring form, so the diagnostic
4990    /// is self-locating (the author can grep their `caixa.lisp` for
4991    /// `:restart-window "<value>"` and fix it in one edit) and
4992    /// uniform with every other manifest-level validate diagnostic.
4993    /// With this gate the four `:restart-window`-shaped surfaces (the
4994    /// flat raw string on [`Caixa`], the typed `Option<Duration>` on
4995    /// [`SupervisorSpec`], the two `MeshPolicy` peer durations) are
4996    /// now structurally equivalent — every value past the codec is in
4997    /// one accepted set, by construction.
4998    ///
4999    /// `None` (the canonical "omit the slot to express no reset"
5000    /// shape) is accepted trivially — the gate is a no-op when the
5001    /// author didn't author a window. The empty string is rejected by
5002    /// the shared codec (its digit-only gate refuses an empty
5003    /// magnitude), surfacing the same `RestartWindowMalformed`
5004    /// diagnostic as every other rejected non-canonical shape.
5005    pub fn validate_restart_window(&self) -> Result<(), ManifestError> {
5006        let Some(s) = self.restart_window() else {
5007            return Ok(());
5008        };
5009        crate::supervisor::duration_codec::parse(s)
5010            .map(|_| ())
5011            .map_err(|reason| ManifestError::restart_window_malformed(s, reason))
5012    }
5013
5014    /// Compound per-`Caixa` entry gate on the Aplicacao-kind mesh-slot
5015    /// family — folds the paired [`crate::AplicacaoSpec::validate`]
5016    /// typed-shape cascade (per-slot gates on `:membros`, `:contratos`,
5017    /// `:entrada`, `:placement`, `:politicas`, in that declared order)
5018    /// plus the cross-slot self-edge gate
5019    /// ([`crate::aplicacao::validate_no_self_membership`], the
5020    /// `:membros :caixa` ≠ `:nome` invariant the typed view cannot
5021    /// enforce on its own because it carries the membros but not the
5022    /// parent `:nome`) onto one substrate primitive on [`Caixa`]. On
5023    /// non-Aplicacao kinds the fold is the identity element — the paired
5024    /// [`Self::aplicacao_view`] accessor returns `None` off the
5025    /// Aplicacao arm (peer with the [`Self::validate_limits`] /
5026    /// [`Self::validate_behavior`] M2 `Option`-arm identity element),
5027    /// so the gate passes trivially without touching the mesh slots.
5028    ///
5029    /// Prior to this lift the paired cascade lived only wired open-coded
5030    /// at the layout wire-up site
5031    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
5032    /// as the three-line `let view = caixa.aplicacao_view().expect(...);
5033    /// view.validate() … validate_no_self_membership(...) …` pattern
5034    /// paired with two `.map_err(|err| LayoutError::AplicacaoViolation
5035    /// { caixa, issue })` wraps — every future consumer that wanted to
5036    /// gate the Aplicacao-shape cascade as a whole (the deferred
5037    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
5038    /// admission webhook re-checking `:membros` / `:contratos` after a
5039    /// per-slot patch, a future `feira validate --aplicacao` per-caixa
5040    /// admission verb, a per-Aplicacao overlay resolver) was structurally
5041    /// forced to either re-inline the two-dispatch cascade in lockstep
5042    /// with the layout wire-up (the duplication the PRIME DIRECTIVE
5043    /// names as a bug) or call the whole
5044    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
5045    /// peer per-Caixa gate to re-check one slot family. Post-fold each
5046    /// such consumer reaches the two-arm compound gate through one call
5047    /// on the substrate primitive.
5048    ///
5049    /// Peer to the [`crate::render::require_aplicacao_view`] compound
5050    /// entry gate every per-Aplicacao *renderer* routes through
5051    /// (3aefefb folded `validate_no_self_membership` onto the renderer
5052    /// path) — this gate mirrors the same fold on the *layout* path, so
5053    /// the two consumers of the Aplicacao-shape cascade (the author-time
5054    /// gate and every per-Aplicacao renderer) share one substrate
5055    /// primitive rather than two open-coded cascades kept in lockstep.
5056    /// Same lift discipline the peer per-slot compound gates
5057    /// ([`Self::validate_upgrade_from`] d6801df, [`Self::validate_deps`]
5058    /// b5dd55e, [`Self::validate_limits`] baa4688,
5059    /// [`Self::validate_behavior`] 0d2877a) each carry.
5060    ///
5061    /// # Errors
5062    ///
5063    /// Returns every [`crate::AplicacaoError`] variant on the present-
5064    /// kind arm — the typed-shape cascade's per-slot arms first
5065    /// (matching [`crate::AplicacaoSpec::validate`]'s declared order),
5066    /// then the cross-slot self-edge arm
5067    /// ([`crate::AplicacaoError::MembroIsSelfAplicacao`]). Passes
5068    /// trivially on non-Aplicacao kinds (the fold's identity element).
5069    pub fn validate_aplicacao_shape(&self) -> Result<(), crate::AplicacaoError> {
5070        let Some(view) = self.aplicacao_view() else {
5071            return Ok(());
5072        };
5073        view.validate()?;
5074        crate::aplicacao::validate_no_self_membership(self.membros(), self.nome())?;
5075        Ok(())
5076    }
5077
5078    /// Compound per-`Caixa` entry gate on the Supervisor-kind
5079    /// supervision-tree slot family — folds the paired
5080    /// [`crate::SupervisorSpec::validate`] typed-shape cascade
5081    /// (`:estrategia` ↔ `:children` invariants, `:max-restarts` /
5082    /// `:restart-window` bounds, per-child DNS-1123 `:caixa` names,
5083    /// semver-valid `:versao` constraints, the set-not-multiset
5084    /// duplicate-child gate) plus the cross-slot self-edge gate
5085    /// ([`crate::supervisor::validate_no_self_supervision`], the
5086    /// `:children :caixa` ≠ `:nome` invariant the typed view cannot
5087    /// enforce on its own because it carries the children but not the
5088    /// parent `:nome`) onto one substrate primitive on [`Caixa`]. On
5089    /// non-Supervisor kinds the fold is the identity element — the paired
5090    /// [`Self::supervisor_view`] accessor returns `None` off the
5091    /// Supervisor arm (peer with the [`Self::validate_limits`] /
5092    /// [`Self::validate_behavior`] M2 `Option`-arm identity element and
5093    /// the sibling per-Aplicacao [`Self::validate_aplicacao_shape`]),
5094    /// so the gate passes trivially without touching the supervision-tree
5095    /// slots.
5096    ///
5097    /// Prior to this lift the paired cascade lived only wired open-coded
5098    /// at the layout wire-up site
5099    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
5100    /// as the three-line `let view = caixa.supervisor_view().expect(...);
5101    /// view.validate() … validate_no_self_supervision(...) …` pattern
5102    /// paired with two `.map_err(|err| LayoutError::SupervisorViolation
5103    /// { caixa, issue })` wraps — every future consumer that wanted to
5104    /// gate the Supervisor-shape cascade as a whole (the wasm-operator's
5105    /// hierarchical reconciliation scheduler re-checking `:children` /
5106    /// `:estrategia` after a per-slot patch, the M4
5107    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
5108    /// webhook, a future `feira validate --supervisor` per-caixa
5109    /// admission verb, a per-Supervisor overlay resolver) was structurally
5110    /// forced to either re-inline the two-dispatch cascade in lockstep
5111    /// with the layout wire-up (the duplication the PRIME DIRECTIVE
5112    /// names as a bug) or call the whole
5113    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
5114    /// peer per-Caixa gate to re-check one slot family. Post-fold each
5115    /// such consumer reaches the two-arm compound gate through one call
5116    /// on the substrate primitive.
5117    ///
5118    /// Peer to the [`crate::render::require_supervisor_view`] compound
5119    /// entry gate every per-Supervisor *renderer* would route through
5120    /// (which already folds the same `spec.validate()` +
5121    /// `validate_no_self_supervision` two-arm cascade behind its
5122    /// `require_kind` + `validate_restart_window` prelude) — this gate
5123    /// mirrors the same fold on the *layout* path, so the two consumers
5124    /// of the Supervisor-shape cascade (the author-time gate and every
5125    /// per-Supervisor renderer) share one substrate primitive rather
5126    /// than two open-coded cascades kept in lockstep. Same lift
5127    /// discipline the peer per-slot compound gates
5128    /// ([`Self::validate_aplicacao_shape`] 949a7a0,
5129    /// [`Self::validate_upgrade_from`] d6801df,
5130    /// [`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5131    /// baa4688, [`Self::validate_behavior`] 0d2877a) each carry.
5132    ///
5133    /// # Errors
5134    ///
5135    /// Returns every [`crate::SupervisorError`] variant on the present-
5136    /// kind arm — the typed-shape cascade's per-slot arms first
5137    /// (matching [`crate::SupervisorSpec::validate`]'s declared order),
5138    /// then the cross-slot self-edge arm
5139    /// ([`crate::SupervisorError::ChildSupervisesSelf`]). Passes
5140    /// trivially on non-Supervisor kinds (the fold's identity element).
5141    pub fn validate_supervisor_shape(&self) -> Result<(), crate::SupervisorError> {
5142        let Some(view) = self.supervisor_view() else {
5143            return Ok(());
5144        };
5145        view.validate()?;
5146        crate::supervisor::validate_no_self_supervision(self.children(), self.nome())?;
5147        Ok(())
5148    }
5149
5150    /// Compound per-`Caixa` entry gate on the Acao-kind `:ci` slot
5151    /// family — folds the [`crate::decompose_ci`] typed decompose gate
5152    /// (`canteiro_types::decompose` refusing every illegal
5153    /// [`canteiro_types::CiRun`] shape: duplicate node name, dependency
5154    /// on an undeclared node, dependency cycle) onto one substrate
5155    /// primitive on [`Caixa`]. On non-`Acao` kinds the fold is the
5156    /// identity element — the paired [`Self::kind`] `is_acao()` guard
5157    /// short-circuits before the decompose gate ever fires (peer with
5158    /// the [`Self::validate_aplicacao_shape`] /
5159    /// [`Self::validate_supervisor_shape`] typed-view identity element
5160    /// and the [`Self::validate_limits`] / [`Self::validate_behavior`]
5161    /// M2 `Option`-arm identity element), so the gate passes trivially
5162    /// without touching the `:ci` slot. An `:kind Acao` caixa with
5163    /// `ci = None` is also an identity-element pass: the presence gate
5164    /// is the sibling axis owned by [`crate::LayoutError::MissingCi`] /
5165    /// [`crate::require_ci`] / [`crate::MissingCiSlot`], not by the
5166    /// decompose gate — a caixa that carries no `:ci` slot has no run
5167    /// to decompose. Same split the peer per-Servico
5168    /// [`crate::LayoutError::ServicoWithoutServicos`] presence gate and
5169    /// per-Binario [`crate::LayoutError::BinarioWithoutExe`] presence
5170    /// gate keep from their sibling per-slot shape gates, so the two
5171    /// axes stay separately diagnosable at the layout altitude.
5172    ///
5173    /// Prior to this lift the decompose gate lived only wired
5174    /// open-coded at the [`caixa_actions::validate`] renderer-side
5175    /// entry gate (routed through the substrate-canonical
5176    /// [`crate::require_acao_view`] compound helper) — the *layout*
5177    /// pipeline ([`crate::layout::StandardLayout::verify`], caixa-core/
5178    /// src/layout.rs) only checked `:ci` *presence* via
5179    /// [`crate::LayoutError::MissingCi`], so a `:kind Acao` caixa
5180    /// carrying a structurally illegal `:ci` (a duplicate node name, a
5181    /// dependency on an undeclared node, a dependency cycle) passed
5182    /// `feira build` cleanly and surfaced the diagnostic only when
5183    /// [`caixa_actions::validate`] later refused it — far from the
5184    /// source `caixa.lisp` on the author-time gate side. Every future
5185    /// consumer that wanted to gate the Acao-shape cascade as a whole
5186    /// (a per-`Acao` CR materializer's admission webhook re-checking
5187    /// `:ci` after a per-node patch, a future `feira validate --acao`
5188    /// per-caixa admission verb, a per-`Acao` overlay resolver
5189    /// rejecting an added / renamed node against a cluster-local
5190    /// snapshot) was structurally forced to either re-inline the
5191    /// decompose dispatch in lockstep with the renderer-side wire-up
5192    /// (the duplication the PRIME DIRECTIVE names as a bug) or call
5193    /// the whole [`caixa_actions::validate`] renderer and pay the
5194    /// per-node accumulation to re-check one slot. Post-fold each such
5195    /// consumer reaches the decompose gate through one call on the
5196    /// substrate primitive.
5197    ///
5198    /// Peer to the [`crate::require_acao_view`] compound entry gate
5199    /// every per-`Acao` *renderer* routes through (which already folds
5200    /// the same `require_ci + decompose_ci` two-arm cascade behind its
5201    /// `require_kind` prelude) — this gate mirrors the same fold on
5202    /// the *layout* path, so the two consumers of the Acao-shape
5203    /// cascade (the author-time gate and every per-`Acao` renderer)
5204    /// share one substrate primitive rather than two open-coded
5205    /// cascades kept in lockstep. Same lift discipline the peer
5206    /// per-kind compound gates ([`Self::validate_aplicacao_shape`]
5207    /// 949a7a0, [`Self::validate_supervisor_shape`] 4c70105,
5208    /// [`Self::validate_upgrade_from`] d6801df, [`Self::validate_deps`]
5209    /// b5dd55e, [`Self::validate_limits`] baa4688,
5210    /// [`Self::validate_behavior`] 0d2877a) each carry. Closes the
5211    /// last per-kind asymmetry: with this lift the four typed
5212    /// named-caixa kinds (`Servico` / `Aplicacao` / `Supervisor` /
5213    /// `Acao`) each carry a compound per-`Caixa` shape gate on the
5214    /// substrate, and the layout pipeline routes through the same one
5215    /// substrate primitive per kind rather than four open-coded
5216    /// cascades.
5217    ///
5218    /// # Errors
5219    ///
5220    /// Returns the [`crate::CiDecomposeFailure`] typed view on the
5221    /// present-slot arm — the caixa's `:nome` alongside the borrowed
5222    /// [`canteiro_types::DecomposeError`] source (`DuplicateNode` /
5223    /// `UnknownDep` / `Cycle`) verbatim, so a consumer that fans on
5224    /// the specific arm reaches for `err.source` directly rather than
5225    /// re-parsing the Display bytes. Passes trivially on non-`Acao`
5226    /// kinds and on `:kind Acao` caixas with absent `:ci` (the fold's
5227    /// two identity-element arms).
5228    pub fn validate_acao_shape(&self) -> Result<(), crate::CiDecomposeFailure> {
5229        if !self.kind().is_acao() {
5230            return Ok(());
5231        }
5232        let Some(ci) = self.ci() else {
5233            return Ok(());
5234        };
5235        crate::render::decompose_ci(self, ci).map(|_| ())
5236    }
5237
5238    /// Compound per-`Caixa` kind ↔ typed-slot coherence gate on the
5239    /// three "declared but ignored" typed-slot families — M3 mesh
5240    /// (`:membros` / `:contratos` / `:politicas` / `:placement` /
5241    /// `:entrada`, owned by `:kind Aplicacao`, MESH-COMPOSITION §III.1),
5242    /// supervisor-tree (`:estrategia` / `:max-restarts` /
5243    /// `:restart-window` / `:children`, owned by `:kind Supervisor`,
5244    /// INSPIRATIONS §II.2), and M2 Servico-runtime (`:limits` /
5245    /// `:behavior` / `:upgrade-from`, owned by `:kind Servico`,
5246    /// INSPIRATIONS §III.1 / §II.3 / §II.4). Folds the three sibling
5247    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5248    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5249    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
5250    /// gates — each pre-lift a self-similar five-line
5251    /// `if !caixa.kind().is_<owner>() { let slots = caixa.declared_
5252    /// <family>_slots(); if !slots.is_empty() { return
5253    /// Err(LayoutError::<family>_on_non_<owner>(caixa, slots)); } }`
5254    /// block at [`crate::layout::StandardLayout::verify`] — onto one
5255    /// substrate primitive on [`Caixa`]. Every arm passes as an
5256    /// identity element on the owner kind (the paired
5257    /// [`Self::kind`] `is_<owner>()` guard short-circuits before the
5258    /// per-family `declared_*_slots` gate fires) and on non-owner
5259    /// kinds carrying no declared slot in that family (the
5260    /// [`Vec::is_empty`] check short-circuits before the wrap fires),
5261    /// so a bare no-code caixa on any kind passes the fold trivially
5262    /// on all three arms.
5263    ///
5264    /// Prior to this lift the three-arm cascade lived only wired
5265    /// open-coded at the layout wire-up site
5266    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/
5267    /// layout.rs) as three self-similar five-line blocks paired with
5268    /// three [`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
5269    /// [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
5270    /// [`crate::LayoutError::servico_slots_on_non_servico`] ctor
5271    /// dispatches (each of which the peer
5272    /// [`crate::layout::layout_slot_kind_ctors!`] macro already folds
5273    /// onto one substrate primitive per typed variant, 0419438) —
5274    /// every future consumer that wanted to gate the whole
5275    /// kind-coherence cascade as a unit (the deferred
5276    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5277    /// webhook re-checking every typed-slot family after a per-slot
5278    /// patch, a future `feira validate --kind-coherence` per-caixa
5279    /// admission verb, a per-`Caixa` overlay resolver rejecting a
5280    /// kind-foreign patch against a cluster-local snapshot) was
5281    /// structurally forced to either re-inline the three-block
5282    /// cascade in lockstep with the layout wire-up (the duplication
5283    /// the PRIME DIRECTIVE names as a bug) or call the whole
5284    /// [`crate::layout::StandardLayout::verify`] pipeline and pay
5285    /// every peer per-`Caixa` gate to re-check three slot families.
5286    /// Post-fold each such consumer reaches the three-arm cascade
5287    /// through one call on the substrate primitive.
5288    ///
5289    /// Diagnostic order matches the pre-fold layout wire-up
5290    /// canonical sequence — mesh → supervisor → servico — pinned by
5291    /// the load-bearing
5292    /// `validate_kind_slot_coherence_mesh_arm_fires_before_supervisor_arm`
5293    /// / `_supervisor_arm_fires_before_servico_arm` ordering pins
5294    /// below. The three arms enumerate every typed-slot family the
5295    /// substrate carries whose "declared but ignored" footgun is
5296    /// gated at the layout altitude by a `{ caixa, kind, slots }`
5297    /// wrap variant — the peer
5298    /// [`crate::LayoutError::ForeignCodeSlot`] gate on the
5299    /// code-surface family sits outside this fold because
5300    /// [`Self::declared_foreign_code_slots`] bakes the kind-check
5301    /// into the helper (so the layout wire-up carries no outer
5302    /// `if !caixa.kind().is_<owner>()` guard), and the peer
5303    /// [`crate::LayoutError::CiOnNonAcao`] gate on the `:ci` axis
5304    /// carries a distinct `{ caixa, kind }` wrap shape (no `slots`
5305    /// field — `:ci` is a single `Option` not a `Vec`-of-named-slots)
5306    /// and rides on its own peer substrate primitive
5307    /// [`Self::validate_ci_kind_coherence`] (the direct sibling to
5308    /// this fold on the `:ci` axis) — the two folds share the same
5309    /// altitude and diagnostic order at the layout wire-up site but
5310    /// keep their distinct envelope shapes, so no consumer of
5311    /// `CiOnNonAcao` sees a variant rename.
5312    ///
5313    /// Peer to the per-kind compound entry gates every substrate
5314    /// primitive on the M2/M3 typed-slot family already carries
5315    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5316    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5317    /// [`Self::validate_upgrade_from`] d6801df,
5318    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5319    /// [`Self::validate_supervisor_shape`] 4c70105,
5320    /// [`Self::validate_acao_shape`] 5d6df54): the author-time gate
5321    /// axis on the *per-slot* algebra now shares one substrate
5322    /// primitive per compound gate, and this lift closes the
5323    /// symmetric axis on the *cross-family* kind ↔ slot coherence
5324    /// algebra so the layout pipeline routes the three self-similar
5325    /// gates through one substrate primitive rather than three
5326    /// open-coded blocks. Every future kind that adds its own
5327    /// exclusive typed-slot family (an `Actor`-owned per-virtual-
5328    /// actor grain slot the M5 Orleans-inspired kind reaches
5329    /// through, a per-Aplicacao overlay slot the M4 CR materializer
5330    /// consults) folds onto this compound gate as one arm addition
5331    /// rather than a fourth open-coded block at the wire-up site.
5332    ///
5333    /// # Errors
5334    ///
5335    /// Returns the first [`crate::LayoutError`] variant surfacing
5336    /// under the canonical mesh → supervisor → servico order:
5337    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] on a non-
5338    /// Aplicacao caixa with a declared M3 mesh slot,
5339    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] on a
5340    /// non-Supervisor caixa with a declared supervisor-tree slot,
5341    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] on a
5342    /// non-Servico caixa with a declared M2 slot. Passes trivially
5343    /// on the owner kind of each family and on non-owner kinds
5344    /// carrying no declared slot in that family (the fold's identity
5345    /// element on both axes).
5346    pub fn validate_kind_slot_coherence(&self) -> Result<(), crate::LayoutError> {
5347        // Each of the three arms routes through the shared
5348        // [`Self::run_kind_owned_slot_family_gate`] substrate primitive
5349        // — the outer non-owner-kind guard + inner accumulator + inner
5350        // emptiness-guard + wrap arm shape now lands on one dispatch
5351        // per family rather than a four-line open-coded block in
5352        // lockstep across all three arms. Canonical mesh → supervisor
5353        // → servico order preserved (the primitive short-circuits
5354        // arm-by-arm; the outer `?;` cascade at this altitude threads
5355        // the first surfaced arm's error verbatim). Each of the three
5356        // ctors ([`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
5357        // [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
5358        // [`crate::LayoutError::servico_slots_on_non_servico`]) was
5359        // already lifted onto the substrate by the peer
5360        // [`crate::layout::layout_slot_kind_ctors!`] macro, so each arm
5361        // routes through the same substrate-canonical
5362        // `Self::<variant> { caixa, kind, slots }` wrap per arm as the
5363        // pre-lift open-coded blocks — byte-equal, pinned by the
5364        // paired `validate_kind_slot_coherence_folds_<family>_arm_matches_gate`
5365        // equivalence pins and the peer
5366        // `validate_kind_slot_coherence_{mesh,supervisor}_arm_fires_before_<next>_arm`
5367        // ordering pins.
5368        self.run_kind_owned_slot_family_gate(
5369            crate::CaixaKind::is_aplicacao,
5370            Caixa::declared_mesh_slots,
5371            crate::LayoutError::mesh_slots_on_non_aplicacao,
5372        )?;
5373        self.run_kind_owned_slot_family_gate(
5374            crate::CaixaKind::is_supervisor,
5375            Caixa::declared_supervisor_slots,
5376            crate::LayoutError::supervisor_slots_on_non_supervisor,
5377        )?;
5378        self.run_kind_owned_slot_family_gate(
5379            crate::CaixaKind::is_servico,
5380            Caixa::declared_servico_slots,
5381            crate::LayoutError::servico_slots_on_non_servico,
5382        )?;
5383        Ok(())
5384    }
5385
5386    /// Compound per-`Caixa` kind ↔ code-surface coherence gate on
5387    /// the three no-code kinds — `Supervisor` (supervises other
5388    /// caixas, INSPIRATIONS §II.2), `Aplicacao` (composes Servicos,
5389    /// MESH-COMPOSITION §III.1), and `Acao` (owns a typed CI run,
5390    /// CANTEIRO §7.1-C). Each carries no code of its own, so
5391    /// declaring any of `:bibliotecas` / `:exe` / `:servicos`
5392    /// silently passes the layout's path-existence loops (the paths
5393    /// still resolve on disk) and then vanishes downstream — the
5394    /// per-kind renderers gate emission on
5395    /// [`crate::render::require_kind`] and only emit the code
5396    /// surface for its owning kind, so a declared code slot on a
5397    /// no-code kind is the manifest field's documented "ignored
5398    /// otherwise" footgun.
5399    ///
5400    /// Pre-lift each of the three arms lived as a self-similar
5401    /// `if !caixa.kind().is_<no-code-kind>() { … } else if has_code
5402    /// { return Err(LayoutError::<kind>_owns_code(caixa)); }` block
5403    /// at [`crate::layout::StandardLayout::verify`] — three
5404    /// consumers, three identical shapes. Every future consumer
5405    /// that wanted to gate the whole code-surface coherence cascade
5406    /// as a unit (the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
5407    /// materializer's admission webhook re-checking after a
5408    /// per-slot patch, a future `feira validate --no-code-kind`
5409    /// per-caixa admission verb, a per-`Caixa` overlay resolver
5410    /// rejecting a kind-foreign patch) was structurally forced to
5411    /// either re-inline the three-block cascade in lockstep with
5412    /// the layout wire-up (the duplication the PRIME DIRECTIVE
5413    /// names as a bug) or call the whole
5414    /// [`crate::layout::StandardLayout::verify`] pipeline. Post-fold
5415    /// each such consumer reaches the three-arm cascade through
5416    /// one call.
5417    ///
5418    /// Mirror of the sibling [`Self::validate_kind_slot_coherence`]
5419    /// fold (f0d286e) on the author-time typed-slot coherence axis:
5420    /// that gate closes the "non-owner kind declares owner-only
5421    /// typed slots" three-arm cascade on the M2 / supervisor-tree /
5422    /// M3 slot families; this gate closes the reciprocal
5423    /// "no-code kind declares code" three-arm cascade on the
5424    /// `:bibliotecas` / `:exe` / `:servicos` code surface. Together
5425    /// the two folds route every kind ↔ author-shape coherence
5426    /// diagnostic at the layout altitude through one substrate
5427    /// primitive per axis.
5428    ///
5429    /// The gate carries two identity elements:
5430    /// - **`has_code == false`** — any kind (including the three
5431    ///   no-code kinds) that declares no code passes the paired
5432    ///   `!has_code` short-circuit before every per-arm dispatch.
5433    /// - **Code-owning kinds** (`Biblioteca` owning
5434    ///   `:bibliotecas`, `Binario` owning `:exe`, `Servico` owning
5435    ///   `:servicos`) — the three no-code arm-firing predicates
5436    ///   short-circuit on every code-owning kind, so the gate
5437    ///   passes trivially regardless of what code they declare.
5438    ///   Foreign-code-slot violations on a code-owning kind (e.g.
5439    ///   `:kind Servico` declaring `:exe`) surface through the
5440    ///   sibling [`crate::LayoutError::ForeignCodeSlot`] gate on
5441    ///   [`Self::declared_foreign_code_slots`], not through this
5442    ///   gate.
5443    ///
5444    /// Unlike the sibling cross-family
5445    /// [`Self::validate_kind_slot_coherence`], the three arms of
5446    /// this fold are mutually exclusive by construction — `:kind`
5447    /// is a single-valued [`CaixaKind`] discriminator so at most
5448    /// one arm can fire per caixa — and no cross-arm ordering pin
5449    /// is meaningful (the pre-fold three-block cascade at the
5450    /// wire-up site was already unreachable past the first
5451    /// matching arm).
5452    ///
5453    /// Peer to the per-kind compound entry gates every substrate
5454    /// primitive on the M2/M3 typed-slot family already carries
5455    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5456    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5457    /// [`Self::validate_upgrade_from`] d6801df,
5458    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5459    /// [`Self::validate_supervisor_shape`] 4c70105,
5460    /// [`Self::validate_acao_shape`] 5d6df54,
5461    /// [`Self::validate_kind_slot_coherence`] f0d286e): the
5462    /// author-time gate axis on the *per-slot* and *cross-family
5463    /// typed-slot* algebras each share one substrate primitive per
5464    /// compound gate, and this lift closes the third axis on the
5465    /// *code-surface* algebra so the layout pipeline routes all
5466    /// three coherence axes through one substrate primitive rather
5467    /// than nine open-coded blocks. Every future no-code kind
5468    /// (an `Actor` virtual-actor arm the M5 Orleans-inspired kind
5469    /// reaches through if it lands as a no-code composer, a future
5470    /// `Namespace` grouping kind) folds onto this compound gate
5471    /// as one arm addition rather than a fourth open-coded block
5472    /// at the wire-up site.
5473    ///
5474    /// # Errors
5475    ///
5476    /// Returns the [`crate::LayoutError`] variant naming the
5477    /// offending no-code kind:
5478    /// [`crate::LayoutError::SupervisorOwnsCode`] on a `:kind
5479    /// Supervisor` caixa with any declared code,
5480    /// [`crate::LayoutError::AplicacaoOwnsCode`] on a `:kind
5481    /// Aplicacao` caixa with any declared code,
5482    /// [`crate::LayoutError::AcaoOwnsCode`] on a `:kind Acao` caixa
5483    /// with any declared code. Passes trivially on every kind with
5484    /// no declared code and on every code-owning kind regardless
5485    /// of declared code (the fold's two identity-element arms).
5486    pub fn validate_no_code_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5487        let has_code =
5488            !self.bibliotecas().is_empty() || !self.exe().is_empty() || !self.servicos().is_empty();
5489        if !has_code {
5490            return Ok(());
5491        }
5492        if self.kind().is_supervisor() {
5493            return Err(crate::LayoutError::supervisor_owns_code(self));
5494        }
5495        if self.kind().is_aplicacao() {
5496            return Err(crate::LayoutError::aplicacao_owns_code(self));
5497        }
5498        if self.kind().is_acao() {
5499            return Err(crate::LayoutError::acao_owns_code(self));
5500        }
5501        Ok(())
5502    }
5503
5504    /// Compound per-`Caixa` kind ↔ `:ci` coherence gate — the `Acao`
5505    /// axis-only companion to the sibling three-arm
5506    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) on the
5507    /// M3 mesh / supervisor-tree / M2 Servico-runtime typed-slot
5508    /// families. `:ci` carries a typed CI run
5509    /// ([`canteiro_types::CiRun`], CANTEIRO §7.1-C) that only the
5510    /// `caixa-actions` renderer decomposes + validates and only for a
5511    /// `:kind Acao`. On any *other* kind a declared `:ci` is the
5512    /// manifest field's documented "ignored otherwise" — it silently
5513    /// passes verify and then vanishes (never decomposed, never
5514    /// rendered), far from the source `caixa.lisp`.
5515    ///
5516    /// Pre-lift the arm lived as a self-similar
5517    /// `if caixa.ci().is_some() && !caixa.kind().is_acao() { return
5518    /// Err(LayoutError::CiOnNonAcao { caixa: caixa.nome().to_string(),
5519    /// kind: caixa.kind() }); }` block at
5520    /// [`crate::layout::StandardLayout::verify`] — one consumer today
5521    /// but every future consumer that wanted to gate the `:ci`
5522    /// coherence axis as a unit (the deferred
5523    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5524    /// webhook re-checking after a per-slot patch, a future
5525    /// `feira validate --ci-coherence` per-caixa admission verb, a
5526    /// per-`Caixa` overlay resolver rejecting a kind-foreign `:ci`
5527    /// patch) was structurally forced to either re-inline the
5528    /// two-condition guard in lockstep with the layout wire-up (the
5529    /// duplication the PRIME DIRECTIVE names as a bug) or call the
5530    /// whole [`crate::layout::StandardLayout::verify`] pipeline.
5531    /// Post-fold each such consumer reaches the arm through one call.
5532    ///
5533    /// Peer of the sibling three-arm
5534    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) — that
5535    /// gate carries the M3 mesh / supervisor-tree / M2 Servico-runtime
5536    /// axes under a uniform `{ caixa, kind, slots }` envelope
5537    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5538    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5539    /// [`crate::LayoutError::ServicoSlotsOnNonServico`]). The `:ci`
5540    /// axis stays on its own primitive because
5541    /// [`crate::LayoutError::CiOnNonAcao`] carries a distinct
5542    /// `{ caixa, kind }` wrap shape (no `slots` field — `:ci` is a
5543    /// single `Option` not a `Vec`-of-named-slots) whose reshape
5544    /// onto the sibling `{ caixa, kind, slots }` envelope would
5545    /// force a variant rename touching every consumer of
5546    /// `CiOnNonAcao`; the two folds share the same
5547    /// author-time-vs-renderer split and diagnostic altitude, and
5548    /// route through peer substrate primitives on the same
5549    /// [`Caixa`] surface.
5550    ///
5551    /// Peer to the per-kind compound entry gates every substrate
5552    /// primitive on the M2/M3 typed-slot family already carries
5553    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5554    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5555    /// [`Self::validate_upgrade_from`] d6801df,
5556    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5557    /// [`Self::validate_supervisor_shape`] 4c70105,
5558    /// [`Self::validate_acao_shape`] 5d6df54,
5559    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5560    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2): every
5561    /// author-time coherence axis on the typed [`Caixa`] surface now
5562    /// routes through one substrate primitive per axis rather than
5563    /// an open-coded block at the layout wire-up site.
5564    ///
5565    /// The gate carries two identity elements:
5566    /// - **`ci().is_none()`** — a caixa that declares no `:ci`
5567    ///   passes the first short-circuit before every per-arm
5568    ///   dispatch, on every kind. The canonical shape of the four
5569    ///   non-`Acao` kinds (`Biblioteca` / `Binario` / `Servico` /
5570    ///   `Supervisor` / `Aplicacao`) is `ci = None` — the arm
5571    ///   never fires on a well-shaped fixture.
5572    /// - **`:kind Acao`** — the owner-kind arm short-circuits on
5573    ///   every `Acao` caixa regardless of its `:ci` shape; a
5574    ///   malformed `:ci` on an `Acao` surfaces through the peer
5575    ///   [`Self::validate_acao_shape`] compound decompose gate
5576    ///   (5d6df54), not through this coherence gate.
5577    ///
5578    /// # Errors
5579    ///
5580    /// Returns [`crate::LayoutError::CiOnNonAcao`] naming the
5581    /// offending caixa's nome + kind on any non-`Acao` caixa with
5582    /// `:ci` declared. Passes trivially on every kind that declares
5583    /// no `:ci` and on every `:kind Acao` caixa regardless of
5584    /// declared `:ci` (the fold's two identity-element arms).
5585    pub fn validate_ci_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5586        if self.ci().is_some() && !self.kind().is_acao() {
5587            return Err(crate::LayoutError::ci_on_non_acao(self));
5588        }
5589        Ok(())
5590    }
5591
5592    /// Compound per-`Caixa` kind ↔ code-surface coherence gate on the
5593    /// two exclusive code-surface slots — `:exe` (owned only by
5594    /// [`crate::CaixaKind::Binario`], the nix-built executable surface)
5595    /// and `:servicos` (owned only by [`crate::CaixaKind::Servico`],
5596    /// the wasm-component + `ComputeUnit` daemon surface). The
5597    /// `caixa-helm` / `caixa-flux` / `caixa-flake` renderers gate
5598    /// emission on [`crate::render::require_kind`]`(_, <owning-kind>)`
5599    /// and only emit the slot for its owning kind — so on any *other*
5600    /// code-running kind a declared `:exe` / `:servicos` is the
5601    /// manifest field's documented "ignored otherwise": the path is
5602    /// validated by the per-kind path-existence loops in
5603    /// [`crate::layout::StandardLayout::verify`], but the value is
5604    /// never rendered into a build target or programs.yaml entry —
5605    /// it silently passes `feira build` and then vanishes, far from
5606    /// the source `caixa.lisp`, with no field naming which slot is
5607    /// foreign.
5608    ///
5609    /// Pre-lift the arm lived as a self-similar four-line `let
5610    /// foreign_code_slots = caixa.declared_foreign_code_slots(); if
5611    /// !foreign_code_slots.is_empty() { return
5612    /// Err(LayoutError::foreign_code_slot(caixa, foreign_code_slots));
5613    /// }` block at [`crate::layout::StandardLayout::verify`] — one
5614    /// consumer today but every future consumer that wanted to gate
5615    /// the code-surface coherence axis as a unit (the deferred
5616    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5617    /// webhook re-checking after a per-slot patch, a future
5618    /// `feira validate --foreign-code` per-caixa admission verb, a
5619    /// per-`Caixa` overlay resolver rejecting a kind-foreign code-
5620    /// slot patch) was structurally forced to either re-inline the
5621    /// two-condition guard in lockstep with the layout wire-up (the
5622    /// duplication the PRIME DIRECTIVE names as a bug) or call the
5623    /// whole [`crate::layout::StandardLayout::verify`] pipeline.
5624    /// Post-fold each such consumer reaches the arm through one call.
5625    ///
5626    /// Peer of the sibling three-arm
5627    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) — that
5628    /// gate carries the M3 mesh / supervisor-tree / M2 Servico-runtime
5629    /// axes under the uniform `{ caixa, kind, slots }` envelope
5630    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5631    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5632    /// [`crate::LayoutError::ServicoSlotsOnNonServico`]); this gate
5633    /// carries the code-surface axis under the same
5634    /// `{ caixa, kind, slots }` envelope
5635    /// ([`crate::LayoutError::ForeignCodeSlot`]). The two folds share
5636    /// the envelope shape but stay separate primitives because the
5637    /// per-arm predicate differs: the cross-family fold rides on the
5638    /// outer `!self.kind().is_<owner>()` guard *paired* with a
5639    /// per-family `declared_<family>_slots` accumulator, while this
5640    /// fold's per-arm kind-check is baked into
5641    /// [`Self::declared_foreign_code_slots`] itself (each arm's
5642    /// `!self.kind().requires_<slot>()` guard fires inside the
5643    /// accumulator, not around it) — so a `:kind Binario` declaring
5644    /// `:servicos` and a `:kind Servico` declaring `:exe` are both
5645    /// caught by one accumulator sweep rather than by two independent
5646    /// arm dispatches. Peer with [`Self::validate_ci_kind_coherence`]
5647    /// (9b55beb) which carries the `:ci` axis on its own primitive
5648    /// for the same "distinct per-arm predicate shape, shared
5649    /// diagnostic altitude" reason.
5650    ///
5651    /// Peer to the per-kind and per-slot compound entry gates every
5652    /// substrate primitive on the M2/M3 typed-slot family already
5653    /// carries ([`Self::validate_deps`] b5dd55e,
5654    /// [`Self::validate_limits`] baa4688,
5655    /// [`Self::validate_behavior`] 0d2877a,
5656    /// [`Self::validate_upgrade_from`] d6801df,
5657    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5658    /// [`Self::validate_supervisor_shape`] 4c70105,
5659    /// [`Self::validate_acao_shape`] 5d6df54,
5660    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5661    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
5662    /// [`Self::validate_ci_kind_coherence`] 9b55beb): every
5663    /// author-time coherence axis on the typed [`Caixa`] surface now
5664    /// routes through one substrate primitive per axis rather than an
5665    /// open-coded block at the layout wire-up site. This closes the
5666    /// last open-coded kind ↔ slot coherence gate at the layout
5667    /// altitude — every kind-coherence diagnostic is now a substrate
5668    /// primitive.
5669    ///
5670    /// The gate carries three identity elements:
5671    /// - **Code-owning kinds on their native slot** — a
5672    ///   [`crate::CaixaKind::Binario`] declaring `:exe`, a
5673    ///   [`crate::CaixaKind::Servico`] declaring `:servicos` — each
5674    ///   arm's `!requires_<slot>()` predicate short-circuits inside
5675    ///   [`Self::declared_foreign_code_slots`], so the accumulator
5676    ///   returns an empty `Vec` and the outer `is_empty` short-
5677    ///   circuits before the wrap fires.
5678    /// - **Bare caixas** — a caixa with no declared code on any kind
5679    ///   passes the same accumulator's `is_empty` short-circuit on
5680    ///   every arm.
5681    /// - **No-code kinds** ([`crate::CaixaKind::Supervisor`] /
5682    ///   [`crate::CaixaKind::Aplicacao`] / [`crate::CaixaKind::Acao`])
5683    ///   declaring code — dominated upstream by the sibling
5684    ///   [`Self::validate_no_code_kind_coherence`] (3bbf6a2) which
5685    ///   surfaces [`crate::LayoutError::SupervisorOwnsCode`] /
5686    ///   [`crate::LayoutError::AplicacaoOwnsCode`] /
5687    ///   [`crate::LayoutError::AcaoOwnsCode`] first at the layout
5688    ///   wire-up site, so this gate never fires on a no-code kind
5689    ///   through the layout pipeline. A standalone caller reaching
5690    ///   this primitive without the sibling `_no_code_` gate first
5691    ///   would see a no-code kind's declared `:exe` / `:servicos`
5692    ///   surface `ForeignCodeSlot` here (the two folds partition the
5693    ///   diagnostic responsibility along the "declared no-code slot"
5694    ///   axis: no-code kinds get `OwnsCode`, code-running kinds get
5695    ///   `ForeignCodeSlot`), and the layout wire-up's canonical
5696    ///   `_no_code_` → `_foreign_code_` ordering keeps the
5697    ///   [`crate::LayoutError::SupervisorOwnsCode`] / … arm the one
5698    ///   that surfaces in the composed pipeline.
5699    ///
5700    /// Diagnostic order within the arm matches the pre-fold layout
5701    /// wire-up canonical sequence — `:exe` → `:servicos` — pinned by
5702    /// [`Self::declared_foreign_code_slots`]'s per-arm push order.
5703    ///
5704    /// # Errors
5705    ///
5706    /// Returns [`crate::LayoutError::ForeignCodeSlot`] naming the
5707    /// offending caixa's nome + kind + declared foreign-code slot
5708    /// list on any code-running kind ([`crate::CaixaKind::Biblioteca`]
5709    /// / [`crate::CaixaKind::Binario`] / [`crate::CaixaKind::Servico`])
5710    /// declaring another code-running kind's exclusive code surface.
5711    /// Passes trivially on every native-slot declaration (Binario
5712    /// with `:exe`, Servico with `:servicos`), on every bare caixa,
5713    /// and on every no-code kind (dominated upstream by the sibling
5714    /// [`Self::validate_no_code_kind_coherence`] `OwnsCode` gates —
5715    /// see the identity-element notes above).
5716    pub fn validate_foreign_code_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5717        let foreign_code_slots = self.declared_foreign_code_slots();
5718        if !foreign_code_slots.is_empty() {
5719            return Err(crate::LayoutError::foreign_code_slot(
5720                self,
5721                foreign_code_slots,
5722            ));
5723        }
5724        Ok(())
5725    }
5726
5727    /// Compound per-`Caixa` required-slot gate on the three
5728    /// [`crate::CaixaKind`] arms whose sole payload is a canonical
5729    /// typed slot: `Binario`'s `:exe`, `Servico`'s `:servicos`,
5730    /// `Acao`'s `:ci`. Each arm refuses a caixa on its owner kind
5731    /// that declares no value in the corresponding required slot,
5732    /// so `feira build` (the canonical author-time gate) surfaces the
5733    /// self-locating "this kind needs this slot" diagnostic at the
5734    /// source `caixa.lisp` rather than deferring the failure to a
5735    /// downstream consumer (a nix build with no `:exe` to build, a
5736    /// programs.yaml fan-out with no `:servicos` to enumerate, a
5737    /// `caixa-actions` decompose with no `:ci` to walk).
5738    ///
5739    /// Pre-lift each of the three arms lived as a self-similar
5740    /// `if caixa.kind().requires_<slot>() && caixa.<slot>().is_<empty>() {
5741    /// return Err(LayoutError::<kind>_without_<slot>(caixa)); }`
5742    /// block at [`crate::layout::StandardLayout::verify`] — three
5743    /// consumers, three identical shapes, one substrate primitive on
5744    /// [`Caixa`] closing the duplication the PRIME DIRECTIVE names as
5745    /// a bug. Each of the three inner ctors
5746    /// ([`crate::LayoutError::binario_without_exe`] /
5747    /// [`crate::LayoutError::servico_without_servicos`] /
5748    /// [`crate::LayoutError::missing_ci`]) was already lifted onto
5749    /// the substrate by the peer [`crate::layout::layout_nome_only_ctors!`]
5750    /// macro, so the primitive routes through the same
5751    /// `Self::<variant>(caixa.nome().to_string())` tuple-literal
5752    /// wrap per arm as the pre-lift open-coded blocks.
5753    ///
5754    /// The paired `Biblioteca`-arm required-slot check
5755    /// ([`crate::LayoutError::MissingLib`]) stays open-coded at the
5756    /// layout wire-up site by design: it needs the filesystem oracle
5757    /// on [`crate::layout::LayoutInvariants`] to check the default
5758    /// `lib/<nome>.lisp` fallback path, which the pure per-`Caixa`
5759    /// typed-shape surface this fold rides on has no reference to.
5760    /// Same posture the peer [`Self::validate_no_code_kind_coherence`]
5761    /// fold takes on the on-disk existence loops.
5762    ///
5763    /// Diagnostic order at the primitive matches the pre-fold layout
5764    /// wire-up canonical sequence — `:exe` → `:servicos` → `:ci` —
5765    /// the same three-arm sweep the peer [`crate::CaixaKind`]
5766    /// discriminator carries at its `requires_*` accessors. Unlike
5767    /// the sibling cross-family [`Self::validate_kind_slot_coherence`]
5768    /// fold, the three arms of this fold are mutually exclusive by
5769    /// construction — `:kind` is a single-valued [`crate::CaixaKind`]
5770    /// discriminator so at most one arm can fire per caixa — and no
5771    /// cross-arm ordering pin is meaningful (the pre-fold three-block
5772    /// cascade at the wire-up site was already unreachable past the
5773    /// first matching arm).
5774    ///
5775    /// Peer to the per-kind and per-slot compound entry gates every
5776    /// substrate primitive on the M2/M3 typed-slot family already
5777    /// carries ([`Self::validate_deps`] b5dd55e,
5778    /// [`Self::validate_limits`] baa4688,
5779    /// [`Self::validate_behavior`] 0d2877a,
5780    /// [`Self::validate_upgrade_from`] d6801df,
5781    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5782    /// [`Self::validate_supervisor_shape`] 4c70105,
5783    /// [`Self::validate_acao_shape`] 5d6df54,
5784    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5785    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
5786    /// [`Self::validate_ci_kind_coherence`] 9b55beb): every
5787    /// author-time coherence axis on the typed [`Caixa`] surface
5788    /// now routes through one substrate primitive per axis rather
5789    /// than an open-coded block at the layout wire-up site.
5790    ///
5791    /// The gate carries two identity elements:
5792    /// - **Non-owner kinds** — each per-arm predicate is
5793    ///   `self.kind().requires_<slot>()`, which returns `true` only
5794    ///   for the owning kind ([`crate::CaixaKind::Binario`] on `:exe`,
5795    ///   [`crate::CaixaKind::Servico`] on `:servicos`,
5796    ///   [`crate::CaixaKind::Acao`] on `:ci`). Every non-owner kind
5797    ///   passes each per-arm dispatch trivially.
5798    /// - **Owner kinds with the required slot present** — a
5799    ///   [`crate::CaixaKind::Binario`] with a non-empty `:exe`, a
5800    ///   [`crate::CaixaKind::Servico`] with a non-empty `:servicos`,
5801    ///   an [`crate::CaixaKind::Acao`] with `ci = Some(_)` — passes
5802    ///   its arm's `is_empty` / `is_none` short-circuit.
5803    ///
5804    /// # Errors
5805    ///
5806    /// Returns the [`crate::LayoutError`] variant naming the
5807    /// offending owner kind:
5808    /// [`crate::LayoutError::BinarioWithoutExe`] on a
5809    /// [`crate::CaixaKind::Binario`] caixa with no declared `:exe`,
5810    /// [`crate::LayoutError::ServicoWithoutServicos`] on a
5811    /// [`crate::CaixaKind::Servico`] caixa with no declared
5812    /// `:servicos`, [`crate::LayoutError::MissingCi`] on a
5813    /// [`crate::CaixaKind::Acao`] caixa with no declared `:ci`.
5814    /// Passes trivially on every non-owner kind and on every owner
5815    /// kind with its required slot present.
5816    pub fn validate_required_kind_slot(&self) -> Result<(), crate::LayoutError> {
5817        if self.kind().requires_exe() && self.exe().is_empty() {
5818            return Err(crate::LayoutError::binario_without_exe(self));
5819        }
5820        if self.kind().requires_servicos() && self.servicos().is_empty() {
5821            return Err(crate::LayoutError::servico_without_servicos(self));
5822        }
5823        if self.kind().requires_ci() && self.ci().is_none() {
5824            return Err(crate::LayoutError::missing_ci(self));
5825        }
5826        Ok(())
5827    }
5828
5829    /// Reject per-entry values on the three Caixa-level code-surface
5830    /// path lists (`:bibliotecas`, `:exe`, `:servicos`) that the
5831    /// layout checker's `root.join(p)` sandbox would silently subvert.
5832    /// Same three structural footguns the peer
5833    /// [`BehaviorSpec::validate`] (b0c8389) and
5834    /// [`crate::UpgradeInstruction::validate`] `StateChange` arm
5835    /// (26da2c7) already close on the M2 `:behavior :on-*` and
5836    /// `:upgrade-from :state-change :script` axes, here lifted onto
5837    /// the three top-level code-path axes through the shared
5838    /// [`is_sandboxed_relative_path`] predicate:
5839    ///
5840    ///   - empty entry (`(:bibliotecas (""))` / `(:exe (""))` /
5841    ///     `(:servicos (""))`): `PathBuf::new()` round-trips through
5842    ///     [`Path::join`] as the base itself — `root.join("")` ==
5843    ///     `root`, so the existence check (`self.exists(&root)`)
5844    ///     trivially passes (the project root exists), and the layout
5845    ///     silently treats the project root as a biblioteca / exe /
5846    ///     servico entry. The `:bibliotecas` loop then hands the root
5847    ///     to `tatara_lisp::read` at `feira build` time as if the root
5848    ///     directory itself were a Lisp source file — a parse error
5849    ///     far from the source `caixa.lisp` with no field naming the
5850    ///     offending entry.
5851    ///   - absolute path (`(:bibliotecas ("/etc/passwd"))`):
5852    ///     [`Path::join`] *replaces* the base when the right-hand side
5853    ///     is absolute, so `root.join("/etc/passwd")` resolves to
5854    ///     `"/etc/passwd"` and escapes the project sandbox entirely.
5855    ///     The existence check then silently consults whatever the
5856    ///     escaped path resolves to — for `:bibliotecas`, the layout
5857    ///     has no `starts_with`-fence (only `:exe` is fenced under
5858    ///     `exe/` and `:servicos` under `servicos/`), so an absolute
5859    ///     `:bibliotecas` entry that happens to resolve on disk
5860    ///     silently passes. For `:exe` / `:servicos` the fence catches
5861    ///     the absolute case downstream as `ExeOutsideDir` /
5862    ///     `ServicoOutsideDir` (or `MissingEntry` if the absolute path
5863    ///     doesn't exist), but with a downstream-shaped diagnostic
5864    ///     that names the resolved escape path rather than the
5865    ///     authoring footgun at the source.
5866    ///   - parent-escape (`(:bibliotecas ("../sibling/x.lisp"))` /
5867    ///     `(:exe ("exe/../../escape.lisp"))`): a [`PathBuf`] with any
5868    ///     [`std::path::Component::ParentDir`] anywhere round-trips
5869    ///     through [`Path::join`] as a traversal above the caixa root.
5870    ///     The `:exe` / `:servicos` `starts_with(<dir>)` fence is
5871    ///     *component-aware* (not canonical-path-aware), so
5872    ///     `root.join("exe/../../escape.lisp")` `starts_with(exe_dir)`
5873    ///     is **true** even though the canonical resolution
5874    ///     `{parent of root}/escape.lisp` lives outside the caixa root
5875    ///     — the fence silently lets the parent-escape through, and
5876    ///     the existence check passes if that escape-target happens
5877    ///     to exist. Caught regardless of where the `..` sits
5878    ///     (leading, mid-path, trailing) so the gate matches the peer
5879    ///     predicate's full coverage.
5880    ///
5881    /// Same `Empty` → `Absolute` → `ParentEscape` arm-ordering every peer
5882    /// `is_sandboxed_relative_path` consumer follows (b0c8389 / 26da2c7);
5883    /// same per-slot diagnostic shape every peer per-axis path-gate
5884    /// exposes (`*Empty { slot }` / `*Absolute { slot, path }` /
5885    /// `*ParentEscape { slot, path }`). Cross-slot precedence is
5886    /// `:bibliotecas` → `:exe` → `:servicos` — the same declaration
5887    /// order [`Caixa::declared_foreign_code_slots`] uses for its
5888    /// canonical foreign-code-slot diagnostic, so a manifest with
5889    /// multiple malformed slots surfaces the lexicographically-earliest
5890    /// slot's diagnostic deterministically.
5891    ///
5892    /// Lifted to the typed surface as a Caixa-level validator (peer
5893    /// of [`Self::validate_nome`] / [`Self::validate_versao`] /
5894    /// [`Self::validate_deps`] / [`Self::validate_restart_window`])
5895    /// and wired into [`crate::StandardLayout::verify`] before the
5896    /// existence-check loops so the diagnostic names the offending
5897    /// slot at the source caixa.lisp rather than reporting a
5898    /// downstream `MissingEntry` / `ExeOutsideDir` /
5899    /// `ServicoOutsideDir` against the resolved sandbox-escape path.
5900    /// The fourth typed code-path surface — every author-supplied
5901    /// path on the manifest — is now structurally accept-shaped
5902    /// past validate, peer with `:behavior :on-*` and
5903    /// `:upgrade-from :state-change :script`.
5904    pub fn validate_code_paths(&self) -> Result<(), ManifestError> {
5905        /// Per-slot file-type contract for the three Caixa-level
5906        /// code-path surfaces (`:bibliotecas`, `:exe`, `:servicos`).
5907        /// Each variant names the predicate the per-entry file-type
5908        /// gate consults; [`Self::None`] opts the slot out of any
5909        /// file-type contract. Lifted as a typed local enum so the
5910        /// per-slot dispatch is exhaustive at the `match` — adding a
5911        /// future axis to the typed-substrate `:` slot set (the
5912        /// future `:assets` resource axis the M5 roadmap names, the
5913        /// future `:nix-flake` derivation axis the caixa-flake
5914        /// emitter consults) lands as one variant + one `match` arm,
5915        /// not a coordinated rewrite of every per-slot bool flag.
5916        ///
5917        /// Peer of the typed-substrate per-slot variant disciplines
5918        /// already established on this surface
5919        /// ([`crate::supervisor::RestartStrategy`] +
5920        /// [`crate::supervisor::RestartPolicy`] on the OTP-shape
5921        /// supervision-tree axis,
5922        /// [`crate::aplicacao::PlacementStrategy`] on the §III.1
5923        /// placement axis, [`crate::aplicacao::WitTarget`] on the
5924        /// `:contratos` payload-target axis): the typed `enum` is
5925        /// the substrate's single source of truth for the per-axis
5926        /// dispatch, and every consumer (the per-arm body here, the
5927        /// future feira-lint per-slot diagnostic renderer, the M4
5928        /// per-axis admission webhook) reaches for the same typed
5929        /// surface rather than re-deriving the partition from inline
5930        /// flag combinations.
5931        enum CodePathFileType {
5932            /// `:exe` — nix-build derivation output, no terminating-
5933            /// extension contract (the canonical `"exe/<name>"`
5934            /// fixtures the layout's `ExeOutsideDir` error message
5935            /// documents carry no extension by convention).
5936            None,
5937            /// `:bibliotecas` — tatara-lisp source files the
5938            /// `feira build` loop reads through `tatara_lisp::read`
5939            /// at parse time. Routes to [`is_lisp_extension`].
5940            LispSource,
5941            /// `:servicos` — ComputeUnit-CR YAML files the
5942            /// caixa-helm / caixa-flux renderers consume through
5943            /// `serde_yaml::from_str`. Routes to
5944            /// [`is_computeunit_yaml_extension`].
5945            ComputeUnitYaml,
5946        }
5947
5948        // The per-slot [`CodePathFileType`] selects which axes carry the
5949        // lifted file-type predicate. `:bibliotecas` is the tatara-lisp
5950        // source axis (the `feira build` loop at
5951        // `caixa-feira/src/cmd/build.rs:33` reads each entry through
5952        // `tatara_lisp::read` at parse time) — the lifted
5953        // [`is_lisp_extension`] predicate gates the `.lisp` extension.
5954        // `:exe` is the nix-built executable surface (per the canonical
5955        // `"exe/<name>"`-shaped fixtures the layout's `ExeOutsideDir`
5956        // error message documents and every in-tree
5957        // `caixa_with_code_paths` positive control uses) — its file-type
5958        // contract is "nix-build derivation output", not a typed source
5959        // file, so [`CodePathFileType::None`] opts the slot out of any
5960        // file-type gate. `:servicos` is the `.computeunit.yaml`
5961        // ComputeUnit-CR axis (the peer caixa-helm / caixa-flux
5962        // renderers consume each entry through `serde_yaml::from_str` as
5963        // a typed `ComputeUnit` CR) — the lifted
5964        // [`is_computeunit_yaml_extension`] predicate gates the compound
5965        // `.computeunit.yaml` suffix. All three axes are surfaced through
5966        // the same iteration so the sandbox-shape + duplicate gates
5967        // apply uniformly; the typed file-type dispatch fires per-slot
5968        // exactly where the downstream consumer's accepted set demands
5969        // it. The third file-type variant ([`ComputeUnitYaml`]) is the
5970        // compounding lift on the peer 64772a9 `:bibliotecas`
5971        // `.lisp`-gate trajectory — the second of the three code-path
5972        // axes to land on a typed compound-suffix gate, with the same
5973        // self-locating per-slot diagnostic shape every peer per-axis
5974        // file-type lift uses (`*NonLispExtension { slot, path }` /
5975        // `*NonComputeUnitYamlExtension { slot, path }`).
5976        for (slot, list, file_type) in [
5977            (
5978                ":bibliotecas",
5979                &self.bibliotecas,
5980                CodePathFileType::LispSource,
5981            ),
5982            (":exe", &self.exe, CodePathFileType::None),
5983            (
5984                ":servicos",
5985                &self.servicos,
5986                CodePathFileType::ComputeUnitYaml,
5987            ),
5988        ] {
5989            // Per-slot set-not-multiset gate on the typed code-path axis.
5990            // Every peer Vec-shaped author-supplied list past validate is
5991            // a set, not a multiset: `:membros :caixa`
5992            // ([`crate::AplicacaoError::MembroDuplicate`]), `:placement
5993            // :clusters` ([`crate::AplicacaoError::PlacementClusterDuplicate`]),
5994            // `:entrada :paths` ([`crate::AplicacaoError::EntradaPathDuplicate`]),
5995            // `:contratos` ([`crate::AplicacaoError::ContratoDuplicate`]),
5996            // `:children :caixa` ([`crate::SupervisorError::DuplicateChild`]),
5997            // `:deps` / `:deps-dev` `:nome` ([`crate::DepError::DuplicateNome`]
5998            // per 359fba5), `:upgrade-from :from` ([`crate::UpgradeError::DuplicateFrom`]),
5999            // `:etiquetas` ([`ManifestError::EtiquetaDuplicate`] per 360a499),
6000            // `:autores` ([`ManifestError::AutorDuplicate`] per 86c769b) —
6001            // the three code-path lists are the last Vec-shaped author-
6002            // supplied slots on the typed Caixa surface still admitting a
6003            // duplicate entry silently. Scope is per-list (`:bibliotecas`
6004            // duplicates are flagged within `:bibliotecas`, not across
6005            // `:bibliotecas` ↔ `:exe`) — the same per-list scope `:deps`
6006            // ↔ `:deps-dev` use (a `:nome` present in both lists is a
6007            // legitimate dev-vs-runtime shape on the dep axis, fenced
6008            // separately by [`crate::dep::validate_no_self_dep`]). On the
6009            // code-path axis a cross-slot collision is structurally
6010            // impossible by the layout's `starts_with(<exe|servicos>_dir)`
6011            // fence — `:exe` and `:servicos` entries are confined to their
6012            // own directory trees, so the only way a string could appear
6013            // on two code-path lists is the (rare, structurally invalid)
6014            // case where `:bibliotecas` carries an `"exe/<x>"` or
6015            // `"servicos/<x>.yaml"`-shaped path.
6016            //
6017            // Without the gate three authoring footguns silently passed:
6018            //
6019            //   - `:bibliotecas ("lib/foo.lisp" "lib/foo.lisp")` — the
6020            //     canonical copy-paste-the-wrong-file footgun. `feira
6021            //     build` (`caixa-feira/src/cmd/build.rs:33`) walks the
6022            //     list and re-parses the same file twice, wasting work
6023            //     and silently masking the author's intent to declare a
6024            //     *second* biblioteca.
6025            //   - `:exe ("exe/cli" "exe/cli")` — the same footgun on the
6026            //     Binario surface. The future `caixa-flake` `nix flake`
6027            //     emitter that materializes each `:exe` entry as a flake
6028            //     `packages.<exe-name>` derivation would collide on the
6029            //     duplicate package name and surface a flake-eval error
6030            //     far from the source `caixa.lisp`.
6031            //   - `:servicos ("servicos/x.computeunit.yaml"
6032            //     "servicos/x.computeunit.yaml")` — the same footgun on
6033            //     the Servico surface. The peer `caixa-helm` / `caixa-flux`
6034            //     renderers already refuse `:servicos.len() != 1` with
6035            //     the narrower [`UnsupportedServicoCount`] diagnostic, but
6036            //     that diagnostic surfaces "too many servicos" without
6037            //     naming "duplicate entry" — the typed self-locating
6038            //     "which entry is the duplicate" framing only lands at
6039            //     this gate.
6040            //
6041            // Same `seen.insert(entry.as_str())` shape every peer per-list
6042            // duplicate gate uses (`:etiquetas` 360a499, `:autores`
6043            // 86c769b, `:deps` 359fba5) and the same "structural shape
6044            // checks fire before the duplicate check on the same entry"
6045            // ordering (a `(:bibliotecas ("" "lib/x.lisp" "lib/x.lisp"))`
6046            // shape surfaces the narrower [`Self::CodePathEmpty`] for the
6047            // empty entry first, not the duplicate on the later pair).
6048            let mut seen = std::collections::HashSet::new();
6049            for entry in list {
6050                let path = Path::new(entry);
6051                match is_sandboxed_relative_path(path) {
6052                    Ok(()) => {}
6053                    Err(PathShapeViolation::Empty) => {
6054                        return Err(ManifestError::code_path_empty(slot));
6055                    }
6056                    Err(PathShapeViolation::Absolute) => {
6057                        return Err(ManifestError::code_path_absolute(slot, path));
6058                    }
6059                    Err(PathShapeViolation::ParentEscape) => {
6060                        return Err(ManifestError::code_path_parent_escape(slot, path));
6061                    }
6062                }
6063                // The per-slot file-type gate dispatched through the
6064                // typed [`CodePathFileType`] selector above. Each variant
6065                // routes to the lifted predicate the downstream consumer
6066                // demands:
6067                //
6068                //   - [`LispSource`] → [`is_lisp_extension`] for
6069                //     `:bibliotecas` (the `feira build` loop's
6070                //     `tatara_lisp::read` consumer);
6071                //   - [`ComputeUnitYaml`] → [`is_computeunit_yaml_extension`]
6072                //     for `:servicos` (the caixa-helm / caixa-flux
6073                //     `serde_yaml::from_str` consumer's `ComputeUnit` CR
6074                //     accepted set);
6075                //   - [`None`] for `:exe` — the nix-build derivation-
6076                //     output axis has no terminating-extension contract.
6077                //
6078                // Fires after the sandbox-shape arms so a path that is
6079                // *both* sandbox-escaping and wrong-extension surfaces
6080                // the more fundamental sandbox-shape diagnostic first
6081                // (mirrors the peer `EmptyPath` → `AbsolutePath` →
6082                // `ParentEscape` → `NonLispExtension` arm-ordering on
6083                // `:behavior :on-*` c97815a, and `EmptyScript` →
6084                // `AbsoluteScript` → `ParentEscapeScript` →
6085                // `NonLispExtensionScript` on
6086                // `:upgrade-from :state-change :script` 33cc830), and
6087                // before the duplicate gate so the narrower per-entry
6088                // file-type shape dominates the cross-entry uniqueness
6089                // diagnostic (a
6090                // `("servicos/x.yaml" "servicos/x.yaml")` shape on
6091                // `:servicos` surfaces
6092                // `CodePathNonComputeUnitYamlExtension` on the first
6093                // entry rather than `CodePathDuplicate` on the pair —
6094                // peer with the 64772a9 `:bibliotecas`
6095                // `("lib/x.txt" "lib/x.txt")` ordering).
6096                match file_type {
6097                    CodePathFileType::None => {}
6098                    CodePathFileType::LispSource => {
6099                        if !is_lisp_extension(path) {
6100                            return Err(ManifestError::code_path_non_lisp_extension(slot, path));
6101                        }
6102                    }
6103                    CodePathFileType::ComputeUnitYaml => {
6104                        if !is_computeunit_yaml_extension(path) {
6105                            return Err(ManifestError::code_path_non_computeunit_yaml_extension(
6106                                slot, path,
6107                            ));
6108                        }
6109                    }
6110                }
6111                crate::render::insert_first_seen(&mut seen, entry.as_str(), || {
6112                    ManifestError::code_path_duplicate(slot, path)
6113                })?;
6114            }
6115        }
6116        Ok(())
6117    }
6118
6119    /// Reject `:etiquetas` lists with an empty entry or with two entries
6120    /// agreeing on the same string. `:etiquetas` is the universal
6121    /// registry-search-tag axis on [`Caixa`] (every kind carries the
6122    /// `Vec<String>` slot) and lands verbatim as the Helm chart
6123    /// `Chart.yaml` `keywords:` array on every Servico (caixa-helm's
6124    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:236` folds it through
6125    /// a [`std::collections::BTreeSet`] alongside the four substrate-
6126    /// fixed tags `lareira` / `wasm` / `tatara-lisp` / `caixa-servico`).
6127    /// Two authoring footguns silently passed validate without this gate:
6128    ///
6129    ///   - Empty entry (`(:etiquetas (""))` — the canonical paste-from-
6130    ///     blank-doc footgun) rendered as `keywords: ["", "caixa-servico",
6131    ///     "lareira", "tatara-lisp", "wasm"]` in `Chart.yaml`. Helm's
6132    ///     `chart.metadata.keywords` admits the value without a strict
6133    ///     parser-side gate, but the empty keyword has no operational
6134    ///     meaning — it indexes nothing in the future caixa-registry
6135    ///     search axis and clutters the rendered chart with a no-op tag.
6136    ///   - Duplicate entries (`(:etiquetas ("demo" "demo"))` — the
6137    ///     copy-paste-the-wrong-tag footgun) silently passed validate
6138    ///     and were silently dedup'd by caixa-helm's `BTreeSet` collect
6139    ///     at chart render — a "second wins / one silently disappears"
6140    ///     shape divergent from every peer typed-graph set gate
6141    ///     ([`crate::AplicacaoError::MembroDuplicate`] on `:membros`,
6142    ///     [`crate::AplicacaoError::PlacementClusterDuplicate`] on
6143    ///     `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
6144    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
6145    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
6146    ///     `:deps` / `:deps-dev` per 359fba5, [`crate::UpgradeError::DuplicateFrom`]
6147    ///     on `:upgrade-from`, the per-instruction-class singularity
6148    ///     gates [`crate::UpgradeError::DuplicateLoadModule`] /
6149    ///     [`crate::UpgradeError::DuplicateStateChange`] /
6150    ///     [`crate::UpgradeError::DuplicateCleanup`]). The typed-graph
6151    ///     discipline is uniform: every Vec-shaped author-supplied list
6152    ///     past validate is set-not-multiset, by construction.
6153    ///
6154    /// Past the empty arm the gate enforces the chart-keyword shape
6155    /// predicate via [`crate::render::is_chart_keyword_shape`]: Cargo's
6156    /// crates.io `[package] keywords` grammar — 1..=20 bytes, starts
6157    /// with an ASCII letter, ASCII alphanumeric / `_` / `-`
6158    /// continuation. Closes the canonical paste-from-doc footguns the
6159    /// bare empty + duplicate arms left open: paste-from-aligned-doc
6160    /// whitespace (`" mesh"`, `"mesh "`), paste-from-multiline-doc
6161    /// newline (`"mesh\nhttp"` — the author pasted a multi-tag block
6162    /// into one entry instead of splitting), paste-from-Windows-CRLF-doc
6163    /// carriage return, CSV-list-separator confusion (`"mesh,http,grpc"`
6164    /// — the author meant three separate list entries), path-separator
6165    /// confusion (`"caixa/servico"`), namespace-suffix (`"http.1"`),
6166    /// leading-digit (`"1foo"`), kebab-leak (`"-foo"`), snake-leak
6167    /// (`"_foo"`), non-ASCII (`"café"`), and paste-from-binary-blob
6168    /// control bytes that would silently land as malformed search tags
6169    /// in the rendered Chart.yaml `keywords:` array and break the
6170    /// Artifact Hub keyword index lookup far from the source caixa.lisp.
6171    /// Mirrors the [`Self::validate_autores`] shape-predicate cascade
6172    /// established on the sibling universal-axis `Vec<String>` surface
6173    /// — the second universal-axis Vec<String> surface to land the
6174    /// empty-first-then-shape-then-duplicate per-entry cascade.
6175    ///
6176    /// Same empty-first cascade discipline every peer per-axis gate
6177    /// uses: the per-entry empty arm fires before the per-entry shape
6178    /// arm fires before the cross-entry duplicate arm, so an
6179    /// `("" "mesh" "mesh")` authoring shape surfaces the narrower
6180    /// [`ManifestError::EtiquetaEmpty`] (the structural "this entry
6181    /// has no value" defect) before either the shape or the duplicate
6182    /// diagnostic. Walks the list in declaration order so the
6183    /// first-collision diagnostic surfaces the lexicographically-
6184    /// earliest offending position, peer with every other duplicate
6185    /// gate on this surface.
6186    ///
6187    /// Universal-axis (every kind carries `:etiquetas`), so wired at the
6188    /// caixa-build gate alongside the peer universal gates
6189    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6190    /// [`Self::validate_deps`] / [`Self::validate_code_paths`] — before
6191    /// the kind-coherence gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]
6192    /// / [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6193    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6194    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
6195    /// slot sets. The future caixa-registry search axis can reach for
6196    /// `caixa.etiquetas` knowing every entry is a non-empty distinct
6197    /// chart-keyword-shaped string without re-deriving the precondition.
6198    pub fn validate_etiquetas(&self) -> Result<(), ManifestError> {
6199        let mut seen = std::collections::HashSet::new();
6200        for etiqueta in self.etiquetas() {
6201            if etiqueta.is_empty() {
6202                return Err(ManifestError::EtiquetaEmpty);
6203            }
6204            crate::render::is_chart_keyword_shape(etiqueta)
6205                .map_err(|reason| ManifestError::etiqueta_invalid(etiqueta, reason))?;
6206            crate::render::insert_first_seen(&mut seen, etiqueta.as_str(), || {
6207                ManifestError::etiqueta_duplicate(etiqueta)
6208            })?;
6209        }
6210        Ok(())
6211    }
6212
6213    /// Reject `:autores` lists with an empty entry or with two entries
6214    /// agreeing on the same string. `:autores` is the universal
6215    /// maintainer-axis on [`Caixa`] (every kind carries the
6216    /// `Vec<String>` slot) and lands verbatim as the Helm chart
6217    /// `Chart.yaml` `maintainers:` array on every Servico (caixa-helm's
6218    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:251` maps each entry
6219    /// to a `Maintainer { name, email: None }` without dedup). Two
6220    /// authoring footguns silently passed validate without this gate:
6221    ///
6222    ///   - Empty entry (`(:autores (""))` — the canonical paste-from-
6223    ///     blank-doc footgun) rendered as
6224    ///     `maintainers: [{name: "", email: null}]` in `Chart.yaml`. The
6225    ///     empty maintainer name has no operational meaning — it
6226    ///     identifies no one in the substrate's authorship index and
6227    ///     clutters the rendered chart with a no-op maintainer.
6228    ///   - Duplicate entries (`(:autores ("pleme-io" "pleme-io"))` —
6229    ///     the copy-paste-the-wrong-author footgun) silently passed
6230    ///     validate and rendered as two identical maintainer entries.
6231    ///     Unlike the [`Self::validate_etiquetas`] peer (caixa-helm's
6232    ///     `BTreeSet`-collect on `:etiquetas` silently dedups the
6233    ///     rendered `keywords:` array at chart-render time), the
6234    ///     `maintainers:` rendering has *no* dedup — duplicate `:autores`
6235    ///     entries stack verbatim in the chart, divergent from every
6236    ///     peer typed-graph set gate ([`crate::AplicacaoError::MembroDuplicate`]
6237    ///     on `:membros`, [`crate::AplicacaoError::PlacementClusterDuplicate`]
6238    ///     on `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
6239    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
6240    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
6241    ///     `:deps` / `:deps-dev`, [`crate::UpgradeError::DuplicateFrom`]
6242    ///     on `:upgrade-from`, [`ManifestError::EtiquetaDuplicate`] on
6243    ///     `:etiquetas`).
6244    ///
6245    /// Past the empty arm the gate enforces the chart-maintainer-name
6246    /// shape predicate via [`crate::render::is_chart_maintainer_name_shape`]:
6247    /// the structural single-line printable-UTF-8 floor every realistic
6248    /// Helm chart maintainer name carries — 1..=128 bytes, no leading
6249    /// or trailing whitespace, no ASCII control characters anywhere,
6250    /// Unicode bytes accepted. Closes the canonical paste-from-doc
6251    /// footguns the bare empty + duplicate arms left open:
6252    /// paste-from-aligned-doc whitespace (`" pleme-io"`, `"pleme-io "`),
6253    /// paste-from-multiline-doc newline (`"alice\nbob"` — the author
6254    /// pasted a multi-line block of author records into one `:autores`
6255    /// entry instead of splitting into one entry per author),
6256    /// paste-from-Windows-CRLF-doc carriage return, tab-from-aligned-doc,
6257    /// and the paste-from-binary-blob control bytes that would silently
6258    /// land as YAML-illegal byte sequences in the rendered Chart.yaml
6259    /// `maintainers:` array. Mirrors the shape-predicate cascade
6260    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
6261    /// [`Self::validate_edicao`] / [`Self::validate_repositorio`]
6262    /// establish past their own empty arms on the sibling universal-axis
6263    /// `Option<String>` surfaces — the first universal-axis Vec<String>
6264    /// surface to land the empty-first-then-shape-then-duplicate per-entry
6265    /// cascade.
6266    ///
6267    /// Same empty-first cascade discipline every peer per-axis gate
6268    /// uses: the per-entry empty arm fires before the per-entry shape
6269    /// arm before the cross-entry duplicate arm. Walks the list in
6270    /// declaration order so the first-collision diagnostic surfaces the
6271    /// lexicographically-earliest offending position, peer with every
6272    /// other duplicate gate on this surface.
6273    ///
6274    /// Universal-axis (every kind carries `:autores`), so wired at the
6275    /// caixa-build gate alongside the peer universal gates
6276    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6277    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6278    /// [`Self::validate_code_paths`] — before the kind-coherence gates
6279    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6280    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6281    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6282    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
6283    /// slot sets.
6284    pub fn validate_autores(&self) -> Result<(), ManifestError> {
6285        let mut seen = std::collections::HashSet::new();
6286        for autor in self.autores() {
6287            if autor.is_empty() {
6288                return Err(ManifestError::AutorEmpty);
6289            }
6290            crate::render::is_chart_maintainer_name_shape(autor)
6291                .map_err(|reason| ManifestError::autor_invalid(autor, reason))?;
6292            crate::render::insert_first_seen(&mut seen, autor.as_str(), || {
6293                ManifestError::autor_duplicate(autor)
6294            })?;
6295        }
6296        Ok(())
6297    }
6298
6299    /// Reject `:repositorio` values whose shape the shared
6300    /// [`crate::render::is_git_repo_url`] predicate refuses. The flat
6301    /// `repositorio: Option<String>` slot on [`Caixa`] is the
6302    /// universal git-shaped homepage axis every kind carries — the
6303    /// substrate routes the same string through two load-bearing
6304    /// consumers:
6305    ///
6306    ///   - [`caixa-helm`] folds it verbatim into the rendered
6307    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `home:` field
6308    ///     (`build_chart_yaml` at `caixa-helm/src/lib.rs:268`) and into
6309    ///     the chart `README.md` `repo = …` interpolation
6310    ///     (`caixa-helm/src/lib.rs:359`).
6311    ///   - [`caixa-flux`] folds it verbatim into the standalone
6312    ///     `ClusterBundleOpts::for_caixa` `git_url:` field
6313    ///     (`caixa-flux/src/lib.rs:293`), which becomes the `FluxCD`
6314    ///     `GitRepository.spec.url` the cluster's source-controller
6315    ///     polls — the load-bearing deploy-time axis.
6316    ///
6317    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
6318    /// substitute a placeholder when the slot is absent (`None` → the
6319    /// fallback fires); a `Some("")` *skips the fallback* and silently
6320    /// passes the empty string through to `Chart.yaml home: ""` /
6321    /// `GitRepository url: ""` — Helm's chart lint and `FluxCD`'s source
6322    /// controller both reject the empty URL far from the source
6323    /// `caixa.lisp`, with no field naming the offending `:repositorio`.
6324    /// Similarly a malformed `:repositorio` (whitespace, control char,
6325    /// missing `:` separator, leading `-`) silently lands in the
6326    /// rendered artifacts and breaks at `git clone` / `helm template`
6327    /// / `flux reconcile` time.
6328    ///
6329    /// Thin wrapper around [`crate::render::is_git_repo_url`] — the
6330    /// same shared predicate the peer [`crate::DepSource::validate`]
6331    /// routes the `:fonte (:tipo git :repo …)` axis through. With this
6332    /// gate the two `git URL`-shaped surfaces on the typed Caixa
6333    /// (`:repositorio` here, `:deps :fonte :repo` peer) are
6334    /// structurally equivalent: every value past validate is
6335    /// guaranteed-acceptable by the predicate's union of constraints
6336    /// (non-empty, length-bounded, no leading `-`, no whitespace, no
6337    /// control chars, ASCII only, no leading `:`, contains a `:`
6338    /// separator). The predicate accepts every documented authoring
6339    /// shape — `github:org/repo` shorthand, `https://host/path`,
6340    /// `ssh://[user@]host/path`, `git://host/path`, `git@host:path`
6341    /// scp-style SSH, `file:///path` — and refuses the canonical
6342    /// paste-from-blank-doc / paste-from-multiline-doc / CLI-arg-
6343    /// injection footguns at validate time. Maps the predicate's
6344    /// `String` reason verbatim into the
6345    /// [`ManifestError::RepositorioInvalid`] variant, carrying the
6346    /// offending value + parser-shaped reason so the diagnostic is
6347    /// self-locating (the author can grep their `caixa.lisp` for
6348    /// `:repositorio "<value>"` and fix it in one edit).
6349    ///
6350    /// `None` (the canonical "omit the slot to express no published
6351    /// homepage" shape) is accepted trivially — the gate is a no-op
6352    /// when the author didn't declare a value. `Some("")` is gated by
6353    /// the narrower [`ManifestError::RepositorioEmpty`] arm before the
6354    /// shape predicate is consulted, mirroring the empty-first cascade
6355    /// every peer per-axis identity gate uses
6356    /// ([`ManifestError::NomeEmpty`] → [`ManifestError::NomeInvalid`],
6357    /// [`ManifestError::VersaoEmpty`] → [`ManifestError::VersaoInvalid`],
6358    /// [`crate::DepError::FonteRepoEmpty`] →
6359    /// [`crate::DepError::FonteRepoInvalid`]).
6360    ///
6361    /// Universal-axis (every kind carries `:repositorio`), so wired at
6362    /// the caixa-build gate alongside the peer universal gates
6363    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6364    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6365    /// [`Self::validate_autores`] / [`Self::validate_code_paths`] —
6366    /// before the kind-coherence gates
6367    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6368    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6369    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6370    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6371    /// specific slot sets.
6372    pub fn validate_repositorio(&self) -> Result<(), ManifestError> {
6373        let Some(s) = self.repositorio() else {
6374            return Ok(());
6375        };
6376        if s.is_empty() {
6377            return Err(ManifestError::RepositorioEmpty);
6378        }
6379        is_git_repo_url(s).map_err(|reason| ManifestError::repositorio_invalid(s, reason))
6380    }
6381
6382    /// Reject `:descricao` values that are the empty string. The flat
6383    /// `descricao: Option<String>` slot on [`Caixa`] is the universal
6384    /// free-form-prose homepage axis every kind carries — the
6385    /// substrate routes the same string through two load-bearing
6386    /// consumers in the [`caixa-helm`] renderer:
6387    ///
6388    ///   - `build_chart_yaml` folds it verbatim into the rendered
6389    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `description:`
6390    ///     field (`caixa-helm/src/lib.rs:232-235`).
6391    ///   - `build_readme` folds it verbatim into the rendered chart
6392    ///     `README.md` header (`caixa-helm/src/lib.rs:333-336`).
6393    ///
6394    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
6395    /// substitute a `caixa.nome`-derived placeholder when the slot is
6396    /// absent (`None` → the fallback fires); a `Some("")` *skips the
6397    /// fallback* and silently passes the empty string through to
6398    /// `Chart.yaml description: ""` / a blank chart `README.md`
6399    /// header. Helm's chart spec requires a non-empty `description:`
6400    /// field on `apiVersion: v2` charts (`helm lint` surfaces it as
6401    /// `WARNING [chart.metadata.description]: description is required`),
6402    /// so the empty `Some("")` silently lands in the rendered
6403    /// artifacts and breaks at `helm lint` / `helm install` time far
6404    /// from the source `caixa.lisp`, with no field naming the
6405    /// offending `:descricao`.
6406    ///
6407    /// `None` (the canonical "omit the slot to defer to the renderer's
6408    /// `caixa.nome`-derived fallback" shape) is accepted trivially —
6409    /// the gate is a no-op when the author didn't declare a value.
6410    /// `Some("")` is gated by the narrower
6411    /// [`ManifestError::DescricaoEmpty`] arm, mirroring the empty-arm
6412    /// shape every peer per-axis empty gate uses
6413    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6414    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6415    /// [`ManifestError::RepositorioEmpty`]).
6416    ///
6417    /// Universal-axis (every kind carries `:descricao`), so wired at
6418    /// the caixa-build gate alongside the peer universal gates
6419    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6420    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6421    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6422    /// [`Self::validate_code_paths`] — before the kind-coherence
6423    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6424    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6425    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6426    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6427    /// specific slot sets.
6428    ///
6429    /// Past the empty arm the gate enforces the chart-description
6430    /// shape predicate via [`crate::render::is_chart_description_shape`]:
6431    /// the structural single-line UTF-8 floor every realistic chart
6432    /// description in the wild matches — 1..=512 bytes, no leading
6433    /// or trailing whitespace, no ASCII control characters anywhere
6434    /// (`0x00..=0x1F` plus `0x7F` DEL — banning tab, newline,
6435    /// carriage return, and every other control byte), Unicode
6436    /// continuation bytes accepted (the canonical fixtures carry
6437    /// `→` and `—`). Closes the canonical paste-from-doc footguns
6438    /// the bare empty-arm gate left open: paste-from-aligned-doc
6439    /// leading / trailing whitespace (`" Checkout flow."`,
6440    /// `"Checkout flow. "`), paste-from-multiline-doc newline
6441    /// (`"Checkout\nflow."`), paste-from-Windows-CRLF-doc CR
6442    /// (`"Checkout\rflow."`), tab-from-aligned-doc
6443    /// (`"Checkout\tflow."`), and paste-from-binary-blob NUL / BEL /
6444    /// ESC / DEL bytes. Mirrors the shape-predicate cascade
6445    /// [`Self::validate_repositorio`] / [`Self::validate_licenca`] /
6446    /// [`Self::validate_edicao`] establish past their own empty arms
6447    /// on the sibling universal-axis `Option<String>` Caixa-level
6448    /// value-shape surfaces.
6449    ///
6450    /// The empty-first cascade discipline mirrors every peer per-axis
6451    /// identity gate: [`ManifestError::DescricaoEmpty`] runs before
6452    /// [`ManifestError::DescricaoInvalid`], so the narrower empty
6453    /// diagnostic surfaces on `Some("")` rather than the broader
6454    /// shape-predicate diagnostic — peer with how
6455    /// [`ManifestError::LicencaEmpty`] runs before
6456    /// [`ManifestError::LicencaInvalid`],
6457    /// [`ManifestError::EdicaoEmpty`] runs before
6458    /// [`ManifestError::EdicaoInvalid`],
6459    /// [`ManifestError::RepositorioEmpty`] runs before
6460    /// [`ManifestError::RepositorioInvalid`].
6461    pub fn validate_descricao(&self) -> Result<(), ManifestError> {
6462        let Some(s) = self.descricao() else {
6463            return Ok(());
6464        };
6465        if s.is_empty() {
6466            return Err(ManifestError::DescricaoEmpty);
6467        }
6468        crate::render::is_chart_description_shape(s)
6469            .map_err(|reason| ManifestError::descricao_invalid(s, reason))?;
6470        Ok(())
6471    }
6472
6473    /// Reject `:licenca` values that are the empty string. The flat
6474    /// `licenca: Option<String>` slot on [`Caixa`] is the universal
6475    /// SPDX-shaped license-expression axis every kind carries — the
6476    /// substrate routes the same string through the [`caixa-helm`]
6477    /// renderer's `build_readme` which folds it verbatim into the
6478    /// rendered `lareira-<nome>` Helm chart's `README.md` `## License`
6479    /// section (`caixa-helm/src/lib.rs:361`) via
6480    /// `caixa.licenca.clone().unwrap_or_else(|| "MIT".into())`. The
6481    /// fallback only fires on `None`; a `Some("")` *skips the
6482    /// fallback* and silently passes the empty string through to a
6483    /// chart `README.md` whose `License` section renders as the bare
6484    /// trailing period (`.\n`) — peer footgun with the
6485    /// `Some("")`-skips-`unwrap_or_else` shape the
6486    /// [`Self::validate_descricao`] and [`Self::validate_repositorio`]
6487    /// gates close on the sibling free-form-prose and git-URL axes.
6488    ///
6489    /// `None` (the canonical "omit the slot to defer to the
6490    /// renderer's `MIT` fallback" shape every existing fixture
6491    /// carries) is accepted trivially — the gate is a no-op when the
6492    /// author didn't declare a value. `Some("")` is gated by the
6493    /// narrower [`ManifestError::LicencaEmpty`] arm, mirroring the
6494    /// empty-arm shape every peer per-axis empty gate uses
6495    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6496    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6497    /// [`ManifestError::RepositorioEmpty`],
6498    /// [`ManifestError::DescricaoEmpty`]).
6499    ///
6500    /// Universal-axis (every kind carries `:licenca`), so wired at
6501    /// the caixa-build gate alongside the peer universal gates
6502    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6503    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6504    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6505    /// [`Self::validate_descricao`] / [`Self::validate_code_paths`]
6506    /// — before the kind-coherence gates
6507    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6508    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6509    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6510    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6511    /// specific slot sets.
6512    ///
6513    /// Past the empty arm the gate enforces the SPDX-expression shape
6514    /// predicate via [`crate::render::is_spdx_expression_shape`]: the
6515    /// structural alphabet floor every realistic SPDX expression in
6516    /// the wild uses — ASCII alphanumeric plus `.`, `-`, `+`, `(`,
6517    /// `)`, `:` (the `DocumentRef-…:LicenseRef-…` separator), and a
6518    /// single ASCII space (token separator). Closes the canonical
6519    /// paste-from-doc footguns the bare empty-arm gate left open:
6520    /// paste-from-doc whitespace (`"MIT "`, `" MIT"`), paste-from-
6521    /// multiline-doc CRLF (`"MIT\n"`), tab-from-aligned-doc
6522    /// (`"MIT\tOR Apache-2.0"`), non-ASCII smart-quote paste,
6523    /// underscore-instead-of-hyphen typo (`"Apache_2.0"`),
6524    /// comma-instead-of-`OR`-keyword colloquial idiom (`"MIT,
6525    /// Apache-2.0"`), slash-dual-license colloquial idiom (`"MIT/
6526    /// Apache-2.0"`), and semicolon-list-separator confusion
6527    /// (`"MIT; Apache-2.0"`). Mirrors the shape-predicate cascade
6528    /// [`Self::validate_repositorio`] / [`Self::validate_edicao`]
6529    /// establish past their own empty arms.
6530    ///
6531    /// The empty-first cascade discipline mirrors every peer per-axis
6532    /// identity gate: [`ManifestError::LicencaEmpty`] runs before
6533    /// [`ManifestError::LicencaInvalid`], so the narrower empty
6534    /// diagnostic surfaces on `Some("")` rather than the broader
6535    /// shape-predicate diagnostic — peer with how
6536    /// [`ManifestError::EdicaoEmpty`] runs before
6537    /// [`ManifestError::EdicaoInvalid`],
6538    /// [`ManifestError::RepositorioEmpty`] runs before
6539    /// [`ManifestError::RepositorioInvalid`].
6540    ///
6541    /// A future tightening on this axis can extend the alphabet
6542    /// floor into a full SPDX expression parser + license-id
6543    /// allowlist (rejecting alphabet-valid values that don't name a
6544    /// real SPDX license identifier — e.g., `"NotAReal"` is
6545    /// alphabet-valid but no `NotAReal` license-id exists). That
6546    /// parser only becomes meaningful past a real SPDX-spec
6547    /// dependency; this gate establishes the structural floor by
6548    /// refusing every non-SPDX-alphabet value at validate time.
6549    pub fn validate_licenca(&self) -> Result<(), ManifestError> {
6550        let Some(s) = self.licenca() else {
6551            return Ok(());
6552        };
6553        if s.is_empty() {
6554            return Err(ManifestError::LicencaEmpty);
6555        }
6556        crate::render::is_spdx_expression_shape(s)
6557            .map_err(|reason| ManifestError::licenca_invalid(s, reason))?;
6558        Ok(())
6559    }
6560
6561    /// Reject `:edicao` values that are the empty string. The flat
6562    /// `edicao: Option<String>` slot on [`Caixa`] is the universal
6563    /// language-edition axis every kind carries — it determines the
6564    /// tatara-lisp macro surface + compatibility flags the substrate
6565    /// applies when building a caixa, and lands verbatim in the
6566    /// `Caixa::template` author-time scaffold (the canonical
6567    /// `:edicao "2026"` line every `feira init` emits via
6568    /// [`Caixa::template`] at `caixa-core/src/manifest.rs:1193`) and
6569    /// in every renderer-side fixture (`caixa-helm/src/lib.rs:375`,
6570    /// `caixa-flux/src/lib.rs:445`, `caixa-mesh/src/lib.rs:629`,
6571    /// `caixa-core/src/render.rs:2510`) via
6572    /// `edicao: Some("2026".into())`.
6573    ///
6574    /// `None` (the canonical "omit the slot to defer to the
6575    /// substrate's default edition" shape every existing
6576    /// [`caixa-resolver`] integration test fixture carries via
6577    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
6578    /// is accepted trivially — the gate is a no-op when the author
6579    /// didn't declare a value. `Some("")` is gated by the narrower
6580    /// [`ManifestError::EdicaoEmpty`] arm, mirroring the empty-arm
6581    /// shape every peer per-axis empty gate uses
6582    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6583    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6584    /// [`ManifestError::RepositorioEmpty`],
6585    /// [`ManifestError::DescricaoEmpty`], [`ManifestError::LicencaEmpty`]).
6586    ///
6587    /// Universal-axis (every kind carries `:edicao`), so wired at
6588    /// the caixa-build gate alongside the peer universal gates
6589    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6590    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6591    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6592    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
6593    /// [`Self::validate_code_paths`] — before the kind-coherence
6594    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6595    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6596    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6597    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6598    /// specific slot sets.
6599    ///
6600    /// Past the empty arm the gate enforces the canonical year-shape
6601    /// predicate: every documented tatara-lisp edition is a 4-digit
6602    /// ASCII decimal year (`"2026"` is the only edition currently
6603    /// minted; future-introduced siblings will follow the same
6604    /// shape, peer with Cargo's `[package] edition` grammar which
6605    /// every value Cargo has ever accepted matches — `"2015"`,
6606    /// `"2018"`, `"2021"`, `"2024"`). Any value that's not exactly
6607    /// 4 ASCII decimal bytes is rejected with the narrower
6608    /// [`ManifestError::EdicaoInvalid`] arm, mirroring the
6609    /// shape-predicate cascade [`Self::validate_repositorio`]
6610    /// establishes past its own empty arm
6611    /// ([`ManifestError::RepositorioEmpty`] →
6612    /// [`ManifestError::RepositorioInvalid`]). Closes the canonical
6613    /// paste-from-doc footguns the bare empty-arm gate left open:
6614    ///
6615    ///   - leading / trailing whitespace from a paste-from-doc
6616    ///     (`"2026 "`, `" 2026"`)
6617    ///   - control characters / CRLF from a paste-from-multiline-doc
6618    ///     (`"2026\n"`)
6619    ///   - non-ASCII look-alikes from a fullwidth keyboard
6620    ///     (`"2026"`) which would silently land as a non-ASCII
6621    ///     string in the rendered caixa.lisp
6622    ///   - free-form non-year values (`"x"`, `"latest"`,
6623    ///     `"nightly"`) that have no operational meaning on the
6624    ///     substrate's build-time edition selector
6625    ///   - leading non-digit prefixes (`"v2026"`, `"e2026"`,
6626    ///     `"r2026"`) — common version-tag idioms that don't apply
6627    ///     to the year-shaped edition axis
6628    ///   - decimal-shaped values (`"2026.1"`, `"2026.0"`) — every
6629    ///     edition is a year, not a fractional version
6630    ///   - wrong-length numeric values (`"26"`, `"202"`, `"20260"`,
6631    ///     `"00026"`) that don't name a year
6632    ///
6633    /// `None` (the canonical "omit the slot to defer to the
6634    /// substrate's default edition" shape every existing
6635    /// [`caixa-resolver`] integration test fixture carries via
6636    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
6637    /// is accepted trivially — the gate is a no-op when the author
6638    /// didn't declare a value. The empty-first cascade discipline
6639    /// mirrors every peer per-axis identity gate:
6640    /// [`ManifestError::EdicaoEmpty`] runs before
6641    /// [`ManifestError::EdicaoInvalid`], so the narrower empty
6642    /// diagnostic surfaces on `Some("")` rather than the broader
6643    /// shape-predicate diagnostic — peer with how
6644    /// [`ManifestError::NomeEmpty`] runs before
6645    /// [`ManifestError::NomeInvalid`],
6646    /// [`ManifestError::VersaoEmpty`] runs before
6647    /// [`ManifestError::VersaoInvalid`],
6648    /// [`ManifestError::RepositorioEmpty`] runs before
6649    /// [`ManifestError::RepositorioInvalid`].
6650    ///
6651    /// A future tightening on this axis can extend the shape
6652    /// predicate into a known-edition allowlist (rejecting
6653    /// year-shaped values that don't name a tatara-lisp edition
6654    /// the substrate actually understands — e.g., `"1999"` is
6655    /// year-shaped but no `1999` edition exists). That allowlist
6656    /// only becomes meaningful past the introduction of a sibling
6657    /// edition to `"2026"`; this gate establishes the structural
6658    /// floor by refusing every non-year-shaped value at validate
6659    /// time.
6660    pub fn validate_edicao(&self) -> Result<(), ManifestError> {
6661        let Some(s) = self.edicao() else {
6662            return Ok(());
6663        };
6664        if s.is_empty() {
6665            return Err(ManifestError::EdicaoEmpty);
6666        }
6667        if s.len() != 4 || !s.bytes().all(|b| b.is_ascii_digit()) {
6668            return Err(ManifestError::edicao_invalid(
6669                s,
6670                "must be a 4-digit ASCII decimal year (canonical \"2026\")",
6671            ));
6672        }
6673        Ok(())
6674    }
6675
6676    /// Compose the supervisor-related flat slots into a single
6677    /// [`SupervisorSpec`] for validation. Returns `None` when the
6678    /// caixa isn't a `:kind Supervisor`.
6679    ///
6680    /// The flat representation in [`Caixa`] keeps tatara-lisp authoring
6681    /// simple (one form, no nested `:supervisor (…)` block); this view
6682    /// is the "typed shape" the operator + supervisor reconciler
6683    /// consume.
6684    #[must_use]
6685    pub fn supervisor_view(&self) -> Option<SupervisorSpec> {
6686        if !self.kind().is_supervisor() {
6687            return None;
6688        }
6689        // Fold through the shared `supervisor::duration_codec::parse`
6690        // — the same parser the serde-routed `with = "duration_codec"`
6691        // on `SupervisorSpec::restart_window`, the `:politicas
6692        // :timeout` codec, and the `:politicas :circuit-breaker
6693        // :window` codec all consume. The prior inline f64-shaped
6694        // duplicate (`parse_window_inline`) admitted every magnitude
6695        // the integer-magnitude gate (1c55a2a) rejects on the three
6696        // serde-routed siblings — `"1.5s"`, `"1.0s"`, `"0.5m"`,
6697        // `"+30s"`, `"-30s"` — and silently dropped malformed input as
6698        // `None` (i.e. "no reset"), divergent from the shared codec's
6699        // integer-magnitude discipline by construction. The fold
6700        // closes the divergence: every value the typed
6701        // `SupervisorSpec` carries past `supervisor_view` is in the
6702        // shared codec's accepted set. The `.ok()` here preserves the
6703        // existing soft-swallow shape on this view-construction path;
6704        // the new [`Caixa::validate_restart_window`] (sibling of
6705        // [`Self::validate_nome`] / [`Self::validate_versao`]) names
6706        // the offending raw string at build time so authoring tools
6707        // (`feira lint`, the future layout-side wire-up) surface a
6708        // self-locating diagnostic instead of a silently dropped
6709        // window.
6710        let restart_window = self
6711            .restart_window()
6712            .and_then(|s| crate::supervisor::duration_codec::parse(s).ok());
6713        Some(SupervisorSpec {
6714            // Route the author-omitted `:estrategia` arm through the
6715            // substrate-canonical
6716            // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
6717            // `pub const` rather than the transitively-derived
6718            // [`RestartStrategy::default`] route the prior
6719            // `.unwrap_or_default()` fold reached for — one source of
6720            // truth for the Erlang/OTP `one_for_one` half of Learn You
6721            // Some Erlang's `{one_for_one, intensity, 5, 60}` worker-
6722            // supervisor canonical default that also backs the
6723            // [`crate::supervisor::Default for RestartStrategy`] impl
6724            // and the [`crate::supervisor::Default for SupervisorSpec`]
6725            // impl's struct-literal `estrategia` field, all now routed
6726            // through the same lifted constant. Prior to the lift the
6727            // composition site carried `.unwrap_or_default()` with no
6728            // compile-time link back to the shared OTP-canonical
6729            // default that the peer paired
6730            // `.unwrap_or(SUPERVISOR_MAX_RESTARTS_DEFAULT)` (b698ec0)
6731            // arm on the sibling `:max-restarts` axis routes through —
6732            // so a future rebrand of the OTP-canonical strategy default
6733            // (a widening to `rest_for_one` once the substrate
6734            // discovers startup-order-coupled child cohorts as the more
6735            // common shape, a per-cluster overlay the operator pins
6736            // through the MESH-COMPOSITION §III.2 supervision-canary
6737            // `:estrategia-overrides` roadmap slot) would have had to
6738            // migrate the paired `MaxIntensity` + `Period` halves
6739            // through the lifted constants and the `one_for_one` half
6740            // through a `RestartStrategy::default()` route in lockstep
6741            // or the three halves of the same OTP-canonical default
6742            // would silently drift out of pairing. Byte-parity against
6743            // the lifted constant closes the split. Pinned by
6744            // [`supervisor_view_estrategia_fallback_routes_through_lifted_default`]
6745            // in the tests module.
6746            estrategia: self
6747                .estrategia()
6748                .unwrap_or(crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT),
6749            // Route the author-omitted `:max-restarts` arm through the
6750            // substrate-canonical [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`]
6751            // typed `pub const` rather than the raw `5` literal — one
6752            // source of truth for the Erlang/OTP-canonical
6753            // `{intensity, 5, 60}` `MaxIntensity` default that also
6754            // backs the serde-side wire-format author-omitted arm on
6755            // [`crate::supervisor::SupervisorSpec::max_restarts`] via
6756            // `#[serde(default = "default_max_restarts")]` and the
6757            // [`Default for SupervisorSpec`] impl's struct-literal
6758            // default field. Prior to the lift the composition site
6759            // carried a raw `5` with no compile-time link back to the
6760            // serde-side default, so a future rebrand of the OTP-
6761            // canonical default (a tightening to Elixir's `3`, a
6762            // widening to a per-cluster overlay the operator pins
6763            // through the MESH-COMPOSITION §III.2 supervision-canary
6764            // `:supervisor :max-restarts-overrides` roadmap slot)
6765            // would have had to be threaded through both open-coded
6766            // copies in lockstep or the wire-format author-omitted arm
6767            // and this view-construction author-omitted arm would
6768            // silently disagree on which restart-budget an omitted
6769            // `:max-restarts` resolves to. Pinned by
6770            // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
6771            // in the tests module.
6772            max_restarts: self
6773                .max_restarts()
6774                .unwrap_or(crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT),
6775            restart_window,
6776            children: self.children().to_vec(),
6777        })
6778    }
6779
6780    /// A minimal starter manifest emitted by `feira init`.
6781    #[must_use]
6782    pub fn template(nome: &str) -> String {
6783        format!(
6784            "(defcaixa\n  \
6785               :nome        {nome:?}\n  \
6786               :versao      \"0.1.0\"\n  \
6787               :kind        Biblioteca\n  \
6788               :edicao      \"2026\"\n  \
6789               :descricao   \"FIXME — describe this caixa\"\n  \
6790               :autores     ()\n  \
6791               :etiquetas   ()\n  \
6792               :deps        ()\n  \
6793               :deps-dev    ()\n  \
6794               :bibliotecas (\"lib/{nome}.lisp\"))\n"
6795        )
6796    }
6797
6798    /// Serialize to a canonical `caixa.lisp` source — suitable for writing
6799    /// back after mutation (e.g. `feira add`).
6800    ///
6801    /// Goes through serde JSON → canonical Sexp → per-field pretty print.
6802    /// The derive-macro `compile_from_sexp` path is the inverse, so any
6803    /// `Caixa` round-trips through `to_lisp` + `from_lisp`.
6804    #[must_use]
6805    pub fn to_lisp(&self) -> String {
6806        let json = serde_json::to_value(self).expect("Caixa serialize");
6807        let sexp = tatara_lisp::domain::json_to_sexp(&json);
6808        let tatara_lisp::Sexp::List(items) = sexp else {
6809            return format!("(defcaixa {sexp})\n");
6810        };
6811        let mut out = String::from("(defcaixa");
6812        let mut i = 0;
6813        while i + 1 < items.len() {
6814            out.push_str("\n  ");
6815            out.push_str(&items[i].to_string());
6816            out.push(' ');
6817            out.push_str(&items[i + 1].to_string());
6818            i += 2;
6819        }
6820        out.push_str(")\n");
6821        out
6822    }
6823}
6824
6825/// Errors raised by top-level [`Caixa`] validators that don't fit
6826/// the per-axis [`DepError`] / [`crate::AplicacaoError`] /
6827/// [`crate::SupervisorError`] / [`crate::LayoutError`] families —
6828/// the Caixa's own identity axes (`:nome`, `:versao`) that flow
6829/// through every substrate-side artifact's `metadata.name` /
6830/// version derivation.
6831///
6832/// A future top-level sum (the M4 `CaixaError` the [`DepError`]
6833/// doc-comment anticipates) can hold one of each per-axis error
6834/// family without reshaping individual diagnostics; this enum is
6835/// the first such per-Caixa-identity family.
6836#[derive(Debug, Error, PartialEq, Eq)]
6837pub enum ManifestError {
6838    #[error(
6839        ":nome is empty (every caixa must name itself; the value flows \
6840         into every K8s artifact's `metadata.name` derivation and into \
6841         the default `lib/<nome>.lisp` / `exe/<nome>` layout paths)"
6842    )]
6843    NomeEmpty,
6844    #[error(
6845        ":nome {nome:?} is not a valid DNS-1123 label: {reason} (the K8s \
6846         apiserver enforces this rule on every `metadata.name` the \
6847         caixa's substrate-side renderers derive from `:nome` — the \
6848         `lareira-<nome>` Helm chart name, the programs.yaml entry \
6849         name, the `LABEL_APLICACAO` label value, the `<aplicacao>-<de>-to-<para>` \
6850         CiliumNetworkPolicy name, the `<aplicacao>-<para>` HTTPRoute \
6851         name; use a lowercase alphanumeric + hyphen identifier like \
6852         `\"checkout\"` or `\"cart-v2\"`)"
6853    )]
6854    NomeInvalid { nome: String, reason: String },
6855    #[error(
6856        ":nome {nome:?} overflows the joint-length budget on the canonical \
6857         `lareira-<nome>` chart-name shape: {reason} (every per-Servico / \
6858         per-Aplicacao renderer the substrate carries — `caixa-helm`'s \
6859         `Chart.yaml::name`, `caixa-flux`'s `cluster_bundle` HelmRelease \
6860         `chart:` slot, `caixa-tatara`'s `release_name` + \
6861         `oci://<registry>/lareira-<nome>` chart ref — derives the same \
6862         joint name through the canonical `lareira_chart_name` helper, and \
6863         Helm's `Chart.yaml::name` admission rule + the K8s apiserver's \
6864         DNS-1123 label cap on every chart-name-derived `metadata.name` \
6865         reject any joint name exceeding 63 bytes; the narrower \
6866         `:nome` shape (`NomeInvalid`) gates the bare-`:nome` budget, this \
6867         arm gates the chart-name budget downstream renderers inherit)"
6868    )]
6869    NomeChartNameBudgetExceeded { nome: String, reason: String },
6870    #[error(
6871        ":versao is empty (every caixa must pin its own version; the value flows \
6872         into the `lareira-<nome>` Helm chart's `Chart.yaml` version + appVersion, \
6873         the `feira publish` `v<versao>` git tag, the OCI image's `:v<versao>` / \
6874         `:latest` tags, the lacre closure's `concrete_versao`, and the \
6875         `:upgrade-from :from` peers — use a SemVer-2 literal like `\"0.1.0\"`)"
6876    )]
6877    VersaoEmpty,
6878    #[error(
6879        ":versao {versao:?} is not a valid SemVer-2 version: {reason} (the substrate \
6880         consumes this string as `semver::Version` — three-part `MAJOR.MINOR.PATCH` \
6881         with optional `-prerelease` and `+build` — across every artifact derived \
6882         from `:versao`: the `lareira-<nome>` Helm chart's `Chart.yaml` version + \
6883         appVersion (Helm SemVer-2-strict), the `feira publish` `v<versao>` git tag, \
6884         the OCI image's `:v<versao>` tag, the lacre closure's `concrete_versao`, \
6885         and the `:upgrade-from :from` peers that match against this exact shape; \
6886         use a literal like `\"0.1.0\"`, `\"0.2.0-rc.1\"`, or `\"1.0.0+build.42\"` — \
6887         not a git-tag-shape like `\"v0.1.0\"`, a docker-tag-shape like `\"latest\"`, \
6888         a requirement-shape like `\"^0.1\"`, or a four-part `\"0.1.0.0\"`)"
6889    )]
6890    VersaoInvalid { versao: String, reason: String },
6891    #[error(
6892        ":restart-window {restart_window:?} is not a valid duration: {reason} (the \
6893         substrate consumes this string through the shared \
6894         `supervisor::duration_codec` — the same parser routed via `with = \
6895         \"duration_codec\"` onto the typed `SupervisorSpec::restart_window`, \
6896         `:politicas :timeout`, and `:politicas :circuit-breaker :window` slots; \
6897         the canonical authoring form is `<integer><unit>` where the unit is one \
6898         of `ms` / `s` / `m` / `h` and the magnitude has no decimal point and no \
6899         leading `+` / `-` sign — e.g. `\"60s\"`, `\"5m\"`, `\"1h\"`, `\"500ms\"`. \
6900         Without this gate a malformed `:restart-window` silently produced a \
6901         supervisor with `restart_window: None` (\"never reset\"), turning OTP's \
6902         `MaxIntensity / Period` invariant into a never-reset supervisor far from \
6903         the source `caixa.lisp`; the gate moves the diagnostic to the manifest \
6904         layer with the offending value named verbatim. Omit the slot entirely to \
6905         express \"no reset\"; carry a positive integer duration to express the \
6906         sliding window)"
6907    )]
6908    RestartWindowMalformed {
6909        restart_window: String,
6910        reason: String,
6911    },
6912    #[error(
6913        "{slot} entry is an empty path string — every {slot} entry must name \
6914         a file relative to the caixa root; omit the entry to omit the file \
6915         (the layout checker's `root.join(\"\")` resolves to the caixa root \
6916         itself, so an empty entry silently aliases the project root as a \
6917         declared {slot} file, then fails downstream at parse / existence \
6918         time with a diagnostic that names the root rather than the offending \
6919         entry)"
6920    )]
6921    CodePathEmpty { slot: &'static str },
6922    #[error(
6923        "{slot} entry {} is an absolute path — entries must be relative to \
6924         the caixa root, since `Path::join` replaces the base with an absolute \
6925         right-hand side and `root.join(\"/abs/...\")` resolves to \"/abs/...\" \
6926         outside the caixa root sandbox; rewrite the entry as a relative path \
6927         under the caixa root (e.g. `\"lib/<name>.lisp\"`, `\"exe/<name>\"`, \
6928         `\"servicos/<name>.computeunit.yaml\"`)",
6929        path.display()
6930    )]
6931    CodePathAbsolute { slot: &'static str, path: PathBuf },
6932    #[error(
6933        "{slot} entry {} contains a `..` component — entries must not traverse \
6934         above the caixa root (the layout's `starts_with(<dir>)` fence on \
6935         `:exe` / `:servicos` is component-aware, not canonical-path-aware, \
6936         so a mid-path `..` silently traverses the sandbox; `:bibliotecas` \
6937         has no such fence, so a leading `..` escapes unconditionally if the \
6938         resolved target happens to exist)",
6939        path.display()
6940    )]
6941    CodePathParentEscape { slot: &'static str, path: PathBuf },
6942    #[error(
6943        "{slot} entry {} does not terminate in the `.lisp` extension — every \
6944         `:bibliotecas` entry is a tatara-lisp source file the `feira build` \
6945         loop reads through `tatara_lisp::read` at parse time, so any other \
6946         extension (`.rs`, `.txt`, `.lisp.bak`) or no-extension shape is \
6947         structurally a parser error far from the source caixa.lisp, with \
6948         no field naming the offending `:bibliotecas` entry. Pin a relative \
6949         path under the caixa root whose terminating extension is \
6950         lowercase-`.lisp` (e.g. `\"lib/<name>.lisp\"`, \
6951         `\"lib/handlers.lisp\"`) — the same file-type contract the peer \
6952         `:behavior :on-*` (c97815a) and `:upgrade-from :state-change :script` \
6953         (33cc830) axes already carry through the same lifted \
6954         `is_lisp_extension` predicate",
6955        path.display()
6956    )]
6957    CodePathNonLispExtension { slot: &'static str, path: PathBuf },
6958    #[error(
6959        "{slot} entry {} does not terminate in the `.computeunit.yaml` \
6960         compound suffix — every `:servicos` entry is a typed `ComputeUnit` \
6961         CR YAML file the peer caixa-helm / caixa-flux renderers consume \
6962         through `serde_yaml::from_str` at chart / FluxCD bundle render \
6963         time, so any other extension (`.yaml`, `.yml`, `.json`, the \
6964         off-by-one-segment `.computeunit-yaml`, the editor-backup \
6965         `.computeunit.yaml.bak`) or no-extension shape is structurally a \
6966         YAML-parser error / `ComputeUnit` schema-mismatch far from the \
6967         source caixa.lisp, with no field naming the offending `:servicos` \
6968         entry. Pin a relative path under the caixa root whose terminating \
6969         compound suffix is lowercase-`.computeunit.yaml` (e.g. \
6970         `\"servicos/<name>.computeunit.yaml\"`, \
6971         `\"servicos/hello-rio.computeunit.yaml\"`) — the same file-type \
6972         contract the sibling `:bibliotecas` axis (64772a9) already carries \
6973         on the tatara-lisp-source axis through the peer lifted \
6974         `is_lisp_extension` predicate, here on the compound-suffix axis \
6975         `Path::extension` can't express on its own through the lifted \
6976         `is_computeunit_yaml_extension` predicate",
6977        path.display()
6978    )]
6979    CodePathNonComputeUnitYamlExtension { slot: &'static str, path: PathBuf },
6980    #[error(
6981        "{slot} entry {} appears more than once (the code-path list is \
6982         a set, not a multiset; every peer Vec-shaped author-supplied \
6983         list past validate is set-not-multiset — `:membros :caixa`, \
6984         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
6985         `:children :caixa`, `:deps` / `:deps-dev` `:nome`, \
6986         `:upgrade-from :from`, `:etiquetas`, `:autores` — and the three \
6987         code-path lists are the last Vec-shaped author-supplied slots on \
6988         the typed Caixa surface still admitting a duplicate entry. \
6989         `:bibliotecas` duplicates re-parse the same file at \
6990         `feira build` time and silently mask the author's intent to \
6991         declare a *second* biblioteca; `:exe` duplicates collide on the \
6992         flake `packages.<name>` derivation key at the future \
6993         `caixa-flake` materializer; `:servicos` duplicates surface as the \
6994         narrower [`caixa-helm`] / [`caixa-flux`] `UnsupportedServicoCount` \
6995         rejection far from the source `caixa.lisp`. Drop the duplicate \
6996         or rename it to the actual second file intended)",
6997        path.display()
6998    )]
6999    CodePathDuplicate { slot: &'static str, path: PathBuf },
7000    #[error(
7001        ":etiquetas entry is empty (every tag must carry a non-empty \
7002         registry-search identifier; the empty entry has no operational \
7003         meaning — it indexes nothing in the future caixa-registry search \
7004         axis and clutters the rendered Helm `Chart.yaml` `keywords:` array \
7005         with a no-op tag; omit the entry to express \"no tag on this \
7006         position\")"
7007    )]
7008    EtiquetaEmpty,
7009    #[error(
7010        ":etiquetas entry {etiqueta:?} appears more than once (the \
7011         registry-search tag set is a set, not a multiset; duplicate \
7012         entries are silently dedup'd by caixa-helm's `BTreeSet` collect \
7013         at chart render — a \"second wins / one silently disappears\" \
7014         shape divergent from every peer typed-graph set gate \
7015         (`:membros :caixa`, `:placement :clusters`, `:entrada :paths`, \
7016         `:contratos`, `:deps :nome`, `:upgrade-from :from`); drop the \
7017         duplicate or rename it to the actual tag intended)"
7018    )]
7019    EtiquetaDuplicate { etiqueta: String },
7020    #[error(
7021        ":etiquetas entry {etiqueta:?} is not a valid chart-keyword shape: \
7022         {reason} (the substrate consumes this string through the shared \
7023         `crate::render::is_chart_keyword_shape` predicate — the same \
7024         Cargo crates.io `[package] keywords` grammar entry shape: 1..=20 \
7025         bytes, starts with an ASCII letter, ASCII alphanumeric / `_` / `-` \
7026         continuation. The canonical authoring shapes are short kebab-case \
7027         identifiers like `\"mesh\"`, `\"wasm\"`, `\"tatara-lisp\"`, \
7028         `\"hello-world\"`, `\"caixa-servico\"`, `\"infrastructure\"`. \
7029         Without this gate a malformed `:etiquetas` entry (paste-from-doc \
7030         leading / trailing whitespace `\" mesh\"` / `\"mesh \"`; \
7031         paste-from-multiline-doc newline `\"mesh\\nhttp\"`; \
7032         paste-from-Windows-CRLF-doc CR; CSV-list-separator confusion \
7033         `\"mesh,http,grpc\"` — the author meant to author three separate \
7034         list entries; path-separator confusion `\"caixa/servico\"`; \
7035         namespace-suffix `\"http.1\"`; leading-digit `\"1foo\"`; \
7036         kebab-leak `\"-foo\"`; snake-leak `\"_foo\"`; non-ASCII \
7037         `\"café\"` — every legitimate search tag is strict ASCII; \
7038         paste-from-binary-blob NUL / BEL / ESC / DEL byte) silently \
7039         passed `from_lisp` + `validate_etiquetas` + \
7040         `StandardLayout::verify` and landed in the rendered \
7041         `lareira-<nome>` Helm chart's `Chart.yaml keywords:` array as a \
7042         malformed search tag — Artifact Hub's keyword index + the future \
7043         caixa-registry's keyword index would either silently drop the \
7044         tag or fail to index it far from the source caixa.lisp; the gate \
7045         moves the diagnostic to the manifest layer with the offending \
7046         value named verbatim)"
7047    )]
7048    EtiquetaInvalid { etiqueta: String, reason: String },
7049    #[error(
7050        ":autores entry is empty (every maintainer must carry a non-empty \
7051         identifier; the empty entry has no operational meaning — it \
7052         identifies no one in the substrate's authorship index and renders \
7053         as `maintainers: [{{name: \"\", email: null}}]` in the Helm chart's \
7054         `Chart.yaml`, a no-op maintainer the substrate cannot route to; \
7055         omit the entry to express \"no maintainer on this position\")"
7056    )]
7057    AutorEmpty,
7058    #[error(
7059        ":autores entry {autor:?} appears more than once (the maintainer \
7060         set is a set, not a multiset; unlike `:etiquetas`, caixa-helm's \
7061         `maintainers:` rendering does *no* dedup — duplicate entries \
7062         stack verbatim in `Chart.yaml` as two identical \
7063         `Maintainer {{ name, email: None }}` records, divergent from every \
7064         peer typed-graph set gate (`:etiquetas`, `:membros :caixa`, \
7065         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
7066         `:deps :nome`, `:upgrade-from :from`); drop the duplicate or \
7067         rename it to the actual author intended)"
7068    )]
7069    AutorDuplicate { autor: String },
7070    #[error(
7071        ":autores entry {autor:?} is not a valid chart-maintainer-name shape: \
7072         {reason} (the substrate consumes this string through the shared \
7073         `crate::render::is_chart_maintainer_name_shape` predicate — the same \
7074         single-line-UTF-8 floor every realistic chart maintainer name carries: \
7075         1..=128 bytes, no leading or trailing whitespace, no ASCII control \
7076         characters anywhere, Unicode bytes accepted. The canonical authoring \
7077         shapes are short single-line identifiers like `\"pleme-io\"`, \
7078         `\"Pleme Contributors\"`, `\"alice <alice@example.com>\"`, \
7079         `\"François Dupont\"`. Without this gate a malformed `:autores` entry \
7080         (paste-from-aligned-doc leading whitespace `\" pleme-io\"` / trailing \
7081         whitespace `\"pleme-io \"`; paste-from-multiline-doc newline \
7082         `\"alice\\nbob\"` — the author pasted a multi-line block of author \
7083         records into one entry instead of splitting into one entry per author; \
7084         paste-from-Windows-CRLF-doc carriage return `\"alice\\rbob\"`; \
7085         tab-from-aligned-doc `\"Pleme\\tContributors\"`; paste-from-binary-blob \
7086         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
7087         `validate_autores` + `StandardLayout::verify` and landed in the \
7088         rendered `lareira-<nome>` Helm chart's `Chart.yaml maintainers:` array \
7089         as a YAML-illegal multi-line scalar or a silently-trimmed whitespace \
7090         round-trip — every chart-aware UI (`helm list`, `helm search`, \
7091         Artifact Hub maintainer index) would render the maintainer name in a \
7092         single-line column far from the source caixa.lisp; the gate moves the \
7093         diagnostic to the manifest layer with the offending value named \
7094         verbatim)"
7095    )]
7096    AutorInvalid { autor: String, reason: String },
7097    #[error(
7098        ":repositorio is the empty string (every published caixa names its \
7099         git source via a non-empty `:repositorio` locator — the value \
7100         flows verbatim into the rendered `lareira-<nome>` Helm chart's \
7101         `Chart.yaml` `home:` field via `caixa-helm` and into the FluxCD \
7102         `GitRepository.spec.url` via `caixa-flux`'s \
7103         `ClusterBundleOpts::for_caixa`; both consumers' \
7104         `Option::unwrap_or_else` fallbacks only fire when the slot is \
7105         `None`, so an empty `Some(\"\")` silently lands as `home: \"\"` / \
7106         `url: \"\"` in the rendered artifacts and breaks at `helm \
7107         template` / FluxCD source-controller reconcile time far from the \
7108         source caixa.lisp; omit the slot entirely to defer to the \
7109         renderer's `https://github.com/pleme-io/<nome>` / \
7110         `caixa.nome`-derived fallback, or carry a canonical authoring \
7111         shape like `\"github:org/repo\"`, `\"https://host/path\"`, \
7112         `\"ssh://[user@]host/path\"`, `\"git@host:path\"`, or \
7113         `\"file:///path\"`)"
7114    )]
7115    RepositorioEmpty,
7116    #[error(
7117        ":repositorio {repositorio:?} is not a valid git repo URL: {reason} \
7118         (the substrate consumes this string through the shared \
7119         `crate::render::is_git_repo_url` predicate — the same parser the \
7120         peer `:deps :fonte (:tipo git :repo …)` axis routes its `:repo` \
7121         value through via `DepSource::validate`; the canonical authoring \
7122         shapes are `\"github:org/repo\"` shorthand, `\"https://host/path\"` \
7123         / `\"ssh://[user@]host/path\"` / `\"git://host/path\"` / \
7124         `\"file:///path\"` URL schemes, or the `\"git@host:path\"` \
7125         scp-style SSH form. Without this gate a malformed `:repositorio` \
7126         (whitespace from a paste-from-doc; control characters / CRLF \
7127         from a paste-from-multiline-doc; a leading `-` from a \
7128         CLI-argument-injection footgun; a missing `:` separator from a \
7129         bare `org/repo` shape git treats as a relative filesystem path) \
7130         silently landed in the rendered `Chart.yaml home:` and the \
7131         FluxCD `GitRepository.spec.url` and broke at `git clone` / \
7132         FluxCD reconcile time far from the source caixa.lisp; the gate \
7133         moves the diagnostic to the manifest layer with the offending \
7134         value named verbatim)"
7135    )]
7136    RepositorioInvalid { repositorio: String, reason: String },
7137    #[error(
7138        ":descricao is the empty string (every published caixa names \
7139         its purpose via a non-empty `:descricao` summary — the value \
7140         flows verbatim into the rendered `lareira-<nome>` Helm \
7141         chart's `Chart.yaml` `description:` field via `caixa-helm`'s \
7142         `build_chart_yaml` and into the chart `README.md` header via \
7143         `build_readme`; both consumers' `Option::unwrap_or_else` \
7144         `caixa.nome`-derived fallbacks only fire when the slot is \
7145         `None`, so an empty `Some(\"\")` silently lands as \
7146         `description: \"\"` / a blank `README.md` header in the \
7147         rendered artifacts and breaks at `helm lint` time \
7148         (`WARNING [chart.metadata.description]: description is \
7149         required` on `apiVersion: v2` charts) far from the source \
7150         caixa.lisp; omit the slot entirely to defer to the \
7151         renderer's `\"Generated chart for caixa Servico <nome>\"` / \
7152         `\"caixa Servico <nome>\"` fallbacks, or carry a non-empty \
7153         summary like `\"Canonical Rust→wasm32-wasip2 caixa \
7154         Servico.\"`)"
7155    )]
7156    DescricaoEmpty,
7157    #[error(
7158        ":descricao {descricao:?} is not a valid chart-description shape: \
7159         {reason} (the substrate consumes this string through the shared \
7160         `crate::render::is_chart_description_shape` predicate — the same \
7161         single-line-UTF-8 floor every realistic chart description carries: \
7162         1..=512 bytes, no leading or trailing whitespace, no ASCII control \
7163         characters anywhere, Unicode prose bytes accepted. The canonical \
7164         authoring shapes are short single-line summaries like `\"Canonical \
7165         Rust→wasm32-wasip2 caixa Servico.\"`, `\"Checkout flow.\"`, \
7166         `\"AWS provider caixa for tatara-lisp\"`. Without this gate a \
7167         malformed `:descricao` (paste-from-aligned-doc leading whitespace \
7168         `\" Checkout flow.\"` / trailing whitespace `\"Checkout flow. \"`; \
7169         paste-from-multiline-doc newline `\"Checkout\\nflow.\"`; \
7170         paste-from-Windows-CRLF-doc carriage return `\"Checkout\\rflow.\"`; \
7171         tab-from-aligned-doc `\"Checkout\\tflow.\"`; paste-from-binary-blob \
7172         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
7173         `validate_descricao` + `StandardLayout::verify` and landed in the \
7174         rendered `lareira-<nome>` Helm chart's `Chart.yaml description:` \
7175         field + `README.md` header paragraph as a YAML-illegal multi-line \
7176         scalar or a silently-trimmed whitespace round-trip — every \
7177         chart-aware UI (`helm list`, `helm search`, Artifact Hub) would \
7178         render the description in a single-line column far from the source \
7179         caixa.lisp; the gate moves the diagnostic to the manifest layer \
7180         with the offending value named verbatim)"
7181    )]
7182    DescricaoInvalid { descricao: String, reason: String },
7183    #[error(
7184        ":licenca is the empty string (every published caixa names \
7185         its license via a non-empty `:licenca` SPDX expression — the \
7186         value flows verbatim into the rendered `lareira-<nome>` Helm \
7187         chart's `README.md` `## License` section via `caixa-helm`'s \
7188         `build_readme` at `caixa-helm/src/lib.rs:361`; the consumer's \
7189         `Option::unwrap_or_else(|| \"MIT\".into())` `MIT` fallback \
7190         only fires when the slot is `None`, so an empty `Some(\"\")` \
7191         silently lands as a bare trailing period in the rendered \
7192         chart `README.md` `License` section far from the source \
7193         caixa.lisp; omit the slot entirely to defer to the \
7194         renderer's `MIT` fallback, or carry a canonical SPDX \
7195         expression like `\"MIT\"`, `\"Apache-2.0\"`, \
7196         `\"Apache-2.0 OR MIT\"`)"
7197    )]
7198    LicencaEmpty,
7199    #[error(
7200        ":licenca {licenca:?} is not a valid SPDX expression shape: {reason} \
7201         (the substrate consumes this string through the shared \
7202         `crate::render::is_spdx_expression_shape` predicate — the same \
7203         alphabet-floor parser every peer per-axis value-shape gate routes \
7204         its value through; the canonical authoring shapes are single \
7205         license identifiers like `\"MIT\"`, `\"Apache-2.0\"`, `\"BSD-3-Clause\"`, \
7206         compound expressions like `\"Apache-2.0 OR MIT\"`, \
7207         `\"MIT AND BSD-3-Clause\"`, `\"(MIT OR Apache-2.0) AND ISC\"`, \
7208         license-with-exception forms like `\"Apache-2.0 WITH LLVM-exception\"`, \
7209         `+`-suffix variants like `\"GPL-2.0+\"`, and user-defined references \
7210         like `\"LicenseRef-MyLicense\"` / \
7211         `\"DocumentRef-doc:LicenseRef-MyLicense\"`. Without this gate a \
7212         malformed `:licenca` (paste-from-doc whitespace `\"MIT \"` / \
7213         `\" MIT\"`; paste-from-multiline-doc CRLF `\"MIT\\n\"`; \
7214         tab-from-aligned-doc `\"MIT\\tOR Apache-2.0\"`; non-ASCII byte from \
7215         a smart-quote paste; underscore-instead-of-hyphen typo \
7216         `\"Apache_2.0\"`; comma-instead-of-`OR`-keyword colloquial idiom \
7217         `\"MIT, Apache-2.0\"`; slash-dual-license colloquial idiom \
7218         `\"MIT/Apache-2.0\"`; semicolon-list-separator confusion \
7219         `\"MIT; Apache-2.0\"`) silently landed in the rendered chart \
7220         `README.md` `## License` section + a future SPDX-aware \
7221         `Chart.yaml license:` emitter would refuse the value at \
7222         `helm lint` time far from the source caixa.lisp; the gate moves \
7223         the diagnostic to the manifest layer with the offending value \
7224         named verbatim)"
7225    )]
7226    LicencaInvalid { licenca: String, reason: String },
7227    #[error(
7228        ":edicao is the empty string (every published caixa names \
7229         its language edition via a non-empty `:edicao` value — the \
7230         edition determines the tatara-lisp macro surface + \
7231         compatibility flags the substrate applies when building \
7232         the caixa; the canonical `Caixa::template` scaffold every \
7233         `feira init` emits carries `:edicao \"2026\"` verbatim and \
7234         every renderer-side fixture (`caixa-helm`, `caixa-flux`, \
7235         `caixa-mesh`) carries `edicao: Some(\"2026\".into())` by \
7236         construction, so an empty `Some(\"\")` silently lands as a \
7237         bare `(:edicao \"\")` line in the rendered `caixa.lisp` and \
7238         a future renderer-side consumer that folds it through \
7239         `Option::unwrap_or_else` will skip the fallback and pass the \
7240         empty edition through to the substrate's build-time edition \
7241         selector far from the source caixa.lisp; omit the slot \
7242         entirely to defer to the substrate's default edition, or \
7243         carry a canonical edition like `\"2026\"`)"
7244    )]
7245    EdicaoEmpty,
7246    #[error(
7247        ":edicao {edicao:?} is not a valid edition: {reason} (every \
7248         documented tatara-lisp edition is a 4-digit ASCII decimal \
7249         year — `\"2026\"` is the only edition currently minted; \
7250         future-introduced siblings will follow the same shape, peer \
7251         with Cargo's `[package] edition` grammar which every value \
7252         Cargo has ever accepted matches: `\"2015\"`, `\"2018\"`, \
7253         `\"2021\"`, `\"2024\"`. Without this gate the canonical \
7254         paste-from-doc footguns silently passed: a trailing space \
7255         (`\"2026 \"`) from a paste-from-doc, a CRLF (`\"2026\\n\"`) \
7256         from a paste-from-multiline-doc, a fullwidth-keyboard \
7257         look-alike (`\"2026\"`), a free-form non-year value \
7258         (`\"x\"`, `\"latest\"`, `\"nightly\"`), a leading non-digit \
7259         version-tag prefix (`\"v2026\"`, `\"e2026\"`), a \
7260         decimal-shaped pseudo-version (`\"2026.1\"`), or a \
7261         wrong-length numeric value (`\"26\"`, `\"202\"`, \
7262         `\"20260\"`) all landed as `(:edicao \"<garbage>\")` in the \
7263         rendered caixa.lisp and broke at the substrate's \
7264         build-time edition selector far from the source caixa.lisp; \
7265         omit the slot entirely to defer to the substrate's default \
7266         edition, or carry a canonical 4-digit ASCII decimal year \
7267         like `\"2026\"`)"
7268    )]
7269    EdicaoInvalid { edicao: String, reason: String },
7270}
7271
7272// Fold the five `Err(ManifestError::CodePath{Absolute,ParentEscape,
7273// NonLispExtension,NonComputeUnitYamlExtension,Duplicate} { slot,
7274// path: path.to_path_buf() })` four-line struct-variant wire-up sites at
7275// [`Caixa::validate_code_path_lists`]'s per-slot per-entry cascade onto
7276// one substrate-primitive family on the `ManifestError` envelope — the
7277// five open-coded ctor sites remaining on the `:bibliotecas` / `:exe` /
7278// `:servicos` code-path-list value-shape trajectory this envelope carries,
7279// and the family sibling of the peer [`crate::behavior::behavior_slot_path_ctors!`]
7280// (67c31ec) two-slot `{ slot: &'static str, path: PathBuf }` envelope on
7281// the [`crate::BehaviorError`] surface that keys off the exact same
7282// `(slot: &'static str, path: &Path)` argument tuple.
7283//
7284// The five wire-up sites this fold closes are the sandbox-shape
7285// absolute-path arm (`return Err(ManifestError::CodePathAbsolute { slot,
7286// path: path.to_path_buf() })` on the [`is_sandboxed_relative_path`]
7287// `PathShapeViolation::Absolute` branch), the sandbox-shape
7288// parent-escape arm (`return Err(ManifestError::CodePathParentEscape {
7289// slot, path: path.to_path_buf() })` on the sibling
7290// `PathShapeViolation::ParentEscape` branch), the LispSource
7291// terminating-extension arm (`return Err(ManifestError::CodePathNonLispExtension {
7292// slot, path: path.to_path_buf() })` on the `!is_lisp_extension(path)`
7293// branch of the `:bibliotecas` file-type gate), the ComputeUnitYaml
7294// compound-suffix arm (`return Err(ManifestError::CodePathNonComputeUnitYamlExtension
7295// { slot, path: path.to_path_buf() })` on the
7296// `!is_computeunit_yaml_extension(path)` branch of the `:servicos`
7297// file-type gate), and the cross-entry duplicate arm
7298// (`ManifestError::CodePathDuplicate { slot, path: path.to_path_buf() }`
7299// inside the closure passed to [`crate::render::insert_first_seen`]) —
7300// each opened the identical `ManifestError::CodePath* { slot,
7301// path: path.to_path_buf() }` four-line struct-literal against the same
7302// `(slot: &'static str, path: &Path)` local tuple, the exact "same
7303// block re-inlined at every consumer" shape the PRIME DIRECTIVE names
7304// as a bug. The variant discriminator is the only thing that varies
7305// between the five sites; the rest of the struct-literal is a
7306// byte-for-byte re-inline.
7307//
7308// The macro below generates one `#[must_use]` inherent constructor per
7309// variant of shape `fn <ctor>(slot: &'static str, path: &std::path::Path)
7310// -> Self`, so every wire-up site collapses onto one dispatch:
7311// `ManifestError::<ctor>(slot, path)`, byte-equal to the pre-lift
7312// struct-literal on the same `(&'static str, &Path)` fixture. The
7313// uniform two-field construction (`slot` verbatim as `&'static str`,
7314// `path.to_path_buf()`) is spelled once — inside the macro — rather
7315// than at every wire-up site. The `slot` parameter stays `&'static str`
7316// (not `&str`) so every arm continues to carry a program-lifetime
7317// `:bibliotecas` / `:exe` / `:servicos` author-key label — one of the
7318// three `&'static str` literals threaded through the outer per-slot
7319// iterator at [`Caixa::validate_code_path_lists`] — matching the
7320// enum-field type. A runtime-borrowed `&str` would silently downgrade
7321// the label lifetime and let a caller stash a non-`'static` borrow into
7322// the returned error. The `&Path` parameter accepts both
7323// `&Path` and `&PathBuf` (via Deref coercion), so every existing
7324// wire-up — each already binds `let path = Path::new(entry);` from the
7325// per-entry loop — threads through the ctor without a pre-conversion.
7326//
7327// Every future consumer that wants to construct one of these five
7328// variants outside the five in-crate wire-up sites (a deferred
7329// `feira validate --code-paths` per-caixa admission verb re-checking
7330// each declared `:bibliotecas` / `:exe` / `:servicos` entry against the
7331// same sandbox-shape + file-type + duplicate cascade, a future
7332// caixa-registry per-lacre code-path re-validator at lacre-resolve
7333// time, a per-`Caixa` overlay resolver rejecting an author-supplied
7334// code-path against a cluster-local snapshot) now reaches each variant
7335// through one call rather than re-inlining the four-line struct-literal
7336// in lockstep with the five in-crate wire-up sites.
7337macro_rules! manifest_code_path_slot_path_ctors {
7338    ($($ctor:ident => $variant:ident),* $(,)?) => {
7339        impl ManifestError {
7340            $(
7341                #[doc = concat!(
7342                    "Construct a [`ManifestError::",
7343                    stringify!($variant),
7344                    "`] naming the offending `:bibliotecas` / `:exe` / ",
7345                    "`:servicos` code-path list `slot` label and the ",
7346                    "offending entry `path`. Folds the uniform `Self::",
7347                    stringify!($variant),
7348                    " { slot, path: path.to_path_buf() }` two-field ",
7349                    "struct-literal onto one substrate primitive so ",
7350                    "every wire-up on this variant at ",
7351                    "[`Caixa::validate_code_path_lists`] reads through ",
7352                    "one dispatch rather than the pre-lift four-line ",
7353                    "open-coded block. The `slot` label threads verbatim ",
7354                    "from the outer per-slot iterator (one of the three ",
7355                    "code-path author-key `&'static str` consts) and the ",
7356                    "`path` from the per-entry inner iterator's ",
7357                    "`Path::new(entry)` binding."
7358                )]
7359                #[must_use]
7360                pub fn $ctor(slot: &'static str, path: &std::path::Path) -> Self {
7361                    Self::$variant {
7362                        slot,
7363                        path: path.to_path_buf(),
7364                    }
7365                }
7366            )*
7367        }
7368    };
7369}
7370
7371manifest_code_path_slot_path_ctors! {
7372    code_path_absolute => CodePathAbsolute,
7373    code_path_parent_escape => CodePathParentEscape,
7374    code_path_non_lisp_extension => CodePathNonLispExtension,
7375    code_path_non_computeunit_yaml_extension => CodePathNonComputeUnitYamlExtension,
7376    code_path_duplicate => CodePathDuplicate,
7377}
7378
7379// Fold the last `ManifestError::CodePathEmpty { slot: <&'static str> }` single-
7380// slot struct-variant wire-up site at [`Caixa::validate_code_path_lists`]'s
7381// per-slot [`PathShapeViolation::Empty`] arm onto one substrate primitive on
7382// `ManifestError` — the last open-coded single-slot `{ slot: &'static str }`
7383// struct-literal on the `:bibliotecas` / `:exe` / `:servicos` code-path-list
7384// value-shape trajectory this envelope carries, matching the peer five-variant
7385// [`manifest_code_path_slot_path_ctors!`] family fold (de11917, 5 variants on
7386// `{ slot: &'static str, path: PathBuf }`) already closed on the sibling
7387// two-slot envelope of the same `ManifestError`, and mirror-symmetric sibling
7388// of the peer [`crate::behavior::BehaviorError::empty_path`] (0e33b37,
7389// `EmptyPath { slot: &'static str }`) ctor on the sibling M2 `:behavior`
7390// envelope's identical one-slot shape. After this lift every wire-up on every
7391// `ManifestError` variant carried by [`Caixa::validate_code_path_lists`]'s
7392// per-slot [`PathShapeViolation`] cascade reads through one substrate-primitive
7393// ctor dispatch per typed variant rather than one macro closing four sites
7394// plus a hand-written empty-slot open-coding the fifth.
7395//
7396// A macro is not warranted on the one-variant envelope shape
7397// `{ slot: &'static str }` — unlike the peer five-variant
7398// `{ slot: &'static str, path: PathBuf }` shape the
7399// [`manifest_code_path_slot_path_ctors!`] macro closes — but the same
7400// substrate-primitive discipline applies: every future consumer that wants to
7401// construct a `CodePathEmpty` outside [`Caixa::validate_code_path_lists`] (a
7402// deferred `feira validate --code-paths` per-caixa admission verb re-checking
7403// each declared `:bibliotecas` / `:exe` / `:servicos` entry against the same
7404// sandbox-shape + file-type + duplicate cascade, a future caixa-registry
7405// per-lacre code-path re-validator at lacre-resolve time, a per-`Caixa`
7406// overlay resolver rejecting an author-supplied empty code-path against a
7407// cluster-local snapshot) reaches the variant through one call rather than
7408// re-inlining the one-line struct-literal in lockstep with the in-crate
7409// wire-up site.
7410//
7411// The `slot` parameter stays `&'static str` (not `&str`) so the constructor
7412// continues to carry a program-lifetime `:bibliotecas` / `:exe` / `:servicos`
7413// author-key label — one of the three `&'static str` literals threaded through
7414// the outer per-slot iterator at [`Caixa::validate_code_path_lists`] — matching
7415// the enum-field type and the peer [`manifest_code_path_slot_path_ctors!`]-
7416// generated arms' `slot: &'static str` parameter verbatim. A runtime-borrowed
7417// `&str` would silently downgrade the label lifetime and let a caller stash a
7418// non-`'static` borrow into the returned error. `const fn` preserves the
7419// zero-runtime-work property of the pre-lift struct-literal verbatim, matching
7420// the peer [`crate::behavior::BehaviorError::empty_path`] `const fn` on the
7421// sibling M2 envelope and the sibling
7422// [`crate::supervisor::supervisor_scalar_ctors!`] / peer
7423// [`crate::aplicacao::aplicacao_policy_scalar_ctors!`] `Copy`-scalar
7424// discipline on their sibling envelopes.
7425impl ManifestError {
7426    /// Construct a [`ManifestError::CodePathEmpty`] naming the offending
7427    /// `:bibliotecas` / `:exe` / `:servicos` code-path list `slot` label.
7428    /// Folds the uniform `Self::CodePathEmpty { slot }` one-field
7429    /// struct-literal onto one substrate primitive so the wire-up at
7430    /// [`Caixa::validate_code_path_lists`]'s per-slot
7431    /// [`PathShapeViolation::Empty`] arm on this variant reads through one
7432    /// dispatch rather than the pre-lift open-coded struct-literal block.
7433    /// Peer of the sibling [`ManifestError::code_path_absolute`] /
7434    /// [`ManifestError::code_path_parent_escape`] /
7435    /// [`ManifestError::code_path_non_lisp_extension`] /
7436    /// [`ManifestError::code_path_non_computeunit_yaml_extension`] /
7437    /// [`ManifestError::code_path_duplicate`] ctors the
7438    /// [`manifest_code_path_slot_path_ctors!`] macro closed on the paired
7439    /// two-slot `{ slot: &'static str, path: PathBuf }` envelope of the same
7440    /// `ManifestError`, and mirror-symmetric sibling of the peer
7441    /// [`crate::behavior::BehaviorError::empty_path`] ctor on the sibling M2
7442    /// `:behavior` envelope's identical one-slot shape — the per-slot
7443    /// [`PathShapeViolation`] cascade at [`Caixa::validate_code_path_lists`]
7444    /// now routes every arm through one substrate-primitive ctor per typed
7445    /// variant.
7446    #[must_use]
7447    pub const fn code_path_empty(slot: &'static str) -> Self {
7448        Self::CodePathEmpty { slot }
7449    }
7450}
7451
7452// Fold the ten `ManifestError::{Nome, NomeChartNameBudgetExceeded, Versao,
7453// Etiqueta, Autor, Repositorio, Descricao, Licenca, Edicao}Invalid +
7454// RestartWindowMalformed
7455// { <field>: <val>.to_string() | <val>.clone(), reason: <expr> }` wire-up
7456// sites at the per-axis [`Caixa::validate_*`] cascade onto one substrate-
7457// primitive family per typed variant — the direct sibling on the
7458// [`ManifestError`] envelope of the peer
7459// [`crate::aplicacao::aplicacao_field_reason_ctors!`] (981060b, 7 variants
7460// on `AplicacaoError` at `MembroCaixaInvalid` / `EntradaParaInvalid` /
7461// `EntradaHostInvalid` / `EntradaPathInvalid` / `PlacementClusterInvalid` /
7462// `PlacementAffinityInvalid` / `ShardKeyInvalid`) on the M3 mesh side, and
7463// of the peer [`crate::dep::dep_nome_axis_reason_ctors!`] (5621f8a,
7464// 3 variants on `DepError` at `VersaoInvalid` / `FonteRepoShape` /
7465// `CaracteristicaInvalid`) on the sibling `:deps` envelope's mirror-
7466// symmetric `{ nome: String, <axis>: String, reason: String }` three-slot
7467// shape (the `nome` axis added at the per-dep-owned altitude). Every one
7468// of the peer four-family `LayoutError` ctor set
7469// ([`crate::layout::layout_violation_ctors!`] 131ca0d — 16 variants on
7470// `{ caixa, issue }`, [`crate::layout::layout_slot_kind_ctors!`] 0419438
7471// — 4 variants on `{ caixa, kind, slots }`,
7472// [`crate::LayoutError::missing_entry`] 1b09f9d — 1 variant on
7473// `{ kind, path }`, [`crate::layout::layout_nome_only_ctors!`] 3fe3dd7 —
7474// 6 variants on `<Variant>(String)`) and the peer three
7475// [`crate::limits::limits_codec_value_*_ctors!`] codec families (81c856c)
7476// each carry the same discipline on their sibling envelopes.
7477//
7478// The ten variants share the identical `{ <field>: String,
7479// reason: String }` two-slot shape:
7480//   - `NomeInvalid { nome, reason }` at [`Caixa::validate_nome`]
7481//     (`|reason| ManifestError::NomeInvalid { nome: nome.to_string(),
7482//     reason }` inside [`crate::render::require_valid_dns_1123_label`]'s
7483//     `on_invalid` bracket-closure slot);
7484//   - `NomeChartNameBudgetExceeded { nome, reason }` at
7485//     [`Caixa::validate_nome_chart_name_budget`]
7486//     (`|reason| ManifestError::NomeChartNameBudgetExceeded { nome:
7487//     nome.to_string(), reason }` after
7488//     [`crate::render::is_lareira_chart_name_shape`] rejects the offending
7489//     `:nome`);
7490//   - `VersaoInvalid { versao, reason }` at [`Caixa::validate_versao`]
7491//     (`|e| ManifestError::VersaoInvalid { versao: versao.to_string(),
7492//     reason: e.to_string() }` after [`semver::Version::parse`] rejects
7493//     the offending `:versao`);
7494//   - `EtiquetaInvalid { etiqueta, reason }` at
7495//     [`Caixa::validate_etiquetas`]
7496//     (`|reason| ManifestError::EtiquetaInvalid { etiqueta:
7497//     etiqueta.clone(), reason }` after
7498//     [`crate::render::is_chart_keyword_shape`] rejects the offending
7499//     `:etiquetas` entry);
7500//   - `AutorInvalid { autor, reason }` at [`Caixa::validate_autores`]
7501//     (`|reason| ManifestError::AutorInvalid { autor: autor.clone(),
7502//     reason }` after [`crate::render::is_chart_maintainer_name_shape`]
7503//     rejects the offending `:autores` entry);
7504//   - `RepositorioInvalid { repositorio, reason }` at
7505//     [`Caixa::validate_repositorio`]
7506//     (`|reason| ManifestError::RepositorioInvalid { repositorio:
7507//     s.to_string(), reason }` after
7508//     [`crate::render::is_git_repo_url`] rejects the offending
7509//     `:repositorio`);
7510//   - `DescricaoInvalid { descricao, reason }` at
7511//     [`Caixa::validate_descricao`]
7512//     (`|reason| ManifestError::DescricaoInvalid { descricao:
7513//     s.to_string(), reason }` after
7514//     [`crate::render::is_chart_description_shape`] rejects the offending
7515//     `:descricao`);
7516//   - `LicencaInvalid { licenca, reason }` at [`Caixa::validate_licenca`]
7517//     (`|reason| ManifestError::LicencaInvalid { licenca: s.to_string(),
7518//     reason }` after [`crate::render::is_spdx_expression_shape`] rejects
7519//     the offending `:licenca`);
7520//   - `EdicaoInvalid { edicao, reason }` at [`Caixa::validate_edicao`]
7521//     (`return Err(ManifestError::EdicaoInvalid { edicao: s.to_string(),
7522//     reason: "must be a 4-digit ASCII decimal year (canonical
7523//     \"2026\")".to_string() })` on the direct year-shape arm);
7524//   - `RestartWindowMalformed { restart_window, reason }` at
7525//     [`Caixa::validate_restart_window`]
7526//     (`|reason| ManifestError::RestartWindowMalformed { restart_window:
7527//     s.to_string(), reason }` after
7528//     [`crate::supervisor::duration_codec::parse`] rejects the offending
7529//     `:restart-window` raw string).
7530//
7531// Each opened the identical four-line
7532// `ManifestError::<Variant> { <field>: <val>.to_string() | .clone(),
7533// reason: <expr> }` struct-literal against the caller-side `<field>: &str`
7534// / `<field>: &String` local — the exact "same block re-inlined at every
7535// consumer" shape the PRIME DIRECTIVE names as a bug, on the same altitude
7536// the peer `aplicacao_field_reason_ctors!` / `dep_nome_axis_reason_ctors!`
7537// / `LayoutError` / `LimitsError` / `BehaviorError` / `UpgradeError`
7538// families each closed on their sibling envelopes.
7539//
7540// The macro below generates one `#[must_use]` inherent constructor per
7541// variant of shape `fn <ctor>(<field>: &str, reason: impl Into<String>)
7542// -> Self`, collapsing every site onto one dispatch per arm:
7543// `ManifestError::<ctor>(<val>, <reason>)`, byte-equal to the pre-lift
7544// struct-literal on the same `(<field>, reason)` pair. The uniform
7545// two-field construction (`<field>: <field>.to_string()`,
7546// `reason: reason.into()`) is spelled once — inside the macro — rather
7547// than at every wire-up site. The `reason: impl Into<String>` bound
7548// accepts owned `String` (the parser-shaped reason every predicate
7549// returns via `Result<(), String>`; the `e.to_string()` result the
7550// `semver::Version::parse` arm passes; the literal `"…".to_string()` the
7551// `EdicaoInvalid` direct arm passes), `&str` literals, and `format!(…)`
7552// outputs verbatim so no wire-up site changes its per-arm diagnostic
7553// shape at the lift, matching the peer
7554// [`crate::aplicacao::aplicacao_field_reason_ctors!`] and
7555// [`crate::dep::dep_nome_axis_reason_ctors!`] bounds on the sibling
7556// two- and three-slot envelopes. The `<field>: &str` parameter accepts
7557// both `&str` (from the [`Caixa::nome`] / [`Caixa::versao`] /
7558// [`Caixa::repositorio`] / [`Caixa::descricao`] / [`Caixa::licenca`] /
7559// [`Caixa::edicao`] accessors) and `&String` (from the
7560// [`Caixa::etiquetas`] / [`Caixa::autores`] slice iterators) via Deref
7561// coercion, so every existing wire-up threads through the ctor without a
7562// pre-conversion. `#[must_use]` fires a compile warning at any wire-up
7563// that mistakenly discards the constructed error rather than routing it
7564// through `return Err(…)` / `.map_err(…)` / a closure return.
7565//
7566// Every future consumer that wants to construct one of these ten
7567// variants outside the current in-crate wire-up sites (a deferred
7568// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-manifest-axis
7569// admission validators re-checking each declared identity / metadata
7570// axis against a cluster-local snapshot, a future `feira validate
7571// --manifest` per-caixa admission verb re-running the same
7572// value-shape gates on demand, a per-lacre overlay resolver rejecting
7573// an author-supplied manifest override against a cluster-local snapshot
7574// the M4 CR materializer projects, a future
7575// `caixa-registry` per-lacre re-validator at lacre-resolve time
7576// re-checking each declared axis against the same predicates) now
7577// reaches each variant through one call rather than re-inlining the
7578// four-line struct-literal in lockstep with the ten in-crate wire-up
7579// sites.
7580macro_rules! manifest_field_reason_ctors {
7581    ($($ctor:ident => $variant:ident { $field:ident }),* $(,)?) => {
7582        impl ManifestError {
7583            $(
7584                #[doc = concat!(
7585                    "Construct a [`ManifestError::",
7586                    stringify!($variant),
7587                    "`] naming the offending `",
7588                    stringify!($field),
7589                    "` under the given `reason`. Folds the uniform ",
7590                    "`Self::",
7591                    stringify!($variant),
7592                    " { ",
7593                    stringify!($field),
7594                    ": ",
7595                    stringify!($field),
7596                    ".to_string(), reason: reason.into() }` two-slot ",
7597                    "construction onto one substrate primitive so every ",
7598                    "wire-up on this variant reads through one dispatch ",
7599                    "rather than the pre-lift four-line struct-literal ",
7600                    "block. `reason` accepts owned `String`, `&str` ",
7601                    "literals, and `format!(…)` outputs through the ",
7602                    "`impl Into<String>` bound; the `",
7603                    stringify!($field),
7604                    ": &str` parameter accepts both `&str` and `&String` ",
7605                    "via Deref coercion."
7606                )]
7607                #[must_use]
7608                pub fn $ctor($field: &str, reason: impl Into<String>) -> Self {
7609                    Self::$variant {
7610                        $field: $field.to_string(),
7611                        reason: reason.into(),
7612                    }
7613                }
7614            )*
7615        }
7616    };
7617}
7618
7619manifest_field_reason_ctors! {
7620    nome_invalid => NomeInvalid { nome },
7621    nome_chart_name_budget_exceeded => NomeChartNameBudgetExceeded { nome },
7622    versao_invalid => VersaoInvalid { versao },
7623    etiqueta_invalid => EtiquetaInvalid { etiqueta },
7624    autor_invalid => AutorInvalid { autor },
7625    repositorio_invalid => RepositorioInvalid { repositorio },
7626    descricao_invalid => DescricaoInvalid { descricao },
7627    licenca_invalid => LicencaInvalid { licenca },
7628    edicao_invalid => EdicaoInvalid { edicao },
7629    restart_window_malformed => RestartWindowMalformed { restart_window },
7630}
7631
7632// Fold the two `ManifestError::{EtiquetaDuplicate, AutorDuplicate}
7633// { <field>: <val>.clone() }` single-`String`-slot wire-up sites at
7634// [`Caixa::validate_etiquetas`] and [`Caixa::validate_autores`] onto one
7635// substrate-primitive family per typed variant — the direct sibling on
7636// the [`ManifestError`] envelope of the peer
7637// [`crate::aplicacao::aplicacao_caixa_only_ctors!`] (d9f6867, 4 variants
7638// on `AplicacaoError` at `ContratoMemberMissing` / `MembroVersaoEmpty` /
7639// `MembroDuplicate` / `MembroIsSelfAplicacao` on the `{ caixa: String }`
7640// shape) and [`crate::aplicacao::aplicacao_path_only_ctors!`] (3ba8de6,
7641// 2 variants on `AplicacaoError` at `EntradaPathNotAbsolute` /
7642// `EntradaPathDuplicate` on the `{ path: String }` shape) on the sibling
7643// M3 mesh `AplicacaoError` envelope, and of the peer
7644// [`crate::supervisor::supervisor_caixa_only_ctors!`] (db09650, 3 variants
7645// on the sibling M2 `SupervisorError` envelope's `{ caixa: String }`
7646// shape), [`crate::dep::dep_nome_only_ctors!`] (792aa92, 5 variants on
7647// `DepError { nome: String }`), and [`crate::upgrade::upgrade_script_only_ctors!`]
7648// (7468ca9, 3 variants on `UpgradeError { script: PathBuf }`) folds on
7649// the sibling envelopes — the last two open-coded single-slot
7650// `{ <field>: String }` struct-literal sites on `ManifestError` fold
7651// onto one substrate primitive per typed variant, matching the
7652// "one substrate primitive per typed variant on the single-slot
7653// `{ <ident>: String }` envelope shape" fold discipline every peer
7654// per-Caixa-identity family already carries.
7655//
7656// Both wire-up sites — one at [`Caixa::validate_etiquetas`]'s per-entry
7657// [`crate::render::insert_first_seen`] dedup closure
7658// (`|| ManifestError::EtiquetaDuplicate { etiqueta: etiqueta.clone() }`
7659// against the per-`:etiquetas` `&String` loop head) and one at
7660// [`Caixa::validate_autores`]'s per-entry [`crate::render::insert_first_seen`]
7661// dedup closure (`|| ManifestError::AutorDuplicate
7662// { autor: autor.clone() }` against the per-`:autores` `&String` loop
7663// head) — opened the identical `ManifestError::<Variant>Duplicate
7664// { <field>: <val>.clone() }` three-line struct-literal against a
7665// caller-side `&String`, the exact "same block re-inlined at every
7666// consumer" shape the PRIME DIRECTIVE names as a bug. The two variants
7667// share one `{ <field>: String }` shape, so the fold routes each wire-up
7668// site through one dispatch per typed variant.
7669//
7670// The macro below generates one `#[must_use]` inherent constructor per
7671// variant of shape `fn <ctor>(<field>: &str) -> ManifestError`, so every
7672// wire-up site collapses onto one dispatch:
7673// `ManifestError::<ctor>(<&str>)`, byte-equal to the pre-lift
7674// struct-literal on the same `&str` fixture. The uniform one-field
7675// construction (`<field>: <field>.to_string()`) is spelled once — inside
7676// the macro — rather than at every wire-up site. The `<field>: &str`
7677// parameter accepts both `&str` and `&String` (via Deref coercion), so
7678// each existing dedup-closure wire-up threading `<val>.as_str()` — or a
7679// bare `&String` head — through the ctor routes through one dispatch
7680// without a pre-conversion, and the `.clone()` the pre-lift wire-up
7681// carried at the closure body folds into the ctor's canonical
7682// `.to_string()` (byte-equal on the same underlying bytes). Every
7683// constructor is `#[must_use]` so a caller who mistakenly discards the
7684// constructed error trips a compile warning at the wire-up site.
7685//
7686// Every future consumer that wants to construct one of these two
7687// variants outside the current in-crate wire-up sites — a deferred
7688// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission webhook
7689// re-checking one added/renamed `:etiquetas` / `:autores` entry against
7690// the same dedup axis, a future `feira validate --etiquetas` /
7691// `--autores` per-caixa admission verb re-running the same per-entry
7692// dedup gate on demand, a per-lacre overlay resolver rejecting an
7693// author-supplied duplicate `:etiquetas` / `:autores` entry against a
7694// cluster-local snapshot the M4 CR materializer projects, a future
7695// `caixa-registry` per-lacre re-validator at lacre-resolve time
7696// re-checking each declared list against the same dedup predicate — now
7697// reaches each variant through one call rather than re-inlining the
7698// three-line struct-literal in lockstep with the two in-crate wire-up
7699// sites.
7700macro_rules! manifest_field_only_ctors {
7701    ($($ctor:ident => $variant:ident { $field:ident }),* $(,)?) => {
7702        impl ManifestError {
7703            $(
7704                #[doc = concat!(
7705                    "Construct a [`ManifestError::",
7706                    stringify!($variant),
7707                    "`] naming the offending `",
7708                    stringify!($field),
7709                    "` entry. Folds the uniform `Self::",
7710                    stringify!($variant),
7711                    " { ",
7712                    stringify!($field),
7713                    ": ",
7714                    stringify!($field),
7715                    ".to_string() }` one-field struct-literal onto one ",
7716                    "substrate primitive so every wire-up on this variant ",
7717                    "reads through one dispatch rather than the pre-lift ",
7718                    "three-line open-coded struct-literal block. The `",
7719                    stringify!($field),
7720                    ": &str` parameter accepts both `&str` and `&String` ",
7721                    "via Deref coercion."
7722                )]
7723                #[must_use]
7724                pub fn $ctor($field: &str) -> Self {
7725                    Self::$variant {
7726                        $field: $field.to_string(),
7727                    }
7728                }
7729            )*
7730        }
7731    };
7732}
7733
7734manifest_field_only_ctors! {
7735    etiqueta_duplicate => EtiquetaDuplicate { etiqueta },
7736    autor_duplicate => AutorDuplicate { autor },
7737}
7738
7739#[cfg(test)]
7740mod tests {
7741    use super::*;
7742
7743    #[test]
7744    fn template_round_trips() {
7745        let src = Caixa::template("demo");
7746        let c = Caixa::from_lisp(&src).expect("template must parse");
7747        assert_eq!(c.nome, "demo");
7748        assert_eq!(c.versao, "0.1.0");
7749        assert_eq!(c.kind, CaixaKind::Biblioteca);
7750        assert_eq!(c.bibliotecas, vec!["lib/demo.lisp".to_string()]);
7751        assert!(c.deps.is_empty());
7752        assert!(c.deps_dev.is_empty());
7753    }
7754
7755    #[test]
7756    fn caixa_universal_axis_scalar_accessor_pair_is_const_fn() {
7757        // Fail-before-pass-after pin on [`Caixa::nome`] +
7758        // [`Caixa::versao`]'s `const`-eval-surface posture. Each
7759        // accessor projects the top-level manifest's per-`:nome` /
7760        // per-`:versao` [`String`] storage through the `pub const fn`
7761        // [`String::as_str`] (const-stable since Rust 1.87, well within
7762        // the workspace MSRV) — any future accidental downgrade to
7763        // non-`const` fails the corresponding `<name>_via_const_fn`
7764        // wrapper at caixa-core build time with E0015 (`cannot call
7765        // non-const method`), strictly stronger than a runtime
7766        // `assert!`. Sibling of the peer per-M2/M3-slot `String → &str`
7767        // scalar-accessor family pins on the sibling `const`-eval-
7768        // surface passes ([`crate::CaixaVersion::as_str`] at the
7769        // typed-newtype wrapper, [`crate::aplicacao::Membro::nome`] /
7770        // [`crate::aplicacao::Membro::versao_requirement`] at the M3
7771        // membership axis, [`crate::aplicacao::Entrada::hostname`] /
7772        // [`crate::aplicacao::Entrada::destination`] at the M3 ingress
7773        // axis, [`crate::supervisor::ChildSpec::nome`] /
7774        // [`crate::supervisor::ChildSpec::versao_requirement`] at the
7775        // M2 supervisor-tree axis,
7776        // [`crate::upgrade::UpgradeFromEntry::prior_versao`] at the M2
7777        // upgrade axis, [`crate::dep::Dep::nome`] /
7778        // [`crate::dep::Dep::versao_requirement`] at the dep-graph
7779        // axis, and the per-`:contratos`
7780        // [`crate::aplicacao::WitContract::source`] /
7781        // [`crate::aplicacao::WitContract::destination`] /
7782        // [`crate::aplicacao::WitContract::world_ref`] trio the
7783        // sibling pin at 279823b already anchors).
7784        const fn nome_via_const_fn(c: &Caixa) -> &str {
7785            c.nome()
7786        }
7787        const fn versao_via_const_fn(c: &Caixa) -> &str {
7788            c.versao()
7789        }
7790        let src = Caixa::template("demo");
7791        let c = Caixa::from_lisp(&src).expect("template must parse");
7792        assert_eq!(nome_via_const_fn(&c), c.nome());
7793        assert_eq!(versao_via_const_fn(&c), c.versao());
7794        assert_eq!(c.nome(), "demo");
7795        assert_eq!(c.versao(), "0.1.0");
7796    }
7797
7798    #[test]
7799    fn caixa_option_string_scalar_accessor_family_is_const_fn() {
7800        // Fail-before-pass-after pin on the five per-`Caixa`
7801        // `Option<String> → Option<&str>` scalar accessors
7802        // ([`Caixa::licenca`] / [`Caixa::repositorio`] /
7803        // [`Caixa::descricao`] / [`Caixa::edicao`] on the top-level
7804        // manifest's optional universal-axis surface, plus
7805        // [`Caixa::restart_window`] on the M2 supervisor-tree
7806        // per-`SupervisorSpec` peer raw-window-string projection axis).
7807        // Each accessor destructures the typed slot's `Option<String>`
7808        // storage through the `match &self.<field> { Some(s) =>
7809        // Some(s.as_str()), None => None }` shape — routing through
7810        // [`String::as_str`] (const-stable since Rust 1.87, well within
7811        // the workspace MSRV) rather than the non-const
7812        // [`Option::as_deref`] the pre-lift bodies carried — and any
7813        // future accidental downgrade to non-`const` fails the
7814        // corresponding `<name>_via_const_fn` wrapper at caixa-core
7815        // build time with E0015 (`cannot call non-const method`),
7816        // strictly stronger than a runtime `assert!` and strictly
7817        // stronger than a module-scope `const _: () = assert!(…)` pin
7818        // (which cannot be formed on a `&Caixa` fixture because the
7819        // type's `String` / `Option<String>` carriers rule out
7820        // `const`-context value construction; the `const fn` wrapper
7821        // is the load-bearing shape that side-steps the destructor-in-
7822        // const restriction on the value axis while still pinning the
7823        // `const`-fn posture on the callee — mirror of the sibling
7824        // [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
7825        // pin's discipline verbatim on the peer non-`Option`
7826        // `String → &str` axis at the same struct).
7827        //
7828        // Peer of the sibling per-M2/M3-slot `Option<String> →
7829        // Option<&str>` accessor family pin
7830        // [`m3_option_string_scalar_accessor_family_is_const_fn`] on
7831        // the M3 mesh-slot atom axes ([`WitContract::endpoint`] /
7832        // [`WitContract::subject`] / [`WitContract::slot`] on the
7833        // per-`:contratos` payload-carrier trio,
7834        // [`Placement::shard_key`] / [`Placement::affinity`] on the
7835        // per-`:placement` optional-scalar pair).
7836        const fn licenca_via_const_fn(c: &Caixa) -> Option<&str> {
7837            c.licenca()
7838        }
7839        const fn repositorio_via_const_fn(c: &Caixa) -> Option<&str> {
7840            c.repositorio()
7841        }
7842        const fn descricao_via_const_fn(c: &Caixa) -> Option<&str> {
7843            c.descricao()
7844        }
7845        const fn edicao_via_const_fn(c: &Caixa) -> Option<&str> {
7846            c.edicao()
7847        }
7848        const fn restart_window_via_const_fn(c: &Caixa) -> Option<&str> {
7849            c.restart_window()
7850        }
7851        // Sweep both the `Some`-carrying arm (author-declared slot,
7852        // the byte-string projection payload) and the `None`-carrying
7853        // arm (author-omitted slot, the default-path projection) on
7854        // every accessor so the `const fn` wrapper family pins each
7855        // axis's canonical two-arm partition through the same const
7856        // dispatch as the runtime path.
7857        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7858        c1.licenca = Some("MIT".to_string());
7859        c1.repositorio = Some("https://github.com/pleme-io/demo".to_string());
7860        c1.descricao = Some("demo caixa".to_string());
7861        c1.edicao = Some("2024".to_string());
7862        c1.restart_window = Some("60s".to_string());
7863        assert_eq!(licenca_via_const_fn(&c1), c1.licenca());
7864        assert_eq!(repositorio_via_const_fn(&c1), c1.repositorio());
7865        assert_eq!(descricao_via_const_fn(&c1), c1.descricao());
7866        assert_eq!(edicao_via_const_fn(&c1), c1.edicao());
7867        assert_eq!(restart_window_via_const_fn(&c1), c1.restart_window());
7868        assert_eq!(c1.licenca(), Some("MIT"));
7869        assert_eq!(c1.repositorio(), Some("https://github.com/pleme-io/demo"));
7870        assert_eq!(c1.descricao(), Some("demo caixa"));
7871        assert_eq!(c1.edicao(), Some("2024"));
7872        assert_eq!(c1.restart_window(), Some("60s"));
7873        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7874        c2.licenca = None;
7875        c2.repositorio = None;
7876        c2.descricao = None;
7877        c2.edicao = None;
7878        c2.restart_window = None;
7879        assert_eq!(licenca_via_const_fn(&c2), None);
7880        assert_eq!(repositorio_via_const_fn(&c2), None);
7881        assert_eq!(descricao_via_const_fn(&c2), None);
7882        assert_eq!(edicao_via_const_fn(&c2), None);
7883        assert_eq!(restart_window_via_const_fn(&c2), None);
7884    }
7885
7886    #[test]
7887    fn caixa_outer_copy_return_accessor_pair_is_const_fn() {
7888        // Fail-before-pass-after pin on the two outer-[`Caixa`]
7889        // `Copy`-return accessors — [`Caixa::kind`] on the required
7890        // [`CaixaKind`] enum-discriminant axis and [`Caixa::estrategia`]
7891        // on the M2 supervisor-tree flat-spread `Option<RestartStrategy>`
7892        // axis. Both accessors project a `Copy`-carrier field
7893        // (`CaixaKind: Copy` at caixa-core/src/kind.rs:17,
7894        // `RestartStrategy: Copy` at caixa-core/src/supervisor.rs:33 →
7895        // `Option<RestartStrategy>: Copy`) by value through a bare
7896        // `self.<field>` field-access — no dispatch, no destructor, no
7897        // heap. Any future accidental downgrade to non-`const` fails
7898        // the corresponding `<name>_via_const_fn` wrapper at caixa-core
7899        // build time with E0015 (`cannot call non-const method`),
7900        // strictly stronger than a runtime `assert!` and strictly
7901        // stronger than a module-scope `const _: () = assert!(…)` pin
7902        // (which cannot be formed on a `&Caixa` fixture because the
7903        // type's `String` / `Vec` / `Option<Composite>` carriers rule
7904        // out `const`-context value construction; the `const fn`
7905        // wrapper is the load-bearing shape that side-steps the
7906        // destructor-in-const restriction on the value axis while still
7907        // pinning the `const`-fn posture on the callee — mirror of the
7908        // sibling [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
7909        // + [`caixa_option_string_scalar_accessor_family_is_const_fn`]
7910        // pins' discipline verbatim on the peer outer-`Caixa`
7911        // `String → &str` + `Option<String> → Option<&str>` axes at the
7912        // same struct).
7913        //
7914        // Peer of the sibling per-M2/M3-slot `Copy`-return accessor pin
7915        // family on the inner-altitude nested-spec typed-slot
7916        // discriminator axes: [`crate::supervisor::SupervisorSpec::estrategia`]
7917        // + [`crate::supervisor::ChildSpec::restart`] on the M2
7918        // supervisor-tree axis (pinned at 152c868), and
7919        // [`crate::aplicacao::Placement::estrategia`] +
7920        // [`crate::aplicacao::Entrada::port`] on the M3 mesh-slot axis
7921        // (pinned at bafa004) — the outer-`Caixa` altitude is the last
7922        // unlifted altitude for the `Copy`-return-accessor family.
7923        const fn kind_via_const_fn(c: &Caixa) -> CaixaKind {
7924            c.kind()
7925        }
7926        const fn estrategia_via_const_fn(c: &Caixa) -> Option<crate::supervisor::RestartStrategy> {
7927            c.estrategia()
7928        }
7929        // Sweep every arm of both discriminant partitions the accessors
7930        // fan on — every [`CaixaKind`] variant the six-arm required
7931        // discriminant carries (Biblioteca / Binario / Servico /
7932        // Supervisor / Aplicacao / Acao) and both arms of the
7933        // [`Option<RestartStrategy>`] flat-spread supervisor-tree slot
7934        // (`Some(<strategy>)` on an author-declared supervisor and
7935        // `None` on the author-omitted default arm every non-Supervisor
7936        // caixa carries by `#[serde(default)]`) — so the `const fn`
7937        // wrapper family pins the closed-set partition through the
7938        // same const dispatch as the runtime path.
7939        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7940        c1.kind = CaixaKind::Servico;
7941        c1.estrategia = Some(crate::supervisor::RestartStrategy::OneForAll);
7942        assert_eq!(kind_via_const_fn(&c1), c1.kind());
7943        assert_eq!(estrategia_via_const_fn(&c1), c1.estrategia());
7944        assert_eq!(c1.kind(), CaixaKind::Servico);
7945        assert_eq!(
7946            c1.estrategia(),
7947            Some(crate::supervisor::RestartStrategy::OneForAll)
7948        );
7949        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7950        c2.kind = CaixaKind::Aplicacao;
7951        c2.estrategia = None;
7952        assert_eq!(kind_via_const_fn(&c2), CaixaKind::Aplicacao);
7953        assert_eq!(estrategia_via_const_fn(&c2), None);
7954        // Anchor the remaining discriminant arms so any future
7955        // reordering of [`CaixaKind`]'s six-variant enum surfaces
7956        // through the wrapper dispatch, not just through the direct
7957        // method call.
7958        for kind in [
7959            CaixaKind::Biblioteca,
7960            CaixaKind::Binario,
7961            CaixaKind::Servico,
7962            CaixaKind::Supervisor,
7963            CaixaKind::Aplicacao,
7964            CaixaKind::Acao,
7965        ] {
7966            let mut c = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7967            c.kind = kind;
7968            assert_eq!(kind_via_const_fn(&c), kind);
7969        }
7970    }
7971
7972    #[test]
7973    fn caixa_outer_string_slice_return_accessor_family_is_const_fn() {
7974        // Fail-before-pass-after pin on the five outer-[`Caixa`]
7975        // `Vec<String> → &[String]` slice-return accessors on the
7976        // universal-axis surface — [`Caixa::autores`] / [`Caixa::etiquetas`]
7977        // / [`Caixa::bibliotecas`] / [`Caixa::exe`] / [`Caixa::servicos`].
7978        // Each body is a bare `self.<field>.as_slice()` dispatch through
7979        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
7980        // the workspace MSRV). Any future accidental downgrade to
7981        // non-`const` fails the corresponding `<name>_via_const_fn`
7982        // wrapper at caixa-core build time with E0015 (`cannot call
7983        // non-const method`) — mirror of the sibling
7984        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] pin's
7985        // discipline on the peer outer-`Caixa` `Copy`-return accessor
7986        // axis, and peer of the sibling composite-carrier slice-return
7987        // pin below on the peer outer-`Caixa` composite-slice axis.
7988        const fn autores_via_const_fn(c: &Caixa) -> &[String] {
7989            c.autores()
7990        }
7991        const fn etiquetas_via_const_fn(c: &Caixa) -> &[String] {
7992            c.etiquetas()
7993        }
7994        const fn bibliotecas_via_const_fn(c: &Caixa) -> &[String] {
7995            c.bibliotecas()
7996        }
7997        const fn exe_via_const_fn(c: &Caixa) -> &[String] {
7998            c.exe()
7999        }
8000        const fn servicos_via_const_fn(c: &Caixa) -> &[String] {
8001            c.servicos()
8002        }
8003        // Sweep the empty arm (`autores` / `etiquetas` / `exe` /
8004        // `servicos` — the template's `Vec::new()` default) and the
8005        // populated arm (mutated below) on every accessor so the
8006        // `const fn` wrapper family pins each axis's two-arm partition
8007        // through the same const dispatch as the runtime path.
8008        // [`Caixa::template`] seeds `lib/demo.lisp` into `:bibliotecas`,
8009        // so that arm's "empty" fixture is the populated arm the
8010        // mutation sweep covers.
8011        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8012        assert!(autores_via_const_fn(&c_empty).is_empty());
8013        assert!(etiquetas_via_const_fn(&c_empty).is_empty());
8014        assert!(exe_via_const_fn(&c_empty).is_empty());
8015        assert!(servicos_via_const_fn(&c_empty).is_empty());
8016        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8017        c_full.autores = vec!["ada".to_string(), "erlang".to_string()];
8018        c_full.etiquetas = vec!["compounding".to_string()];
8019        c_full.bibliotecas = vec!["lib/one.lisp".to_string(), "lib/two.lisp".to_string()];
8020        c_full.exe = vec!["exe/cli.lisp".to_string()];
8021        c_full.servicos = vec!["servicos/one.computeunit.yaml".to_string()];
8022        assert_eq!(autores_via_const_fn(&c_full), c_full.autores());
8023        assert_eq!(autores_via_const_fn(&c_full), &["ada", "erlang"]);
8024        assert_eq!(etiquetas_via_const_fn(&c_full), c_full.etiquetas());
8025        assert_eq!(etiquetas_via_const_fn(&c_full), &["compounding"]);
8026        assert_eq!(bibliotecas_via_const_fn(&c_full), c_full.bibliotecas());
8027        assert_eq!(
8028            bibliotecas_via_const_fn(&c_full),
8029            &["lib/one.lisp", "lib/two.lisp"]
8030        );
8031        assert_eq!(exe_via_const_fn(&c_full), c_full.exe());
8032        assert_eq!(exe_via_const_fn(&c_full), &["exe/cli.lisp"]);
8033        assert_eq!(servicos_via_const_fn(&c_full), c_full.servicos());
8034        assert_eq!(
8035            servicos_via_const_fn(&c_full),
8036            &["servicos/one.computeunit.yaml"]
8037        );
8038    }
8039
8040    #[test]
8041    fn caixa_outer_composite_slice_return_accessor_family_is_const_fn() {
8042        // Fail-before-pass-after pin on the six outer-[`Caixa`] composite-
8043        // carrier `Vec<T> → &[T]` slice-return accessors — [`Caixa::deps`]
8044        // / [`Caixa::deps_dev`] on the dep-graph axis,
8045        // [`Caixa::upgrade_from`] on the M2 appup axis, [`Caixa::children`]
8046        // on the M2 supervisor-tree axis, and [`Caixa::membros`] /
8047        // [`Caixa::contratos`] on the M3 mesh-slot axis. Each body is a
8048        // bare `self.<field>.as_slice()` dispatch through
8049        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
8050        // the workspace MSRV) — peer of the sibling `String`-payload
8051        // slice-return pin above on the peer outer-`Caixa` universal-
8052        // axis surface, and peer of the sibling inner-composite-
8053        // altitude reference-return pin family
8054        // [`crate::aplicacao::tests::m3_aplicacao_spec_reference_return_accessor_family_is_const_fn`]
8055        // + [`crate::supervisor::tests::supervisor_children_slice_return_accessor_is_const_fn`]
8056        // + [`crate::upgrade::tests::upgrade_from_entry_instructions_slice_return_accessor_is_const_fn`]
8057        // (all pinned at 0b23e0f).
8058        const fn deps_via_const_fn(c: &Caixa) -> &[Dep] {
8059            c.deps()
8060        }
8061        const fn deps_dev_via_const_fn(c: &Caixa) -> &[Dep] {
8062            c.deps_dev()
8063        }
8064        const fn upgrade_from_via_const_fn(c: &Caixa) -> &[UpgradeFromEntry] {
8065            c.upgrade_from()
8066        }
8067        const fn children_via_const_fn(c: &Caixa) -> &[crate::supervisor::ChildSpec] {
8068            c.children()
8069        }
8070        const fn membros_via_const_fn(c: &Caixa) -> &[crate::aplicacao::Membro] {
8071            c.membros()
8072        }
8073        const fn contratos_via_const_fn(c: &Caixa) -> &[crate::aplicacao::WitContract] {
8074            c.contratos()
8075        }
8076        // Empty-arm sweep on all six composite-carrier axes — every
8077        // `Caixa::template` starts with `Vec::new()` on each.
8078        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8079        assert!(deps_via_const_fn(&c_empty).is_empty());
8080        assert!(deps_dev_via_const_fn(&c_empty).is_empty());
8081        assert!(upgrade_from_via_const_fn(&c_empty).is_empty());
8082        assert!(children_via_const_fn(&c_empty).is_empty());
8083        assert!(membros_via_const_fn(&c_empty).is_empty());
8084        assert!(contratos_via_const_fn(&c_empty).is_empty());
8085        // Populate `:membros` / `:contratos` directly via struct literals
8086        // — the parser-side validation path fans on `:kind`-gated cross-
8087        // slot invariants irrelevant to the accessor dispatch under test.
8088        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8089        c_full.membros = vec![
8090            crate::aplicacao::Membro {
8091                caixa: "demo-a".to_string(),
8092                versao: "^0.1.0".to_string(),
8093            },
8094            crate::aplicacao::Membro {
8095                caixa: "demo-b".to_string(),
8096                versao: "^0.2.0".to_string(),
8097            },
8098        ];
8099        c_full.contratos = vec![crate::aplicacao::WitContract {
8100            de: "demo-a".to_string(),
8101            para: "demo-b".to_string(),
8102            wit: "wasi:http/proxy".to_string(),
8103            endpoint: Some("/edge".to_string()),
8104            subject: None,
8105            slot: None,
8106        }];
8107        assert_eq!(membros_via_const_fn(&c_full), c_full.membros());
8108        assert_eq!(contratos_via_const_fn(&c_full), c_full.contratos());
8109        assert_eq!(membros_via_const_fn(&c_full).len(), 2);
8110        assert_eq!(contratos_via_const_fn(&c_full).len(), 1);
8111        // Alias-borrow check on the four remaining composite-carrier
8112        // slice-return arms — the wrapper's return borrow must alias the
8113        // caller's borrow so any future accessor re-routing that skips
8114        // the storage field surfaces through the assertion.
8115        assert!(std::ptr::eq(deps_via_const_fn(&c_full), c_full.deps()));
8116        assert!(std::ptr::eq(
8117            deps_dev_via_const_fn(&c_full),
8118            c_full.deps_dev()
8119        ));
8120        assert!(std::ptr::eq(
8121            upgrade_from_via_const_fn(&c_full),
8122            c_full.upgrade_from()
8123        ));
8124        assert!(std::ptr::eq(
8125            children_via_const_fn(&c_full),
8126            c_full.children()
8127        ));
8128    }
8129
8130    #[test]
8131    fn caixa_outer_option_composite_reference_return_accessor_family_is_const_fn() {
8132        // Fail-before-pass-after pin on the six outer-[`Caixa`]
8133        // `Option<Composite> → Option<&Composite>` reference-return
8134        // accessors — [`Caixa::limits`] / [`Caixa::behavior`] on the M2
8135        // Servico-runtime typed-slot axis, [`Caixa::politicas`] /
8136        // [`Caixa::placement`] / [`Caixa::entrada`] on the M3 mesh-slot
8137        // axis, and [`Caixa::ci`] on the Acao-kind typed-CI-run axis.
8138        // Each body is a bare `self.<field>.as_ref()` dispatch through
8139        // [`Option::as_ref`] (const-stable since Rust 1.83, well within
8140        // the workspace MSRV of 1.89). Any future accidental downgrade
8141        // to non-`const` fails the corresponding `<name>_via_const_fn`
8142        // wrapper at caixa-core build time with E0015 (`cannot call
8143        // non-const method`), strictly stronger than a runtime `assert!`
8144        // and strictly stronger than a module-scope `const _: () =
8145        // assert!(…)` pin (which cannot be formed on a `&Caixa` fixture
8146        // because the type's `String` / `Vec` / `Option<Composite>`
8147        // carriers rule out `const`-context value construction; the
8148        // `const fn` wrapper is the load-bearing shape that side-steps
8149        // the destructor-in-const restriction on the value axis while
8150        // still pinning the `const`-fn posture on the callee — mirror
8151        // of the sibling
8152        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] +
8153        // [`caixa_outer_string_slice_return_accessor_family_is_const_fn`] +
8154        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
8155        // pins' discipline verbatim on the peer outer-`Caixa` axes at
8156        // the same struct).
8157        //
8158        // Closes the outer-`Caixa` `Option<&Composite>` composite-
8159        // reference-return sub-family — the last unlifted altitude on
8160        // the outer-`Caixa` accessor-family const-eval surface after
8161        // the sibling `Copy`-return / universal-axis-`&str` /
8162        // `Option<&str>` / `&[String]` / composite-`&[T]` pins already
8163        // closed the sibling arms at 866d1d5 / 29c5d7e / 0650f64 /
8164        // 231a968 (the last of these pins the `Vec<T> → &[T]`
8165        // composite-slice arm the six accessors here close as their
8166        // `Option<Composite> → Option<&Composite>` peer). Peer of the
8167        // sibling inner-altitude nested-spec composite-reference-return
8168        // pin family — [`crate::AplicacaoSpec::politicas`] /
8169        // [`crate::AplicacaoSpec::placement`] /
8170        // [`crate::AplicacaoSpec::entrada`] on the inner
8171        // [`crate::AplicacaoSpec`] altitude (already `pub const fn`
8172        // per 0b23e0f), and the outer-`Caixa` altitude here now carries
8173        // the same shape so both altitudes of the reference-return
8174        // discipline (per-`Caixa` outer-slot presence + per-
8175        // `AplicacaoSpec` inner-slot presence) route through one typed
8176        // const dispatch on the substrate primitive.
8177        const fn limits_via_const_fn(c: &Caixa) -> Option<&LimitsSpec> {
8178            c.limits()
8179        }
8180        const fn behavior_via_const_fn(c: &Caixa) -> Option<&crate::BehaviorSpec> {
8181            c.behavior()
8182        }
8183        const fn politicas_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::MeshPolicy> {
8184            c.politicas()
8185        }
8186        const fn placement_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Placement> {
8187            c.placement()
8188        }
8189        const fn entrada_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Entrada> {
8190            c.entrada()
8191        }
8192        const fn ci_via_const_fn(c: &Caixa) -> Option<&canteiro_types::CiRun> {
8193            c.ci()
8194        }
8195        // Both-arm sweep on every accessor: the `None` author-omitted
8196        // arm (template default — no M2/M3/CI slot declared) and the
8197        // `Some(<composite>)` authored arm (mutated below via struct-
8198        // literal seeds, side-stepping the parser-side `:kind`-gated
8199        // cross-slot invariants irrelevant to the accessor dispatch
8200        // under test). Both arms route through the `const fn` wrapper
8201        // family so the two-arm `Option` partition is pinned through
8202        // the same const dispatch as the runtime path.
8203        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8204        assert!(limits_via_const_fn(&c_empty).is_none());
8205        assert!(behavior_via_const_fn(&c_empty).is_none());
8206        assert!(politicas_via_const_fn(&c_empty).is_none());
8207        assert!(placement_via_const_fn(&c_empty).is_none());
8208        assert!(entrada_via_const_fn(&c_empty).is_none());
8209        assert!(ci_via_const_fn(&c_empty).is_none());
8210        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8211        c_full.limits = Some(LimitsSpec::default());
8212        c_full.behavior = Some(crate::BehaviorSpec::default());
8213        c_full.politicas = Some(crate::aplicacao::MeshPolicy::default());
8214        c_full.placement = Some(crate::aplicacao::Placement::default());
8215        c_full.entrada = Some(crate::aplicacao::Entrada {
8216            host: "demo.quero.cloud".to_string(),
8217            para: "demo".to_string(),
8218            paths: Vec::new(),
8219            port: crate::aplicacao::DEFAULT_SERVICO_PORT,
8220        });
8221        c_full.ci = Some(canteiro_types::CiRun {
8222            workspace: "pleme-io".into(),
8223            repo: "caixa".into(),
8224            nodes: vec![],
8225        });
8226        assert!(limits_via_const_fn(&c_full).is_some());
8227        assert!(behavior_via_const_fn(&c_full).is_some());
8228        assert!(politicas_via_const_fn(&c_full).is_some());
8229        assert!(placement_via_const_fn(&c_full).is_some());
8230        assert!(entrada_via_const_fn(&c_full).is_some());
8231        assert!(ci_via_const_fn(&c_full).is_some());
8232        // Alias-borrow check on every arm: the wrapper's inner-`Option`
8233        // reference must alias the caller's borrow so any future accessor
8234        // re-routing that skips the storage field surfaces through the
8235        // assertion.
8236        assert!(std::ptr::eq(
8237            limits_via_const_fn(&c_full).unwrap(),
8238            c_full.limits().unwrap()
8239        ));
8240        assert!(std::ptr::eq(
8241            behavior_via_const_fn(&c_full).unwrap(),
8242            c_full.behavior().unwrap()
8243        ));
8244        assert!(std::ptr::eq(
8245            politicas_via_const_fn(&c_full).unwrap(),
8246            c_full.politicas().unwrap()
8247        ));
8248        assert!(std::ptr::eq(
8249            placement_via_const_fn(&c_full).unwrap(),
8250            c_full.placement().unwrap()
8251        ));
8252        assert!(std::ptr::eq(
8253            entrada_via_const_fn(&c_full).unwrap(),
8254            c_full.entrada().unwrap()
8255        ));
8256        assert!(std::ptr::eq(
8257            ci_via_const_fn(&c_full).unwrap(),
8258            c_full.ci().unwrap()
8259        ));
8260    }
8261
8262    #[test]
8263    fn register_populates_registry() {
8264        Caixa::register().expect("first register call in this test process must succeed");
8265        let kws = tatara_lisp::domain::registered_keywords();
8266        assert!(kws.contains(&"defcaixa"));
8267    }
8268
8269    #[test]
8270    fn to_lisp_round_trips() {
8271        let src = Caixa::template("demo");
8272        let c1 = Caixa::from_lisp(&src).unwrap();
8273        let emitted = c1.to_lisp();
8274        let c2 = Caixa::from_lisp(&emitted).expect("emitted lisp parses back");
8275        assert_eq!(c1, c2);
8276    }
8277
8278    // ── DialetoEstrangeiro carries a single typed axis ────────────────────
8279    //
8280    // The compounding pin: the variant stores only the typed
8281    // [`crate::dialeto::CaixaDialeto`], and every user-facing byte-string
8282    // (canonical keyword, description, consumer) routes through the enum's
8283    // own accessors at Display time. Prior to that closure the variant
8284    // carried each accessor's return value as a stored `&'static str`
8285    // snapshot alongside `dialeto`; a caller could construct the variant
8286    // with a snapshot that drifted from what `dialeto`'s accessors would
8287    // return, and every downstream user-facing projection would silently
8288    // disagree with the classification. Storing only the axis makes the
8289    // drift structurally impossible.
8290
8291    #[test]
8292    fn dialeto_estrangeiro_variant_carries_only_the_typed_dialeto_axis() {
8293        // Single-field construction is the whole compounding shape — a
8294        // future re-introduction of a snapshot field (a `palavra_canonica:
8295        // &'static str`, a stored `descricao:`, a stored `consumidor:`)
8296        // would re-open the drift surface and this construction would fail
8297        // to compile with "missing field" until every snapshot was seeded
8298        // at the call site again. The compile-time guarantee is the
8299        // invariant; the assertion below only witnesses that the
8300        // construction is well-formed after the closure.
8301        let err = LeituraError::DialetoEstrangeiro {
8302            dialeto: crate::dialeto::CaixaDialeto::Molde,
8303        };
8304        assert!(matches!(
8305            err,
8306            LeituraError::DialetoEstrangeiro {
8307                dialeto: crate::dialeto::CaixaDialeto::Molde,
8308            }
8309        ));
8310    }
8311
8312    #[test]
8313    fn dialeto_estrangeiro_display_routes_through_typed_dialeto_accessors() {
8314        // For every foreign-dialect classification the variant surfaces —
8315        // [`crate::dialeto::CaixaDialeto::Molde`] and
8316        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two
8317        // variants [`Caixa::from_lisp`] raises this error for — the
8318        // rendered [`std::fmt::Display`] byte-string must interpolate each
8319        // typed accessor's return verbatim. A future re-introduction of a
8320        // stored `&'static str` snapshot alongside `dialeto` that Display
8321        // read instead of the accessor would fail this pin as soon as the
8322        // two disagreed; a future accessor rebrand (a per-dialect
8323        // consumer rename, a canonical-keyword shift once the substrate
8324        // migration named in [`crate::dialeto`] completes) reaches every
8325        // consumer through one typed dispatch and this pin verifies the
8326        // display path is one of them.
8327        for d in [
8328            crate::dialeto::CaixaDialeto::Molde,
8329            crate::dialeto::CaixaDialeto::MoldePosicional,
8330        ] {
8331            let rendered = LeituraError::DialetoEstrangeiro { dialeto: d }.to_string();
8332            assert!(
8333                rendered.contains(d.palavra_canonica()),
8334                "Display must interpolate `dialeto.palavra_canonica()` \
8335                 verbatim — a stored snapshot would silently drift from \
8336                 the typed accessor. dialect: {d}, rendered: {rendered:?}"
8337            );
8338            assert!(
8339                rendered.contains(d.descricao()),
8340                "Display must interpolate `dialeto.descricao()` verbatim. \
8341                 dialect: {d}, rendered: {rendered:?}"
8342            );
8343            assert!(
8344                rendered.contains(d.consumidor()),
8345                "Display must interpolate `dialeto.consumidor()` verbatim. \
8346                 dialect: {d}, rendered: {rendered:?}"
8347            );
8348        }
8349    }
8350
8351    #[test]
8352    fn from_lisp_rejects_molde_dialect_via_typed_variant() {
8353        // The end-to-end pin the compounding closure defends: a
8354        // Molde-dialect source lands as [`LeituraError::DialetoEstrangeiro`]
8355        // carrying [`crate::dialeto::CaixaDialeto::Molde`], and the
8356        // rendered Display byte-string names the Molde accessors'
8357        // returns verbatim. Any future path that constructed the variant
8358        // with a mismatched snapshot (a stored `palavra_canonica:
8359        // "defcaixa"` on a `Molde` classification) would land Display
8360        // pointing at `defcaixa` while the typed axis said `Molde` — the
8361        // exact drift the closure removes.
8362        let src = r#"
8363          (defcaixa
8364            :name "x"
8365            :kind :Biblioteca
8366            :ecosystem :rust-single-crate
8367            :package {:name "x" :version "0.1.0"})
8368        "#;
8369        let err = Caixa::from_lisp(src).expect_err("Molde dialect must not parse as Pacote");
8370        match err {
8371            LeituraError::DialetoEstrangeiro { dialeto } => {
8372                assert_eq!(dialeto, crate::dialeto::CaixaDialeto::Molde);
8373                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
8374                assert!(rendered.contains(dialeto.palavra_canonica()));
8375                assert!(rendered.contains(dialeto.consumidor()));
8376                assert!(rendered.contains(dialeto.descricao()));
8377            }
8378            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
8379        }
8380    }
8381
8382    #[test]
8383    fn from_lisp_rejects_molde_posicional_dialect_via_typed_variant() {
8384        // Coverage pin for the [`crate::dialeto::CaixaDialeto::MoldePosicional`]
8385        // arm of the [`Caixa::from_lisp`] foreign-dialect gate — the
8386        // positional-arity `defmolde` form written under a `(defcaixa …)`
8387        // head (`(defcaixa todoku-go :kind :Biblioteca :ecosystem :go
8388        // …)`). Pre-lift this arm rode the same `foreign =>` wildcard
8389        // the [`crate::dialeto::CaixaDialeto::Molde`] sibling arm rode,
8390        // so no test exercised the positional-arity path through
8391        // `Caixa::from_lisp` specifically; the sibling
8392        // [`from_lisp_rejects_molde_dialect_via_typed_variant`] only
8393        // covered [`crate::dialeto::CaixaDialeto::Molde`]. Post-lift the
8394        // two arms route through the lifted
8395        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
8396        // typed predicate — the same predicate the pre-lift `foreign =>`
8397        // wildcard resolved to today — and this pin makes the
8398        // positional-arity arm's byte-shape at the gate explicit rather
8399        // than implied by wildcard-absorption. A future regression that
8400        // silently reordered [`crate::dialeto::CaixaDialeto::is_molde_family`]'s
8401        // arm-set (dropped [`crate::dialeto::CaixaDialeto::MoldePosicional`]
8402        // from the two-arity closure) would fail this pin at caixa-core
8403        // test time rather than surfacing far from the change as a
8404        // `caixa.lisp` carrying a `(defcaixa todoku-go :ecosystem :go
8405        // …)` silently parsing past the derive.
8406        let src = r#"
8407          (defcaixa todoku-go
8408            :kind :Biblioteca
8409            :ecosystem :go
8410            :package {:name "todoku-go" :version "0.3.0"})
8411        "#;
8412        let err =
8413            Caixa::from_lisp(src).expect_err("MoldePosicional dialect must not parse as Pacote");
8414        match err {
8415            LeituraError::DialetoEstrangeiro { dialeto } => {
8416                assert_eq!(
8417                    dialeto,
8418                    crate::dialeto::CaixaDialeto::MoldePosicional,
8419                    "DialetoEstrangeiro must carry the MoldePosicional \
8420                     variant verbatim — the positional-arity `defmolde` \
8421                     form under a `(defcaixa …)` head is the \
8422                     `MoldePosicional` arm's canonical byte-shape"
8423                );
8424                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
8425                assert!(
8426                    rendered.contains(dialeto.palavra_canonica()),
8427                    "Display must interpolate `dialeto.palavra_canonica()` \
8428                     verbatim on the MoldePosicional arm; rendered: \
8429                     {rendered:?}"
8430                );
8431                assert!(
8432                    rendered.contains(dialeto.consumidor()),
8433                    "Display must interpolate `dialeto.consumidor()` \
8434                     verbatim on the MoldePosicional arm; rendered: \
8435                     {rendered:?}"
8436                );
8437                assert!(
8438                    rendered.contains(dialeto.descricao()),
8439                    "Display must interpolate `dialeto.descricao()` \
8440                     verbatim on the MoldePosicional arm; rendered: \
8441                     {rendered:?}"
8442                );
8443            }
8444            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
8445        }
8446    }
8447
8448    #[test]
8449    fn from_lisp_dialect_gate_dispatches_through_caixa_dialeto_is_molde_family_predicate() {
8450        // Load-bearing byte-parity pin: for every arm in
8451        // [`crate::dialeto::CaixaDialeto::ALL`], the
8452        // [`Caixa::from_lisp`] foreign-dialect gate's DialetoEstrangeiro
8453        // partition must agree with the lifted
8454        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
8455        // typed predicate — i.e. from_lisp raises
8456        // [`LeituraError::DialetoEstrangeiro`] carrying `d` iff
8457        // `d.is_molde_family()` returns `true`, and does NOT raise
8458        // [`LeituraError::DialetoEstrangeiro`] on any arm where the
8459        // predicate returns `false` (the arm's source falls through to
8460        // the derive — parses cleanly on
8461        // [`crate::dialeto::CaixaDialeto::Pacote`], surfaces a
8462        // [`LeituraError::Leitura`] on
8463        // [`crate::dialeto::CaixaDialeto::Desconhecido`]).
8464        //
8465        // Pre-lift the gate hand-rolled a three-arm match
8466        // (`Pacote => {}`, `Desconhecido => {}`, `foreign => Err(…)`)
8467        // whose `foreign =>` wildcard expressed no compile-time link
8468        // back to the substrate primitive's arm-family; a future fifth
8469        // dialect the [`crate::dialeto`] module doc's "third dialect"
8470        // hazard actualises would fall silently onto the wildcard
8471        // regardless of whether it belonged to the `defmolde` family or
8472        // to a distinct `defcaixa`-family. Post-lift the partition
8473        // resolves through
8474        // [`crate::dialeto::CaixaDialeto::is_molde_family`]'s single
8475        // typed dispatch, and this pin refuses any future regression
8476        // that silently split the from_lisp partition from the typed
8477        // predicate — the two paths now migrate as one on any future
8478        // arm addition.
8479        //
8480        // Sibling in shape to the peer
8481        // [`crate::dialeto::tests::caixa_dialeto_is_molde_family_agrees_with_palavra_canonica_defmolde_projection`]
8482        // (e9d2315) that pins the same byte-parity between
8483        // [`crate::dialeto::CaixaDialeto::is_molde_family`] and the
8484        // sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
8485        // `== "defmolde"` classifier — extends the discipline from the
8486        // two paths within the [`crate::dialeto`] primitive onto the
8487        // third external consumer of the `defmolde`-family partition
8488        // (the [`Caixa::from_lisp`] gate that raises
8489        // [`LeituraError::DialetoEstrangeiro`]).
8490        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
8491            (
8492                crate::dialeto::CaixaDialeto::Pacote,
8493                r#"
8494                  (defcaixa
8495                    :nome   "checkout"
8496                    :versao "0.1.0"
8497                    :kind   Biblioteca
8498                    :edicao "2026"
8499                    :descricao "canonical Pacote source"
8500                    :autores ()
8501                    :etiquetas ()
8502                    :deps ()
8503                    :deps-dev ()
8504                    :bibliotecas ("lib/checkout.lisp"))
8505                "#,
8506            ),
8507            (
8508                crate::dialeto::CaixaDialeto::Molde,
8509                r#"
8510                  (defcaixa
8511                    :name "base64"
8512                    :kind :Biblioteca
8513                    :ecosystem :rust-single-crate
8514                    :package {:name "base64" :version "0.22.1"}
8515                    :workflows [:auto-release])
8516                "#,
8517            ),
8518            (
8519                crate::dialeto::CaixaDialeto::MoldePosicional,
8520                r#"
8521                  (defcaixa todoku-go
8522                    :kind :Biblioteca
8523                    :ecosystem :go
8524                    :package {:name "todoku-go" :version "0.3.0"})
8525                "#,
8526            ),
8527            (
8528                crate::dialeto::CaixaDialeto::Desconhecido,
8529                r#"(defcaixa :licenca "MIT")"#,
8530            ),
8531        ];
8532
8533        // Coverage: every arm in [`crate::dialeto::CaixaDialeto::ALL`]
8534        // must appear in the fixture table so the pin's arm-set stays
8535        // synchronised with the enum's arm-set. Fails at test time if a
8536        // future fifth arm added to [`crate::dialeto::CaixaDialeto`]
8537        // (with a corresponding `is_molde_family` return) forgot to
8538        // extend this fixture table with a canonical source for the new
8539        // arm — the pin cannot cover an arm it has no source for.
8540        for &expected in crate::dialeto::CaixaDialeto::ALL {
8541            assert!(
8542                fixtures.iter().any(|(d, _)| *d == expected),
8543                "fixture table must carry a canonical source for every \
8544                 CaixaDialeto arm; missing: {expected:?}"
8545            );
8546        }
8547
8548        for &(expected_dialect, src) in fixtures {
8549            let classified = crate::dialeto::classify(src.trim()).unwrap_or_else(|err| {
8550                panic!(
8551                    "fixture source for {expected_dialect:?} must classify \
8552                     cleanly, got err: {err:?}"
8553                )
8554            });
8555            assert_eq!(
8556                classified, expected_dialect,
8557                "fixture source for {expected_dialect:?} must classify as \
8558                 {expected_dialect:?} (drift here defeats the byte-parity \
8559                 pin below — a source labelled for one arm but classifying \
8560                 as another would silently satisfy or violate the pin for \
8561                 the wrong reason)"
8562            );
8563
8564            let outcome = Caixa::from_lisp(src);
8565            match (expected_dialect.is_molde_family(), &outcome) {
8566                (true, Err(LeituraError::DialetoEstrangeiro { dialeto })) => {
8567                    assert_eq!(
8568                        *dialeto, expected_dialect,
8569                        "DialetoEstrangeiro must carry the same typed arm \
8570                         the classifier returned — a drift here would let \
8571                         from_lisp raise the error while pointing at the \
8572                         wrong dialect (e.g. rejecting a \
8573                         MoldePosicional source as Molde). arm: \
8574                         {expected_dialect:?}"
8575                    );
8576                }
8577                (true, other) => panic!(
8578                    "arm {expected_dialect:?} has is_molde_family() = true \
8579                     so from_lisp must raise DialetoEstrangeiro carrying \
8580                     {expected_dialect:?}; got: {other:?}"
8581                ),
8582                (false, Err(LeituraError::DialetoEstrangeiro { dialeto })) => panic!(
8583                    "arm {expected_dialect:?} has is_molde_family() = false \
8584                     so from_lisp must NOT raise DialetoEstrangeiro; got \
8585                     one carrying: {dialeto:?}. This means the typed \
8586                     predicate and the from_lisp partition disagree on \
8587                     this arm — exactly the drift this pin refuses."
8588                ),
8589                (false, _) => {
8590                    // A non-molde arm's source falls through to the
8591                    // derive: Pacote sources parse to Ok(_); Desconhecido
8592                    // sources surface as LeituraError::Leitura from the
8593                    // derive's own unknown-keyword rejection. Either
8594                    // shape is acceptable here — the pin's promise is
8595                    // narrower: "no DialetoEstrangeiro on
8596                    // is_molde_family() == false".
8597                }
8598            }
8599        }
8600    }
8601
8602    // ── M2 typed-substrate slot tests (limits, behavior, upgrade-from, supervisor) ──
8603
8604    #[test]
8605    fn limits_round_trip_via_json() {
8606        use crate::LimitsSpec;
8607        use std::time::Duration;
8608        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8609        c.limits = Some(LimitsSpec {
8610            memory: Some(64 * 1024 * 1024),
8611            fuel: Some(1_000_000),
8612            wall_clock: Some(Duration::from_secs(30)),
8613            cpu: Some(500),
8614        });
8615        let json = serde_json::to_string(&c).unwrap();
8616        assert!(json.contains("\"limits\""));
8617        assert!(json.contains("\"64MiB\""));
8618        assert!(json.contains("\"30s\""));
8619        assert!(json.contains("\"500m\""));
8620        let back: Caixa = serde_json::from_str(&json).unwrap();
8621        assert_eq!(c.limits, back.limits);
8622    }
8623
8624    #[test]
8625    fn behavior_round_trip_via_json() {
8626        use crate::BehaviorSpec;
8627        use std::path::PathBuf;
8628        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8629        c.behavior = Some(BehaviorSpec {
8630            on_init: Some(PathBuf::from("lib/init.lisp")),
8631            on_call: Some(PathBuf::from("lib/handlers.lisp")),
8632            ..Default::default()
8633        });
8634        let json = serde_json::to_string(&c).unwrap();
8635        let back: Caixa = serde_json::from_str(&json).unwrap();
8636        assert_eq!(c.behavior, back.behavior);
8637    }
8638
8639    #[test]
8640    fn upgrade_from_round_trip_via_json() {
8641        use crate::{UpgradeFromEntry, UpgradeInstruction};
8642        use std::path::PathBuf;
8643        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8644        c.upgrade_from = vec![UpgradeFromEntry {
8645            from: "0.1.0".into(),
8646            instructions: vec![
8647                UpgradeInstruction::LoadModule {
8648                    module: "demo".into(),
8649                },
8650                UpgradeInstruction::StateChange {
8651                    script: PathBuf::from("lib/migrations/v01-to-v02.lisp"),
8652                },
8653                UpgradeInstruction::SoftPurge {
8654                    module: "demo-old".into(),
8655                },
8656            ],
8657        }];
8658        let json = serde_json::to_string(&c).unwrap();
8659        let back: Caixa = serde_json::from_str(&json).unwrap();
8660        assert_eq!(c.upgrade_from, back.upgrade_from);
8661    }
8662
8663    #[test]
8664    fn supervisor_view_returns_typed_shape() {
8665        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
8666        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
8667        c.kind = CaixaKind::Supervisor;
8668        c.bibliotecas.clear();
8669        c.estrategia = Some(RestartStrategy::OneForOne);
8670        c.max_restarts = Some(5);
8671        c.restart_window = Some("60s".into());
8672        c.children = vec![ChildSpec {
8673            caixa: "worker".into(),
8674            versao: "^0.1".into(),
8675            restart: RestartPolicy::Permanent,
8676        }];
8677        let view = c.supervisor_view().expect("Supervisor kind has a view");
8678        assert_eq!(view.estrategia, RestartStrategy::OneForOne);
8679        assert_eq!(view.max_restarts, 5);
8680        assert_eq!(
8681            view.restart_window,
8682            Some(std::time::Duration::from_secs(60))
8683        );
8684        assert_eq!(view.children.len(), 1);
8685        view.validate().unwrap();
8686    }
8687
8688    #[test]
8689    fn supervisor_view_none_for_non_supervisor_kinds() {
8690        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8691        assert!(c.supervisor_view().is_none());
8692    }
8693
8694    #[test]
8695    fn declared_mesh_slots_empty_for_bare_caixa() {
8696        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8697        assert!(c.declared_mesh_slots().is_empty());
8698    }
8699
8700    #[test]
8701    fn declared_mesh_slots_reports_only_set_slots_in_canonical_order() {
8702        use crate::{Entrada, Membro};
8703        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8704        // Set a non-adjacent pair (:membros + :entrada) to pin that the
8705        // canonical declaration order is preserved regardless of which
8706        // subset is populated.
8707        c.membros = vec![Membro {
8708            caixa: "a".into(),
8709            versao: "^0.1".into(),
8710        }];
8711        c.entrada = Some(Entrada {
8712            host: "x.example.com".into(),
8713            para: "a".into(),
8714            paths: vec![],
8715            port: 8080,
8716        });
8717        assert_eq!(
8718            c.declared_mesh_slots(),
8719            vec![
8720                crate::render::M3_AUTHOR_KEY_MEMBROS,
8721                crate::render::M3_AUTHOR_KEY_ENTRADA,
8722            ]
8723        );
8724    }
8725
8726    #[test]
8727    fn m3_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8728        // Scalar-value pin: the five author-facing kebab-case labels the
8729        // `(defcaixa … :<slot> (…))` surface admits on the M3 top-level
8730        // mesh slot axis, one arm per typed slot. Mirrors the peer
8731        // scalar-value pin the sibling
8732        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
8733        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
8734        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] M2 top-level slot consts
8735        // carry (f49c8b0), so both altitudes of the typed-slot algebra
8736        // (per-Servico M2 + per-Aplicacao M3) share the same
8737        // "one canonical byte-string per arm" discipline. A future
8738        // rebrand (`:membros` → `:members`, `:contratos` → `:contracts`,
8739        // `:politicas` → `:policies`, `:placement` → `:distribution`,
8740        // `:entrada` → `:ingress`) lands as an edit to exactly one const,
8741        // and every consumer that reaches for the label picks it up at
8742        // build time rather than at runtime as a downstream mismatch.
8743        assert_eq!(crate::render::M3_AUTHOR_KEY_MEMBROS, ":membros");
8744        assert_eq!(crate::render::M3_AUTHOR_KEY_CONTRATOS, ":contratos");
8745        assert_eq!(crate::render::M3_AUTHOR_KEY_POLITICAS, ":politicas");
8746        assert_eq!(crate::render::M3_AUTHOR_KEY_PLACEMENT, ":placement");
8747        assert_eq!(crate::render::M3_AUTHOR_KEY_ENTRADA, ":entrada");
8748    }
8749
8750    #[test]
8751    fn declared_mesh_slots_route_through_lifted_m3_author_key_consts() {
8752        // Production-through-const pin: the five per-arm labels the
8753        // [`Caixa::declared_mesh_slots`] tagger pushes onto its return
8754        // `Vec` route through the lifted
8755        // [`crate::M3_AUTHOR_KEY_MEMBROS`] /
8756        // [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
8757        // [`crate::M3_AUTHOR_KEY_POLITICAS`] /
8758        // [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
8759        // [`crate::M3_AUTHOR_KEY_ENTRADA`] consts, in canonical
8760        // declaration order. A future re-order or drift at the tagger
8761        // (a rename that reaches the tagger but not the const, or vice
8762        // versa) surfaces here at build time rather than at runtime as
8763        // a [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
8764        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8765        // commit. Mirror of the peer
8766        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
8767        // pin (f49c8b0) on the sibling per-Servico M2 top-level slot
8768        // axis.
8769        use crate::{Entrada, Membro, MeshPolicy, Placement, PlacementStrategy, WitContract};
8770        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8771        c.membros = vec![Membro {
8772            caixa: "a".into(),
8773            versao: "^0.1".into(),
8774        }];
8775        c.contratos = vec![WitContract {
8776            de: "a".into(),
8777            para: "a".into(),
8778            wit: "wasi:http/proxy".into(),
8779            endpoint: Some("/x".into()),
8780            subject: None,
8781            slot: None,
8782        }];
8783        c.politicas = Some(MeshPolicy::default());
8784        c.placement = Some(Placement {
8785            estrategia: PlacementStrategy::Replicated,
8786            clusters: vec!["rio".into()],
8787            affinity: None,
8788            shard_key: None,
8789        });
8790        c.entrada = Some(Entrada {
8791            host: "x.example.com".into(),
8792            para: "a".into(),
8793            paths: vec![],
8794            port: 8080,
8795        });
8796        assert_eq!(
8797            c.declared_mesh_slots(),
8798            vec![
8799                crate::render::M3_AUTHOR_KEY_MEMBROS,
8800                crate::render::M3_AUTHOR_KEY_CONTRATOS,
8801                crate::render::M3_AUTHOR_KEY_POLITICAS,
8802                crate::render::M3_AUTHOR_KEY_PLACEMENT,
8803                crate::render::M3_AUTHOR_KEY_ENTRADA,
8804            ]
8805        );
8806    }
8807
8808    #[test]
8809    fn declared_supervisor_slots_empty_for_bare_caixa() {
8810        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8811        assert!(c.declared_supervisor_slots().is_empty());
8812    }
8813
8814    #[test]
8815    fn declared_supervisor_slots_reports_only_set_slots_in_canonical_order() {
8816        use crate::RestartStrategy;
8817        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8818        // Set a non-adjacent pair (:estrategia + :restart-window) to pin
8819        // that the canonical declaration order is preserved regardless
8820        // of which subset is populated.
8821        c.estrategia = Some(RestartStrategy::OneForOne);
8822        c.restart_window = Some("60s".into());
8823        assert_eq!(
8824            c.declared_supervisor_slots(),
8825            vec![
8826                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8827                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8828            ]
8829        );
8830    }
8831
8832    #[test]
8833    fn supervisor_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8834        // Scalar-value pin: the four author-facing kebab-case labels the
8835        // `(defcaixa … :<slot> (…))` surface admits on the Supervisor
8836        // supervision-tree slot axis, one arm per typed slot. Mirrors the
8837        // peer scalar-value pins the sibling
8838        // [`crate::render::M2_AUTHOR_KEY_LIMITS`] /
8839        // [`crate::render::M2_AUTHOR_KEY_BEHAVIOR`] /
8840        // [`crate::render::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot
8841        // consts and [`crate::render::M3_AUTHOR_KEY_MEMBROS`] etc.
8842        // top-level M3 slot consts carry, so all three kind-scoped
8843        // typed-slot-family author-facing-label axes route through one
8844        // canonical per-arm declaration. A future rebrand
8845        // (`:estrategia` → `:strategy` for English uniformity,
8846        // `:max-restarts` → `:max-intensity` matching Erlang/OTP's
8847        // `MaxIntensity` name, `:restart-window` → `:period` matching
8848        // OTP's `Period` name, `:children` → `:workers` matching Elixir
8849        // idiom) lands as an edit to exactly one const, and every
8850        // consumer that reaches for the label picks it up at build time
8851        // rather than at runtime as a downstream mismatch.
8852        assert_eq!(
8853            crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8854            ":estrategia"
8855        );
8856        assert_eq!(
8857            crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
8858            ":max-restarts"
8859        );
8860        assert_eq!(
8861            crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8862            ":restart-window"
8863        );
8864        assert_eq!(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN, ":children");
8865    }
8866
8867    #[test]
8868    fn declared_supervisor_slots_route_through_lifted_supervisor_author_key_consts() {
8869        // Production-through-const pin: the four per-arm labels the
8870        // [`Caixa::declared_supervisor_slots`] tagger pushes onto its
8871        // return `Vec` route through the lifted
8872        // [`crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] /
8873        // [`crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`] /
8874        // [`crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW`] /
8875        // [`crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN`] consts, in
8876        // canonical declaration order. A future re-order or drift at the
8877        // tagger (a rename that reaches the tagger but not the const, or
8878        // vice versa) surfaces here at build time rather than at runtime
8879        // as a [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
8880        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8881        // commit. Mirror of the peer
8882        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
8883        // (f49c8b0) and
8884        // [`declared_mesh_slots_route_through_lifted_m3_author_key_consts`]
8885        // (882f498) pins on the sibling M2 / M3 top-level slot axes.
8886        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
8887        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8888        c.estrategia = Some(RestartStrategy::OneForOne);
8889        c.max_restarts = Some(5);
8890        c.restart_window = Some("60s".into());
8891        c.children = vec![ChildSpec {
8892            caixa: "worker".into(),
8893            versao: "^0.1".into(),
8894            restart: RestartPolicy::Permanent,
8895        }];
8896        assert_eq!(
8897            c.declared_supervisor_slots(),
8898            vec![
8899                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8900                crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
8901                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8902                crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN,
8903            ]
8904        );
8905    }
8906
8907    #[test]
8908    fn declared_servico_slots_empty_for_bare_caixa() {
8909        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8910        assert!(c.declared_servico_slots().is_empty());
8911    }
8912
8913    #[test]
8914    fn declared_servico_slots_reports_only_set_slots_in_canonical_order() {
8915        use crate::{UpgradeFromEntry, UpgradeInstruction};
8916        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8917        // Set a non-adjacent pair (:limits + :upgrade-from) to pin that
8918        // the canonical declaration order is preserved regardless of
8919        // which subset is populated.
8920        c.limits = Some(crate::LimitsSpec {
8921            fuel: Some(1_000_000),
8922            ..Default::default()
8923        });
8924        c.upgrade_from = vec![UpgradeFromEntry {
8925            from: "0.1.0".into(),
8926            instructions: vec![UpgradeInstruction::Restart],
8927        }];
8928        assert_eq!(
8929            c.declared_servico_slots(),
8930            vec![
8931                crate::render::M2_AUTHOR_KEY_LIMITS,
8932                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
8933            ]
8934        );
8935    }
8936
8937    #[test]
8938    fn m2_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8939        // Scalar-value pin: the three author-facing kebab-case labels
8940        // the `(defcaixa … :<slot> (…))` surface admits on the M2
8941        // top-level slot axis, one arm per typed slot. Mirrors the peer
8942        // scalar-value pin the sibling renderer-side
8943        // [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
8944        // [`crate::M2_KEY_UPGRADE_FROM`] camelCase overlay-container
8945        // consts carry, so both halves of the M2 top-level slot dual
8946        // axis (author-facing kebab-case label + renderer-side
8947        // camelCase overlay-container wire key) route through one
8948        // canonical per-arm declaration. A future rebrand
8949        // (`:limits` → `:sandbox` matching Lunatic per-process
8950        // terminology INSPIRATIONS §III.1, `:behavior` → `:gen-server`
8951        // matching Erlang's verbatim name, `:upgrade-from` → `:appup`
8952        // matching Erlang's verbatim appup name) lands as an edit to
8953        // exactly one const, and every consumer that reaches for the
8954        // label picks it up at build time rather than at runtime as a
8955        // downstream mismatch.
8956        assert_eq!(crate::render::M2_AUTHOR_KEY_LIMITS, ":limits");
8957        assert_eq!(crate::render::M2_AUTHOR_KEY_BEHAVIOR, ":behavior");
8958        assert_eq!(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM, ":upgrade-from");
8959    }
8960
8961    #[test]
8962    fn declared_servico_slots_route_through_lifted_m2_author_key_consts() {
8963        // Production-through-const pin: the three per-arm labels the
8964        // [`Caixa::declared_servico_slots`] tagger pushes onto its
8965        // return `Vec` route through the lifted
8966        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
8967        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
8968        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts, in canonical
8969        // declaration order. A future re-order or drift at the tagger
8970        // (a rename that reaches the tagger but not the const, or vice
8971        // versa) surfaces here at build time rather than at runtime as
8972        // a [`crate::LayoutError::ServicoSlotsOnNonServico`]
8973        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8974        // commit. Mirror of the peer
8975        // [`crate::behavior::BehaviorSpec::declared_slots`] production
8976        // tagger pin (889dc18) on the sibling per-callback axis.
8977        use crate::{BehaviorSpec, UpgradeFromEntry, UpgradeInstruction};
8978        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8979        c.limits = Some(crate::LimitsSpec {
8980            fuel: Some(1_000_000),
8981            ..Default::default()
8982        });
8983        c.behavior = Some(BehaviorSpec {
8984            on_init: Some(PathBuf::from("lib/init.lisp")),
8985            ..Default::default()
8986        });
8987        c.upgrade_from = vec![UpgradeFromEntry {
8988            from: "0.1.0".into(),
8989            instructions: vec![UpgradeInstruction::Restart],
8990        }];
8991        assert_eq!(
8992            c.declared_servico_slots(),
8993            vec![
8994                crate::render::M2_AUTHOR_KEY_LIMITS,
8995                crate::render::M2_AUTHOR_KEY_BEHAVIOR,
8996                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
8997            ]
8998        );
8999    }
9000
9001    #[test]
9002    fn existing_manifests_unaffected_by_new_optional_slots() {
9003        // Regression test: a caixa.lisp authored before M2 typed slots
9004        // should still parse + serialize cleanly. The bare `defcaixa`
9005        // emitted by `Caixa::template` has none of the new fields.
9006        let src = Caixa::template("legacy");
9007        let c = Caixa::from_lisp(&src).unwrap();
9008        assert!(c.limits.is_none());
9009        assert!(c.behavior.is_none());
9010        assert!(c.upgrade_from.is_empty());
9011        assert!(c.estrategia.is_none());
9012        assert!(c.children.is_empty());
9013
9014        // And to_lisp emits a manifest with the new slots in the
9015        // empty/default state — round-trippable.
9016        let emitted = c.to_lisp();
9017        let back = Caixa::from_lisp(&emitted).unwrap();
9018        assert_eq!(c, back);
9019    }
9020
9021    #[test]
9022    fn validate_deps_accepts_canonical_caixa() {
9023        // Positive control: the bare template — zero deps, zero
9024        // deps_dev — passes the gate trivially. A future axis added to
9025        // `Dep::validate` mustn't regress an empty-deps caixa to a
9026        // build error.
9027        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9028        c.validate_deps().unwrap();
9029    }
9030
9031    #[test]
9032    fn validate_deps_rejects_invalid_versao_in_deps() {
9033        // Fail-before-pass-after pin: a malformed `:deps :versao`
9034        // surfaces at validate_deps() time, not at lacre-resolve time.
9035        // Mirrors `rejects_invalid_membro_versao_requirement` and
9036        // `validate_rejects_invalid_child_versao_requirement` on the
9037        // other two `:versao` axes.
9038        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9039        c.deps = vec![Dep::simple("caixa-teia", "^bad-version")];
9040        let err = c.validate_deps().unwrap_err();
9041        assert!(
9042            matches!(
9043                err,
9044                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9045                    if nome == "caixa-teia" && versao == "^bad-version"
9046            ),
9047            "got {err:?}"
9048        );
9049    }
9050
9051    #[test]
9052    fn validate_deps_rejects_invalid_versao_in_deps_dev() {
9053        // Parity pin: `:deps-dev` must run through the same per-entry
9054        // validator as `:deps` — a typo in either axis surfaces the
9055        // same diagnostic. Without this leg, `:deps-dev` would be a
9056        // second-class citizen of the typed surface and an author
9057        // could land a build that passes validate_deps but fails at
9058        // `feira lock`-time when the dev-dep is resolved for a test
9059        // build.
9060        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9061        c.deps_dev = vec![Dep::simple("tatara-check", "^^0.1")];
9062        let err = c.validate_deps().unwrap_err();
9063        assert!(
9064            matches!(
9065                err,
9066                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9067                    if nome == "tatara-check" && versao == "^^0.1"
9068            ),
9069            "got {err:?}"
9070        );
9071    }
9072
9073    #[test]
9074    fn validate_deps_runs_deps_before_deps_dev() {
9075        // Order pin: when both lists carry typos, the `:deps`
9076        // diagnostic surfaces first. The author's mental model is
9077        // "runtime deps are load-bearing; dev deps are scaffolding";
9078        // surfacing the runtime axis first matches that hierarchy.
9079        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9080        c.deps = vec![Dep::simple("runtime-dep", "^bad-runtime")];
9081        c.deps_dev = vec![Dep::simple("dev-dep", "^bad-dev")];
9082        let err = c.validate_deps().unwrap_err();
9083        assert!(
9084            matches!(
9085                err,
9086                crate::dep::DepError::VersaoInvalid { ref nome, .. }
9087                    if nome == "runtime-dep"
9088            ),
9089            "expected `:deps` typo to surface first, got {err:?}"
9090        );
9091    }
9092
9093    #[test]
9094    fn validate_deps_accepts_canonical_versao_forms_in_both_lists() {
9095        // Positive control sweep across both lists. Pin every
9096        // canonical Cargo-shaped form so a future tightening of the
9097        // accepted set surfaces here as a test failure (parity with
9098        // `accepts_canonical_membro_versao_forms` and
9099        // `validate_accepts_canonical_child_versao_forms`).
9100        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9101        c.deps = vec![
9102            Dep::simple("caret", "^0.1"),
9103            Dep::simple("tilde", "~0.1.2"),
9104            Dep::simple("exact", "0.1.0"),
9105            Dep::simple("wildcard", "*"),
9106            Dep::simple("multi-range", ">=0.1, <2"),
9107        ];
9108        c.deps_dev = vec![
9109            Dep::simple("dev-caret", "^0.1"),
9110            Dep::simple("dev-wildcard", "*"),
9111        ];
9112        c.validate_deps().unwrap();
9113    }
9114
9115    #[test]
9116    fn validate_deps_diagnostic_carries_offending_dep() {
9117        // Diagnostic-shape pin: the error names the offending entry's
9118        // `:nome` + `:versao` verbatim and carries a non-empty
9119        // `reason` from `semver::VersionReq::parse`, so a `feira lint`
9120        // run can render the diagnostic without re-parsing.
9121        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9122        c.deps = vec![Dep::simple("caixa-teia", "not-a-req")];
9123        let err = c.validate_deps().unwrap_err();
9124        let crate::dep::DepError::VersaoInvalid {
9125            nome,
9126            versao,
9127            reason,
9128        } = err
9129        else {
9130            panic!("expected VersaoInvalid, got other variant");
9131        };
9132        assert_eq!(nome, "caixa-teia");
9133        assert_eq!(versao, "not-a-req");
9134        assert!(
9135            !reason.is_empty(),
9136            "VersaoInvalid `reason` must carry the parser's wording verbatim"
9137        );
9138    }
9139
9140    #[test]
9141    fn validate_deps_rejects_ambiguous_fonte_in_deps_dev() {
9142        // Cross-axis pin: `validate_deps` walks both :deps and
9143        // :deps-dev through `Dep::validate`, and the new fonte gate
9144        // (`:tag` + `:branch` both set — the canonical "pin drift"
9145        // footgun) must surface from the :deps-dev arm with the
9146        // offending entry's :nome named. Pin the :deps-dev arm
9147        // explicitly so a future shortcut that only walks :deps
9148        // surfaces here as a regression.
9149        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9150        c.deps_dev = vec![Dep {
9151            nome: "dev-only".into(),
9152            versao: "^0.1".into(),
9153            fonte: Some(crate::DepSource::Git {
9154                repo: "github:p/x".into(),
9155                tag: Some("v1".into()),
9156                rev: None,
9157                branch: Some("main".into()),
9158            }),
9159            opcional: false,
9160            caracteristicas: vec![],
9161        }];
9162        let err = c.validate_deps().unwrap_err();
9163        let crate::dep::DepError::FontePinAmbiguous { nome, pins } = err else {
9164            panic!("expected FontePinAmbiguous from :deps-dev walk");
9165        };
9166        assert_eq!(nome, "dev-only");
9167        assert!(pins.contains(":tag") && pins.contains(":branch"));
9168    }
9169
9170    #[test]
9171    fn validate_deps_rejects_empty_repo_in_deps() {
9172        // Parity pin on the :deps arm: an empty :repo on the runtime
9173        // deps list surfaces the same FonteRepoEmpty diagnostic the
9174        // dep.rs per-entry tests pin, naming the offending entry.
9175        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9176        c.deps = vec![Dep {
9177            nome: "runtime".into(),
9178            versao: "^0.1".into(),
9179            fonte: Some(crate::DepSource::Git {
9180                repo: String::new(),
9181                tag: Some("v1".into()),
9182                rev: None,
9183                branch: None,
9184            }),
9185            opcional: false,
9186            caracteristicas: vec![],
9187        }];
9188        let err = c.validate_deps().unwrap_err();
9189        assert!(
9190            matches!(
9191                err,
9192                crate::dep::DepError::FonteRepoEmpty { ref nome }
9193                    if nome == "runtime"
9194            ),
9195            "got {err:?}"
9196        );
9197    }
9198
9199    // ── validate_deps: within-list :nome set-not-multiset gate ─────────
9200
9201    #[test]
9202    fn validate_deps_rejects_duplicate_nome_in_deps() {
9203        // Fail-before-pass-after pin: two `:deps` entries naming the same
9204        // caixa carry two `:versao` / `:fonte` / feature triples that the
9205        // caixa-resolver's lacre pipeline collapses (the second silently
9206        // overwrites the first at `concrete_versao`-resolve time). The
9207        // gate surfaces the duplicate at validate-time, naming the
9208        // offending caixa + the list, before the resolver-side silent
9209        // drop. Mirrors the peer typed-graph duplicate gates
9210        // (`DuplicateChildCaixa`, `MembroDuplicate`, `DuplicateFrom`, …).
9211        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9212        c.deps = vec![
9213            Dep::simple("caixa-teia", "^0.1"),
9214            Dep::simple("caixa-teia", "^0.2"),
9215        ];
9216        let err = c.validate_deps().unwrap_err();
9217        assert!(
9218            matches!(
9219                err,
9220                crate::dep::DepError::DuplicateNome { ref nome, list }
9221                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9222            ),
9223            "got {err:?}"
9224        );
9225    }
9226
9227    #[test]
9228    fn validate_deps_rejects_duplicate_nome_in_deps_dev() {
9229        // Parity pin: `:deps-dev` runs through the same per-list
9230        // duplicate check as `:deps` — neither axis is a second-class
9231        // citizen of the set-not-multiset discipline.
9232        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9233        c.deps_dev = vec![
9234            Dep::simple("tatara-check", "*"),
9235            Dep::simple("tatara-check", "^0.1"),
9236        ];
9237        let err = c.validate_deps().unwrap_err();
9238        assert!(
9239            matches!(
9240                err,
9241                crate::dep::DepError::DuplicateNome { ref nome, list }
9242                    if nome == "tatara-check" && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
9243            ),
9244            "got {err:?}"
9245        );
9246    }
9247
9248    #[test]
9249    fn validate_deps_accepts_cross_list_same_nome() {
9250        // The Cargo `[dependencies]` + `[dev-dependencies]` override
9251        // convention is preserved: a name appearing in *both* lists is
9252        // valid (the dev-pin overrides at test/dev time). Only
9253        // within-list duplicates are structurally incoherent — pin the
9254        // permissive cross-list semantics so a future shortcut that
9255        // collapses the two seen-sets into one surfaces here as a test
9256        // failure.
9257        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9258        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
9259        c.deps_dev = vec![Dep::simple("caixa-teia", "^0.2")];
9260        c.validate_deps().unwrap();
9261    }
9262
9263    #[test]
9264    fn validate_deps_accepts_distinct_nome_in_both_lists() {
9265        // Positive control: distinct names within each list pass — the
9266        // gate's identity element on the canonical authoring shape.
9267        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9268        c.deps = vec![
9269            Dep::simple("caixa-teia", "^0.1"),
9270            Dep::simple("pleme-mesh", "*"),
9271        ];
9272        c.deps_dev = vec![
9273            Dep::simple("tatara-check", "*"),
9274            Dep::simple("dev-shim", "^0.1"),
9275        ];
9276        c.validate_deps().unwrap();
9277    }
9278
9279    #[test]
9280    fn validate_deps_per_entry_validate_fires_before_duplicate_in_deps() {
9281        // Diagnostic-precedence pin: a malformed `:versao` on the
9282        // duplicating entry surfaces its narrower `VersaoInvalid`
9283        // diagnostic first, before the cross-entry duplicate gate fires
9284        // — the canonical "per-entry shape before cross-entry uniqueness"
9285        // precedence every peer set-not-multiset gate establishes
9286        // (`*_invalid_fires_before_duplicate_check` pins on
9287        // `SupervisorSpec::validate`, `AplicacaoSpec::validate_membros`,
9288        // `validate_upgrade_from`).
9289        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9290        c.deps = vec![
9291            Dep::simple("caixa-teia", "^0.1"),
9292            Dep::simple("caixa-teia", "^bad-version"),
9293        ];
9294        let err = c.validate_deps().unwrap_err();
9295        assert!(
9296            matches!(
9297                err,
9298                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9299                    if nome == "caixa-teia" && versao == "^bad-version"
9300            ),
9301            "expected VersaoInvalid to surface before DuplicateNome, got {err:?}"
9302        );
9303    }
9304
9305    #[test]
9306    fn validate_deps_duplicate_diagnostic_names_first_collision() {
9307        // First-collision determinism pin: with three entries naming the
9308        // same caixa, the first colliding pair surfaces — not the last.
9309        // Mirrors the peer first-collision posture on every
9310        // duplicate-target gate
9311        // (`validate_upgrade_from_duplicate_diagnostic_names_second_collision`
9312        // — the second entry is the first collision; this gate uses the
9313        // same shape: the second entry's `:nome` lands in the diagnostic
9314        // because `seen.insert(first.nome)` already populated the set).
9315        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9316        c.deps = vec![
9317            Dep::simple("caixa-teia", "^0.1"),
9318            Dep::simple("caixa-teia", "^0.2"),
9319            Dep::simple("caixa-teia", "^0.3"),
9320        ];
9321        let err = c.validate_deps().unwrap_err();
9322        // The diagnostic carries the offending caixa name; the
9323        // implementation surfaces on the *second* entry (the first
9324        // collision), so the test pins the `:nome` value.
9325        assert!(
9326            matches!(
9327                err,
9328                crate::dep::DepError::DuplicateNome { ref nome, list }
9329                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9330            ),
9331            "got {err:?}"
9332        );
9333    }
9334
9335    #[test]
9336    fn validate_deps_duplicate_in_deps_fires_before_duplicate_in_deps_dev() {
9337        // Cross-list precedence pin: when both lists carry duplicates,
9338        // the `:deps` diagnostic surfaces first — same author-mental-
9339        // model ordering the `validate_deps_runs_deps_before_deps_dev`
9340        // pin establishes for malformed `:versao` (runtime axis before
9341        // dev axis).
9342        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9343        c.deps = vec![
9344            Dep::simple("runtime-dep", "^0.1"),
9345            Dep::simple("runtime-dep", "^0.2"),
9346        ];
9347        c.deps_dev = vec![Dep::simple("dev-dep", "*"), Dep::simple("dev-dep", "^0.1")];
9348        let err = c.validate_deps().unwrap_err();
9349        assert!(
9350            matches!(
9351                err,
9352                crate::dep::DepError::DuplicateNome { ref nome, list }
9353                    if nome == "runtime-dep" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9354            ),
9355            "expected :deps duplicate to surface before :deps-dev duplicate, got {err:?}"
9356        );
9357    }
9358
9359    #[test]
9360    fn validate_deps_empty_lists_pass_duplicate_gate() {
9361        // Empty-set identity pin: the bare template (zero deps, zero
9362        // deps_dev) passes the duplicate gate as the gate's identity
9363        // element. A future tighten that conflates "empty" with
9364        // "missing" would regress this baseline.
9365        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9366        c.validate_deps().unwrap();
9367    }
9368
9369    #[test]
9370    fn validate_deps_duplicate_diagnostic_carries_list_tag() {
9371        // Diagnostic-shape pin: the `list:` field tags which list the
9372        // duplicate landed in (`:deps` vs `:deps-dev`) verbatim, so a
9373        // `feira lint` run can route the author to the right block in
9374        // their caixa.lisp without re-deriving the list from context.
9375        // Same self-locating shape every peer per-axis diagnostic
9376        // already exposes.
9377        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9378        c.deps_dev = vec![
9379            Dep::simple("dev-thing", "*"),
9380            Dep::simple("dev-thing", "^0.1"),
9381        ];
9382        let err = c.validate_deps().unwrap_err();
9383        let crate::dep::DepError::DuplicateNome { nome, list } = err else {
9384            panic!("expected DuplicateNome from :deps-dev walk");
9385        };
9386        assert_eq!(nome, "dev-thing");
9387        assert_eq!(list, crate::render::DEP_AUTHOR_KEY_DEPS_DEV);
9388    }
9389
9390    // ── validate_deps: per-entry :caracteristicas set-discipline gate ──
9391
9392    #[test]
9393    fn validate_deps_surfaces_caracteristicas_duplicate_in_deps_list() {
9394        // Thread-through pin on `:deps`: the per-entry
9395        // `Dep::validate_caracteristicas` gate fires inside
9396        // `Caixa::validate_deps`'s linear walk, so a malformed feature
9397        // list on any `:deps` entry surfaces as a `DepError` from
9398        // `validate_deps` — the same reachability shape every per-entry
9399        // `Dep::validate` arm threads through. Without this pin a future
9400        // shortcut that skips the per-entry `Dep::validate` call on the
9401        // cross-entry-uniqueness path would mask the within-entry
9402        // `:caracteristicas` gates.
9403        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9404        c.deps = vec![Dep {
9405            nome: "caixa-teia".into(),
9406            versao: "^0.1".into(),
9407            fonte: None,
9408            opcional: false,
9409            caracteristicas: vec!["http".into(), "http".into()],
9410        }];
9411        let err = c.validate_deps().unwrap_err();
9412        let crate::dep::DepError::CaracteristicaDuplicate {
9413            nome,
9414            caracteristica,
9415        } = err
9416        else {
9417            panic!("expected CaracteristicaDuplicate from :deps walk, got {err:?}");
9418        };
9419        assert_eq!(nome, "caixa-teia");
9420        assert_eq!(caracteristica, "http");
9421    }
9422
9423    #[test]
9424    fn validate_deps_surfaces_caracteristicas_empty_in_deps_dev_list() {
9425        // Peer thread-through pin on `:deps-dev`: same reachability as
9426        // the `:deps` arm above, on the dev-only authoring axis. Pins
9427        // that the `validate_deps` walk visits both lists' per-entry
9428        // gates uniformly. The empty-feature arm carries here so both
9429        // new `:caracteristicas` arms are surfaced via at least one
9430        // `validate_deps` thread-through.
9431        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9432        c.deps_dev = vec![Dep {
9433            nome: "caixa-teia".into(),
9434            versao: "^0.1".into(),
9435            fonte: None,
9436            opcional: false,
9437            caracteristicas: vec![String::new()],
9438        }];
9439        let err = c.validate_deps().unwrap_err();
9440        let crate::dep::DepError::CaracteristicaEmpty { nome } = err else {
9441            panic!("expected CaracteristicaEmpty from :deps-dev walk, got {err:?}");
9442        };
9443        assert_eq!(nome, "caixa-teia");
9444    }
9445
9446    #[test]
9447    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_list() {
9448        // Thread-through pin on `:deps`: the per-entry
9449        // `Dep::validate_caracteristicas` value-shape gate (lifted via
9450        // `crate::render::is_cargo_feature_name`) fires inside
9451        // `Caixa::validate_deps`'s linear walk on the `:deps` list, so
9452        // a structurally invalid feature name on any `:deps` entry
9453        // surfaces as `DepError::CaracteristicaInvalid` from
9454        // `validate_deps` — the same reachability shape every per-entry
9455        // `Dep::validate` arm threads through. Without this pin a
9456        // future shortcut that skips the per-entry `Dep::validate` call
9457        // on the cross-entry-uniqueness path would mask the within-
9458        // entry `:caracteristicas` value-shape gate.
9459        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9460        c.deps = vec![Dep {
9461            nome: "caixa-teia".into(),
9462            versao: "^0.1".into(),
9463            fonte: None,
9464            opcional: false,
9465            caracteristicas: vec!["+http".into()],
9466        }];
9467        let err = c.validate_deps().unwrap_err();
9468        let crate::dep::DepError::CaracteristicaInvalid {
9469            nome,
9470            caracteristica,
9471            ..
9472        } = err
9473        else {
9474            panic!("expected CaracteristicaInvalid from :deps walk, got {err:?}");
9475        };
9476        assert_eq!(nome, "caixa-teia");
9477        assert_eq!(caracteristica, "+http");
9478    }
9479
9480    #[test]
9481    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_dev_list() {
9482        // Peer thread-through pin on `:deps-dev`: same reachability as
9483        // the `:deps` arm above, on the dev-only authoring axis. The
9484        // `http/json` shape carries here so the segment-separator
9485        // diagnostic (the canonical Cargo `dep/feat` namespaced-dep
9486        // confusion footgun) is surfaced via the cross-entry walk too —
9487        // pinning that the `:deps-dev` list visits the same per-entry
9488        // value-shape gate as the `:deps` list.
9489        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9490        c.deps_dev = vec![Dep {
9491            nome: "caixa-teia".into(),
9492            versao: "^0.1".into(),
9493            fonte: None,
9494            opcional: false,
9495            caracteristicas: vec!["http/json".into()],
9496        }];
9497        let err = c.validate_deps().unwrap_err();
9498        let crate::dep::DepError::CaracteristicaInvalid {
9499            nome,
9500            caracteristica,
9501            ..
9502        } = err
9503        else {
9504            panic!("expected CaracteristicaInvalid from :deps-dev walk, got {err:?}");
9505        };
9506        assert_eq!(nome, "caixa-teia");
9507        assert_eq!(caracteristica, "http/json");
9508    }
9509
9510    #[test]
9511    fn to_lisp_preserves_deps() {
9512        let src = r#"
9513(defcaixa
9514  :nome "x"
9515  :versao "0.1.0"
9516  :kind Biblioteca
9517  :deps ((:nome "a" :versao "^0.1")
9518         (:nome "b" :versao "*" :fonte (:tipo git :repo "github:o/b" :tag "v1"))))
9519"#;
9520        let c1 = Caixa::from_lisp(src).unwrap();
9521        let emitted = c1.to_lisp();
9522        let c2 = Caixa::from_lisp(&emitted).expect("round trip");
9523        assert_eq!(c1.deps, c2.deps);
9524    }
9525
9526    // ── Caixa::validate_nome — top-level :nome value-shape gate ─────────
9527
9528    fn caixa_with_nome(nome: &str) -> Caixa {
9529        let mut c = Caixa::from_lisp(&Caixa::template("placeholder")).unwrap();
9530        c.nome = nome.to_string();
9531        c
9532    }
9533
9534    #[test]
9535    fn validate_nome_accepts_canonical_template() {
9536        // Positive control: the bare `feira init`-style template's
9537        // `:nome` ("demo") is a canonical DNS-1123 label; the gate must
9538        // not regress this baseline shape. A future tightening of the
9539        // accepted set surfaces here as a test failure first.
9540        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9541        c.validate_nome().unwrap();
9542    }
9543
9544    #[test]
9545    fn validate_nome_accepts_canonical_forms() {
9546        // Positive-set sweep: each realistic caixa-name shape the K8s
9547        // apiserver accepts as a `metadata.name` label must pass —
9548        // single-word, hyphen-joined, version-suffixed, single-char,
9549        // two-char, digit-start (DNS-1123 allows this; the stricter
9550        // DNS-1035 Service-name rule doesn't), version-suffix-bearing.
9551        // Mirrors `accepts_canonical_membro_caixa_forms` (3f9d7a0) on
9552        // the peer member-name axis.
9553        for nome in [
9554            "checkout",
9555            "cart-v2",
9556            "a",
9557            "db",
9558            "3rd-party-shim",
9559            "payment-retry",
9560            "0",
9561        ] {
9562            caixa_with_nome(nome)
9563                .validate_nome()
9564                .unwrap_or_else(|e| panic!("canonical :nome {nome:?} must validate, got {e:?}"));
9565        }
9566    }
9567
9568    #[test]
9569    fn validate_nome_rejects_empty() {
9570        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
9571        // an empty `:nome` (the derive macro stores the raw String);
9572        // the gate's empty arm names the offending axis with a narrower
9573        // diagnostic than the `NomeInvalid` parse arm would emit.
9574        let c = caixa_with_nome("");
9575        let err = c.validate_nome().unwrap_err();
9576        assert_eq!(err, ManifestError::NomeEmpty);
9577    }
9578
9579    #[test]
9580    fn validate_nome_rejects_uppercase() {
9581        // The canonical "I copied the TitleCase display name verbatim"
9582        // footgun. The K8s apiserver rejects `metadata.name: MyApp` at
9583        // admission on every derived artifact (Helm chart, ComputeUnit,
9584        // CNP, HTTPRoute, label values); the gate moves the diagnostic
9585        // to the source `caixa.lisp` and the reason suggests the
9586        // lowercased fix verbatim.
9587        let c = caixa_with_nome("MyApp");
9588        let err = c.validate_nome().unwrap_err();
9589        let ManifestError::NomeInvalid { nome, reason } = err else {
9590            panic!("expected NomeInvalid for uppercase :nome");
9591        };
9592        assert_eq!(nome, "MyApp");
9593        assert!(
9594            reason.contains("uppercase") && reason.contains("myapp"),
9595            "diagnostic must name the violation + the lowercased fix, got {reason:?}"
9596        );
9597    }
9598
9599    #[test]
9600    fn validate_nome_rejects_underscore() {
9601        // The Python-/Postgres-style `snake_case` leak. DNS-1123 forbids
9602        // `_`; the apiserver rejects on admission across every derived
9603        // artifact. Same fixture pinned for `:membros :caixa` (3f9d7a0)
9604        // and `:children :caixa` (31bfa43).
9605        let c = caixa_with_nome("my_app");
9606        let err = c.validate_nome().unwrap_err();
9607        assert!(
9608            matches!(
9609                err,
9610                ManifestError::NomeInvalid { ref nome, ref reason }
9611                    if nome == "my_app" && reason.contains('_')
9612            ),
9613            "got {err:?}"
9614        );
9615    }
9616
9617    #[test]
9618    fn validate_nome_rejects_dot() {
9619        // A `:nome` is a single DNS-1123 label, not a subdomain. The
9620        // "I want to namespace with `.`" footgun the gate redirects to
9621        // `-` via the shared predicate's reason wording.
9622        let c = caixa_with_nome("team.app");
9623        let err = c.validate_nome().unwrap_err();
9624        assert!(
9625            matches!(
9626                err,
9627                ManifestError::NomeInvalid { ref nome, ref reason }
9628                    if nome == "team.app" && reason.contains('.')
9629            ),
9630            "got {err:?}"
9631        );
9632    }
9633
9634    #[test]
9635    fn validate_nome_rejects_leading_hyphen() {
9636        // DNS-1123 boundary rule: the label must start with an ASCII
9637        // alphanumeric. Pin the leading-`-` arm explicitly.
9638        let c = caixa_with_nome("-app");
9639        let err = c.validate_nome().unwrap_err();
9640        assert!(
9641            matches!(
9642                err,
9643                ManifestError::NomeInvalid { ref nome, .. } if nome == "-app"
9644            ),
9645            "got {err:?}"
9646        );
9647    }
9648
9649    #[test]
9650    fn validate_nome_rejects_trailing_hyphen() {
9651        // Symmetric arm of the boundary rule, pinned separately so a
9652        // future relaxation that only checks the leading position
9653        // surfaces here. Mirrors `rejects_membro_caixa_with_trailing_hyphen`
9654        // and `_with_trailing_hyphen` on the supervisor / aplicacao
9655        // axes.
9656        let c = caixa_with_nome("app-");
9657        let err = c.validate_nome().unwrap_err();
9658        assert!(
9659            matches!(
9660                err,
9661                ManifestError::NomeInvalid { ref nome, .. } if nome == "app-"
9662            ),
9663            "got {err:?}"
9664        );
9665    }
9666
9667    #[test]
9668    fn validate_nome_rejects_unicode() {
9669        // IDN must be pre-encoded as Punycode (`xn--…`); raw Unicode
9670        // bytes are rejected by the K8s apiserver on every name axis.
9671        let c = caixa_with_nome("café");
9672        let err = c.validate_nome().unwrap_err();
9673        assert!(
9674            matches!(
9675                err,
9676                ManifestError::NomeInvalid { ref nome, .. } if nome == "café"
9677            ),
9678            "got {err:?}"
9679        );
9680    }
9681
9682    #[test]
9683    fn validate_nome_rejects_whitespace() {
9684        // The paste-from-sketch / paste-from-spec footgun. Internal
9685        // whitespace is rejected by every K8s name axis.
9686        let c = caixa_with_nome("my app");
9687        let err = c.validate_nome().unwrap_err();
9688        assert!(
9689            matches!(
9690                err,
9691                ManifestError::NomeInvalid { ref nome, .. } if nome == "my app"
9692            ),
9693            "got {err:?}"
9694        );
9695    }
9696
9697    #[test]
9698    fn validate_nome_rejects_too_long() {
9699        // 64-byte boundary pin: the K8s apiserver rejects any
9700        // `metadata.name` over 63 bytes at admission; the diagnostic
9701        // names both the 63-byte cap and the actual length so the
9702        // author can shorten in one edit. Mirrors `_too_long` on the
9703        // peer member-/cluster-/child-name axes.
9704        let over = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN + 1);
9705        let c = caixa_with_nome(&over);
9706        let err = c.validate_nome().unwrap_err();
9707        let ManifestError::NomeInvalid { nome, reason } = err else {
9708            panic!("expected NomeInvalid for over-cap :nome");
9709        };
9710        assert_eq!(nome.len(), crate::DNS_1123_LABEL_MAX_LEN + 1);
9711        assert!(
9712            reason.contains("63") && reason.contains("64"),
9713            "diagnostic must name the cap + actual length, got {reason:?}"
9714        );
9715    }
9716
9717    #[test]
9718    fn nome_max_length_validates() {
9719        // The 63-byte cap exactly — the boundary-accepting case pinned
9720        // alongside `validate_nome_rejects_too_long` so a future cap
9721        // shift surfaces both arms simultaneously. Mirrors
9722        // `membro_caixa_max_length_validates`,
9723        // `placement_cluster_max_length_validates`,
9724        // `child_caixa_max_length_validates`.
9725        let at_cap = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
9726        caixa_with_nome(&at_cap).validate_nome().unwrap();
9727    }
9728
9729    #[test]
9730    fn nome_empty_takes_precedence_over_invalid() {
9731        // Order pin: the empty arm fires before the predicate is
9732        // consulted. Empty < invalid in self-locating-ness — the
9733        // narrower `NomeEmpty` diagnostic doesn't carry a useless
9734        // `nome: ""` reference into the parser-shaped reason. Mirrors
9735        // `membro_caixa_empty_takes_precedence_over_invalid` on the
9736        // peer axis (3f9d7a0).
9737        let c = caixa_with_nome("");
9738        assert_eq!(c.validate_nome().unwrap_err(), ManifestError::NomeEmpty);
9739    }
9740
9741    #[test]
9742    fn nome_invalid_diagnostic_carries_offending_nome() {
9743        // Diagnostic-shape pin: the error names the offending `:nome`
9744        // verbatim with a non-empty parser-shaped reason, so a `feira
9745        // lint` run can render the diagnostic without re-parsing.
9746        // Mirrors `membro_caixa_invalid_diagnostic_carries_offending_caixa`.
9747        let c = caixa_with_nome("MyApp");
9748        let err = c.validate_nome().unwrap_err();
9749        let ManifestError::NomeInvalid { nome, reason } = err else {
9750            panic!("expected NomeInvalid variant");
9751        };
9752        assert_eq!(nome, "MyApp");
9753        assert!(
9754            !reason.is_empty(),
9755            "NomeInvalid `reason` must carry the predicate's wording verbatim"
9756        );
9757    }
9758
9759    // ── Caixa::validate_nome_chart_name_budget — joint-length on `:nome` ──
9760    //
9761    // The bare-`:nome` axis [`Caixa::validate_nome`] caps at 63 bytes
9762    // via DNS-1123; this second-axis gate caps the joint
9763    // `lareira-<nome>` chart name at the same 63-byte ceiling. The
9764    // canonical [`crate::lareira_chart_name`] helper's doc comment
9765    // (f7320d7, caixa-core/src/render.rs:3198) explicitly deferred:
9766    // "the M4 admission webhook will pin the joint-length invariant
9767    // when it lands". These tests pin it at the manifest-validate
9768    // layer instead, fail-before-pass-after on the 56-byte boundary.
9769
9770    #[test]
9771    fn validate_nome_chart_name_budget_accepts_canonical_template() {
9772        // Positive control: the bare `feira init`-style template's
9773        // `:nome` ("demo") sits far below the cap; the gate must not
9774        // regress this baseline. Same shape every peer
9775        // value-shape-gate baseline pin uses.
9776        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9777        c.validate_nome_chart_name_budget().unwrap();
9778    }
9779
9780    #[test]
9781    fn validate_nome_chart_name_budget_accepts_canonical_fixtures() {
9782        // Positive-set sweep across the canonical author surface every
9783        // in-tree fixture uses (`hello-rio`, `cart`, `checkout`,
9784        // `worker`, the `checkout-aplicacao` example members, the
9785        // `example-attest` caixa-tatara fixture). Every value sits
9786        // far below the 55-byte per-`:nome` budget. Same shape every
9787        // peer per-axis baseline pin uses.
9788        for nome in [
9789            "hello-rio",
9790            "cart",
9791            "checkout",
9792            "worker",
9793            "example-attest",
9794            "demo",
9795            "a",
9796        ] {
9797            caixa_with_nome(nome)
9798                .validate_nome_chart_name_budget()
9799                .unwrap_or_else(|e| {
9800                    panic!("canonical :nome {nome:?} must pass chart-name budget, got {e:?}")
9801                });
9802        }
9803    }
9804
9805    #[test]
9806    fn validate_nome_chart_name_budget_accepts_nome_at_cap() {
9807        // Boundary-accepting case at the 55-byte per-`:nome` budget —
9808        // the joint chart name is exactly 63 bytes, the DNS-1123 label
9809        // cap. Pinned alongside the rejecting-arm test so a future cap
9810        // shift surfaces both arms simultaneously. Mirrors
9811        // `nome_max_length_validates` on the peer bare-`:nome` axis.
9812        let at_cap = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN);
9813        caixa_with_nome(&at_cap)
9814            .validate_nome_chart_name_budget()
9815            .unwrap();
9816    }
9817
9818    #[test]
9819    fn validate_nome_chart_name_budget_rejects_nome_one_over_cap() {
9820        // Fail-before-pass-after pin on the 56-byte boundary: the
9821        // smallest `:nome` length that overflows the joint chart-name
9822        // cap. The inner [`is_dns_1123_label`] gate
9823        // (`Caixa::validate_nome`) accepts it (56 ≤ 63), so prior to
9824        // this gate it silently passed the manifest-validate cascade
9825        // and surfaced as a `helm lint` / apiserver rejection on the
9826        // rendered chart name far from the source `caixa.lisp`, with
9827        // no field naming the overflow. With this gate the diagnostic
9828        // names the offending `:nome` verbatim alongside the rendered
9829        // chart name and the budget, so the author can shorten in one
9830        // edit. Mirrors `validate_nome_rejects_too_long` on the peer
9831        // bare-`:nome` axis.
9832        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9833        let c = caixa_with_nome(&over);
9834        let err = c.validate_nome_chart_name_budget().unwrap_err();
9835        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
9836            panic!("expected NomeChartNameBudgetExceeded for over-budget :nome");
9837        };
9838        assert_eq!(nome.len(), crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9839        assert_eq!(nome, over);
9840        assert!(
9841            reason.contains("63") && reason.contains("64") && reason.contains("55"),
9842            "diagnostic must name the DNS-1123 cap (63), the actual chart-name length (64), \
9843             and the per-`:nome` budget (55), got {reason:?}"
9844        );
9845    }
9846
9847    #[test]
9848    fn validate_nome_chart_name_budget_rejects_nome_at_bare_dns_cap() {
9849        // The 63-byte `:nome` boundary — passes the bare-`:nome`
9850        // [`is_dns_1123_label`] cap exactly, but produces a 71-byte
9851        // joint chart name that overflows the DNS-1123 label cap
9852        // structurally. The most stringent fail-before-pass-after
9853        // surface: every `:nome` in the 56..=63-byte range passed the
9854        // prior cascade and broke at admission.
9855        let bare_max = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
9856        let c = caixa_with_nome(&bare_max);
9857        // The bare-`:nome` gate accepts the 63-byte length.
9858        c.validate_nome().unwrap();
9859        // The new joint-length gate rejects it.
9860        let err = c.validate_nome_chart_name_budget().unwrap_err();
9861        assert!(
9862            matches!(
9863                err,
9864                ManifestError::NomeChartNameBudgetExceeded { ref nome, .. }
9865                    if nome.len() == crate::DNS_1123_LABEL_MAX_LEN
9866            ),
9867            "got {err:?}"
9868        );
9869    }
9870
9871    #[test]
9872    fn validate_nome_chart_name_budget_diagnostic_carries_offending_chart_name() {
9873        // Diagnostic-shape pin: the rendered `lareira-<nome>` chart
9874        // name appears verbatim in the diagnostic so the author sees
9875        // exactly the string the apiserver / `helm lint` would have
9876        // rejected — no re-derivation required to grep the source.
9877        // Peer with `nome_invalid_diagnostic_carries_offending_nome`
9878        // on the bare-`:nome` axis.
9879        let over = "x".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 5);
9880        let c = caixa_with_nome(&over);
9881        let err = c.validate_nome_chart_name_budget().unwrap_err();
9882        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
9883            panic!("expected NomeChartNameBudgetExceeded variant");
9884        };
9885        assert_eq!(nome, over);
9886        let expected_chart = crate::lareira_chart_name(&over);
9887        assert!(
9888            reason.contains(&expected_chart),
9889            "diagnostic must carry the rendered chart name {expected_chart:?} verbatim, \
9890             got {reason:?}"
9891        );
9892        assert!(
9893            reason.contains("lareira-"),
9894            "diagnostic must name the canonical chart-name prefix verbatim, got {reason:?}"
9895        );
9896    }
9897
9898    #[test]
9899    fn validate_nome_chart_name_budget_runs_after_nome_shape_via_layout_verify() {
9900        // Order pin on the layout cascade: the narrower
9901        // `NomeInvalid` (bare-DNS-1123 shape) fires before the
9902        // joint-length budget. A structurally-malformed `:nome` (here:
9903        // uppercase) surfaces its specific shape error rather than
9904        // the chart-name-budget error, even when the joint length
9905        // would also overflow — the narrower diagnostic is more
9906        // self-locating. Mirrors the cascade-precedence pins peer
9907        // gates already use (e.g. `EntradaParaEmpty` before
9908        // `EntradaParaInvalid`).
9909        let over = "A".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9910        let c = caixa_with_nome(&over);
9911        // The bare-shape gate fires first.
9912        let err = c.validate_nome().unwrap_err();
9913        assert!(
9914            matches!(err, ManifestError::NomeInvalid { .. }),
9915            "bare-shape gate must fire before chart-name-budget gate; got {err:?}"
9916        );
9917        // And the layout verify cascade surfaces that diagnostic, not
9918        // the budget arm. Inject a path-exists oracle so the cascade
9919        // gets past the manifest-presence check and into the
9920        // value-shape gates.
9921        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
9922        let err = crate::LayoutInvariants::verify(
9923            &layout,
9924            &c,
9925            std::path::Path::new("/tmp/caixa-test-fake-root"),
9926        )
9927        .unwrap_err();
9928        let issue = err.to_string();
9929        assert!(
9930            issue.contains("DNS-1123") || issue.contains("uppercase"),
9931            "layout cascade must surface the bare-DNS-1123 diagnostic on a \
9932             structurally-malformed :nome, not the chart-name-budget diagnostic; got {issue:?}"
9933        );
9934    }
9935
9936    #[test]
9937    fn layout_verify_routes_chart_name_budget_through_nome_violation() {
9938        // Cross-axis envelope pin: the layout cascade wraps both
9939        // bare-`:nome` and joint-length-`:nome` failures through the
9940        // same [`LayoutError::NomeViolation`] envelope, since both
9941        // arms are on the `:nome` axis. The user's diagnostic stays
9942        // self-locating ("which axis"), and a future consumer that
9943        // dispatches on the layout-error variant (e.g. a `feira lint`
9944        // exit-code mapping) sees a single per-axis envelope. The
9945        // wrapped `issue:` carries the full inner diagnostic.
9946        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9947        let c = caixa_with_nome(&over);
9948        // The bare-shape gate accepts.
9949        c.validate_nome().unwrap();
9950        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
9951        let err = crate::LayoutInvariants::verify(
9952            &layout,
9953            &c,
9954            std::path::Path::new("/tmp/caixa-test-fake-root"),
9955        )
9956        .unwrap_err();
9957        let crate::LayoutError::NomeViolation { caixa, issue } = err else {
9958            panic!("expected LayoutError::NomeViolation, got {err:?}");
9959        };
9960        assert_eq!(caixa, over);
9961        assert!(
9962            issue.contains("lareira-") && issue.contains("63") && issue.contains("55"),
9963            "wrapped issue must carry the joint-length diagnostic verbatim, got {issue:?}"
9964        );
9965    }
9966
9967    // ── Caixa::validate_versao — top-level :versao value-shape gate ─────
9968
9969    fn caixa_with_versao(versao: &str) -> Caixa {
9970        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9971        c.versao = versao.to_string();
9972        c
9973    }
9974
9975    #[test]
9976    fn validate_versao_accepts_canonical_template() {
9977        // Positive control: the bare `feira init`-style template's
9978        // `:versao` ("0.1.0") is a canonical SemVer-2 literal; the gate
9979        // must not regress this baseline shape. A future tightening of
9980        // the accepted set surfaces here as a test failure first.
9981        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9982        c.validate_versao().unwrap();
9983    }
9984
9985    #[test]
9986    fn validate_versao_accepts_canonical_forms() {
9987        // Positive-set sweep: each realistic SemVer-2 shape the
9988        // substrate's downstream consumers accept must pass — bare
9989        // MAJOR.MINOR.PATCH, pre-release tags (`-rc.1`, `-alpha.0`),
9990        // build metadata (`+build.42`), the combined form, and the
9991        // `0.0.0` boundary case. Mirrors `accepts_canonical_forms` on
9992        // the peer `:nome` axis (6c992f8).
9993        for versao in [
9994            "0.1.0",
9995            "0.0.0",
9996            "1.0.0",
9997            "0.2.0-rc.1",
9998            "1.0.0-alpha.0",
9999            "1.0.0+build.42",
10000            "1.0.0-rc.1+build.42",
10001            "10.20.30",
10002        ] {
10003            caixa_with_versao(versao)
10004                .validate_versao()
10005                .unwrap_or_else(|e| {
10006                    panic!("canonical :versao {versao:?} must validate, got {e:?}")
10007                });
10008        }
10009    }
10010
10011    #[test]
10012    fn validate_versao_rejects_empty() {
10013        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
10014        // an empty `:versao` (the derive macro stores the raw String);
10015        // the gate's empty arm names the offending axis with a narrower
10016        // diagnostic than the `VersaoInvalid` parse arm would emit.
10017        // Mirrors `validate_nome_rejects_empty` (6c992f8).
10018        let c = caixa_with_versao("");
10019        let err = c.validate_versao().unwrap_err();
10020        assert_eq!(err, ManifestError::VersaoEmpty);
10021    }
10022
10023    #[test]
10024    fn validate_versao_rejects_git_tag_shape() {
10025        // The canonical "I copied the git tag verbatim" footgun —
10026        // `feira publish` *emits* `v<versao>` git tags, so a leaked
10027        // `v0.1.0` in `:versao` would render as `vv0.1.0` and silently
10028        // shift every downstream consumer's version axis. `semver`
10029        // rejects the leading `v` at parse time; the gate moves the
10030        // diagnostic to the source `caixa.lisp`.
10031        let c = caixa_with_versao("v0.1.0");
10032        let err = c.validate_versao().unwrap_err();
10033        let ManifestError::VersaoInvalid { versao, reason } = err else {
10034            panic!("expected VersaoInvalid for git-tag-shape :versao");
10035        };
10036        assert_eq!(versao, "v0.1.0");
10037        assert!(
10038            !reason.is_empty(),
10039            "VersaoInvalid `reason` must carry the parser's wording, got {reason:?}"
10040        );
10041    }
10042
10043    #[test]
10044    fn validate_versao_rejects_missing_patch() {
10045        // The canonical "I shortened it" footgun — SemVer-2 requires
10046        // three parts. Cargo's `version =` field accepts the shortened
10047        // form as a requirement, conflating the two leaks across the
10048        // typed `:deps :versao` vs top-level `:versao` axes; the gate
10049        // pins the top-level axis to the strict three-part shape.
10050        let c = caixa_with_versao("0.1");
10051        let err = c.validate_versao().unwrap_err();
10052        assert!(
10053            matches!(
10054                err,
10055                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1"
10056            ),
10057            "got {err:?}"
10058        );
10059    }
10060
10061    #[test]
10062    fn validate_versao_rejects_requirement_shape() {
10063        // The canonical "I leaked a requirement into a version" footgun —
10064        // the typed `:deps :versao` / `:membros :versao` axes accept
10065        // `^0.1` (a `VersionReq`); the top-level `:versao` requires a
10066        // concrete `Version`. Without this gate the two typed surfaces
10067        // would silently overlap, and a top-level `^0.1` would surface
10068        // at `helm install` time as a Chart.yaml version rejection far
10069        // from the source `caixa.lisp`.
10070        let c = caixa_with_versao("^0.1");
10071        let err = c.validate_versao().unwrap_err();
10072        assert!(
10073            matches!(
10074                err,
10075                ManifestError::VersaoInvalid { ref versao, .. } if versao == "^0.1"
10076            ),
10077            "got {err:?}"
10078        );
10079    }
10080
10081    #[test]
10082    fn validate_versao_rejects_docker_tag_shape() {
10083        // The "I confused it with a docker tag" footgun — `latest`,
10084        // `main`, `stable` parse as identifiers, not SemVer-2 versions.
10085        // SemVer rejects at parse time; the gate moves the diagnostic
10086        // to the source `caixa.lisp`.
10087        for bad in ["latest", "main", "stable"] {
10088            let c = caixa_with_versao(bad);
10089            let err = c.validate_versao().unwrap_err();
10090            assert!(
10091                matches!(
10092                    err,
10093                    ManifestError::VersaoInvalid { ref versao, .. } if versao == bad
10094                ),
10095                "got {err:?} for {bad:?}"
10096            );
10097        }
10098    }
10099
10100    #[test]
10101    fn validate_versao_rejects_four_part_form() {
10102        // The Java/Microsoft "MAJOR.MINOR.PATCH.BUILD" convention
10103        // SemVer-2 forbids. A leak from a non-SemVer ecosystem; the
10104        // semver crate rejects the extra `.0` at parse time.
10105        let c = caixa_with_versao("0.1.0.0");
10106        let err = c.validate_versao().unwrap_err();
10107        assert!(
10108            matches!(
10109                err,
10110                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1.0.0"
10111            ),
10112            "got {err:?}"
10113        );
10114    }
10115
10116    #[test]
10117    fn versao_empty_takes_precedence_over_invalid() {
10118        // Order pin: the empty arm fires before the parser is consulted.
10119        // Empty < invalid in self-locating-ness — the narrower
10120        // `VersaoEmpty` diagnostic doesn't carry a useless `versao: ""`
10121        // reference into the parser-shaped reason. Mirrors
10122        // `nome_empty_takes_precedence_over_invalid` (6c992f8) on the
10123        // peer axis.
10124        let c = caixa_with_versao("");
10125        assert_eq!(c.validate_versao().unwrap_err(), ManifestError::VersaoEmpty);
10126    }
10127
10128    #[test]
10129    fn versao_invalid_diagnostic_carries_offending_versao() {
10130        // Diagnostic-shape pin: the error names the offending `:versao`
10131        // verbatim with a non-empty parser-shaped reason, so a `feira
10132        // lint` run can render the diagnostic without re-parsing.
10133        // Mirrors `nome_invalid_diagnostic_carries_offending_nome`.
10134        let c = caixa_with_versao("v0.1.0");
10135        let err = c.validate_versao().unwrap_err();
10136        let ManifestError::VersaoInvalid { versao, reason } = err else {
10137            panic!("expected VersaoInvalid variant");
10138        };
10139        assert_eq!(versao, "v0.1.0");
10140        assert!(
10141            !reason.is_empty(),
10142            "VersaoInvalid `reason` must carry the parser's wording verbatim"
10143        );
10144    }
10145
10146    #[test]
10147    fn validate_versao_accepts_what_upgrade_from_from_accepts() {
10148        // Parity pin: every shape `UpgradeFromEntry::validate` accepts
10149        // for `:upgrade-from :from` must also pass `validate_versao` —
10150        // the two `:versao`-typed surfaces (top-level `:versao`,
10151        // `:upgrade-from :from`) consume the *same* `semver::Version`
10152        // parser, so they must agree on the accepted set. Without this
10153        // pin, a future tightening of one axis could silently diverge
10154        // from the other. Mirrors the `:versao` requirement-axis
10155        // parity (`:deps`/`:deps-dev`/`:membros`/`:children`) the prior
10156        // commits established.
10157        for versao in ["0.1.0", "0.2.0-rc.1", "1.0.0+build.42"] {
10158            // From the canonical UpgradeFromEntry round-trip fixture
10159            // (`upgrade::tests::round_trip_load_module` peers).
10160            let entry = crate::UpgradeFromEntry {
10161                from: versao.to_string(),
10162                instructions: Vec::new(),
10163            };
10164            entry
10165                .validate()
10166                .unwrap_or_else(|e| panic!(":from {versao:?} must validate, got {e:?}"));
10167            caixa_with_versao(versao)
10168                .validate_versao()
10169                .unwrap_or_else(|e| {
10170                    panic!(":versao {versao:?} must validate, got {e:?} — peer axis diverges")
10171                });
10172        }
10173    }
10174
10175    // ── Caixa::validate_restart_window — supervisor restart-window
10176    //    folds through the shared `supervisor::duration_codec` ────────
10177
10178    fn caixa_with_restart_window(window: Option<&str>) -> Caixa {
10179        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
10180        c.kind = CaixaKind::Supervisor;
10181        c.restart_window = window.map(str::to_string);
10182        c
10183    }
10184
10185    #[test]
10186    fn validate_restart_window_accepts_none() {
10187        // The canonical "omit the slot to express no reset" shape — a
10188        // `None` raw string is the absence of the typed
10189        // `:restart-window` slot, which is exactly the SupervisorSpec
10190        // "never reset" semantics. The gate must be a no-op here; a
10191        // future tightening that rejected `None` would force every
10192        // supervisor caixa to authoring-time pin a window even when
10193        // the OTP semantics call for none.
10194        caixa_with_restart_window(None)
10195            .validate_restart_window()
10196            .unwrap();
10197    }
10198
10199    #[test]
10200    fn validate_restart_window_accepts_canonical_forms() {
10201        // Positive-set sweep across the canonical authoring units the
10202        // shared `supervisor::duration_codec::parse` accepts —
10203        // matches the codec-side `parse_accepts_integer_canonical_units`
10204        // pin in supervisor::tests so a future codec-side tightening
10205        // surfaces simultaneously on both axes.
10206        for window in ["60s", "5m", "1h", "500ms", "30", "0s"] {
10207            caixa_with_restart_window(Some(window))
10208                .validate_restart_window()
10209                .unwrap_or_else(|e| {
10210                    panic!("canonical :restart-window {window:?} must validate, got {e:?}")
10211                });
10212        }
10213    }
10214
10215    #[test]
10216    fn validate_restart_window_rejects_fractional_seconds() {
10217        // Fail-before-pass-after pin: the `"1.5s"` drift class (parses
10218        // as f64 to 1.5 → renders back as `"1500ms"` on first
10219        // serialize). Prior to the fold + this gate, the inline
10220        // `parse_window_inline` accepted f64 magnitudes and silently
10221        // produced a `Duration::from_secs_f64(1.5)`, divergent from
10222        // the shared codec's integer-magnitude discipline on the
10223        // serde-routed siblings. The gate now surfaces a self-locating
10224        // diagnostic at the manifest layer.
10225        let err = caixa_with_restart_window(Some("1.5s"))
10226            .validate_restart_window()
10227            .unwrap_err();
10228        let ManifestError::RestartWindowMalformed {
10229            restart_window,
10230            reason,
10231        } = err
10232        else {
10233            panic!("expected RestartWindowMalformed for fractional seconds");
10234        };
10235        assert_eq!(restart_window, "1.5s");
10236        assert!(
10237            reason.contains("\"1.5\"") && reason.contains("not a non-negative integer"),
10238            "diagnostic must carry shared-codec wording, got {reason:?}"
10239        );
10240    }
10241
10242    #[test]
10243    fn validate_restart_window_rejects_decimal_shaped_integer() {
10244        // The `"1.0s"` class — numerically `1s` exactly, but the
10245        // canonical form is `"1s"` not `"1.0s"`. Decimal-shape leak
10246        // gets the same canonical-form diagnostic.
10247        let err = caixa_with_restart_window(Some("1.0s"))
10248            .validate_restart_window()
10249            .unwrap_err();
10250        assert!(
10251            matches!(
10252                err,
10253                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10254                    if restart_window == "1.0s"
10255            ),
10256            "got {err:?}"
10257        );
10258    }
10259
10260    #[test]
10261    fn validate_restart_window_rejects_half_unit_minute() {
10262        // `"0.5m"` is the unit-fraction footgun — author writes a
10263        // human-readable half-minute, the prior inline parser silently
10264        // produced `Duration::from_secs_f64(30.0)` and serde
10265        // re-emitted as `"30s"`, rewriting author intent. The gate
10266        // closes the loop at the manifest layer.
10267        let err = caixa_with_restart_window(Some("0.5m"))
10268            .validate_restart_window()
10269            .unwrap_err();
10270        let ManifestError::RestartWindowMalformed {
10271            restart_window,
10272            reason,
10273        } = err
10274        else {
10275            panic!("expected RestartWindowMalformed");
10276        };
10277        assert_eq!(restart_window, "0.5m");
10278        assert!(
10279            reason.contains("\"30s\""),
10280            "diagnostic must point at the canonical-form remediation, got {reason:?}"
10281        );
10282    }
10283
10284    #[test]
10285    fn validate_restart_window_rejects_leading_sign() {
10286        // `"+30s"` and `"-30s"` both round-tripped through f64 cleanly
10287        // on the prior parser (`+30` parses as `30.0`; `-30` parsed
10288        // and was caught by the `num < 0.0` arm which silently
10289        // returned `None`, dropping the author-supplied window). The
10290        // shared codec's digit-only gate rejects both with a unified
10291        // canonical-form diagnostic; the manifest-layer wrapper names
10292        // the offending value.
10293        for bad in ["+30s", "-30s"] {
10294            let err = caixa_with_restart_window(Some(bad))
10295                .validate_restart_window()
10296                .unwrap_err();
10297            assert!(
10298                matches!(
10299                    err,
10300                    ManifestError::RestartWindowMalformed { ref restart_window, .. }
10301                        if restart_window == bad
10302                ),
10303                "got {err:?} for {bad:?}"
10304            );
10305        }
10306    }
10307
10308    #[test]
10309    fn validate_restart_window_rejects_unknown_unit() {
10310        // `"30x"` — the typo / wrong-unit footgun. The shared codec's
10311        // unit dispatch surfaces an `unknown duration unit` reason;
10312        // the manifest-layer wrapper names the offending value.
10313        let err = caixa_with_restart_window(Some("30x"))
10314            .validate_restart_window()
10315            .unwrap_err();
10316        let ManifestError::RestartWindowMalformed {
10317            restart_window,
10318            reason,
10319        } = err
10320        else {
10321            panic!("expected RestartWindowMalformed for unknown unit");
10322        };
10323        assert_eq!(restart_window, "30x");
10324        assert!(
10325            reason.contains("unknown duration unit"),
10326            "diagnostic must carry shared-codec unit-rejection wording, got {reason:?}"
10327        );
10328    }
10329
10330    #[test]
10331    fn validate_restart_window_rejects_garbage() {
10332        // Pure non-numeric magnitude (`"abc"`) falls through to the
10333        // shared codec's narrower `"bad duration magnitude"` arm. Same
10334        // diagnostic shape as the codec-side
10335        // `parse_garbage_still_falls_through_to_bad_magnitude` pin.
10336        let err = caixa_with_restart_window(Some("abc"))
10337            .validate_restart_window()
10338            .unwrap_err();
10339        let ManifestError::RestartWindowMalformed {
10340            restart_window,
10341            reason,
10342        } = err
10343        else {
10344            panic!("expected RestartWindowMalformed for garbage");
10345        };
10346        assert_eq!(restart_window, "abc");
10347        assert!(
10348            reason.contains("bad duration magnitude"),
10349            "diagnostic must carry shared-codec garbage-rejection wording, got {reason:?}"
10350        );
10351    }
10352
10353    #[test]
10354    fn validate_restart_window_rejects_empty_string() {
10355        // The empty-after-trim edge case — distinct from the `None`
10356        // canonical "omit the slot" shape. The shared codec's
10357        // digit-only gate refuses an empty magnitude; the manifest
10358        // layer names the offending `""` so the author can grep for
10359        // the literal empty value in their `caixa.lisp` and either
10360        // remove the slot (the canonical "no reset" shape) or pin a
10361        // positive duration.
10362        let err = caixa_with_restart_window(Some(""))
10363            .validate_restart_window()
10364            .unwrap_err();
10365        assert!(
10366            matches!(
10367                err,
10368                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10369                    if restart_window.is_empty()
10370            ),
10371            "got {err:?}"
10372        );
10373    }
10374
10375    #[test]
10376    fn validate_restart_window_diagnostic_carries_offending_value() {
10377        // Diagnostic-shape pin (peer with
10378        // `nome_invalid_diagnostic_carries_offending_nome` /
10379        // `versao_invalid_diagnostic_carries_offending_versao`): the
10380        // error names the offending raw `:restart-window` verbatim
10381        // with a non-empty shared-codec-shaped reason, so a `feira
10382        // lint` run can render the diagnostic without re-parsing.
10383        let err = caixa_with_restart_window(Some("1.5s"))
10384            .validate_restart_window()
10385            .unwrap_err();
10386        let ManifestError::RestartWindowMalformed {
10387            restart_window,
10388            reason,
10389        } = err
10390        else {
10391            panic!("expected RestartWindowMalformed variant");
10392        };
10393        assert_eq!(restart_window, "1.5s");
10394        assert!(
10395            !reason.is_empty(),
10396            "RestartWindowMalformed `reason` must carry the codec's wording verbatim"
10397        );
10398    }
10399
10400    #[test]
10401    fn supervisor_view_folds_through_shared_codec_on_canonical_form() {
10402        // Behavioral parity pin after the fold (`parse_window_inline`
10403        // deletion): the canonical `"60s"` still produces
10404        // `Duration::from_secs(60)` on the typed view — the fold is
10405        // semantically equivalent to the prior inline parser on the
10406        // accepted set. Mirrors the pre-fold `supervisor_view_returns_typed_shape`
10407        // pin, narrowed to the parser-side contract.
10408        let c = caixa_with_restart_window(Some("60s"));
10409        let view = c.supervisor_view().expect("Supervisor kind has a view");
10410        assert_eq!(
10411            view.restart_window,
10412            Some(std::time::Duration::from_secs(60))
10413        );
10414    }
10415
10416    #[test]
10417    fn supervisor_view_soft_swallows_what_validate_rejects() {
10418        // Parity pin between the view-construction path and the
10419        // manifest-level validator: the same `"1.5s"` that surfaces
10420        // `RestartWindowMalformed` at `validate_restart_window` time
10421        // becomes `restart_window: None` on the typed view (the fold
10422        // preserves the existing best-effort shape of `supervisor_view`).
10423        // The contract is: a layout-verifier / `feira lint` flow that
10424        // cares about the malformed-window axis MUST consult
10425        // `validate_restart_window` — relying solely on the view's
10426        // `None` swallows the diagnostic silently. This pin makes the
10427        // expectation a typed invariant.
10428        let c = caixa_with_restart_window(Some("1.5s"));
10429        let view = c.supervisor_view().expect("Supervisor kind has a view");
10430        assert_eq!(
10431            view.restart_window, None,
10432            "view-construction path soft-swallows the parse error to None"
10433        );
10434        // And the manifest-level validator does NOT soft-swallow:
10435        assert!(
10436            matches!(
10437                c.validate_restart_window().unwrap_err(),
10438                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10439                    if restart_window == "1.5s"
10440            ),
10441            "validator must surface the offending value",
10442        );
10443    }
10444
10445    // ── validate_code_paths — per-entry shape on :bibliotecas / :exe / :servicos ──
10446
10447    fn caixa_with_code_paths(bibliotecas: Vec<&str>, exe: Vec<&str>, servicos: Vec<&str>) -> Caixa {
10448        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10449        c.bibliotecas = bibliotecas.into_iter().map(String::from).collect();
10450        c.exe = exe.into_iter().map(String::from).collect();
10451        c.servicos = servicos.into_iter().map(String::from).collect();
10452        c
10453    }
10454
10455    #[test]
10456    fn validate_code_paths_accepts_canonical_template() {
10457        // The bare `Caixa::template` shape is the gate's identity element
10458        // on the canonical authoring shape — `:bibliotecas
10459        // ("lib/demo.lisp")` + empty `:exe` + empty `:servicos`. Pins
10460        // that the gate is non-disruptive against every existing caixa.
10461        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10462        c.validate_code_paths().unwrap();
10463    }
10464
10465    #[test]
10466    fn validate_code_paths_accepts_explicit_relative_paths_on_every_slot() {
10467        // Positive control sweep: a canonical-shaped path on every slot
10468        // passes. Mirrors the peer
10469        // `behavior::validate_every_slot_relative_is_ok` pin.
10470        let c = caixa_with_code_paths(
10471            vec!["lib/demo.lisp", "lib/helpers.lisp"],
10472            vec!["exe/demo", "exe/tool"],
10473            vec!["servicos/demo.computeunit.yaml"],
10474        );
10475        c.validate_code_paths().unwrap();
10476    }
10477
10478    #[test]
10479    fn validate_code_paths_accepts_all_empty_lists() {
10480        // The empty-list identity element: every Caixa with no declared
10481        // code paths trivially passes (Supervisor / Aplicacao kinds rely
10482        // on this — the OwnCode gate already rejected them before the
10483        // path-shape gate runs in the layout, but the validator itself
10484        // must accept the empty shape).
10485        let c = caixa_with_code_paths(vec![], vec![], vec![]);
10486        c.validate_code_paths().unwrap();
10487    }
10488
10489    #[test]
10490    fn validate_code_paths_rejects_empty_bibliotecas_entry() {
10491        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
10492        let err = c.validate_code_paths().unwrap_err();
10493        assert!(
10494            matches!(
10495                err,
10496                ManifestError::CodePathEmpty {
10497                    slot: ":bibliotecas"
10498                }
10499            ),
10500            "got {err:?}",
10501        );
10502    }
10503
10504    #[test]
10505    fn validate_code_paths_rejects_empty_exe_entry() {
10506        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
10507        let err = c.validate_code_paths().unwrap_err();
10508        assert!(
10509            matches!(err, ManifestError::CodePathEmpty { slot: ":exe" }),
10510            "got {err:?}",
10511        );
10512    }
10513
10514    #[test]
10515    fn validate_code_paths_rejects_empty_servicos_entry() {
10516        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
10517        let err = c.validate_code_paths().unwrap_err();
10518        assert!(
10519            matches!(err, ManifestError::CodePathEmpty { slot: ":servicos" }),
10520            "got {err:?}",
10521        );
10522    }
10523
10524    #[test]
10525    fn validate_code_paths_rejects_absolute_bibliotecas_entry() {
10526        // `:bibliotecas` has no `starts_with(<dir>)` fence downstream,
10527        // so an absolute path that resolves on disk silently passes the
10528        // layout's existence check — the canonical sandbox-escape on
10529        // the biblioteca axis.
10530        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10531        let err = c.validate_code_paths().unwrap_err();
10532        let ManifestError::CodePathAbsolute { slot, path } = err else {
10533            panic!("expected CodePathAbsolute, got {err:?}");
10534        };
10535        assert_eq!(slot, ":bibliotecas");
10536        assert_eq!(path, PathBuf::from("/etc/passwd"));
10537    }
10538
10539    #[test]
10540    fn validate_code_paths_rejects_absolute_exe_entry() {
10541        let c = caixa_with_code_paths(vec![], vec!["/usr/bin/env"], vec![]);
10542        let err = c.validate_code_paths().unwrap_err();
10543        let ManifestError::CodePathAbsolute { slot, path } = err else {
10544            panic!("expected CodePathAbsolute, got {err:?}");
10545        };
10546        assert_eq!(slot, ":exe");
10547        assert_eq!(path, PathBuf::from("/usr/bin/env"));
10548    }
10549
10550    #[test]
10551    fn validate_code_paths_rejects_absolute_servicos_entry() {
10552        let c = caixa_with_code_paths(vec![], vec![], vec!["/var/servicos/x.yaml"]);
10553        let err = c.validate_code_paths().unwrap_err();
10554        let ManifestError::CodePathAbsolute { slot, path } = err else {
10555            panic!("expected CodePathAbsolute, got {err:?}");
10556        };
10557        assert_eq!(slot, ":servicos");
10558        assert_eq!(path, PathBuf::from("/var/servicos/x.yaml"));
10559    }
10560
10561    #[test]
10562    fn validate_code_paths_rejects_parent_escape_bibliotecas_leading() {
10563        // Canonical "I want a lib from a sibling caixa" footgun on the
10564        // biblioteca axis. `:bibliotecas` has no `starts_with` fence
10565        // downstream, so a leading `..` traverses to the parent of the
10566        // caixa root with no diagnostic at layout time if the resolved
10567        // target exists.
10568        let c = caixa_with_code_paths(vec!["../sibling/x.lisp"], vec![], vec![]);
10569        let err = c.validate_code_paths().unwrap_err();
10570        let ManifestError::CodePathParentEscape { slot, path } = err else {
10571            panic!("expected CodePathParentEscape, got {err:?}");
10572        };
10573        assert_eq!(slot, ":bibliotecas");
10574        assert_eq!(path, PathBuf::from("../sibling/x.lisp"));
10575    }
10576
10577    #[test]
10578    fn validate_code_paths_rejects_parent_escape_exe_mid_path() {
10579        // Mid-path `..` defeats the layout's component-aware
10580        // `starts_with(exe_dir)` fence — `root.join("exe/../../escape")`
10581        // `starts_with(<root>/exe)` is true, but the canonical resolution
10582        // lives outside the caixa root. Caught regardless of where the
10583        // `..` sits — mirrors the peer
10584        // `behavior::validate_rejects_parent_escape_mid_path` pin.
10585        let c = caixa_with_code_paths(vec![], vec!["exe/../../escape"], vec![]);
10586        let err = c.validate_code_paths().unwrap_err();
10587        let ManifestError::CodePathParentEscape { slot, path } = err else {
10588            panic!("expected CodePathParentEscape, got {err:?}");
10589        };
10590        assert_eq!(slot, ":exe");
10591        assert_eq!(path, PathBuf::from("exe/../../escape"));
10592    }
10593
10594    #[test]
10595    fn validate_code_paths_rejects_parent_escape_servicos_trailing() {
10596        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/foo/../../escape.yaml"]);
10597        let err = c.validate_code_paths().unwrap_err();
10598        let ManifestError::CodePathParentEscape { slot, path } = err else {
10599            panic!("expected CodePathParentEscape, got {err:?}");
10600        };
10601        assert_eq!(slot, ":servicos");
10602        assert_eq!(path, PathBuf::from("servicos/foo/../../escape.yaml"));
10603    }
10604
10605    #[test]
10606    fn validate_code_paths_cross_slot_precedence_bibliotecas_before_exe_before_servicos() {
10607        // Cross-slot precedence pin: `:bibliotecas` → `:exe` →
10608        // `:servicos`. A manifest with malformed entries on all three
10609        // surfaces surfaces the `:bibliotecas` defect first, mirroring
10610        // the canonical declaration order
10611        // `Caixa::declared_foreign_code_slots` already establishes for
10612        // the foreign-code-slot diagnostic.
10613        let c = caixa_with_code_paths(vec![""], vec![""], vec![""]);
10614        let err = c.validate_code_paths().unwrap_err();
10615        assert!(
10616            matches!(
10617                err,
10618                ManifestError::CodePathEmpty {
10619                    slot: ":bibliotecas"
10620                }
10621            ),
10622            "got {err:?}",
10623        );
10624    }
10625
10626    #[test]
10627    fn validate_code_paths_within_slot_precedence_empty_before_absolute_before_parent_escape() {
10628        // Within-slot precedence pin: empty → absolute → parent-escape,
10629        // matching the [`PathShapeViolation`] arm-ordering every peer
10630        // `is_sandboxed_relative_path` caller follows (b0c8389
10631        // BehaviorSpec, 26da2c7 UpgradeInstruction::StateChange). A
10632        // `:bibliotecas` list whose first entry is empty *and* whose
10633        // later entries are absolute/parent-escape surfaces the empty
10634        // arm first, on the lexicographically-earliest offending entry.
10635        let c = caixa_with_code_paths(vec!["", "/etc/passwd", "../escape.lisp"], vec![], vec![]);
10636        let err = c.validate_code_paths().unwrap_err();
10637        assert!(
10638            matches!(
10639                err,
10640                ManifestError::CodePathEmpty {
10641                    slot: ":bibliotecas"
10642                }
10643            ),
10644            "got {err:?}",
10645        );
10646    }
10647
10648    #[test]
10649    fn validate_code_paths_first_offender_per_slot_wins() {
10650        // Within a single slot, the first declaration-order offender
10651        // surfaces — pins that the gate is left-to-right deterministic
10652        // (peer of every `*_first_collision_*` pin on duplicate gates).
10653        let c = caixa_with_code_paths(
10654            vec!["lib/ok.lisp", "/etc/escape", "../also-escape"],
10655            vec![],
10656            vec![],
10657        );
10658        let err = c.validate_code_paths().unwrap_err();
10659        let ManifestError::CodePathAbsolute { slot, path } = err else {
10660            panic!("expected CodePathAbsolute, got {err:?}");
10661        };
10662        assert_eq!(slot, ":bibliotecas");
10663        assert_eq!(path, PathBuf::from("/etc/escape"));
10664    }
10665
10666    #[test]
10667    fn validate_code_paths_diagnostic_carries_offending_slot_and_path() {
10668        // Diagnostic-shape pin (peer with
10669        // `nome_invalid_diagnostic_carries_offending_nome` /
10670        // `versao_invalid_diagnostic_carries_offending_versao`): the
10671        // error's Display surfaces both the offending `:slot` tag and
10672        // the offending path verbatim, so a `feira lint` run can render
10673        // the diagnostic without re-parsing.
10674        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10675        let rendered = c.validate_code_paths().unwrap_err().to_string();
10676        assert!(
10677            rendered.contains(":bibliotecas"),
10678            "diagnostic must name the offending slot: {rendered}",
10679        );
10680        assert!(
10681            rendered.contains("/etc/passwd"),
10682            "diagnostic must quote the offending path: {rendered}",
10683        );
10684    }
10685
10686    #[test]
10687    fn validate_code_paths_rejects_duplicate_bibliotecas_entry() {
10688        // Canonical copy-paste-the-wrong-file footgun on the biblioteca
10689        // axis. Without the gate `feira build` re-parses the same lib
10690        // twice, wasting work and silently masking the author's intent
10691        // to declare a *second* biblioteca.
10692        let c = caixa_with_code_paths(vec!["lib/demo.lisp", "lib/demo.lisp"], vec![], vec![]);
10693        let err = c.validate_code_paths().unwrap_err();
10694        let ManifestError::CodePathDuplicate { slot, path } = err else {
10695            panic!("expected CodePathDuplicate, got {err:?}");
10696        };
10697        assert_eq!(slot, ":bibliotecas");
10698        assert_eq!(path, PathBuf::from("lib/demo.lisp"));
10699    }
10700
10701    #[test]
10702    fn validate_code_paths_rejects_duplicate_exe_entry() {
10703        // Same footgun on the Binario surface. The future `caixa-flake`
10704        // emitter that materializes each `:exe` entry as a flake
10705        // `packages.<name>` derivation would collide on the duplicate
10706        // package key — surfaced here at the typed-validate layer with a
10707        // self-locating diagnostic instead.
10708        let c = caixa_with_code_paths(vec![], vec!["exe/cli", "exe/cli"], vec![]);
10709        let err = c.validate_code_paths().unwrap_err();
10710        let ManifestError::CodePathDuplicate { slot, path } = err else {
10711            panic!("expected CodePathDuplicate, got {err:?}");
10712        };
10713        assert_eq!(slot, ":exe");
10714        assert_eq!(path, PathBuf::from("exe/cli"));
10715    }
10716
10717    #[test]
10718    fn validate_code_paths_rejects_duplicate_servicos_entry() {
10719        // Same footgun on the Servico surface. The peer caixa-helm /
10720        // caixa-flux renderers refuse `:servicos.len() != 1` with the
10721        // narrower `UnsupportedServicoCount` diagnostic, but that
10722        // diagnostic surfaces "too many servicos" without naming
10723        // "duplicate entry" — the typed self-locating framing only lands
10724        // at this gate.
10725        let c = caixa_with_code_paths(
10726            vec![],
10727            vec![],
10728            vec![
10729                "servicos/demo.computeunit.yaml",
10730                "servicos/demo.computeunit.yaml",
10731            ],
10732        );
10733        let err = c.validate_code_paths().unwrap_err();
10734        let ManifestError::CodePathDuplicate { slot, path } = err else {
10735            panic!("expected CodePathDuplicate, got {err:?}");
10736        };
10737        assert_eq!(slot, ":servicos");
10738        assert_eq!(path, PathBuf::from("servicos/demo.computeunit.yaml"));
10739    }
10740
10741    #[test]
10742    fn validate_code_paths_accepts_same_path_across_slots() {
10743        // Per-list scope pin: a `:bibliotecas` entry that happens to
10744        // collide with an `:exe` or `:servicos` entry as a *string* is
10745        // not a duplicate by this gate (each list gets its own HashSet),
10746        // mirroring the peer `:deps` ↔ `:deps-dev` per-list scope
10747        // (a `:nome` present in both lists is a legitimate dev-vs-runtime
10748        // shape on the dep axis). The structural `starts_with(<exe |
10749        // servicos>_dir)` fence at layout time prevents the realistic
10750        // cross-slot collision case from existing on disk, but the gate's
10751        // per-list scope is correct independent of that downstream fence.
10752        let c = caixa_with_code_paths(
10753            vec!["lib/x.lisp"],
10754            vec!["exe/x"],
10755            vec!["servicos/x.computeunit.yaml"],
10756        );
10757        c.validate_code_paths().unwrap();
10758    }
10759
10760    #[test]
10761    fn validate_code_paths_duplicate_fires_after_structural_checks_on_same_slot() {
10762        // Within-slot ordering pin: structural defects (empty / absolute
10763        // / parent-escape) fire before the duplicate gate on the same
10764        // slot. A `:bibliotecas ("" "lib/x.lisp" "lib/x.lisp")` shape
10765        // surfaces the narrower `CodePathEmpty` for the empty entry
10766        // first, not the duplicate on the later pair — same arm-ordering
10767        // every peer per-list duplicate gate uses (`:etiquetas` 360a499,
10768        // `:autores` 86c769b, `:deps` 359fba5).
10769        let c = caixa_with_code_paths(vec!["", "lib/x.lisp", "lib/x.lisp"], vec![], vec![]);
10770        let err = c.validate_code_paths().unwrap_err();
10771        assert!(
10772            matches!(
10773                err,
10774                ManifestError::CodePathEmpty {
10775                    slot: ":bibliotecas"
10776                }
10777            ),
10778            "got {err:?}",
10779        );
10780    }
10781
10782    #[test]
10783    fn validate_code_paths_duplicate_in_bibliotecas_fires_before_duplicate_in_exe() {
10784        // Cross-slot ordering pin on the duplicate arm: `:bibliotecas`
10785        // duplicates surface before `:exe` duplicates, matching the
10786        // canonical `:bibliotecas` → `:exe` → `:servicos` declaration
10787        // order every peer per-slot diagnostic on this surface follows.
10788        let c = caixa_with_code_paths(
10789            vec!["lib/x.lisp", "lib/x.lisp"],
10790            vec!["exe/y", "exe/y"],
10791            vec![],
10792        );
10793        let err = c.validate_code_paths().unwrap_err();
10794        let ManifestError::CodePathDuplicate { slot, path } = err else {
10795            panic!("expected CodePathDuplicate, got {err:?}");
10796        };
10797        assert_eq!(slot, ":bibliotecas");
10798        assert_eq!(path, PathBuf::from("lib/x.lisp"));
10799    }
10800
10801    #[test]
10802    fn validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path() {
10803        // Diagnostic-shape pin (peer with
10804        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
10805        // on the structural arm): the duplicate-arm Display surfaces both
10806        // the offending `:slot` tag and the offending path verbatim, so a
10807        // `feira lint` run can render the diagnostic without re-parsing.
10808        let c = caixa_with_code_paths(
10809            vec![],
10810            vec![],
10811            vec![
10812                "servicos/demo.computeunit.yaml",
10813                "servicos/demo.computeunit.yaml",
10814            ],
10815        );
10816        let rendered = c.validate_code_paths().unwrap_err().to_string();
10817        assert!(
10818            rendered.contains(":servicos"),
10819            "diagnostic must name the offending slot: {rendered}",
10820        );
10821        assert!(
10822            rendered.contains("servicos/demo.computeunit.yaml"),
10823            "diagnostic must quote the offending path: {rendered}",
10824        );
10825    }
10826
10827    // ── validate_code_paths — `.lisp` extension gate on :bibliotecas ──
10828    //
10829    // The lifted [`crate::render::is_lisp_extension`] predicate (33cc830)
10830    // now gates `:bibliotecas` entries on the tatara-lisp-source file-type
10831    // contract. The `feira build` loop (`caixa-feira/src/cmd/build.rs:33`)
10832    // reads every declared `:bibliotecas` entry through `tatara_lisp::read`
10833    // at parse time — the same downstream consumer the peer `:behavior
10834    // :on-*` (c97815a, [`crate::BehaviorError::NonLispExtension`]) and
10835    // `:upgrade-from :state-change :script` (33cc830,
10836    // [`crate::UpgradeError::NonLispExtensionScript`]) axes route through.
10837    // `:exe` and `:servicos` are deliberately excluded — `:exe` is the
10838    // nix-built executable surface (`"exe/<name>"` shape per the canonical
10839    // [`crate::LayoutError::ExeOutsideDir`] error message and every
10840    // in-tree `caixa_with_code_paths` positive control), and `:servicos`
10841    // is the `.computeunit.yaml` ComputeUnit-CR axis.
10842
10843    #[test]
10844    fn validate_code_paths_rejects_no_extension_bibliotecas_entry() {
10845        // Canonical "I dragged the wrong file from the workspace tree"
10846        // footgun on the biblioteca axis. Without the gate `feira build`
10847        // hands the extensionless path to `tatara_lisp::read` and fails
10848        // with a parser-shaped diagnostic far from the source caixa.lisp,
10849        // with no field naming the offending `:bibliotecas` entry.
10850        for relpath in ["lib/demo", "demo", "lib/handlers/inner"] {
10851            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10852            let err = c.validate_code_paths().unwrap_err();
10853            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10854                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10855            };
10856            assert_eq!(slot, ":bibliotecas");
10857            assert_eq!(path, PathBuf::from(relpath));
10858        }
10859    }
10860
10861    #[test]
10862    fn validate_code_paths_rejects_wrong_extension_bibliotecas_entry() {
10863        // Wrong-extension sweep across common authoring footguns. Same
10864        // sweep posture as the peer
10865        // `behavior::validate_rejects_wrong_extension` (c97815a) and
10866        // `upgrade::tests::state_change_rejects_wrong_extension_script`
10867        // (33cc830) cases.
10868        for relpath in [
10869            "lib/demo.rs",
10870            "lib/demo.txt",
10871            "lib/demo.md",
10872            "lib/demo.json",
10873            "lib/demo.yaml",
10874            "lib/demo.toml",
10875            "lib/demo.lisp.bak",
10876            "lib/demo.lispx",
10877            "lib/demo.lis",
10878        ] {
10879            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10880            let err = c.validate_code_paths().unwrap_err();
10881            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10882                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10883            };
10884            assert_eq!(slot, ":bibliotecas");
10885            assert_eq!(path, PathBuf::from(relpath));
10886        }
10887    }
10888
10889    #[test]
10890    fn validate_code_paths_rejects_case_folded_extension_bibliotecas_entry() {
10891        // Case-sensitivity sweep — pins the strict lowercase `.lisp`
10892        // contract. An uppercase `.LISP` shape that the layout's existence
10893        // check would (case-insensitively, on case-insensitive volumes)
10894        // match the on-disk file still mismatches the canonical form the
10895        // codec emits, breaking the THEORY.md §V.2.7 render-determinism
10896        // contract. Mirrors the peer
10897        // `behavior::validate_rejects_case_folded_extension` (c97815a) and
10898        // `upgrade::tests::state_change_rejects_case_folded_extension_script`
10899        // (33cc830) sweeps.
10900        for relpath in [
10901            "lib/demo.LISP",
10902            "lib/demo.Lisp",
10903            "lib/demo.LiSp",
10904            "lib/demo.lISP",
10905        ] {
10906            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10907            let err = c.validate_code_paths().unwrap_err();
10908            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10909                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10910            };
10911            assert_eq!(slot, ":bibliotecas");
10912            assert_eq!(path, PathBuf::from(relpath));
10913        }
10914    }
10915
10916    #[test]
10917    fn validate_code_paths_accepts_canonical_lisp_shapes() {
10918        // Positive-control sweep through every canonical authoring shape
10919        // every in-tree fixture and the `Caixa::template` scaffold use.
10920        // Mirrors the peer `behavior::validate_accepts_canonical_lisp_paths`
10921        // (c97815a) and the lifted predicate's own
10922        // `is_lisp_extension_accepts_canonical_shapes` sweep in render.rs
10923        // (33cc830).
10924        for relpath in [
10925            "lib/demo.lisp",
10926            "lib/handlers.lisp",
10927            "lib/migrations/v01-to-v02.lisp",
10928            "demo.lisp",
10929            "a.lisp",
10930            "./lib/demo.lisp",
10931            "lib/./handlers.lisp",
10932            "lib/migrations/v.0.1.lisp",
10933        ] {
10934            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10935            c.validate_code_paths()
10936                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
10937        }
10938    }
10939
10940    #[test]
10941    fn validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos() {
10942        // The file-type gate is per-slot — only `:bibliotecas` carries the
10943        // tatara-lisp-source contract. An extensionless `:exe` entry
10944        // (`exe/demo`) and a `.computeunit.yaml` `:servicos` entry are the
10945        // canonical shapes every in-tree fixture uses, and must continue
10946        // to pass validate. Pins that a future tightening that broadens
10947        // the `.lisp` gate to either axis surfaces as a test failure
10948        // rather than as a silent breaking change to existing valid
10949        // manifests.
10950        let c = caixa_with_code_paths(
10951            vec![],
10952            vec!["exe/demo", "exe/tool"],
10953            vec!["servicos/demo.computeunit.yaml"],
10954        );
10955        c.validate_code_paths().unwrap();
10956    }
10957
10958    #[test]
10959    fn validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension() {
10960        // Cross-arm precedence pin: a `:bibliotecas` entry that is *both*
10961        // sandbox-escaping and non-`.lisp` surfaces the more fundamental
10962        // sandbox-shape diagnostic first (the `.lisp` remediation would
10963        // be misleading when the offending path can never resolve under
10964        // the caixa root anyway). Mirrors the peer
10965        // `EmptyPath` → `AbsolutePath` → `ParentEscape` → `NonLispExtension`
10966        // ordering on `:behavior :on-*` (c97815a) and `EmptyScript` →
10967        // `AbsoluteScript` → `ParentEscapeScript` → `NonLispExtensionScript`
10968        // on `:upgrade-from :state-change :script` (33cc830).
10969        //
10970        // Empty wins (the strictly-smaller-scope structural arm).
10971        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
10972        assert!(
10973            matches!(
10974                c.validate_code_paths().unwrap_err(),
10975                ManifestError::CodePathEmpty {
10976                    slot: ":bibliotecas"
10977                }
10978            ),
10979            "empty must win over non-lisp-extension",
10980        );
10981        // Absolute wins (the path can't resolve under the caixa root).
10982        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10983        let err = c.validate_code_paths().unwrap_err();
10984        let ManifestError::CodePathAbsolute { slot, .. } = err else {
10985            panic!("absolute must win over non-lisp-extension, got {err:?}");
10986        };
10987        assert_eq!(slot, ":bibliotecas");
10988        // ParentEscape wins (the path escapes the caixa root).
10989        let c = caixa_with_code_paths(vec!["../sibling/x.txt"], vec![], vec![]);
10990        let err = c.validate_code_paths().unwrap_err();
10991        let ManifestError::CodePathParentEscape { slot, .. } = err else {
10992            panic!("parent-escape must win over non-lisp-extension, got {err:?}");
10993        };
10994        assert_eq!(slot, ":bibliotecas");
10995    }
10996
10997    #[test]
10998    fn validate_code_paths_non_lisp_extension_precedes_duplicate() {
10999        // Within-slot precedence pin: the per-entry file-type shape gate
11000        // fires before the cross-entry duplicate gate, so the narrower
11001        // structural defect dominates the uniqueness diagnostic. A
11002        // `("lib/x.txt" "lib/x.txt")` shape surfaces
11003        // `CodePathNonLispExtension` on the first entry rather than
11004        // `CodePathDuplicate` on the pair — same posture every per-entry
11005        // shape-gate-precedes-duplicate cascade follows on this surface
11006        // (the empty / absolute / parent-escape arms already precede the
11007        // duplicate arm; the lifted file-type arm joins that set).
11008        let c = caixa_with_code_paths(vec!["lib/x.txt", "lib/x.txt"], vec![], vec![]);
11009        let err = c.validate_code_paths().unwrap_err();
11010        let ManifestError::CodePathNonLispExtension { slot, path } = err else {
11011            panic!("expected CodePathNonLispExtension, got {err:?}");
11012        };
11013        assert_eq!(slot, ":bibliotecas");
11014        assert_eq!(path, PathBuf::from("lib/x.txt"));
11015    }
11016
11017    #[test]
11018    fn validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path() {
11019        // Diagnostic-shape pin (peer with
11020        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
11021        // on the sandbox-shape arms and
11022        // `validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path`
11023        // on the duplicate arm): the file-type-arm Display surfaces both
11024        // the offending `:slot` tag, the offending path verbatim, and the
11025        // expected `.lisp` extension named in the remediation text, so a
11026        // `feira lint` run can render the diagnostic without re-parsing.
11027        let c = caixa_with_code_paths(vec!["lib/demo.rs"], vec![], vec![]);
11028        let rendered = c.validate_code_paths().unwrap_err().to_string();
11029        assert!(
11030            rendered.contains(":bibliotecas"),
11031            "diagnostic must name the offending slot: {rendered}",
11032        );
11033        assert!(
11034            rendered.contains("lib/demo.rs"),
11035            "diagnostic must quote the offending path: {rendered}",
11036        );
11037        assert!(
11038            rendered.contains(".lisp"),
11039            "diagnostic must name the expected extension: {rendered}",
11040        );
11041    }
11042
11043    // ── validate_code_paths — `.computeunit.yaml` compound-suffix gate on :servicos ──
11044    //
11045    // The lifted [`crate::render::is_computeunit_yaml_extension`] predicate
11046    // now gates `:servicos` entries on the ComputeUnit-CR YAML file-type
11047    // contract. The peer caixa-helm / caixa-flux renderers consume each
11048    // `:servicos` entry through `serde_yaml::from_str` as a typed
11049    // `ComputeUnit` CR — same downstream-consumer-shape lift as the peer
11050    // `:bibliotecas` `.lisp` gate (64772a9), here on the compound-suffix
11051    // axis `Path::extension` can't express on its own.
11052
11053    #[test]
11054    fn validate_code_paths_rejects_no_extension_servicos_entry() {
11055        // Canonical "I dragged the wrong file from the workspace tree"
11056        // footgun on the Servico axis. Without the gate the peer
11057        // caixa-helm / caixa-flux renderers hand the extensionless path
11058        // to `serde_yaml::from_str` and fail with a parser-shaped
11059        // diagnostic far from the source caixa.lisp, with no field
11060        // naming the offending `:servicos` entry.
11061        for relpath in ["servicos/demo", "demo", "servicos/sub/nested"] {
11062            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11063            let err = c.validate_code_paths().unwrap_err();
11064            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11065                panic!(
11066                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11067                     got {err:?}"
11068                );
11069            };
11070            assert_eq!(slot, ":servicos");
11071            assert_eq!(path, PathBuf::from(relpath));
11072        }
11073    }
11074
11075    #[test]
11076    fn validate_code_paths_rejects_wrong_extension_servicos_entry() {
11077        // Wrong-extension sweep across common authoring footguns on the
11078        // Servico axis. Bare `.yaml` is the canonical "I forgot the
11079        // `.computeunit` segment" typo; the off-by-one-segment shapes
11080        // (`.computeunit-yaml` / `.computeunit_yaml`) silently pass the
11081        // bare `Path::extension` view but mismatch the typed compound
11082        // suffix the renderers' `serde_yaml::from_str` consumer demands.
11083        // Same sweep-posture as the peer
11084        // `validate_code_paths_rejects_wrong_extension_bibliotecas_entry`
11085        // (64772a9) on the sibling tatara-lisp-source axis.
11086        for relpath in [
11087            "servicos/demo.yaml",
11088            "servicos/demo.yml",
11089            "servicos/demo.json",
11090            "servicos/demo.toml",
11091            "servicos/demo.txt",
11092            "servicos/demo.computeunit.yaml.bak",
11093            "servicos/demo.computeunit.yam",
11094            "servicos/demo.computeunit",
11095            "servicos/demo-computeunit.yaml",
11096            "servicos/demo_computeunit.yaml",
11097        ] {
11098            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11099            let err = c.validate_code_paths().unwrap_err();
11100            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11101                panic!(
11102                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11103                     got {err:?}"
11104                );
11105            };
11106            assert_eq!(slot, ":servicos");
11107            assert_eq!(path, PathBuf::from(relpath));
11108        }
11109    }
11110
11111    #[test]
11112    fn validate_code_paths_rejects_case_folded_extension_servicos_entry() {
11113        // Case-sensitivity sweep — pins the strict lowercase
11114        // `.computeunit.yaml` contract. A case-folded shape that the
11115        // layout's existence check would (case-insensitively, on
11116        // case-insensitive volumes) match the on-disk file still
11117        // mismatches the canonical form the codec emits, breaking the
11118        // THEORY.md §V.2.7 render-determinism contract. Mirrors the peer
11119        // `validate_code_paths_rejects_case_folded_extension_bibliotecas_entry`
11120        // (64772a9) sweep on the sibling tatara-lisp-source axis.
11121        for relpath in [
11122            "servicos/demo.ComputeUnit.yaml",
11123            "servicos/demo.COMPUTEUNIT.yaml",
11124            "servicos/demo.computeunit.YAML",
11125            "servicos/demo.computeunit.Yaml",
11126            "servicos/demo.COMPUTEUNIT.YAML",
11127        ] {
11128            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11129            let err = c.validate_code_paths().unwrap_err();
11130            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11131                panic!(
11132                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11133                     got {err:?}"
11134                );
11135            };
11136            assert_eq!(slot, ":servicos");
11137            assert_eq!(path, PathBuf::from(relpath));
11138        }
11139    }
11140
11141    #[test]
11142    fn validate_code_paths_rejects_empty_stem_servicos_entry() {
11143        // Degenerate hidden-file shape: a file name exactly equal to the
11144        // suffix (`.computeunit.yaml` — no stem preceding the suffix) is
11145        // the structural "Servico declared with no identity" footgun.
11146        // The substrate identifies each ComputeUnit by the file-stem
11147        // segment that precedes `.computeunit.yaml` (the rendered
11148        // `lareira-<stem>` Helm chart, the per-Servico `metadata.name`,
11149        // the M3 `:contratos` membership lookup), so an empty stem
11150        // leaves the Servico unidentifiable. Pinned at the typed-axis
11151        // level so a future regression that drops the `name.len() >
11152        // SUFFIX.len()` bound at the predicate surfaces here, not
11153        // piecemeal as a `lareira-` chart-name collision at render time.
11154        for relpath in ["servicos/.computeunit.yaml"] {
11155            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11156            let err = c.validate_code_paths().unwrap_err();
11157            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11158                panic!(
11159                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11160                     got {err:?}"
11161                );
11162            };
11163            assert_eq!(slot, ":servicos");
11164            assert_eq!(path, PathBuf::from(relpath));
11165        }
11166    }
11167
11168    #[test]
11169    fn validate_code_paths_accepts_canonical_computeunit_yaml_shapes() {
11170        // Positive-control sweep through every canonical authoring shape
11171        // every in-tree fixture and the `Caixa::template` scaffold use.
11172        // Mirrors the peer
11173        // `validate_code_paths_accepts_canonical_lisp_shapes` (64772a9)
11174        // and the lifted predicate's own
11175        // `computeunit_yaml_extension_accepts_canonical_shapes` sweep in
11176        // render.rs.
11177        for relpath in [
11178            "servicos/demo.computeunit.yaml",
11179            "servicos/hello-rio.computeunit.yaml",
11180            "servicos/my-service.computeunit.yaml",
11181            "servicos/a.computeunit.yaml",
11182            "./servicos/demo.computeunit.yaml",
11183            "servicos/./demo.computeunit.yaml",
11184            "servicos/sub/nested.computeunit.yaml",
11185            "servicos/v0.1.computeunit.yaml",
11186        ] {
11187            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11188            c.validate_code_paths()
11189                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
11190        }
11191    }
11192
11193    #[test]
11194    fn validate_code_paths_non_computeunit_yaml_extension_does_not_fire_on_bibliotecas_or_exe() {
11195        // The file-type gate is per-slot — only `:servicos` carries the
11196        // ComputeUnit-CR YAML contract. A canonical `.lisp` `:bibliotecas`
11197        // entry and an extensionless `:exe` entry are the canonical
11198        // shapes every in-tree fixture uses, and must continue to pass
11199        // validate. Peer of
11200        // `validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos`
11201        // (64772a9) — together pin that the typed
11202        // [`CodePathFileType`] dispatch is exhaustively per-slot, with no
11203        // cross-axis leakage in either direction.
11204        let c = caixa_with_code_paths(
11205            vec!["lib/demo.lisp"],
11206            vec!["exe/demo", "exe/tool"],
11207            vec!["servicos/demo.computeunit.yaml"],
11208        );
11209        c.validate_code_paths().unwrap();
11210    }
11211
11212    #[test]
11213    fn validate_code_paths_sandbox_shape_arms_precede_non_computeunit_yaml_extension() {
11214        // Cross-arm precedence pin: a `:servicos` entry that is *both*
11215        // sandbox-escaping and wrong-extension surfaces the more
11216        // fundamental sandbox-shape diagnostic first (the
11217        // `.computeunit.yaml` remediation would be misleading when the
11218        // offending path can never resolve under the caixa root
11219        // anyway). Mirrors the peer
11220        // `validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension`
11221        // (64772a9) ordering on the sibling `:bibliotecas` axis and the
11222        // peer `EmptyPath` → `AbsolutePath` → `ParentEscape` →
11223        // `NonComputeUnitYamlExtension` arm-ordering the dispatch
11224        // table establishes.
11225        //
11226        // Empty wins (the strictly-smaller-scope structural arm).
11227        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
11228        assert!(
11229            matches!(
11230                c.validate_code_paths().unwrap_err(),
11231                ManifestError::CodePathEmpty { slot: ":servicos" }
11232            ),
11233            "empty must win over non-computeunit-yaml-extension",
11234        );
11235        // Absolute wins (the path can't resolve under the caixa root).
11236        let c = caixa_with_code_paths(vec![], vec![], vec!["/etc/foo.yaml"]);
11237        let err = c.validate_code_paths().unwrap_err();
11238        let ManifestError::CodePathAbsolute { slot, .. } = err else {
11239            panic!("absolute must win over non-computeunit-yaml-extension, got {err:?}");
11240        };
11241        assert_eq!(slot, ":servicos");
11242        // ParentEscape wins (the path escapes the caixa root).
11243        let c = caixa_with_code_paths(vec![], vec![], vec!["../sibling/x.yaml"]);
11244        let err = c.validate_code_paths().unwrap_err();
11245        let ManifestError::CodePathParentEscape { slot, .. } = err else {
11246            panic!("parent-escape must win over non-computeunit-yaml-extension, got {err:?}");
11247        };
11248        assert_eq!(slot, ":servicos");
11249    }
11250
11251    #[test]
11252    fn validate_code_paths_non_computeunit_yaml_extension_precedes_duplicate() {
11253        // Within-slot precedence pin: the per-entry file-type shape gate
11254        // fires before the cross-entry duplicate gate, so the narrower
11255        // structural defect dominates the uniqueness diagnostic. A
11256        // `("servicos/x.yaml" "servicos/x.yaml")` shape surfaces
11257        // `CodePathNonComputeUnitYamlExtension` on the first entry
11258        // rather than `CodePathDuplicate` on the pair — same posture
11259        // every per-entry shape-gate-precedes-duplicate cascade follows
11260        // on this surface, peer of the 64772a9 `:bibliotecas`
11261        // `("lib/x.txt" "lib/x.txt")` ordering.
11262        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/x.yaml", "servicos/x.yaml"]);
11263        let err = c.validate_code_paths().unwrap_err();
11264        let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11265            panic!("expected CodePathNonComputeUnitYamlExtension, got {err:?}");
11266        };
11267        assert_eq!(slot, ":servicos");
11268        assert_eq!(path, PathBuf::from("servicos/x.yaml"));
11269    }
11270
11271    #[test]
11272    fn validate_code_paths_non_computeunit_yaml_extension_diagnostic_carries_offending_slot_and_path()
11273     {
11274        // Diagnostic-shape pin (peer with
11275        // `validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path`
11276        // on the sibling tatara-lisp-source axis): the file-type-arm
11277        // Display surfaces both the offending `:slot` tag, the
11278        // offending path verbatim, and the expected
11279        // `.computeunit.yaml` compound suffix named in the remediation
11280        // text, so a `feira lint` run can render the diagnostic without
11281        // re-parsing.
11282        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.yaml"]);
11283        let rendered = c.validate_code_paths().unwrap_err().to_string();
11284        assert!(
11285            rendered.contains(":servicos"),
11286            "diagnostic must name the offending slot: {rendered}",
11287        );
11288        assert!(
11289            rendered.contains("servicos/demo.yaml"),
11290            "diagnostic must quote the offending path: {rendered}",
11291        );
11292        assert!(
11293            rendered.contains(".computeunit.yaml"),
11294            "diagnostic must name the expected compound suffix: {rendered}",
11295        );
11296    }
11297
11298    // ── validate_etiquetas — universal-axis registry-search-tag shape ──
11299
11300    fn caixa_with_etiquetas(etiquetas: Vec<&str>) -> Caixa {
11301        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11302        c.etiquetas = etiquetas.into_iter().map(String::from).collect();
11303        c
11304    }
11305
11306    #[test]
11307    fn validate_etiquetas_accepts_empty_list() {
11308        // The empty-list identity: every caixa with no declared tags
11309        // trivially passes — `Caixa::template` emits `:etiquetas ()`,
11310        // so the gate is non-disruptive against every existing manifest.
11311        let c = caixa_with_etiquetas(vec![]);
11312        c.validate_etiquetas().unwrap();
11313    }
11314
11315    #[test]
11316    fn validate_etiquetas_accepts_canonical_forms() {
11317        // Positive control sweep: a canonical-shaped non-empty distinct
11318        // tag list passes, mirroring the example checkout-aplicacao
11319        // (`:etiquetas ("example" "aplicacao" "mesh" "ecommerce" "demo")`)
11320        // and the hello-rio fixture (`("hello-world" "wasm" "rust")`).
11321        let c = caixa_with_etiquetas(vec!["example", "aplicacao", "mesh", "ecommerce", "demo"]);
11322        c.validate_etiquetas().unwrap();
11323    }
11324
11325    #[test]
11326    fn validate_etiquetas_rejects_empty_entry() {
11327        // Canonical paste-from-blank-doc footgun. Without the gate the
11328        // empty entry rendered as `keywords: [""]` in `Chart.yaml`, a
11329        // no-op tag indexing nothing in the future caixa-registry.
11330        let c = caixa_with_etiquetas(vec![""]);
11331        let err = c.validate_etiquetas().unwrap_err();
11332        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11333    }
11334
11335    #[test]
11336    fn validate_etiquetas_rejects_duplicate_entry() {
11337        // Canonical copy-paste-the-wrong-tag footgun. Without the gate
11338        // the duplicate was silently dedup'd by caixa-helm's BTreeSet
11339        // collect at chart render — a "second wins / one silently
11340        // disappears" shape divergent from every peer typed-graph set
11341        // gate. The duplicate-arm names the offending tag verbatim.
11342        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
11343        let err = c.validate_etiquetas().unwrap_err();
11344        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
11345            panic!("expected EtiquetaDuplicate, got {err:?}");
11346        };
11347        assert_eq!(etiqueta, "demo");
11348    }
11349
11350    #[test]
11351    fn validate_etiquetas_empty_takes_precedence_over_duplicate() {
11352        // Empty-first cascade pin: `("" "demo" "demo")` surfaces
11353        // `EtiquetaEmpty` not `EtiquetaDuplicate` — the narrower
11354        // structural "this entry has no value" defect dominates the
11355        // cross-entry uniqueness diagnostic. Mirrors the peer
11356        // empty-before-duplicate cascades on `:caracteristicas`
11357        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
11358        // fc3b4d5) and `:membros :caixa` (`MembroCaixaEmpty` before
11359        // `MembroDuplicate`).
11360        let c = caixa_with_etiquetas(vec!["", "demo", "demo"]);
11361        let err = c.validate_etiquetas().unwrap_err();
11362        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11363    }
11364
11365    #[test]
11366    fn validate_etiquetas_duplicate_reports_first_collision() {
11367        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
11368        // duplicate (the lexicographically-earliest offending position
11369        // — the second `"a"` at index 2 collides with the first `"a"`
11370        // at index 0), not the later `"b"` collision at index 3,
11371        // peer with every other first-collision diagnostic posture on
11372        // this surface (`validate_load_singularity_reports_first_collision`,
11373        // `validate_cleanup_singularity_reports_first_collision`).
11374        let c = caixa_with_etiquetas(vec!["a", "b", "a", "b"]);
11375        let err = c.validate_etiquetas().unwrap_err();
11376        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
11377            panic!("expected EtiquetaDuplicate, got {err:?}");
11378        };
11379        assert_eq!(etiqueta, "a");
11380    }
11381
11382    #[test]
11383    fn validate_etiquetas_case_sensitive() {
11384        // Case-sensitivity pin: `("Foo" "foo")` is two distinct entries,
11385        // mirroring the peer `:membros :caixa` / `:children :caixa`
11386        // exact-string-match discipline. The shape gate this routine
11387        // landed (`is_chart_keyword_shape`, Cargo crates.io keyword
11388        // grammar) accepts mixed case — crates.io's keyword rule is
11389        // "case-insensitive" at the index layer but admits mixed case
11390        // at the entry layer (the canonical Helm chart `keywords:`
11391        // shape is lowercase by convention, but the grammar admits
11392        // uppercase). Case-sensitivity at the duplicate-set layer
11393        // remains structural — two distinct strings are two distinct
11394        // entries.
11395        let c = caixa_with_etiquetas(vec!["Foo", "foo"]);
11396        c.validate_etiquetas().unwrap();
11397    }
11398
11399    #[test]
11400    fn validate_etiquetas_diagnostic_carries_offending_tag() {
11401        // Diagnostic-shape pin (peer with
11402        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`):
11403        // the error's Display surfaces the offending tag verbatim, so a
11404        // `feira lint` run can render the diagnostic without re-parsing
11405        // and the author can grep their caixa.lisp for the offending
11406        // value.
11407        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
11408        let rendered = c.validate_etiquetas().unwrap_err().to_string();
11409        assert!(
11410            rendered.contains(":etiquetas"),
11411            "diagnostic must name the offending slot: {rendered}",
11412        );
11413        assert!(
11414            rendered.contains("demo"),
11415            "diagnostic must quote the offending tag: {rendered}",
11416        );
11417    }
11418
11419    #[test]
11420    fn validate_etiquetas_rejects_leading_whitespace_entry() {
11421        // Canonical paste-from-aligned-doc footgun. Without the shape
11422        // gate `" mesh"` silently passed validate and landed as a
11423        // YAML plain-style scalar with leading whitespace in the
11424        // rendered Chart.yaml `keywords:` array — every YAML 1.2
11425        // dumper trims leading whitespace from plain-style scalars,
11426        // so the authored space round-tripped inconsistently back
11427        // through `caixa.lisp`. Mirrors the peer
11428        // `validate_autores_rejects_leading_whitespace_entry`.
11429        let c = caixa_with_etiquetas(vec![" mesh"]);
11430        let err = c.validate_etiquetas().unwrap_err();
11431        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11432            panic!("expected EtiquetaInvalid, got {err:?}");
11433        };
11434        assert_eq!(etiqueta, " mesh");
11435        assert!(reason.contains("whitespace"), "got: {reason}");
11436    }
11437
11438    #[test]
11439    fn validate_etiquetas_rejects_embedded_newline_entry() {
11440        // Canonical paste-from-multiline-doc footgun — the author
11441        // pasted a multi-tag block into one `:etiquetas` entry
11442        // instead of splitting into one entry per tag. Without the
11443        // shape gate `"mesh\nhttp"` silently passed validate and
11444        // landed as a YAML-illegal multi-line scalar in the rendered
11445        // Chart.yaml `keywords:` array.
11446        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
11447        let err = c.validate_etiquetas().unwrap_err();
11448        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11449            panic!("expected EtiquetaInvalid, got {err:?}");
11450        };
11451        assert_eq!(etiqueta, "mesh\nhttp");
11452        assert!(reason.contains("newline"), "got: {reason}");
11453    }
11454
11455    #[test]
11456    fn validate_etiquetas_rejects_embedded_comma_entry() {
11457        // Canonical CSV-list-separator-confusion footgun: the author
11458        // confused the CSV-style separator convention with the
11459        // `:etiquetas` list grammar. Without the shape gate
11460        // `"mesh,http,grpc"` silently passed validate and landed as a
11461        // single malformed search tag in the rendered Chart.yaml
11462        // `keywords:` array — Artifact Hub's keyword index would
11463        // either silently drop the tag or index it as
11464        // `mesh,http,grpc` instead of three separate tags.
11465        let c = caixa_with_etiquetas(vec!["mesh,http,grpc"]);
11466        let err = c.validate_etiquetas().unwrap_err();
11467        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11468            panic!("expected EtiquetaInvalid, got {err:?}");
11469        };
11470        assert_eq!(etiqueta, "mesh,http,grpc");
11471        assert!(reason.contains('`'), "got: {reason}");
11472        assert!(reason.contains(','), "got: {reason}");
11473    }
11474
11475    #[test]
11476    fn validate_etiquetas_rejects_embedded_slash_entry() {
11477        // Canonical path-separator-confusion footgun: the author
11478        // confused namespace-path notation with the keyword grammar.
11479        let c = caixa_with_etiquetas(vec!["caixa/servico"]);
11480        let err = c.validate_etiquetas().unwrap_err();
11481        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11482            panic!("expected EtiquetaInvalid, got {err:?}");
11483        };
11484        assert_eq!(etiqueta, "caixa/servico");
11485        assert!(reason.contains('/'), "got: {reason}");
11486    }
11487
11488    #[test]
11489    fn validate_etiquetas_rejects_leading_digit_entry() {
11490        // Canonical paste-from-numbered-list footgun: the author
11491        // copied `1. mesh` from a numbered doc and the `1` leaked
11492        // into the tag.
11493        let c = caixa_with_etiquetas(vec!["1mesh"]);
11494        let err = c.validate_etiquetas().unwrap_err();
11495        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11496            panic!("expected EtiquetaInvalid, got {err:?}");
11497        };
11498        assert_eq!(etiqueta, "1mesh");
11499        assert!(reason.contains("digit"), "got: {reason}");
11500    }
11501
11502    #[test]
11503    fn validate_etiquetas_rejects_leading_hyphen_entry() {
11504        // Canonical kebab-leak footgun.
11505        let c = caixa_with_etiquetas(vec!["-foo"]);
11506        let err = c.validate_etiquetas().unwrap_err();
11507        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11508            panic!("expected EtiquetaInvalid, got {err:?}");
11509        };
11510        assert_eq!(etiqueta, "-foo");
11511        assert!(reason.contains('-'), "got: {reason}");
11512    }
11513
11514    #[test]
11515    fn validate_etiquetas_rejects_non_ascii_entry() {
11516        // Canonical paste-from-Unicode-doc footgun. Every legitimate
11517        // search tag is strict ASCII; raw non-ASCII silently
11518        // round-trips inconsistently across NFC/NFD normalization on
11519        // APFS / case-folding filesystems and breaks the Artifact Hub
11520        // keyword search index lookup.
11521        let c = caixa_with_etiquetas(vec!["café"]);
11522        let err = c.validate_etiquetas().unwrap_err();
11523        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11524            panic!("expected EtiquetaInvalid, got {err:?}");
11525        };
11526        assert_eq!(etiqueta, "café");
11527        assert!(reason.contains("non-ASCII"), "got: {reason}");
11528    }
11529
11530    #[test]
11531    fn validate_etiquetas_rejects_period_entry() {
11532        // Canonical namespace-confusion / version-suffix footgun
11533        // (`"http.1"` / `"v1.0"`): Cargo's crates.io keyword grammar
11534        // excludes `.` from the continuation set even though the
11535        // sibling `:caracteristicas` axis (Cargo's feature-name
11536        // grammar) admits it. Tighter than the sibling axis, peer
11537        // with Cargo's own crates.io keyword shape.
11538        let c = caixa_with_etiquetas(vec!["http.1"]);
11539        let err = c.validate_etiquetas().unwrap_err();
11540        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11541            panic!("expected EtiquetaInvalid, got {err:?}");
11542        };
11543        assert_eq!(etiqueta, "http.1");
11544        assert!(reason.contains('.'), "got: {reason}");
11545    }
11546
11547    #[test]
11548    fn validate_etiquetas_empty_takes_precedence_over_shape() {
11549        // Per-entry empty-first cascade pin: an entry that is both
11550        // empty *and* shape-invalid surfaces `EtiquetaEmpty` (the
11551        // narrower "this entry has no value" structural defect
11552        // dominates the broader shape-predicate diagnostic). The
11553        // empty arm fires before the shape predicate is consulted,
11554        // mirroring the peer `validate_autores_empty_takes_precedence_over_shape`
11555        // cascade established on the sibling universal-axis Vec<String>
11556        // surface.
11557        let c = caixa_with_etiquetas(vec![""]);
11558        let err = c.validate_etiquetas().unwrap_err();
11559        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11560    }
11561
11562    #[test]
11563    fn validate_etiquetas_shape_takes_precedence_over_duplicate() {
11564        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
11565        // entry that is malformed surfaces `EtiquetaInvalid` even when
11566        // a later entry would have collided on duplicate. The
11567        // per-entry shape arm fires inside the same loop iteration as
11568        // the empty arm, before the seen-set insert at end-of-iteration
11569        // — structural per-entry defects dominate the cross-entry
11570        // uniqueness diagnostic. Mirrors the peer
11571        // `validate_autores_shape_takes_precedence_over_duplicate`.
11572        let c = caixa_with_etiquetas(vec!["mesh\nhttp", "mesh\nhttp"]);
11573        let err = c.validate_etiquetas().unwrap_err();
11574        assert!(
11575            matches!(err, ManifestError::EtiquetaInvalid { .. }),
11576            "got {err:?}",
11577        );
11578    }
11579
11580    #[test]
11581    fn validate_etiquetas_invalid_diagnostic_names_offending_slot_and_value() {
11582        // Diagnostic-shape pin on the new shape arm (peer with
11583        // `validate_autores_invalid_diagnostic_names_offending_slot_and_value`):
11584        // the rendered Display surfaces both the offending slot name
11585        // and the offending value verbatim, so a `feira lint` run
11586        // points the author at the exact `:etiquetas` entry to fix.
11587        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
11588        let rendered = c.validate_etiquetas().unwrap_err().to_string();
11589        assert!(
11590            rendered.contains(":etiquetas"),
11591            "diagnostic must name the offending slot: {rendered}",
11592        );
11593        assert!(
11594            rendered.contains("mesh\\nhttp"),
11595            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11596        );
11597    }
11598
11599    #[test]
11600    fn validate_etiquetas_rejects_at_21_byte_boundary() {
11601        // The 20-byte cap pin — boundary-exceeding case rejected,
11602        // boundary-accepting case passes. Mirrors the peer
11603        // `chart_keyword_shape_rejects_at_21_byte_boundary` substrate-
11604        // side pin, surfaced at the per-axis caller so the cap
11605        // propagates through validate end-to-end. Constructed as a
11606        // single all-`a` token so only the cap arm fires.
11607        let max_ok = "a".repeat(20);
11608        let c = caixa_with_etiquetas(vec![max_ok.as_str()]);
11609        c.validate_etiquetas().unwrap();
11610        let too_long = "a".repeat(21);
11611        let c = caixa_with_etiquetas(vec![too_long.as_str()]);
11612        let err = c.validate_etiquetas().unwrap_err();
11613        let ManifestError::EtiquetaInvalid { reason, .. } = err else {
11614            panic!("expected EtiquetaInvalid, got {err:?}");
11615        };
11616        assert!(reason.contains("20"), "got: {reason}");
11617        assert!(reason.contains("21"), "got: {reason}");
11618    }
11619
11620    #[test]
11621    fn validate_etiquetas_accepts_canonical_shaped_forms() {
11622        // Positive control sweep: every canonical-shaped tag from the
11623        // hello-rio / checkout-aplicacao / pangea-tatara-akeyless
11624        // example fixtures plus the substrate-fixed tags caixa-helm
11625        // unions in at chart render. Drift between this list and the
11626        // substrate-side `chart_keyword_shape_accepts_canonical_forms`
11627        // sweep surfaces here — one source of truth for the rule.
11628        let c = caixa_with_etiquetas(vec![
11629            "example",
11630            "aplicacao",
11631            "mesh",
11632            "ecommerce",
11633            "demo",
11634            "infrastructure",
11635            "aws",
11636            "akeyless",
11637            "pangea-native",
11638            "hello-world",
11639            "wasm",
11640            "rust",
11641            "tatara-lisp",
11642            "caixa-servico",
11643            "lareira",
11644        ]);
11645        c.validate_etiquetas().unwrap();
11646    }
11647
11648    // ── validate_autores — universal-axis maintainer shape ────────────
11649
11650    fn caixa_with_autores(autores: Vec<&str>) -> Caixa {
11651        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11652        c.autores = autores.into_iter().map(String::from).collect();
11653        c
11654    }
11655
11656    #[test]
11657    fn validate_autores_accepts_empty_list() {
11658        // The empty-list identity: `Caixa::template` emits `:autores ()`,
11659        // so the gate is non-disruptive against every existing manifest.
11660        let c = caixa_with_autores(vec![]);
11661        c.validate_autores().unwrap();
11662    }
11663
11664    #[test]
11665    fn validate_autores_accepts_canonical_forms() {
11666        // Positive control sweep: every canonical-shaped non-empty
11667        // distinct maintainer list passes — the hello-rio / checkout-
11668        // aplicacao fixtures' `:autores ("pleme-io")` shape, plus the
11669        // multi-author shape downstream packaging surfaces emit.
11670        let c = caixa_with_autores(vec!["pleme-io"]);
11671        c.validate_autores().unwrap();
11672        let c = caixa_with_autores(vec!["alice <alice@example.com>", "bob <bob@example.com>"]);
11673        c.validate_autores().unwrap();
11674    }
11675
11676    #[test]
11677    fn validate_autores_rejects_empty_entry() {
11678        // Canonical paste-from-blank-doc footgun. Without the gate the
11679        // empty entry rendered as `maintainers: [{name: "", email: null}]`
11680        // in `Chart.yaml`, a no-op maintainer the substrate cannot route
11681        // to.
11682        let c = caixa_with_autores(vec![""]);
11683        let err = c.validate_autores().unwrap_err();
11684        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11685    }
11686
11687    #[test]
11688    fn validate_autores_rejects_duplicate_entry() {
11689        // Canonical copy-paste-the-wrong-author footgun. Unlike the
11690        // `:etiquetas` peer (caixa-helm's `BTreeSet` collect silently
11691        // dedups the rendered `keywords:` array), the `maintainers:`
11692        // rendering has *no* dedup — duplicates stack verbatim. The
11693        // duplicate-arm names the offending author verbatim.
11694        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
11695        let err = c.validate_autores().unwrap_err();
11696        let ManifestError::AutorDuplicate { autor } = err else {
11697            panic!("expected AutorDuplicate, got {err:?}");
11698        };
11699        assert_eq!(autor, "pleme-io");
11700    }
11701
11702    #[test]
11703    fn validate_autores_empty_takes_precedence_over_duplicate() {
11704        // Empty-first cascade pin: `("" "pleme-io" "pleme-io")` surfaces
11705        // `AutorEmpty` not `AutorDuplicate` — the narrower structural
11706        // "this entry has no value" defect dominates the cross-entry
11707        // uniqueness diagnostic. Mirrors the peer empty-before-duplicate
11708        // cascades on `:etiquetas` (`EtiquetaEmpty` before
11709        // `EtiquetaDuplicate`, 360a499), `:caracteristicas`
11710        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
11711        // fc3b4d5), and `:membros :caixa` (`MembroCaixaEmpty` before
11712        // `MembroDuplicate`).
11713        let c = caixa_with_autores(vec!["", "pleme-io", "pleme-io"]);
11714        let err = c.validate_autores().unwrap_err();
11715        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11716    }
11717
11718    #[test]
11719    fn validate_autores_duplicate_reports_first_collision() {
11720        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
11721        // duplicate (the lexicographically-earliest offending position
11722        // — the second `"a"` at index 2 collides with the first `"a"`
11723        // at index 0), not the later `"b"` collision at index 3,
11724        // peer with every other first-collision diagnostic posture on
11725        // this surface.
11726        let c = caixa_with_autores(vec!["a", "b", "a", "b"]);
11727        let err = c.validate_autores().unwrap_err();
11728        let ManifestError::AutorDuplicate { autor } = err else {
11729            panic!("expected AutorDuplicate, got {err:?}");
11730        };
11731        assert_eq!(autor, "a");
11732    }
11733
11734    #[test]
11735    fn validate_autores_case_sensitive() {
11736        // Case-sensitivity pin: `("Pleme-io" "pleme-io")` is two distinct
11737        // entries, mirroring the peer `:etiquetas` / `:membros :caixa`
11738        // / `:children :caixa` exact-string-match discipline.
11739        let c = caixa_with_autores(vec!["Pleme-io", "pleme-io"]);
11740        c.validate_autores().unwrap();
11741    }
11742
11743    #[test]
11744    fn validate_autores_diagnostic_carries_offending_author() {
11745        // Diagnostic-shape pin (peer with
11746        // `validate_etiquetas_diagnostic_carries_offending_tag`): the
11747        // error's Display surfaces the offending author verbatim, so a
11748        // `feira lint` run can render the diagnostic without re-parsing
11749        // and the author can grep their caixa.lisp for the offending
11750        // value.
11751        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
11752        let rendered = c.validate_autores().unwrap_err().to_string();
11753        assert!(
11754            rendered.contains(":autores"),
11755            "diagnostic must name the offending slot: {rendered}",
11756        );
11757        assert!(
11758            rendered.contains("pleme-io"),
11759            "diagnostic must quote the offending author: {rendered}",
11760        );
11761    }
11762
11763    #[test]
11764    fn validate_autores_rejects_leading_whitespace_entry() {
11765        // Canonical paste-from-aligned-doc footgun. Without the shape
11766        // gate `" pleme-io"` silently passed validate and landed as a
11767        // YAML plain-style scalar with leading whitespace in the
11768        // rendered Chart.yaml `maintainers:` array — every YAML 1.2
11769        // dumper trims leading whitespace from plain-style scalars, so
11770        // the authored space round-tripped inconsistently back through
11771        // `caixa.lisp`. Mirrors the peer
11772        // `validate_descricao_rejects_leading_whitespace`.
11773        let c = caixa_with_autores(vec![" pleme-io"]);
11774        let err = c.validate_autores().unwrap_err();
11775        let ManifestError::AutorInvalid { autor, reason } = err else {
11776            panic!("expected AutorInvalid, got {err:?}");
11777        };
11778        assert_eq!(autor, " pleme-io");
11779        assert!(reason.contains("whitespace"), "got: {reason}");
11780    }
11781
11782    #[test]
11783    fn validate_autores_rejects_trailing_whitespace_entry() {
11784        // Canonical paste-from-doc footgun.
11785        let c = caixa_with_autores(vec!["pleme-io "]);
11786        let err = c.validate_autores().unwrap_err();
11787        let ManifestError::AutorInvalid { autor, reason } = err else {
11788            panic!("expected AutorInvalid, got {err:?}");
11789        };
11790        assert_eq!(autor, "pleme-io ");
11791        assert!(reason.contains("whitespace"), "got: {reason}");
11792    }
11793
11794    #[test]
11795    fn validate_autores_rejects_embedded_newline_entry() {
11796        // Canonical paste-from-multiline-doc footgun — the author
11797        // pasted a multi-line block of author records into one
11798        // `:autores` entry instead of splitting into one entry per
11799        // author. Without the shape gate `"alice\nbob"` silently
11800        // passed validate and landed as a YAML-illegal multi-line
11801        // scalar in the rendered Chart.yaml `maintainers:` array.
11802        let c = caixa_with_autores(vec!["alice\nbob"]);
11803        let err = c.validate_autores().unwrap_err();
11804        let ManifestError::AutorInvalid { autor, reason } = err else {
11805            panic!("expected AutorInvalid, got {err:?}");
11806        };
11807        assert_eq!(autor, "alice\nbob");
11808        assert!(reason.contains("newline"), "got: {reason}");
11809    }
11810
11811    #[test]
11812    fn validate_autores_rejects_embedded_carriage_return_entry() {
11813        // Canonical paste-from-Windows-CRLF-doc footgun.
11814        let c = caixa_with_autores(vec!["alice\rbob"]);
11815        let err = c.validate_autores().unwrap_err();
11816        let ManifestError::AutorInvalid { autor, reason } = err else {
11817            panic!("expected AutorInvalid, got {err:?}");
11818        };
11819        assert_eq!(autor, "alice\rbob");
11820        assert!(reason.contains("carriage return"), "got: {reason}");
11821    }
11822
11823    #[test]
11824    fn validate_autores_rejects_embedded_tab_entry() {
11825        // Canonical tab-from-aligned-doc footgun.
11826        let c = caixa_with_autores(vec!["Pleme\tContributors"]);
11827        let err = c.validate_autores().unwrap_err();
11828        let ManifestError::AutorInvalid { autor, reason } = err else {
11829            panic!("expected AutorInvalid, got {err:?}");
11830        };
11831        assert_eq!(autor, "Pleme\tContributors");
11832        assert!(reason.contains("tab"), "got: {reason}");
11833    }
11834
11835    #[test]
11836    fn validate_autores_rejects_embedded_control_bytes_entry() {
11837        // Paste-from-binary-blob footguns: NUL, BEL, ESC, DEL all
11838        // surface the same control-byte arm.
11839        for entry in [
11840            "alice\x00bob",
11841            "alice\x07bob",
11842            "alice\x1bbob",
11843            "alice\x7fbob",
11844        ] {
11845            let c = caixa_with_autores(vec![entry]);
11846            let err = c.validate_autores().unwrap_err();
11847            let ManifestError::AutorInvalid { autor, reason } = err else {
11848                panic!("expected AutorInvalid for {entry:?}, got {err:?}");
11849            };
11850            assert_eq!(autor, entry);
11851            assert!(
11852                reason.contains("control character"),
11853                "{entry:?} reason: {reason}",
11854            );
11855        }
11856    }
11857
11858    #[test]
11859    fn validate_autores_accepts_unicode_entry() {
11860        // Unicode positive control: realistic maintainer names carry
11861        // Unicode (`François`, `日本語`, `naïve`). The predicate must
11862        // round-trip Unicode losslessly, peer with the
11863        // `chart_maintainer_name_shape_accepts_unicode` substrate-side
11864        // sweep.
11865        let c = caixa_with_autores(vec![
11866            "François Dupont",
11867            "日本語の名前",
11868            "naïve <naive@example.com>",
11869        ]);
11870        c.validate_autores().unwrap();
11871    }
11872
11873    #[test]
11874    fn validate_autores_empty_takes_precedence_over_shape() {
11875        // Per-entry empty-first cascade pin: an entry that is both
11876        // empty *and* shape-invalid surfaces `AutorEmpty` (the narrower
11877        // "this entry has no value" structural defect dominates the
11878        // broader shape-predicate diagnostic). The empty arm fires
11879        // before the shape predicate is consulted, mirroring the peer
11880        // `validate_repositorio_empty_takes_precedence_over_shape`
11881        // cascade on the universal `Option<String>` siblings — and now
11882        // established on the Vec<String> per-entry surface.
11883        let c = caixa_with_autores(vec![""]);
11884        let err = c.validate_autores().unwrap_err();
11885        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11886    }
11887
11888    #[test]
11889    fn validate_autores_shape_takes_precedence_over_duplicate() {
11890        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
11891        // entry that is malformed surfaces `AutorInvalid` even when a
11892        // later entry would have collided on duplicate. The per-entry
11893        // shape arm fires inside the same loop iteration as the empty
11894        // arm, before the seen-set insert at end-of-iteration —
11895        // structural per-entry defects dominate the cross-entry
11896        // uniqueness diagnostic.
11897        let c = caixa_with_autores(vec!["alice\nbob", "alice\nbob"]);
11898        let err = c.validate_autores().unwrap_err();
11899        assert!(
11900            matches!(err, ManifestError::AutorInvalid { .. }),
11901            "got {err:?}",
11902        );
11903    }
11904
11905    #[test]
11906    fn validate_autores_invalid_diagnostic_names_offending_slot_and_value() {
11907        // Diagnostic-shape pin on the new shape arm (peer with
11908        // `validate_descricao_invalid_diagnostic_carries_offending_value`):
11909        // the rendered Display surfaces both the offending slot name
11910        // and the offending value verbatim, so a `feira lint` run
11911        // points the author at the exact `:autores` entry to fix.
11912        let c = caixa_with_autores(vec!["alice\nbob"]);
11913        let rendered = c.validate_autores().unwrap_err().to_string();
11914        assert!(
11915            rendered.contains(":autores"),
11916            "diagnostic must name the offending slot: {rendered}",
11917        );
11918        assert!(
11919            rendered.contains("alice\\nbob"),
11920            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11921        );
11922    }
11923
11924    #[test]
11925    fn validate_autores_rejects_at_129_byte_boundary() {
11926        // The 128-byte cap pin — boundary-exceeding case rejected,
11927        // boundary-accepting case passes. Mirrors the peer
11928        // `chart_maintainer_name_shape_rejects_at_129_byte_boundary`
11929        // substrate-side pin, surfaced at the per-axis caller so the
11930        // cap propagates through validate end-to-end. Constructed as
11931        // a single all-`a` token so only the cap arm fires.
11932        let max_ok = "a".repeat(128);
11933        let c = caixa_with_autores(vec![max_ok.as_str()]);
11934        c.validate_autores().unwrap();
11935        let too_long = "a".repeat(129);
11936        let c = caixa_with_autores(vec![too_long.as_str()]);
11937        let err = c.validate_autores().unwrap_err();
11938        let ManifestError::AutorInvalid { reason, .. } = err else {
11939            panic!("expected AutorInvalid, got {err:?}");
11940        };
11941        assert!(reason.contains("128"), "got: {reason}");
11942        assert!(reason.contains("129"), "got: {reason}");
11943    }
11944
11945    // ── validate_repositorio — universal-axis git-repo-URL shape ──────
11946
11947    fn caixa_with_repositorio(repositorio: Option<&str>) -> Caixa {
11948        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11949        c.repositorio = repositorio.map(String::from);
11950        c
11951    }
11952
11953    #[test]
11954    fn validate_repositorio_accepts_none() {
11955        // The omit-the-slot identity: `:repositorio` is optional. The
11956        // gate is a no-op when the author didn't declare a value —
11957        // every caixa without a `:repositorio` line trivially passes,
11958        // and the substrate-side renderers fall back to their
11959        // documented placeholder (`caixa-helm`'s `home: None`,
11960        // `caixa-flux`'s `https://github.com/pleme-io/<nome>` derived
11961        // URL). Mirrors the peer `validate_restart_window_accepts_none`
11962        // posture on the other `Option<String>` Caixa slot.
11963        let c = caixa_with_repositorio(None);
11964        c.validate_repositorio().unwrap();
11965    }
11966
11967    #[test]
11968    fn validate_repositorio_accepts_canonical_forms() {
11969        // Positive control sweep across every documented `:repositorio`
11970        // authoring shape — the same union the shared
11971        // `crate::render::is_git_repo_url` predicate accepts and the
11972        // peer `:deps :fonte :repo` axis already routes through.
11973        // Covers the `github:` shorthand (the canonical pleme-io
11974        // convention used in the `:repositorio` field of every
11975        // manifest fixture across `caixa-helm` / `caixa-mesh` and the
11976        // `examples/`), the `https://…` URL the README quickstart uses,
11977        // the `ssh://`, `git://`, `git@host:path` scp-style SSH, and
11978        // `file://` URL schemes the shared predicate documents.
11979        for repo in [
11980            "github:pleme-io/hello-rio",
11981            "github:pleme-io/checkout",
11982            "https://github.com/pleme-io/hello-rio",
11983            "ssh://git@github.com/pleme-io/hello-rio.git",
11984            "git://github.com/pleme-io/hello-rio.git",
11985            "git@github.com:pleme-io/hello-rio.git",
11986            "file:///srv/pleme/hello-rio",
11987        ] {
11988            let c = caixa_with_repositorio(Some(repo));
11989            c.validate_repositorio()
11990                .unwrap_or_else(|err| panic!("canonical {repo:?} must pass: {err:?}"));
11991        }
11992    }
11993
11994    #[test]
11995    fn validate_repositorio_rejects_empty_some() {
11996        // Canonical paste-from-blank-doc footgun. The narrower
11997        // [`ManifestError::RepositorioEmpty`] arm fires before the
11998        // shape predicate is consulted, mirroring the empty-first
11999        // cascade every peer per-axis identity gate uses
12000        // (`NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
12001        // `FonteRepoEmpty` → `FonteRepoInvalid`). Without this gate
12002        // the empty `Some("")` silently passed the renderer's
12003        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
12004        // on `None`) and landed as `home: ""` in `Chart.yaml` /
12005        // `url: ""` in the FluxCD `GitRepository`.
12006        let c = caixa_with_repositorio(Some(""));
12007        let err = c.validate_repositorio().unwrap_err();
12008        assert!(
12009            matches!(err, ManifestError::RepositorioEmpty),
12010            "got {err:?}",
12011        );
12012    }
12013
12014    #[test]
12015    fn validate_repositorio_rejects_whitespace() {
12016        // Paste-from-doc whitespace footgun. The shared
12017        // `is_git_repo_url` predicate refuses any whitespace byte; a
12018        // trailing space in a `:repositorio` value silently broke
12019        // `git clone '<value> '` at clone time. The diagnostic names
12020        // the offending value verbatim.
12021        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio "));
12022        let err = c.validate_repositorio().unwrap_err();
12023        let ManifestError::RepositorioInvalid { repositorio, .. } = err else {
12024            panic!("expected RepositorioInvalid, got {err:?}");
12025        };
12026        assert_eq!(repositorio, "github:pleme-io/hello-rio ");
12027    }
12028
12029    #[test]
12030    fn validate_repositorio_rejects_control_char() {
12031        // Paste-from-multiline-doc CRLF footgun — control characters
12032        // at the URL boundary are a class of subprocess-arg injection
12033        // and break git's URL parser at every porcelain entry point.
12034        let c = caixa_with_repositorio(Some("https://example.com/repo\n"));
12035        let err = c.validate_repositorio().unwrap_err();
12036        assert!(
12037            matches!(err, ManifestError::RepositorioInvalid { .. }),
12038            "got {err:?}",
12039        );
12040    }
12041
12042    #[test]
12043    fn validate_repositorio_rejects_leading_dash() {
12044        // Canonical CLI-argument-injection footgun: `git clone <repo>`
12045        // interprets a leading `-` as a CLI flag, so a
12046        // `-upload-pack=…` value escapes the subprocess argument
12047        // boundary. The shared predicate refuses every leading-`-`
12048        // shape at validate time.
12049        let c = caixa_with_repositorio(Some("-upload-pack=evil"));
12050        let err = c.validate_repositorio().unwrap_err();
12051        assert!(
12052            matches!(err, ManifestError::RepositorioInvalid { .. }),
12053            "got {err:?}",
12054        );
12055    }
12056
12057    #[test]
12058    fn validate_repositorio_rejects_missing_colon_separator() {
12059        // The bare `org/repo` ambiguity footgun — `git clone` reads
12060        // a no-`:` form as a relative filesystem path rather than the
12061        // GitHub-shorthand expansion the author probably intended.
12062        // The shared predicate refuses every shape without a `:`
12063        // separator.
12064        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
12065        let err = c.validate_repositorio().unwrap_err();
12066        assert!(
12067            matches!(err, ManifestError::RepositorioInvalid { .. }),
12068            "got {err:?}",
12069        );
12070    }
12071
12072    #[test]
12073    fn validate_repositorio_rejects_fragment_anchor() {
12074        // Paste-from-browser-address-bar footgun on the
12075        // `:repositorio` axis — an author copies a GitHub permalink
12076        // to a README section / line-permalink and forgets to trim
12077        // the `#fragment` tail. The shared `is_git_repo_url`
12078        // predicate refuses the byte at the URL-grammar layer
12079        // (libcurl strips the fragment before opening the
12080        // transport, so the byte rides verbatim into the rendered
12081        // `Chart.yaml` `home:` and FluxCD `GitRepository` `url:`
12082        // fields but is silently dropped on the wire — two
12083        // manifest variants whose values differ only in their
12084        // fragment anchor lock to two distinct rendered artifacts
12085        // for the byte-identical clone, defeating the THEORY.md
12086        // §V.2 render-determinism contract on the `:repositorio`
12087        // axis the peer `:fonte :repo` axis already closes).
12088        let c = caixa_with_repositorio(Some("https://github.com/pleme-io/hello-rio#readme"));
12089        let err = c.validate_repositorio().unwrap_err();
12090        let ManifestError::RepositorioInvalid {
12091            repositorio,
12092            reason,
12093        } = err
12094        else {
12095            panic!("expected RepositorioInvalid, got {err:?}");
12096        };
12097        assert_eq!(repositorio, "https://github.com/pleme-io/hello-rio#readme");
12098        assert!(
12099            reason.contains("must not contain `#`"),
12100            "reason must surface the fragment-`#` arm, got {reason:?}"
12101        );
12102    }
12103
12104    #[test]
12105    fn validate_repositorio_rejects_query_string() {
12106        // Paste-from-browser-address-bar footgun on the
12107        // `:repositorio` axis (peer with the a68f818 fragment-`#`
12108        // arm on the same axis). An author copies a GitHub tab
12109        // deep-link out of the address bar and forgets to trim
12110        // the `?tab=…` query tail. The shared `is_git_repo_url`
12111        // predicate refuses the byte at the URL-grammar layer
12112        // (GitHub / GitLab / Bitbucket silently ignore the
12113        // `?query` tail and serve the same repo regardless, so
12114        // the byte rides verbatim into the rendered `Chart.yaml`
12115        // `home:` and FluxCD `GitRepository` `url:` fields but
12116        // is silently masked at the wire — two manifest variants
12117        // whose values differ only in their query tail lock to
12118        // two distinct rendered artifacts for the byte-identical
12119        // clone, defeating the THEORY.md §V.2 render-determinism
12120        // contract on the `:repositorio` axis the peer `:fonte
12121        // :repo` axis already closes).
12122        let c = caixa_with_repositorio(Some(
12123            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file",
12124        ));
12125        let err = c.validate_repositorio().unwrap_err();
12126        let ManifestError::RepositorioInvalid {
12127            repositorio,
12128            reason,
12129        } = err
12130        else {
12131            panic!("expected RepositorioInvalid, got {err:?}");
12132        };
12133        assert_eq!(
12134            repositorio,
12135            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file"
12136        );
12137        assert!(
12138            reason.contains("must not contain `?`"),
12139            "reason must surface the query-`?` arm, got {reason:?}"
12140        );
12141    }
12142
12143    #[test]
12144    fn validate_repositorio_rejects_embedded_backslash() {
12145        // Windows-file-path-confusion footgun on the `:repositorio`
12146        // axis (peer with the prior fragment-`#` / query-`?` arms on
12147        // the same axis, and peer with the new dep-level `:fonte :repo`
12148        // backslash arm on the URL-grammar trajectory). An author
12149        // pastes a Windows Explorer address-bar `file:///C:\Users\me\
12150        // hello-rio` into the `:repositorio` slot, expecting the
12151        // `lareira-<nome>` chart's `home:` field and the FluxCD
12152        // `GitRepository` `url:` field to render the canonical local
12153        // file-URI. The shared `is_git_repo_url` predicate refuses
12154        // the byte at the URL-grammar layer (libcurl silently
12155        // translates `\` → `/` on some platforms and refuses it on
12156        // others, so the byte rides verbatim into the rendered
12157        // artifacts but is silently rewritten or rejected at the wire
12158        // — two manifest variants whose values differ only in
12159        // backslash-vs-forward-slash lock to two distinct rendered
12160        // artifacts for the byte-identical clone, defeating the
12161        // THEORY.md §V.2 render-determinism contract on the
12162        // `:repositorio` axis the peer `:fonte :repo` axis already
12163        // closes).
12164        let c = caixa_with_repositorio(Some("file:///C:\\Users\\me\\hello-rio"));
12165        let err = c.validate_repositorio().unwrap_err();
12166        let ManifestError::RepositorioInvalid {
12167            repositorio,
12168            reason,
12169        } = err
12170        else {
12171            panic!("expected RepositorioInvalid, got {err:?}");
12172        };
12173        assert_eq!(repositorio, "file:///C:\\Users\\me\\hello-rio");
12174        assert!(
12175            reason.contains("must not contain `\\`"),
12176            "reason must surface the backslash-`\\` arm, got {reason:?}"
12177        );
12178    }
12179
12180    #[test]
12181    fn validate_repositorio_rejects_uri_template_placeholder() {
12182        // URI Template (RFC 6570) placeholder footgun on the
12183        // `:repositorio` axis (peer with the prior fragment-`#` /
12184        // query-`?` / backslash-`\` arms on the same axis, and peer
12185        // with the new dep-level `:fonte :repo` `{` / `}` arm on the
12186        // URL-grammar trajectory). An author pastes a quick-start
12187        // README snippet / OpenAPI `servers:` URL / Helm chart
12188        // `home:` template carrying unresolved `{org}` / `{repo}`
12189        // placeholders into the `:repositorio` slot, expecting the
12190        // substrate to resolve the placeholder downstream. The
12191        // shared `is_git_repo_url` predicate refuses the byte at the
12192        // URL-grammar layer (libcurl percent-encodes `{` / `}` to
12193        // `%7B` / `%7D` on the wire, so the byte round-trips
12194        // inconsistently between the rendered `Chart.yaml home:` /
12195        // FluxCD `GitRepository url:` and the resolver's `git clone`
12196        // invocation, defeating the THEORY.md §V.2 render-
12197        // determinism contract on the `:repositorio` axis the peer
12198        // `:fonte :repo` axis already closes; every git porcelain
12199        // entry-point additionally fetches a nonexistent literal-
12200        // `{placeholder}`-named path far from the source caixa.lisp).
12201        let c = caixa_with_repositorio(Some("https://github.com/{org}/hello-rio"));
12202        let err = c.validate_repositorio().unwrap_err();
12203        let ManifestError::RepositorioInvalid {
12204            repositorio,
12205            reason,
12206        } = err
12207        else {
12208            panic!("expected RepositorioInvalid, got {err:?}");
12209        };
12210        assert_eq!(repositorio, "https://github.com/{org}/hello-rio");
12211        assert!(
12212            reason.contains("must not contain `{`"),
12213            "reason must surface the open-brace `{{` arm, got {reason:?}"
12214        );
12215        assert!(
12216            reason.contains("URI Template") || reason.contains("RFC 6570"),
12217            "reason must name the RFC 6570 URI Template grammar, got {reason:?}"
12218        );
12219    }
12220
12221    #[test]
12222    fn validate_repositorio_empty_takes_precedence_over_shape() {
12223        // Empty-first cascade pin: the empty `Some("")` surfaces the
12224        // narrower `RepositorioEmpty` not the shape-predicate-wrapped
12225        // `RepositorioInvalid`, mirroring the peer
12226        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
12227        // `FonteRepoEmpty` → `FonteRepoInvalid` cascades. The shared
12228        // `is_git_repo_url` predicate also rejects the empty input
12229        // (defensively, with its own `"must not be empty"` reason),
12230        // but the manifest-layer empty arm runs first to surface the
12231        // narrower diagnostic verbatim.
12232        let c = caixa_with_repositorio(Some(""));
12233        let err = c.validate_repositorio().unwrap_err();
12234        assert!(
12235            matches!(err, ManifestError::RepositorioEmpty),
12236            "got {err:?}",
12237        );
12238    }
12239
12240    #[test]
12241    fn validate_repositorio_diagnostic_carries_offending_value() {
12242        // Diagnostic-shape pin (peer with
12243        // `validate_autores_diagnostic_carries_offending_author`): the
12244        // error's Display surfaces the offending value + slot name
12245        // verbatim, so a `feira lint` run can render the diagnostic
12246        // without re-parsing and the author can grep their caixa.lisp
12247        // for the offending `:repositorio` value.
12248        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
12249        let rendered = c.validate_repositorio().unwrap_err().to_string();
12250        assert!(
12251            rendered.contains(":repositorio"),
12252            "diagnostic must name the offending slot: {rendered}",
12253        );
12254        assert!(
12255            rendered.contains("pleme-io/hello-rio"),
12256            "diagnostic must quote the offending value: {rendered}",
12257        );
12258    }
12259
12260    // ── validate_descricao — universal-axis Chart.yaml description shape ──
12261
12262    fn caixa_with_descricao(descricao: Option<&str>) -> Caixa {
12263        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12264        c.descricao = descricao.map(String::from);
12265        c
12266    }
12267
12268    #[test]
12269    fn validate_descricao_accepts_none() {
12270        // The omit-the-slot identity: `:descricao` is optional. The
12271        // gate is a no-op when the author didn't declare a value —
12272        // every caixa without a `:descricao` line trivially passes,
12273        // and the substrate-side renderers fall back to their
12274        // documented `caixa.nome`-derived placeholder. Mirrors the
12275        // peer `validate_repositorio_accepts_none` posture on the
12276        // sibling `Option<String>` Caixa slot.
12277        let c = caixa_with_descricao(None);
12278        c.validate_descricao().unwrap();
12279    }
12280
12281    #[test]
12282    fn validate_descricao_accepts_canonical_summary() {
12283        // Positive control: the canonical pleme-io descricao shape —
12284        // a short free-form prose summary — passes the gate. Covers
12285        // the fixture shapes the `caixa-helm` / `caixa-flux` /
12286        // `caixa-mesh` test fixtures use (`"Canonical Rust→wasm32-
12287        // wasip2 caixa Servico."`, `"Checkout flow."`).
12288        for desc in [
12289            "Canonical Rust→wasm32-wasip2 caixa Servico.",
12290            "Checkout flow.",
12291            "AWS provider caixa for tatara-lisp",
12292            "FIXME — describe this caixa",
12293            "x",
12294        ] {
12295            let c = caixa_with_descricao(Some(desc));
12296            c.validate_descricao()
12297                .unwrap_or_else(|err| panic!("canonical {desc:?} must pass: {err:?}"));
12298        }
12299    }
12300
12301    #[test]
12302    fn validate_descricao_rejects_empty_some() {
12303        // Canonical paste-from-blank-doc footgun. Without this gate
12304        // the empty `Some("")` silently passed the renderer's
12305        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
12306        // on `None`) and landed as `description: ""` in `Chart.yaml`
12307        // and a blank `README.md` header. Mirrors the peer
12308        // [`ManifestError::RepositorioEmpty`] empty-arm on the
12309        // sibling `Option<String>` Caixa slot.
12310        let c = caixa_with_descricao(Some(""));
12311        let err = c.validate_descricao().unwrap_err();
12312        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
12313    }
12314
12315    #[test]
12316    fn validate_descricao_rejects_leading_whitespace() {
12317        // Paste-from-aligned-doc footgun: a leading ASCII space the
12318        // bare empty-arm gate accepted, the shape predicate now
12319        // refuses. The diagnostic carries the offending value
12320        // verbatim (with the leading space preserved) so the author
12321        // can grep their caixa.lisp for the exact `:descricao` line
12322        // and fix the round-trip-inconsistent leading whitespace.
12323        // Mirrors the peer
12324        // `validate_licenca_rejects_leading_whitespace` arm on the
12325        // sibling `:licenca` axis.
12326        let c = caixa_with_descricao(Some(" Checkout flow."));
12327        let err = c.validate_descricao().unwrap_err();
12328        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
12329            panic!("expected DescricaoInvalid, got {err:?}");
12330        };
12331        assert_eq!(descricao, " Checkout flow.");
12332        assert!(reason.contains("whitespace"), "got: {reason:?}");
12333    }
12334
12335    #[test]
12336    fn validate_descricao_rejects_trailing_whitespace() {
12337        // Paste-from-doc footgun: a trailing ASCII space the bare
12338        // empty-arm gate accepted, the shape predicate now refuses.
12339        let c = caixa_with_descricao(Some("Checkout flow. "));
12340        let err = c.validate_descricao().unwrap_err();
12341        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
12342            panic!("expected DescricaoInvalid, got {err:?}");
12343        };
12344        assert_eq!(descricao, "Checkout flow. ");
12345        assert!(reason.contains("whitespace"), "got: {reason:?}");
12346    }
12347
12348    #[test]
12349    fn validate_descricao_rejects_embedded_newline() {
12350        // Paste-from-multiline-doc footgun: an embedded LF the bare
12351        // empty-arm gate accepted, the shape predicate now refuses.
12352        // Without this gate the embedded newline silently landed in
12353        // the rendered Chart.yaml as a multi-line YAML block scalar,
12354        // and every chart-aware UI (`helm list`, `helm search`,
12355        // Artifact Hub) renders the description in a single-line
12356        // column so the embedded newline is silently dropped at
12357        // every downstream consumer.
12358        let c = caixa_with_descricao(Some("Checkout\nflow."));
12359        let err = c.validate_descricao().unwrap_err();
12360        assert!(
12361            matches!(err, ManifestError::DescricaoInvalid { .. }),
12362            "got {err:?}",
12363        );
12364        assert!(err.to_string().contains("newline"), "got {err}");
12365    }
12366
12367    #[test]
12368    fn validate_descricao_rejects_embedded_carriage_return() {
12369        // Paste-from-Windows-CRLF-doc footgun.
12370        let c = caixa_with_descricao(Some("Checkout\rflow."));
12371        let err = c.validate_descricao().unwrap_err();
12372        assert!(
12373            matches!(err, ManifestError::DescricaoInvalid { .. }),
12374            "got {err:?}",
12375        );
12376        assert!(err.to_string().contains("carriage return"), "got {err}");
12377    }
12378
12379    #[test]
12380    fn validate_descricao_rejects_embedded_tab() {
12381        // Tab-from-aligned-doc footgun.
12382        let c = caixa_with_descricao(Some("Checkout\tflow."));
12383        let err = c.validate_descricao().unwrap_err();
12384        assert!(
12385            matches!(err, ManifestError::DescricaoInvalid { .. }),
12386            "got {err:?}",
12387        );
12388        assert!(err.to_string().contains("tab"), "got {err}");
12389    }
12390
12391    #[test]
12392    fn validate_descricao_rejects_embedded_control_bytes() {
12393        // Paste-from-binary-blob footgun: every other control byte
12394        // (NUL, BEL, ESC, DEL) is refused at validate time. Mirrors
12395        // the peer SPDX-expression control-byte arm.
12396        for s in [
12397            "Checkout\x00flow.",
12398            "Checkout\x07flow.",
12399            "Checkout\x1bflow.",
12400            "Checkout\x7fflow.",
12401        ] {
12402            let c = caixa_with_descricao(Some(s));
12403            let err = c.validate_descricao().unwrap_err();
12404            assert!(
12405                matches!(err, ManifestError::DescricaoInvalid { .. }),
12406                "{s:?} got {err:?}",
12407            );
12408            assert!(
12409                err.to_string().contains("control character"),
12410                "{s:?} got {err}",
12411            );
12412        }
12413    }
12414
12415    #[test]
12416    fn validate_descricao_accepts_unicode_prose() {
12417        // Positive control: Unicode prose is accepted — the
12418        // canonical fixtures carry `→` (U+2192) and `—` (U+2014),
12419        // and `Caixa::template`'s `"FIXME — describe this caixa"`
12420        // scaffold every `feira init` emits must continue to pass.
12421        for s in [
12422            "Canonical Rust→wasm32-wasip2 caixa Servico.",
12423            "FIXME — describe this caixa",
12424            "Caixa pour le projet tâche",
12425            "日本語の説明",
12426        ] {
12427            let c = caixa_with_descricao(Some(s));
12428            c.validate_descricao()
12429                .unwrap_or_else(|err| panic!("Unicode {s:?} must pass: {err:?}"));
12430        }
12431    }
12432
12433    #[test]
12434    fn validate_descricao_empty_takes_precedence_over_shape() {
12435        // Cascade pin: a `Some("")` surfaces the narrower
12436        // `DescricaoEmpty` arm, not the broader `DescricaoInvalid`
12437        // shape-predicate arm. Mirrors the peer
12438        // `validate_licenca_empty_takes_precedence_over_shape` pin
12439        // on the sibling `:licenca` axis.
12440        let c = caixa_with_descricao(Some(""));
12441        let err = c.validate_descricao().unwrap_err();
12442        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
12443    }
12444
12445    #[test]
12446    fn validate_descricao_invalid_diagnostic_carries_offending_value_and_slot() {
12447        // Diagnostic-shape pin: the error's Display surfaces both
12448        // the `:descricao` slot name and the offending value
12449        // verbatim, so a `feira lint` run can render the diagnostic
12450        // without re-parsing and the author can grep their caixa.lisp
12451        // for the offending `:descricao` line. Mirrors the peer
12452        // `validate_licenca_invalid_diagnostic_carries_offending_value_and_slot`
12453        // pin (ee2e888) on the sibling `:licenca` axis.
12454        // The `{descricao:?}` Debug format escapes embedded control
12455        // bytes; the quoted offending value surfaces as
12456        // `"Checkout\nflow."` (literal backslash-n) in the rendered
12457        // diagnostic. The author can grep their caixa.lisp for the
12458        // literal `Checkout` summary prefix.
12459        let c = caixa_with_descricao(Some("Checkout\nflow."));
12460        let rendered = c.validate_descricao().unwrap_err().to_string();
12461        assert!(
12462            rendered.contains(":descricao"),
12463            "diagnostic must name the offending slot: {rendered}",
12464        );
12465        assert!(
12466            rendered.contains("Checkout\\nflow."),
12467            "diagnostic must quote the offending value (debug-escaped): {rendered}",
12468        );
12469    }
12470
12471    #[test]
12472    fn validate_descricao_template_passes() {
12473        // Round-trip pin: the bare `Caixa::template` shape carries
12474        // `:descricao "FIXME — describe this caixa"` (a non-empty
12475        // sentinel), so the template-derived Caixa passes the gate by
12476        // construction. A future template-shape change that omits or
12477        // empties `:descricao` would surface here as a regression.
12478        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12479        c.validate_descricao().unwrap();
12480    }
12481
12482    #[test]
12483    fn validate_descricao_diagnostic_names_offending_slot() {
12484        // Diagnostic-shape pin (peer with
12485        // `validate_repositorio_diagnostic_carries_offending_value`):
12486        // the error's Display surfaces the `:descricao` slot name
12487        // verbatim, so a `feira lint` run can render the diagnostic
12488        // without re-parsing and the author can grep their caixa.lisp
12489        // for the offending `:descricao` line.
12490        let c = caixa_with_descricao(Some(""));
12491        let rendered = c.validate_descricao().unwrap_err().to_string();
12492        assert!(
12493            rendered.contains(":descricao"),
12494            "diagnostic must name the offending slot: {rendered}",
12495        );
12496    }
12497
12498    // ── validate_licenca — universal-axis chart README license shape ──
12499
12500    fn caixa_with_licenca(licenca: Option<&str>) -> Caixa {
12501        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12502        c.licenca = licenca.map(String::from);
12503        c
12504    }
12505
12506    #[test]
12507    fn validate_licenca_accepts_none() {
12508        // The omit-the-slot identity: `:licenca` is optional. The
12509        // gate is a no-op when the author didn't declare a value —
12510        // every caixa without a `:licenca` line trivially passes,
12511        // and the substrate-side `caixa-helm` renderer falls back to
12512        // the documented `"MIT"` placeholder. Mirrors the peer
12513        // `validate_descricao_accepts_none` posture on the sibling
12514        // `Option<String>` Caixa slot.
12515        let c = caixa_with_licenca(None);
12516        c.validate_licenca().unwrap();
12517    }
12518
12519    #[test]
12520    fn validate_licenca_accepts_canonical_expressions() {
12521        // Positive control: every canonical SPDX expression shape
12522        // pleme-io carries in its existing fixtures + the canonical
12523        // SPDX dual-license / with-exception / `+`-suffix / grouped /
12524        // user-defined-reference shapes all pass the gate. Covers
12525        // the single-license, `OR`-compound, `AND`-compound,
12526        // `WITH`-exception, parenthesis-grouped, `+`-suffix, and
12527        // `LicenseRef-` / `DocumentRef-:LicenseRef-` shapes — every
12528        // production the SPDX 2.1 expression grammar admits that
12529        // sits within the alphabet floor the
12530        // `is_spdx_expression_shape` predicate enforces.
12531        for lic in [
12532            "MIT",
12533            "Apache-2.0",
12534            "Apache-2.0 OR MIT",
12535            "Apache-2.0 AND MIT",
12536            "BSD-3-Clause",
12537            "MPL-2.0",
12538            "GPL-3.0-or-later",
12539            "GPL-2.0+",
12540            "Apache-2.0 WITH LLVM-exception",
12541            "(MIT OR Apache-2.0) AND BSD-3-Clause",
12542            "(MIT OR Apache-2.0) AND BSD-3-Clause AND ISC",
12543            "LicenseRef-MyLicense",
12544            "DocumentRef-spdx-tool:LicenseRef-MIT-Style",
12545            "x",
12546        ] {
12547            let c = caixa_with_licenca(Some(lic));
12548            c.validate_licenca()
12549                .unwrap_or_else(|err| panic!("canonical {lic:?} must pass: {err:?}"));
12550        }
12551    }
12552
12553    #[test]
12554    fn validate_licenca_rejects_trailing_whitespace() {
12555        // Paste-from-doc whitespace footgun. A trailing space in the
12556        // `:licenca` value would silently break a downstream SPDX
12557        // parser that splits on exact `AND` / `OR` / `WITH` keyword
12558        // boundaries. The shape predicate refuses every trailing
12559        // whitespace byte by construction. Peer with
12560        // `validate_repositorio_rejects_whitespace` and
12561        // `validate_edicao_rejects_trailing_whitespace`.
12562        let c = caixa_with_licenca(Some("MIT "));
12563        let err = c.validate_licenca().unwrap_err();
12564        let ManifestError::LicencaInvalid { licenca, .. } = err else {
12565            panic!("expected LicencaInvalid, got {err:?}");
12566        };
12567        assert_eq!(licenca, "MIT ");
12568    }
12569
12570    #[test]
12571    fn validate_licenca_rejects_leading_whitespace() {
12572        // Symmetric paste-from-doc whitespace footgun on the leading
12573        // boundary — the gate refuses every shape that starts with a
12574        // space byte by construction. Peer with
12575        // `validate_edicao_rejects_leading_whitespace`.
12576        let c = caixa_with_licenca(Some(" MIT"));
12577        let err = c.validate_licenca().unwrap_err();
12578        assert!(
12579            matches!(err, ManifestError::LicencaInvalid { .. }),
12580            "got {err:?}",
12581        );
12582    }
12583
12584    #[test]
12585    fn validate_licenca_rejects_control_char() {
12586        // Paste-from-multiline-doc CRLF footgun — control characters
12587        // at the value boundary land as a malformed line in the
12588        // rendered chart `README.md` `## License` section. Peer with
12589        // `validate_repositorio_rejects_control_char` and
12590        // `validate_edicao_rejects_control_char`.
12591        for lic in ["MIT\n", "MIT\r\n", "MIT\rApache-2.0"] {
12592            let c = caixa_with_licenca(Some(lic));
12593            let err = c.validate_licenca().unwrap_err();
12594            assert!(
12595                matches!(err, ManifestError::LicencaInvalid { .. }),
12596                "expected LicencaInvalid on {lic:?}, got {err:?}",
12597            );
12598        }
12599    }
12600
12601    #[test]
12602    fn validate_licenca_rejects_tab() {
12603        // Tab-from-aligned-doc footgun — SPDX expressions use a
12604        // single ASCII space between tokens; a tab breaks every
12605        // downstream SPDX parser that splits on exact `" "`
12606        // boundaries.
12607        let c = caixa_with_licenca(Some("MIT\tOR Apache-2.0"));
12608        let err = c.validate_licenca().unwrap_err();
12609        assert!(
12610            matches!(err, ManifestError::LicencaInvalid { .. }),
12611            "got {err:?}",
12612        );
12613    }
12614
12615    #[test]
12616    fn validate_licenca_rejects_non_ascii() {
12617        // Smart-quote / non-ASCII paste footgun — SPDX identifiers
12618        // are ASCII per the `idstring = 1*(ALPHA / DIGIT / "-" /
12619        // ".")` production. The shape predicate refuses every
12620        // non-ASCII byte by construction; peer with
12621        // `validate_edicao_rejects_non_ascii_lookalike`.
12622        for lic in ["MIT\u{a0}OR Apache-2.0", "MIT\u{2013}1.0", "Café-1.0"] {
12623            let c = caixa_with_licenca(Some(lic));
12624            let err = c.validate_licenca().unwrap_err();
12625            assert!(
12626                matches!(err, ManifestError::LicencaInvalid { .. }),
12627                "expected LicencaInvalid on {lic:?}, got {err:?}",
12628            );
12629        }
12630    }
12631
12632    #[test]
12633    fn validate_licenca_rejects_underscore() {
12634        // Underscore-instead-of-hyphen typo footgun — `Apache_2.0` /
12635        // `MIT_Style` / `BSD_3_Clause` are familiar shapes from
12636        // snake-case identifier conventions that don't apply to the
12637        // SPDX `idstring` grammar (which admits only `ALPHA / DIGIT /
12638        // "-" / "."`). The shape predicate refuses every underscore
12639        // byte by construction.
12640        for lic in ["Apache_2.0", "MIT_Style", "BSD_3_Clause"] {
12641            let c = caixa_with_licenca(Some(lic));
12642            let err = c.validate_licenca().unwrap_err();
12643            assert!(
12644                matches!(err, ManifestError::LicencaInvalid { .. }),
12645                "expected LicencaInvalid on {lic:?}, got {err:?}",
12646            );
12647        }
12648    }
12649
12650    #[test]
12651    fn validate_licenca_rejects_comma_separator() {
12652        // Comma-instead-of-`OR`-keyword colloquial idiom footgun —
12653        // SPDX expressions compose multiple licenses via `AND` / `OR`
12654        // keywords, not the comma separator. The shape predicate
12655        // refuses every comma byte by construction.
12656        for lic in ["MIT, Apache-2.0", "MIT,Apache-2.0"] {
12657            let c = caixa_with_licenca(Some(lic));
12658            let err = c.validate_licenca().unwrap_err();
12659            assert!(
12660                matches!(err, ManifestError::LicencaInvalid { .. }),
12661                "expected LicencaInvalid on {lic:?}, got {err:?}",
12662            );
12663        }
12664    }
12665
12666    #[test]
12667    fn validate_licenca_rejects_slash_dual_license() {
12668        // Slash-dual-license colloquial idiom footgun — the
12669        // `MIT/Apache-2.0` shape is common in Cargo's pre-SPDX
12670        // `package.license` field but non-SPDX; the SPDX equivalent
12671        // is `MIT OR Apache-2.0`. The shape predicate refuses every
12672        // forward-slash byte by construction.
12673        for lic in ["MIT/Apache-2.0", "MIT/BSD-3-Clause"] {
12674            let c = caixa_with_licenca(Some(lic));
12675            let err = c.validate_licenca().unwrap_err();
12676            assert!(
12677                matches!(err, ManifestError::LicencaInvalid { .. }),
12678                "expected LicencaInvalid on {lic:?}, got {err:?}",
12679            );
12680        }
12681    }
12682
12683    #[test]
12684    fn validate_licenca_rejects_semicolon_separator() {
12685        // Semicolon-list-separator confusion footgun — adjacent to
12686        // the comma-separator idiom, every list-separator-belongs-
12687        // to-list-grammar confusion lands here.
12688        let c = caixa_with_licenca(Some("MIT; Apache-2.0"));
12689        let err = c.validate_licenca().unwrap_err();
12690        assert!(
12691            matches!(err, ManifestError::LicencaInvalid { .. }),
12692            "got {err:?}",
12693        );
12694    }
12695
12696    #[test]
12697    fn validate_licenca_empty_takes_precedence_over_shape() {
12698        // Empty-first cascade pin: the empty `Some("")` surfaces the
12699        // narrower `LicencaEmpty` not the shape-predicate-wrapped
12700        // `LicencaInvalid`, mirroring the peer
12701        // `validate_edicao_empty_takes_precedence_over_shape` and
12702        // `validate_repositorio_empty_takes_precedence_over_shape`
12703        // (`RepositorioEmpty` → `RepositorioInvalid`), `NomeEmpty` →
12704        // `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid` cascades.
12705        // The shape predicate also refuses the empty input
12706        // (defensively — `"must not be empty"`), but the manifest-
12707        // layer empty arm runs first to surface the narrower
12708        // diagnostic verbatim.
12709        let c = caixa_with_licenca(Some(""));
12710        let err = c.validate_licenca().unwrap_err();
12711        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
12712    }
12713
12714    #[test]
12715    fn validate_licenca_invalid_diagnostic_carries_offending_value() {
12716        // Diagnostic-shape pin on the shape-predicate arm (peer with
12717        // `validate_edicao_invalid_diagnostic_carries_offending_value`
12718        // and `validate_repositorio_diagnostic_carries_offending_value`):
12719        // the error's Display surfaces the offending value + slot
12720        // name verbatim, so a `feira lint` run can render the
12721        // diagnostic without re-parsing and the author can grep
12722        // their caixa.lisp for the offending `:licenca` value.
12723        let c = caixa_with_licenca(Some("Apache_2.0"));
12724        let rendered = c.validate_licenca().unwrap_err().to_string();
12725        assert!(
12726            rendered.contains(":licenca"),
12727            "diagnostic must name the offending slot: {rendered}",
12728        );
12729        assert!(
12730            rendered.contains("Apache_2.0"),
12731            "diagnostic must quote the offending value: {rendered}",
12732        );
12733    }
12734
12735    #[test]
12736    fn validate_licenca_rejects_empty_some() {
12737        // Canonical paste-from-blank-doc footgun. Without this gate
12738        // the empty `Some("")` silently passed the renderer's
12739        // `Option::unwrap_or_else(|| "MIT".into())` (which only
12740        // fires on `None`) and landed as a bare trailing period in
12741        // the rendered chart `README.md` `## License` section.
12742        // Mirrors the peer [`ManifestError::DescricaoEmpty`] empty-
12743        // arm on the sibling `Option<String>` Caixa slot.
12744        let c = caixa_with_licenca(Some(""));
12745        let err = c.validate_licenca().unwrap_err();
12746        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
12747    }
12748
12749    #[test]
12750    fn validate_licenca_template_passes() {
12751        // Round-trip pin: the bare `Caixa::template` shape (whether
12752        // it carries `:licenca` or omits it) passes the gate by
12753        // construction. A future template-shape change that
12754        // introduced `(:licenca "")` would surface here as a
12755        // regression. Mirrors the peer
12756        // `validate_descricao_template_passes` pin.
12757        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12758        c.validate_licenca().unwrap();
12759    }
12760
12761    #[test]
12762    fn validate_licenca_diagnostic_names_offending_slot() {
12763        // Diagnostic-shape pin (peer with
12764        // `validate_descricao_diagnostic_names_offending_slot`):
12765        // the error's Display surfaces the `:licenca` slot name
12766        // verbatim, so a `feira lint` run can render the diagnostic
12767        // without re-parsing and the author can grep their caixa.lisp
12768        // for the offending `:licenca` line.
12769        let c = caixa_with_licenca(Some(""));
12770        let rendered = c.validate_licenca().unwrap_err().to_string();
12771        assert!(
12772            rendered.contains(":licenca"),
12773            "diagnostic must name the offending slot: {rendered}",
12774        );
12775    }
12776
12777    // ── Caixa::licenca — outer top-level Option<&str> scalar accessor ──
12778
12779    #[test]
12780    fn licenca_returns_licenca_byte_string_verbatim_across_permutations() {
12781        // The canonical per-`Caixa` `:licenca` SPDX-expression scalar
12782        // pin: [`Caixa::licenca`] must return the `:licenca` typed
12783        // byte-string verbatim as an `Option<&str>`, byte-equal to the
12784        // raw `self.licenca.as_deref()` access across every
12785        // representative value in the accept-set — `None` (the "omit
12786        // the slot to defer to the caixa-helm renderer's `MIT`
12787        // fallback" arm every existing fixture without a `:licenca`
12788        // line carries), `Some("")` (a past-the-guard sentinel that
12789        // pins the accessor doesn't perform a silent
12790        // `Some("") → None` collapse on the empty arm — validate
12791        // rejects `Some("")` through `LicencaEmpty` but the accessor
12792        // must ship the raw slot verbatim so a validate-time gate
12793        // regression surfaces at the caixa-helm emit boundary rather
12794        // than being silently absorbed into the fallback), `Some("MIT")`
12795        // (the canonical single-license shape every `feira init`
12796        // template scaffolds), `Some("Apache-2.0 OR MIT")` (the
12797        // canonical `OR`-compound shape the peer
12798        // `validate_licenca_accepts_canonical_expressions` positive
12799        // sweep exercises), `Some("(MIT OR Apache-2.0) AND
12800        // BSD-3-Clause")` (the canonical parenthesis-grouped shape),
12801        // `Some("MIT ")` / `Some(" MIT")` / `Some("MIT\n")` /
12802        // `Some("Apache_2.0")` / `Some("MIT,Apache-2.0")` (past-the-
12803        // guard sentinels — validate rejects each through
12804        // `LicencaInvalid` but the accessor must ship the raw slot
12805        // verbatim).
12806        //
12807        // First outer top-level [`Caixa`] `Option<&str>`-return scalar
12808        // accessor pin on the substrate primitive — opens the "outer
12809        // [`Caixa`] `Option<&str>` scalar" projection pattern the
12810        // sibling per-`Caixa` `:descricao` / `:repositorio` / `:edicao`
12811        // future lifts fold on. Sibling in shape to the peer per-`:placement`
12812        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12813        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12814        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12815        // axes, extended onto the outer top-level [`Caixa`] universal-
12816        // axis surface. Pins against a future silent detour that
12817        // returned an owned `Option<String>` (which would type-check
12818        // but silently allocate on every accessor call, breaking the
12819        // zero-cost projection every peer sibling accessor carries), a
12820        // `Some("") → None` collapse (which would silently absorb the
12821        // `LicencaEmpty` refusal case at the accessor boundary and the
12822        // caixa-helm emit path would silently fall back to `"MIT"` on
12823        // a struct-literal `Caixa { licenca: Some(""), .. }`), or a
12824        // `None → Some("MIT")` collapse (which would silently reify
12825        // the caixa-helm renderer's `"MIT"` fallback at the accessor
12826        // boundary and every downstream consumer keying off the
12827        // `Option::is_none()` discriminator would lose the "author
12828        // omitted the slot" signal).
12829        for licenca in [
12830            None,
12831            Some(""),
12832            Some("MIT"),
12833            Some("Apache-2.0 OR MIT"),
12834            Some("(MIT OR Apache-2.0) AND BSD-3-Clause"),
12835            Some("MIT "),
12836            Some(" MIT"),
12837            Some("MIT\n"),
12838            Some("Apache_2.0"),
12839            Some("MIT,Apache-2.0"),
12840        ] {
12841            let c = caixa_with_licenca(licenca);
12842            assert_eq!(
12843                c.licenca(),
12844                licenca,
12845                "Caixa::licenca must return :licenca verbatim (got {:?}, \
12846                 expected {licenca:?})",
12847                c.licenca(),
12848            );
12849            assert_eq!(
12850                c.licenca(),
12851                c.licenca.as_deref(),
12852                "Caixa::licenca must byte-equal the raw \
12853                 `self.licenca.as_deref()` field access across every \
12854                 value in the Option<&str> accept-set",
12855            );
12856        }
12857    }
12858
12859    #[test]
12860    fn validate_licenca_empty_arm_routes_through_accessor() {
12861        // Composition pin: [`Caixa::validate_licenca`]'s empty-arm gate
12862        // must key off [`Caixa::licenca`], not the raw
12863        // `self.licenca.as_deref()` field access. Structurally: a
12864        // `Caixa { licenca: Some(""), .. }` must surface the
12865        // `LicencaEmpty` refusal exactly, and a
12866        // `Caixa { licenca: Some("MIT"), .. }` (the canonical
12867        // single-license form) must pass validate. The pair jointly
12868        // pins the accessor + validate-gate composition: any future
12869        // silent detour that had the accessor return `None` on the
12870        // empty arm (a `.filter(|s| !s.is_empty())` collapse) would
12871        // silently absorb the `LicencaEmpty` refusal at the accessor
12872        // boundary and the validate gate would accept a struct-literal
12873        // `Caixa { licenca: Some(""), .. }` — the composition pin
12874        // catches that at caixa-core build time.
12875        //
12876        // Peer of the per-`:politicas :circuit-breaker`
12877        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
12878        // accessor-composition pin
12879        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
12880        // on the sibling per-M3-mesh-slot required-`u32` axis — same
12881        // "the validate / shape-gate predicate must route through the
12882        // substrate-primitive typed dispatch" discipline extended onto
12883        // the outer top-level [`Caixa`] universal-axis
12884        // `Option<&str>`-composition surface.
12885        let c = caixa_with_licenca(Some(""));
12886        assert!(
12887            matches!(c.validate_licenca(), Err(ManifestError::LicencaEmpty)),
12888            "validate_licenca must reject licenca == Some(\"\") with \
12889             LicencaEmpty — the accessor and the validate gate must \
12890             route through the same substrate-primitive typed dispatch \
12891             on the :licenca empty arm",
12892        );
12893        let c = caixa_with_licenca(Some("MIT"));
12894        assert!(
12895            c.validate_licenca().is_ok(),
12896            "validate_licenca must accept licenca == Some(\"MIT\") \
12897             (the canonical single-license SPDX shape)",
12898        );
12899    }
12900
12901    #[test]
12902    fn licenca_projects_option_str_by_borrow() {
12903        // The by-borrow pin: [`Caixa::licenca`] returns
12904        // `Option<&str>` by borrow — the `&str` borrows the underlying
12905        // `String` storage of the `Option<String>` slot and the
12906        // accessor must not allocate a fresh `String` on every call.
12907        // Peer of the per-`:placement`
12908        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
12909        // borrow pin on the peer per-M3-mesh-slot
12910        // `Option<&str>`-return axis, extended onto the outer top-
12911        // level [`Caixa`] universal-axis `Option<&str>` shape — the
12912        // accessor's returned `&str` must borrow from `&self` (the
12913        // returned reference's lifetime is tied to `&self`), and
12914        // calling the accessor twice on the same [`Caixa`] must yield
12915        // the same `Option<&str>` verbatim (idempotent, no side
12916        // effects on `&self`).
12917        //
12918        // Pins against a future silent detour that returned an owned
12919        // `Option<String>` (which would type-check but silently
12920        // allocate on every call, breaking the zero-cost projection
12921        // every peer sibling accessor carries), or a one-arm-only
12922        // accessor that returned a saturating value on some sentinel
12923        // input (breaking the pass-through invariant the sibling
12924        // required-scalar accessors carry).
12925        for licenca in [None, Some(""), Some("MIT"), Some("Apache-2.0 OR MIT")] {
12926            let c = caixa_with_licenca(licenca);
12927            let first = c.licenca();
12928            let second = c.licenca();
12929            assert_eq!(
12930                first, second,
12931                "Caixa::licenca must be idempotent — two successive \
12932                 calls on the same &self must return the same \
12933                 Option<&str>",
12934            );
12935            assert_eq!(
12936                first, licenca,
12937                "Caixa::licenca must return :licenca verbatim by \
12938                 borrow — got {first:?}, expected {licenca:?}",
12939            );
12940        }
12941    }
12942
12943    // ── Caixa::repositorio — outer top-level Option<&str> scalar accessor ──
12944
12945    #[test]
12946    fn repositorio_returns_repositorio_byte_string_verbatim_across_permutations() {
12947        // The canonical per-`Caixa` `:repositorio` git-repo-URL scalar
12948        // pin: [`Caixa::repositorio`] must return the `:repositorio`
12949        // typed byte-string verbatim as an `Option<&str>`, byte-equal
12950        // to the raw `self.repositorio.as_deref()` access across every
12951        // representative value in the accept-set — `None` (the "omit
12952        // the slot to defer to the per-renderer placeholder" arm every
12953        // existing fixture without a `:repositorio` line carries),
12954        // `Some("")` (a past-the-guard sentinel that pins the accessor
12955        // doesn't perform a silent `Some("") → None` collapse on the
12956        // empty arm — validate rejects `Some("")` through
12957        // `RepositorioEmpty` but the accessor must ship the raw slot
12958        // verbatim so a validate-time gate regression surfaces at the
12959        // caixa-helm / caixa-flux emit boundary rather than being
12960        // silently absorbed into the per-renderer fallback),
12961        // `Some("github:pleme-io/hello-rio")` (the canonical `github:`
12962        // shorthand every existing manifest fixture across
12963        // `caixa-helm` / `caixa-mesh` and the `examples/` uses),
12964        // `Some("https://github.com/pleme-io/checkout")` (the canonical
12965        // `https://` URL the README quickstart uses),
12966        // `Some("ssh://git@github.com/pleme-io/checkout.git")` /
12967        // `Some("git://github.com/pleme-io/checkout.git")` /
12968        // `Some("git@github.com:pleme-io/checkout.git")` /
12969        // `Some("file:///opt/mirrors/pleme-io/checkout")` (every non-
12970        // github scheme the shared `is_git_repo_url` predicate
12971        // documents), and five past-the-guard sentinels for the
12972        // `RepositorioInvalid` refusal cases (`Some("pleme-io/checkout")`
12973        // missing-colon, `Some("-upload-pack=evil")` leading-dash, /
12974        // `Some("github:pleme-io/checkout?ref=main")` query-string, /
12975        // `Some("github:pleme-io/checkout#main")` fragment-anchor, /
12976        // `Some("github:pleme-io/{tpl}")` URI-template-placeholder — the
12977        // sentinels pin the accessor doesn't silently absorb the
12978        // refusal cases into a fallback).
12979        //
12980        // Second outer top-level [`Caixa`] `Option<&str>`-return scalar
12981        // accessor pin on the substrate primitive — sibling of the peer
12982        // [`Caixa::licenca`] (6d5bc28) pin
12983        // (`licenca_returns_licenca_byte_string_verbatim_across_permutations`)
12984        // that opened the "outer [`Caixa`] `Option<&str>` scalar"
12985        // projection pin pattern this pin folds on. Sibling in shape to
12986        // the peer per-`:placement`
12987        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12988        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12989        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12990        // axes, extended onto the outer top-level [`Caixa`] universal-
12991        // axis surface. Pins against a future silent detour that
12992        // returned an owned `Option<String>` (which would type-check
12993        // but silently allocate on every accessor call, breaking the
12994        // zero-cost projection every peer sibling accessor carries), a
12995        // `Some("") → None` collapse (which would silently absorb the
12996        // `RepositorioEmpty` refusal case at the accessor boundary and
12997        // the caixa-helm `Chart.yaml` `home:` fold would silently
12998        // render a `home: null` / omitted field on a struct-literal
12999        // `Caixa { repositorio: Some(""), .. }`), or a
13000        // `None → Some(<default>)` collapse (which would silently reify
13001        // the per-renderer fallback at the accessor boundary and every
13002        // downstream consumer keying off the `Option::is_none()`
13003        // discriminator would lose the "author omitted the slot"
13004        // signal).
13005        for repositorio in [
13006            None,
13007            Some(""),
13008            Some("github:pleme-io/hello-rio"),
13009            Some("https://github.com/pleme-io/checkout"),
13010            Some("ssh://git@github.com/pleme-io/checkout.git"),
13011            Some("git://github.com/pleme-io/checkout.git"),
13012            Some("git@github.com:pleme-io/checkout.git"),
13013            Some("file:///opt/mirrors/pleme-io/checkout"),
13014            Some("pleme-io/checkout"),
13015            Some("-upload-pack=evil"),
13016            Some("github:pleme-io/checkout?ref=main"),
13017            Some("github:pleme-io/checkout#main"),
13018            Some("github:pleme-io/{tpl}"),
13019        ] {
13020            let c = caixa_with_repositorio(repositorio);
13021            assert_eq!(
13022                c.repositorio(),
13023                repositorio,
13024                "Caixa::repositorio must return :repositorio verbatim \
13025                 (got {:?}, expected {repositorio:?})",
13026                c.repositorio(),
13027            );
13028            assert_eq!(
13029                c.repositorio(),
13030                c.repositorio.as_deref(),
13031                "Caixa::repositorio must byte-equal the raw \
13032                 `self.repositorio.as_deref()` field access across every \
13033                 value in the Option<&str> accept-set",
13034            );
13035        }
13036    }
13037
13038    #[test]
13039    fn validate_repositorio_empty_arm_routes_through_accessor() {
13040        // Composition pin: [`Caixa::validate_repositorio`]'s empty-arm
13041        // gate must key off [`Caixa::repositorio`], not the raw
13042        // `self.repositorio.as_deref()` field access. Structurally: a
13043        // `Caixa { repositorio: Some(""), .. }` must surface the
13044        // `RepositorioEmpty` refusal exactly, and a
13045        // `Caixa { repositorio: Some("github:pleme-io/hello-rio"), .. }`
13046        // (the canonical `github:` shorthand form) must pass validate.
13047        // The pair jointly pins the accessor + validate-gate
13048        // composition: any future silent detour that had the accessor
13049        // return `None` on the empty arm (a `.filter(|s| !s.is_empty())`
13050        // collapse) would silently absorb the `RepositorioEmpty` refusal
13051        // at the accessor boundary and the validate gate would accept a
13052        // struct-literal `Caixa { repositorio: Some(""), .. }` — the
13053        // composition pin catches that at caixa-core build time.
13054        //
13055        // Peer of the [`Caixa::licenca`] (6d5bc28)
13056        // `validate_licenca_empty_arm_routes_through_accessor`
13057        // composition pin on the sibling outer top-level [`Caixa`]
13058        // `Option<&str>` universal-axis surface — same "the validate /
13059        // shape-gate predicate must route through the substrate-
13060        // primitive typed dispatch" discipline extended onto the second
13061        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
13062        // composition surface.
13063        let c = caixa_with_repositorio(Some(""));
13064        assert!(
13065            matches!(
13066                c.validate_repositorio(),
13067                Err(ManifestError::RepositorioEmpty),
13068            ),
13069            "validate_repositorio must reject repositorio == Some(\"\") \
13070             with RepositorioEmpty — the accessor and the validate gate \
13071             must route through the same substrate-primitive typed \
13072             dispatch on the :repositorio empty arm",
13073        );
13074        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio"));
13075        assert!(
13076            c.validate_repositorio().is_ok(),
13077            "validate_repositorio must accept repositorio == \
13078             Some(\"github:pleme-io/hello-rio\") (the canonical \
13079             `github:` shorthand git-repo-URL shape)",
13080        );
13081    }
13082
13083    #[test]
13084    fn repositorio_projects_option_str_by_borrow() {
13085        // The by-borrow pin: [`Caixa::repositorio`] returns
13086        // `Option<&str>` by borrow — the `&str` borrows the underlying
13087        // `String` storage of the `Option<String>` slot and the
13088        // accessor must not allocate a fresh `String` on every call.
13089        // Peer of the per-`:placement`
13090        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) and the
13091        // [`Caixa::licenca`] (6d5bc28) by-borrow pins on the peer
13092        // `Option<&str>`-return axes, extended onto the second outer
13093        // top-level [`Caixa`] universal-axis `Option<&str>` shape —
13094        // the accessor's returned `&str` must borrow from `&self` (the
13095        // returned reference's lifetime is tied to `&self`), and
13096        // calling the accessor twice on the same [`Caixa`] must yield
13097        // the same `Option<&str>` verbatim (idempotent, no side effects
13098        // on `&self`).
13099        //
13100        // Pins against a future silent detour that returned an owned
13101        // `Option<String>` (which would type-check but silently
13102        // allocate on every call, breaking the zero-cost projection
13103        // every peer sibling accessor carries), or a one-arm-only
13104        // accessor that returned a saturating value on some sentinel
13105        // input (breaking the pass-through invariant the sibling
13106        // required-scalar accessors carry).
13107        for repositorio in [
13108            None,
13109            Some(""),
13110            Some("github:pleme-io/hello-rio"),
13111            Some("https://github.com/pleme-io/checkout"),
13112        ] {
13113            let c = caixa_with_repositorio(repositorio);
13114            let first = c.repositorio();
13115            let second = c.repositorio();
13116            assert_eq!(
13117                first, second,
13118                "Caixa::repositorio must be idempotent — two successive \
13119                 calls on the same &self must return the same \
13120                 Option<&str>",
13121            );
13122            assert_eq!(
13123                first, repositorio,
13124                "Caixa::repositorio must return :repositorio verbatim by \
13125                 borrow — got {first:?}, expected {repositorio:?}",
13126            );
13127        }
13128    }
13129
13130    // ── Caixa::canonical_git_url — resolved-git-URL composer ──────────
13131
13132    #[test]
13133    fn canonical_git_url_returns_repositorio_verbatim_on_some_arm() {
13134        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] must
13135        // return the author-declared `:repositorio` byte-string verbatim
13136        // on the `Some` arm — no scheme rewrite, no trailing-slash
13137        // canonicalization, no `github:` → `https://github.com/`
13138        // desugaring. The resolved-URL composer is the projection of
13139        // the raw [`Caixa::repositorio`] `Option<&str>` accessor onto
13140        // the `String`-return arity every substrate-side field-fill
13141        // consumer keys off; on the `Some` arm the projection is
13142        // `str::to_owned` verbatim, so every accept-set value the
13143        // sibling `repositorio_returns_repositorio_byte_string_verbatim_
13144        // across_permutations` pin covers (`https://…`, `github:…`,
13145        // `ssh://…`, `git://…`, `git@…`, `file://…`, and the past-the-
13146        // guard sentinel `pleme-io/…`) must survive the accessor
13147        // byte-equal. Pins against a future silent detour that rewrote
13148        // the `github:` shorthand to the `https://github.com/` full URL
13149        // at the accessor boundary (which would silently split the
13150        // resolved-URL surface from the raw [`Caixa::repositorio`]
13151        // accessor's documented pass-through invariant), or a trailing-
13152        // slash normalization (which would silently break the
13153        // FluxCD `GitRepository` `spec.url` byte-exact match every
13154        // downstream consumer keys the source-controller reconcile off).
13155        for repositorio in [
13156            "github:pleme-io/hello-rio",
13157            "https://github.com/pleme-io/checkout",
13158            "ssh://git@github.com/pleme-io/checkout.git",
13159            "git://github.com/pleme-io/checkout.git",
13160            "git@github.com:pleme-io/checkout.git",
13161            "file:///opt/mirrors/pleme-io/checkout",
13162        ] {
13163            let c = caixa_with_repositorio(Some(repositorio));
13164            assert_eq!(
13165                c.canonical_git_url(),
13166                repositorio,
13167                "Caixa::canonical_git_url on the Some arm must return \
13168                 :repositorio verbatim (got {:?}, expected {repositorio:?})",
13169                c.canonical_git_url(),
13170            );
13171        }
13172    }
13173
13174    #[test]
13175    fn canonical_git_url_falls_back_to_pleme_org_url_on_none_arm() {
13176        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] on the
13177        // `None` arm must emit the substrate's canonical pleme-org github
13178        // URL derived from `caixa.nome()` — `https://github.com/<org>/
13179        // <nome>` with `<org>` bound to [`crate::DEFAULT_PLEME_GIT_ORG`]
13180        // and `<nome>` bound to the typed [`Caixa::nome`] accessor. This
13181        // is the exact byte-image of the prior inline
13182        // [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url`
13183        // composer at caixa-flux/src/lib.rs:2080 that every prior caller
13184        // re-derived open-coded. Pins against a future silent detour
13185        // that migrated the `<org>` segment to a different constant (a
13186        // fork rebranding that split off a new
13187        // `DEFAULT_PLEME_GIT_ORG_MIRROR` const the accessor would need
13188        // to migrate onto), a scheme change (`https://` → `git://` or
13189        // `ssh://`), or a per-`Caixa` `.canonical_git_url_prefix`
13190        // override (which would break the substrate-wide single-source-
13191        // of-truth guarantee this method encodes).
13192        let c = caixa_with_repositorio(None);
13193        let expected = format!(
13194            "https://github.com/{org}/{nome}",
13195            org = crate::DEFAULT_PLEME_GIT_ORG,
13196            nome = c.nome(),
13197        );
13198        assert_eq!(
13199            c.canonical_git_url(),
13200            expected,
13201            "Caixa::canonical_git_url on the None arm must fold through \
13202             the substrate's canonical pleme-org github URL fallback \
13203             `https://github.com/<DEFAULT_PLEME_GIT_ORG>/<nome>` — got \
13204             {:?}, expected {expected:?}",
13205            c.canonical_git_url(),
13206        );
13207    }
13208
13209    #[test]
13210    fn canonical_git_url_byte_matches_manual_composition() {
13211        // Byte-parity pin: [`Caixa::canonical_git_url`] must render
13212        // byte-identically to the manual open-coded
13213        // `caixa.repositorio().map(str::to_owned).unwrap_or_else(||
13214        //  format!("https://github.com/{org}/{nome}", ...))` composition
13215        // every prior substrate-side caller re-derived. Guards the
13216        // paired-site convergence just applied at caixa-flux's
13217        // [`ClusterBundleOpts::for_caixa`] `git_url` composer (which
13218        // now routes through this accessor): a future implementation of
13219        // this method that reordered the format arguments, swapped the
13220        // `<org>` constant for a different one, or interposed a
13221        // canonicalization pass on the `Some` arm surfaces here as a
13222        // caixa-core build-time test failure rather than as a downstream
13223        // FluxCD `GitRepository` reconcile mismatch far from this
13224        // method's source.
13225        for repositorio in [
13226            None,
13227            Some("github:pleme-io/hello-rio"),
13228            Some("https://github.com/pleme-io/checkout"),
13229            Some("ssh://git@github.com/pleme-io/checkout.git"),
13230        ] {
13231            let c = caixa_with_repositorio(repositorio);
13232            let manual = c.repositorio().map_or_else(
13233                || {
13234                    format!(
13235                        "https://github.com/{org}/{nome}",
13236                        org = crate::DEFAULT_PLEME_GIT_ORG,
13237                        nome = c.nome(),
13238                    )
13239                },
13240                str::to_owned,
13241            );
13242            assert_eq!(
13243                c.canonical_git_url(),
13244                manual,
13245                "Caixa::canonical_git_url must byte-equal the manual \
13246                 open-coded `repositorio().map(str::to_owned)\
13247                 .unwrap_or_else(|| format!(...))` composition across \
13248                 every representative :repositorio input — got {:?}, \
13249                 expected {manual:?}",
13250                c.canonical_git_url(),
13251            );
13252        }
13253    }
13254
13255    // ── Caixa::publish_tag — resolved-publish-tag composer ───────────
13256
13257    #[test]
13258    fn publish_tag_composes_prefix_and_versao_on_all_shapes() {
13259        // Fail-before-pass-after pin: [`Caixa::publish_tag`] must compose
13260        // [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] against the caixa's typed
13261        // [`Caixa::versao`] byte-string across every SemVer-2 shape the
13262        // sibling [`validate_versao_accepts_canonical_forms`] positive-set
13263        // sweep documents — bare MAJOR.MINOR.PATCH, pre-release tags
13264        // (`-rc.1`), build metadata (`+build.42`), the combined form, and
13265        // the `0.0.0` boundary case. Every accept-set value the peer
13266        // validate gate lets through must survive the resolved-tag
13267        // projection byte-equal.
13268        for versao in [
13269            "0.1.0",
13270            "0.0.0",
13271            "1.0.0",
13272            "1.2.3-rc.1",
13273            "1.2.3+build.42",
13274            "1.2.3-rc.1+build.42",
13275        ] {
13276            let c = caixa_with_versao(versao);
13277            let expected = format!(
13278                "{prefix}{versao}",
13279                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13280            );
13281            assert_eq!(
13282                c.publish_tag(),
13283                expected,
13284                "Caixa::publish_tag must compose \
13285                 DEFAULT_PUBLISH_TAG_PREFIX ({prefix:?}) against \
13286                 :versao ({versao:?}) verbatim — got {got:?}, \
13287                 expected {expected:?}",
13288                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13289                got = c.publish_tag(),
13290            );
13291        }
13292    }
13293
13294    #[test]
13295    fn publish_tag_starts_with_default_publish_tag_prefix() {
13296        // Prefix-shape pin: every [`Caixa::publish_tag`] emission must
13297        // begin with the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
13298        // byte-string on every input, guarding a hypothetical future
13299        // implementation that migrated the prefix segment to an inline
13300        // literal (`"v"`) that would silently drift from any rebrand of
13301        // the lifted constant. Peer to the sibling caixa-flux
13302        // `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`
13303        // test which pins the same prefix invariant at the reader-side
13304        // `GitRefSpec::Tag` emit site.
13305        for versao in ["0.0.0", "0.1.0", "1.2.3-rc.1", "9.9.9+build.1"] {
13306            let c = caixa_with_versao(versao);
13307            let tag = c.publish_tag();
13308            assert!(
13309                tag.starts_with(crate::DEFAULT_PUBLISH_TAG_PREFIX),
13310                "Caixa::publish_tag emission {tag:?} must start with \
13311                 the lifted crate::DEFAULT_PUBLISH_TAG_PREFIX \
13312                 ({prefix:?})",
13313                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13314            );
13315        }
13316    }
13317
13318    #[test]
13319    fn publish_tag_byte_matches_manual_composition() {
13320        // Byte-parity pin: [`Caixa::publish_tag`] must render byte-
13321        // identically to the manual open-coded
13322        // `format!("{prefix}{versao}", prefix =
13323        //  caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao =
13324        //  caixa.versao())` composition every prior substrate-side
13325        // caller re-derived. Guards the paired-site convergence just
13326        // applied at caixa-flux's [`ClusterBundleOpts::for_caixa`]
13327        // `git_ref` composer (which now routes through this accessor):
13328        // a future implementation of this method that reordered the
13329        // format arguments, swapped the `<prefix>` constant for a
13330        // different one, or interposed a canonicalization pass on the
13331        // `:versao` axis surfaces here as a caixa-core build-time test
13332        // failure rather than as a downstream FluxCD `GitRepository`
13333        // reconcile mismatch far from this method's source.
13334        for versao in [
13335            "0.1.0",
13336            "0.0.0",
13337            "1.2.3-rc.1",
13338            "1.2.3+build.42",
13339            "1.2.3-rc.1+build.42",
13340        ] {
13341            let c = caixa_with_versao(versao);
13342            let manual = format!(
13343                "{prefix}{versao}",
13344                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13345                versao = c.versao(),
13346            );
13347            assert_eq!(
13348                c.publish_tag(),
13349                manual,
13350                "Caixa::publish_tag must byte-equal the manual \
13351                 open-coded `format!(\"{{prefix}}{{versao}}\", ...)` \
13352                 composition across every representative :versao input \
13353                 — got {got:?}, expected {manual:?}",
13354                got = c.publish_tag(),
13355            );
13356        }
13357    }
13358
13359    // ── Caixa::lareira_chart_name — resolved-chart-name composer ─────
13360
13361    #[test]
13362    fn lareira_chart_name_composes_prefix_and_nome_on_all_shapes() {
13363        // Fail-before-pass-after pin: [`Caixa::lareira_chart_name`] must
13364        // compose [`crate::LAREIRA_CHART_NAME_PREFIX`] against the caixa's
13365        // typed [`Caixa::nome`] byte-string across every DNS-1123 shape
13366        // the sibling [`validate_nome_accepts_canonical_forms`] positive-
13367        // set sweep documents — single-word, hyphen-joined, version-
13368        // suffixed, single-char, two-char, digit-start, retry-suffixed.
13369        // Every accept-set value the peer validate gate lets through must
13370        // survive the resolved-chart-name projection byte-equal.
13371        for nome in [
13372            "checkout",
13373            "cart-v2",
13374            "a",
13375            "db",
13376            "3rd-party-shim",
13377            "payment-retry",
13378            "0",
13379        ] {
13380            let c = caixa_with_nome(nome);
13381            let expected = format!("{prefix}{nome}", prefix = crate::LAREIRA_CHART_NAME_PREFIX);
13382            assert_eq!(
13383                c.lareira_chart_name(),
13384                expected,
13385                "Caixa::lareira_chart_name must compose \
13386                 LAREIRA_CHART_NAME_PREFIX ({prefix:?}) against \
13387                 :nome ({nome:?}) verbatim — got {got:?}, \
13388                 expected {expected:?}",
13389                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
13390                got = c.lareira_chart_name(),
13391            );
13392        }
13393    }
13394
13395    #[test]
13396    fn lareira_chart_name_starts_with_lifted_prefix() {
13397        // Prefix-shape pin: every [`Caixa::lareira_chart_name`] emission
13398        // must begin with the canonical
13399        // [`crate::LAREIRA_CHART_NAME_PREFIX`] byte-string on every
13400        // input, guarding a hypothetical future implementation that
13401        // migrated the prefix segment to an inline literal (`"lareira-"`)
13402        // that would silently drift from any rebrand of the lifted
13403        // constant. Peer to the sibling
13404        // [`publish_tag_starts_with_default_publish_tag_prefix`] pin on
13405        // the co-resident resolved-publish-tag composer's prefix axis.
13406        for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
13407            let c = caixa_with_nome(nome);
13408            let chart = c.lareira_chart_name();
13409            assert!(
13410                chart.starts_with(crate::LAREIRA_CHART_NAME_PREFIX),
13411                "Caixa::lareira_chart_name emission {chart:?} must start \
13412                 with the lifted crate::LAREIRA_CHART_NAME_PREFIX \
13413                 ({prefix:?})",
13414                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
13415            );
13416        }
13417    }
13418
13419    #[test]
13420    fn lareira_chart_name_byte_matches_canonical_helper_composition() {
13421        // Byte-parity pin: [`Caixa::lareira_chart_name`] must render
13422        // byte-identically to the manual open-coded
13423        // `caixa_core::lareira_chart_name(caixa.nome())` two-step
13424        // composition every prior substrate-side caller re-derived.
13425        // Guards the paired-site convergence just applied at caixa-helm's
13426        // [`render_chart_for_servico_with`] `ChartDir.name` composer,
13427        // caixa-flux's [`cluster_bundle`] per-CR `chart_name` binding,
13428        // and caixa-tatara's [`process_for_aplicacao`] `release_name`
13429        // composer (all of which now route through this accessor): a
13430        // future implementation of this method that reordered the
13431        // composition arguments, swapped the `<prefix>` constant for a
13432        // different one, or interposed a canonicalization pass on the
13433        // `:nome` axis surfaces here as a caixa-core build-time test
13434        // failure rather than as a downstream Helm chart-render / FluxCD
13435        // reconcile / tatara Process-CR mismatch far from this method's
13436        // source.
13437        for nome in [
13438            "checkout",
13439            "cart-v2",
13440            "a",
13441            "db",
13442            "3rd-party-shim",
13443            "payment-retry",
13444        ] {
13445            let c = caixa_with_nome(nome);
13446            let manual = crate::lareira_chart_name(c.nome());
13447            assert_eq!(
13448                c.lareira_chart_name(),
13449                manual,
13450                "Caixa::lareira_chart_name must byte-equal the manual \
13451                 open-coded `caixa_core::lareira_chart_name(caixa.nome())` \
13452                 composition across every representative :nome input — \
13453                 got {got:?}, expected {manual:?}",
13454                got = c.lareira_chart_name(),
13455            );
13456        }
13457    }
13458
13459    // ── Caixa::oci_chart_ref — resolved-OCI-chart-ref composer ────────
13460
13461    #[test]
13462    fn oci_chart_ref_composes_scheme_and_lareira_chart_name_on_all_shapes() {
13463        // Fail-before-pass-after pin: [`Caixa::oci_chart_ref`] must
13464        // compose [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied
13465        // `registry` + [`crate::lareira_chart_name`]-of-[`Caixa::nome`]
13466        // across the full paired `(registry, :nome)` accept-set — every
13467        // representative registry the substrate-side emitters carry
13468        // (`ghcr.io/pleme-io/charts`, the canonical CAIXA-SDLC §II
13469        // ArtifactHub-tier registry; `ghcr.io/pleme-io`, the bare-org
13470        // arm the sibling `oci_chart_ref_pins_byte_shape_against_prior_
13471        // inline_format` render-side pin exercises; `registry.example.
13472        // com`, an off-org shape; `localhost:5000`, the local-dev shape
13473        // every `feira chart` iteration path lands under) × every DNS-
13474        // 1123 `:nome` shape the peer `validate_nome_accepts_canonical_
13475        // forms` positive-set sweep documents (single-word, hyphen-
13476        // joined, single-char, two-char, digit-start, retry-suffixed).
13477        // Every accept-set pair the peer validate gates let through must
13478        // survive the resolved-OCI-ref projection byte-equal.
13479        for registry in [
13480            "ghcr.io/pleme-io/charts",
13481            "ghcr.io/pleme-io",
13482            "registry.example.com",
13483            "localhost:5000",
13484        ] {
13485            for nome in [
13486                "checkout",
13487                "cart-v2",
13488                "a",
13489                "db",
13490                "3rd-party-shim",
13491                "payment-retry",
13492                "0",
13493            ] {
13494                let c = caixa_with_nome(nome);
13495                let expected = format!(
13496                    "{scheme}{registry}/{chart}",
13497                    scheme = crate::OCI_SCHEME_PREFIX,
13498                    chart = crate::lareira_chart_name(nome),
13499                );
13500                assert_eq!(
13501                    c.oci_chart_ref(registry),
13502                    expected,
13503                    "Caixa::oci_chart_ref must compose \
13504                     OCI_SCHEME_PREFIX ({scheme:?}) + registry ({registry:?}) + \
13505                     lareira_chart_name(:nome ({nome:?})) verbatim — got {got:?}, \
13506                     expected {expected:?}",
13507                    scheme = crate::OCI_SCHEME_PREFIX,
13508                    got = c.oci_chart_ref(registry),
13509                );
13510            }
13511        }
13512    }
13513
13514    #[test]
13515    fn oci_chart_ref_starts_with_lifted_scheme_prefix() {
13516        // Scheme-prefix-shape pin: every [`Caixa::oci_chart_ref`]
13517        // emission must begin with the canonical
13518        // [`crate::OCI_SCHEME_PREFIX`] byte-string on every input, guarding
13519        // a hypothetical future implementation that migrated the scheme
13520        // segment to an inline literal (`"oci://"`) that would silently
13521        // drift from any rebrand of the lifted constant. Peer to the
13522        // sibling [`publish_tag_starts_with_default_publish_tag_prefix`]
13523        // + [`lareira_chart_name_starts_with_lifted_prefix`] pins on the
13524        // co-resident resolved-publish-tag / resolved-chart-name
13525        // composers' prefix axes.
13526        for registry in [
13527            "ghcr.io/pleme-io/charts",
13528            "ghcr.io/pleme-io",
13529            "localhost:5000",
13530        ] {
13531            for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
13532                let c = caixa_with_nome(nome);
13533                let ref_ = c.oci_chart_ref(registry);
13534                assert!(
13535                    ref_.starts_with(crate::OCI_SCHEME_PREFIX),
13536                    "Caixa::oci_chart_ref emission {ref_:?} must start \
13537                     with the lifted crate::OCI_SCHEME_PREFIX ({scheme:?}) \
13538                     — registry ({registry:?}), :nome ({nome:?})",
13539                    scheme = crate::OCI_SCHEME_PREFIX,
13540                );
13541            }
13542        }
13543    }
13544
13545    #[test]
13546    fn oci_chart_ref_byte_matches_canonical_helper_composition() {
13547        // Byte-parity pin: [`Caixa::oci_chart_ref`] must render byte-
13548        // identically to the manual open-coded
13549        // `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step
13550        // composition every prior substrate-side caller re-derived.
13551        // Guards the paired-site convergence just applied at caixa-
13552        // tatara's [`derive_chart_ref`] helper (which now routes through
13553        // this accessor): a future implementation of this method that
13554        // reordered the composition arguments, swapped the `<scheme>`
13555        // constant for a different one, migrated the `<chart>` segment
13556        // off the paired [`crate::lareira_chart_name`] composer, or
13557        // interposed a canonicalization pass on either input axis
13558        // surfaces here as a caixa-core build-time test failure rather
13559        // than as a downstream `helm install` / FluxCD OCI-source
13560        // reconcile / tatara `Process`-CR mismatch far from this
13561        // method's source. Sibling to the peer
13562        // [`lareira_chart_name_byte_matches_canonical_helper_composition`]
13563        // / [`publish_tag_byte_matches_manual_composition`] /
13564        // [`canonical_git_url_byte_matches_manual_composition`] byte-
13565        // parity pins that carry the same discipline on the co-resident
13566        // resolved-chart-name / resolved-publish-tag / resolved-git-URL
13567        // composers.
13568        for registry in [
13569            "ghcr.io/pleme-io/charts",
13570            "ghcr.io/pleme-io",
13571            "registry.example.com",
13572            "localhost:5000",
13573        ] {
13574            for nome in [
13575                "checkout",
13576                "cart-v2",
13577                "a",
13578                "db",
13579                "3rd-party-shim",
13580                "payment-retry",
13581            ] {
13582                let c = caixa_with_nome(nome);
13583                let manual = crate::oci_chart_ref(registry, c.nome());
13584                assert_eq!(
13585                    c.oci_chart_ref(registry),
13586                    manual,
13587                    "Caixa::oci_chart_ref must byte-equal the manual \
13588                     open-coded `caixa_core::oci_chart_ref(registry, \
13589                     caixa.nome())` composition across every representative \
13590                     (registry, :nome) pair — registry ({registry:?}), \
13591                     :nome ({nome:?}), got {got:?}, expected {manual:?}",
13592                    got = c.oci_chart_ref(registry),
13593                );
13594            }
13595        }
13596    }
13597
13598    // ── Caixa::descricao — outer top-level Option<&str> scalar accessor ──
13599
13600    #[test]
13601    fn descricao_returns_descricao_byte_string_verbatim_across_permutations() {
13602        // The canonical per-`Caixa` `:descricao` free-form-prose scalar
13603        // pin: [`Caixa::descricao`] must return the `:descricao` typed
13604        // byte-string verbatim as an `Option<&str>`, byte-equal to the
13605        // raw `self.descricao.as_deref()` access across every
13606        // representative value in the accept-set — `None` (the "omit
13607        // the slot to defer to the per-renderer `caixa.nome`-derived
13608        // fallback" arm every existing fixture without a `:descricao`
13609        // line carries), `Some("")` (a past-the-guard sentinel that
13610        // pins the accessor doesn't perform a silent `Some("") → None`
13611        // collapse on the empty arm — validate rejects `Some("")`
13612        // through `DescricaoEmpty` but the accessor must ship the raw
13613        // slot verbatim so a validate-time gate regression surfaces at
13614        // the caixa-helm / caixa-feira emit boundary rather than being
13615        // silently absorbed into the per-renderer `caixa.nome`-derived
13616        // fallback), `Some("Checkout flow.")` (the canonical one-line
13617        // prose descriptor the peer
13618        // `validate_descricao_accepts_canonical_value` positive sweep
13619        // exercises), `Some("Canonical Rust→wasm32-wasip2 caixa
13620        // Servico.")` (the multi-byte Unicode continuation-byte shape
13621        // the `hello-rio` fixture carries), `Some("→ — · ✓")` (a
13622        // multi-glyph Unicode shape the peer
13623        // `is_chart_description_shape` predicate accepts), and five
13624        // past-the-guard sentinels for the `DescricaoInvalid` refusal
13625        // cases (`Some(" Checkout flow.")` leading-whitespace,
13626        // `Some("Checkout flow. ")` trailing-whitespace,
13627        // `Some("Checkout\nflow.")` embedded-LF,
13628        // `Some("Checkout\tflow.")` embedded-TAB, and
13629        // `Some("Checkout\x00flow.")` embedded-NUL — the sentinels pin
13630        // the accessor doesn't silently absorb the refusal cases into
13631        // a fallback).
13632        //
13633        // Third outer top-level [`Caixa`] `Option<&str>`-return scalar
13634        // accessor pin on the substrate primitive — sibling of the peer
13635        // [`Caixa::licenca`] (6d5bc28) and [`Caixa::repositorio`]
13636        // (cc7332d) pins that opened the "outer [`Caixa`]
13637        // `Option<&str>` scalar" projection pin pattern this pin folds
13638        // on. Sibling in shape to the peer per-`:placement`
13639        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
13640        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
13641        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
13642        // axes, extended onto the outer top-level [`Caixa`] universal-
13643        // axis surface. Pins against a future silent detour that
13644        // returned an owned `Option<String>` (which would type-check
13645        // but silently allocate on every accessor call, breaking the
13646        // zero-cost projection every peer sibling accessor carries), a
13647        // `Some("") → None` collapse (which would silently absorb the
13648        // `DescricaoEmpty` refusal case at the accessor boundary and
13649        // the caixa-helm `Chart.yaml` `description:` fold would
13650        // silently render a `caixa.nome`-derived fallback on a
13651        // struct-literal `Caixa { descricao: Some(""), .. }`), or a
13652        // `None → Some(<default>)` collapse (which would silently
13653        // reify the per-renderer `caixa.nome`-derived fallback at the
13654        // accessor boundary and every downstream consumer keying off
13655        // the `Option::is_none()` discriminator would lose the "author
13656        // omitted the slot" signal).
13657        for descricao in [
13658            None,
13659            Some(""),
13660            Some("Checkout flow."),
13661            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
13662            Some("→ — · ✓"),
13663            Some(" Checkout flow."),
13664            Some("Checkout flow. "),
13665            Some("Checkout\nflow."),
13666            Some("Checkout\tflow."),
13667            Some("Checkout\x00flow."),
13668        ] {
13669            let c = caixa_with_descricao(descricao);
13670            assert_eq!(
13671                c.descricao(),
13672                descricao,
13673                "Caixa::descricao must return :descricao verbatim (got \
13674                 {:?}, expected {descricao:?})",
13675                c.descricao(),
13676            );
13677            assert_eq!(
13678                c.descricao(),
13679                c.descricao.as_deref(),
13680                "Caixa::descricao must byte-equal the raw \
13681                 `self.descricao.as_deref()` field access across every \
13682                 value in the Option<&str> accept-set",
13683            );
13684        }
13685    }
13686
13687    #[test]
13688    fn validate_descricao_empty_arm_routes_through_accessor() {
13689        // Composition pin: [`Caixa::validate_descricao`]'s empty-arm
13690        // gate must key off [`Caixa::descricao`], not the raw
13691        // `self.descricao.as_deref()` field access. Structurally: a
13692        // `Caixa { descricao: Some(""), .. }` must surface the
13693        // `DescricaoEmpty` refusal exactly, and a
13694        // `Caixa { descricao: Some("Checkout flow."), .. }` (the
13695        // canonical one-line-prose form) must pass validate. The pair
13696        // jointly pins the accessor + validate-gate composition: any
13697        // future silent detour that had the accessor return `None` on
13698        // the empty arm (a `.filter(|s| !s.is_empty())` collapse) would
13699        // silently absorb the `DescricaoEmpty` refusal at the accessor
13700        // boundary and the validate gate would accept a struct-literal
13701        // `Caixa { descricao: Some(""), .. }` — the composition pin
13702        // catches that at caixa-core build time.
13703        //
13704        // Peer of the [`Caixa::licenca`] (6d5bc28)
13705        // `validate_licenca_empty_arm_routes_through_accessor` and
13706        // [`Caixa::repositorio`] (cc7332d)
13707        // `validate_repositorio_empty_arm_routes_through_accessor`
13708        // composition pins on the sibling outer top-level [`Caixa`]
13709        // `Option<&str>` universal-axis surface — same "the validate /
13710        // shape-gate predicate must route through the substrate-
13711        // primitive typed dispatch" discipline extended onto the third
13712        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
13713        // composition surface.
13714        let c = caixa_with_descricao(Some(""));
13715        assert!(
13716            matches!(c.validate_descricao(), Err(ManifestError::DescricaoEmpty),),
13717            "validate_descricao must reject descricao == Some(\"\") \
13718             with DescricaoEmpty — the accessor and the validate gate \
13719             must route through the same substrate-primitive typed \
13720             dispatch on the :descricao empty arm",
13721        );
13722        let c = caixa_with_descricao(Some("Checkout flow."));
13723        assert!(
13724            c.validate_descricao().is_ok(),
13725            "validate_descricao must accept descricao == \
13726             Some(\"Checkout flow.\") (the canonical one-line-prose \
13727             chart-description shape)",
13728        );
13729    }
13730
13731    #[test]
13732    fn descricao_projects_option_str_by_borrow() {
13733        // The by-borrow pin: [`Caixa::descricao`] returns
13734        // `Option<&str>` by borrow — the `&str` borrows the underlying
13735        // `String` storage of the `Option<String>` slot and the
13736        // accessor must not allocate a fresh `String` on every call.
13737        // Peer of the [`Caixa::licenca`] (6d5bc28) and
13738        // [`Caixa::repositorio`] (cc7332d) by-borrow pins on the peer
13739        // outer top-level [`Caixa`] `Option<&str>`-return axes, and of
13740        // the per-`:placement`
13741        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
13742        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
13743        // return axis, extended onto the third outer top-level
13744        // [`Caixa`] universal-axis `Option<&str>` shape — the
13745        // accessor's returned `&str` must borrow from `&self` (the
13746        // returned reference's lifetime is tied to `&self`), and
13747        // calling the accessor twice on the same [`Caixa`] must yield
13748        // the same `Option<&str>` verbatim (idempotent, no side
13749        // effects on `&self`).
13750        //
13751        // Pins against a future silent detour that returned an owned
13752        // `Option<String>` (which would type-check but silently
13753        // allocate on every call, breaking the zero-cost projection
13754        // every peer sibling accessor carries), or a one-arm-only
13755        // accessor that returned a saturating value on some sentinel
13756        // input (breaking the pass-through invariant the sibling
13757        // required-scalar accessors carry).
13758        for descricao in [
13759            None,
13760            Some(""),
13761            Some("Checkout flow."),
13762            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
13763        ] {
13764            let c = caixa_with_descricao(descricao);
13765            let first = c.descricao();
13766            let second = c.descricao();
13767            assert_eq!(
13768                first, second,
13769                "Caixa::descricao must be idempotent — two successive \
13770                 calls on the same &self must return the same \
13771                 Option<&str>",
13772            );
13773            assert_eq!(
13774                first, descricao,
13775                "Caixa::descricao must return :descricao verbatim by \
13776                 borrow — got {first:?}, expected {descricao:?}",
13777            );
13778        }
13779    }
13780
13781    // ── validate_edicao — universal-axis language-edition shape ──
13782
13783    fn caixa_with_edicao(edicao: Option<&str>) -> Caixa {
13784        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13785        c.edicao = edicao.map(String::from);
13786        c
13787    }
13788
13789    #[test]
13790    fn validate_edicao_accepts_none() {
13791        // The omit-the-slot identity: `:edicao` is optional. The
13792        // gate is a no-op when the author didn't declare a value —
13793        // every caixa without an `:edicao` line trivially passes,
13794        // and the substrate-side build pipeline falls back to the
13795        // documented default edition. Mirrors the peer
13796        // `validate_licenca_accepts_none` posture on the sibling
13797        // `Option<String>` Caixa slot.
13798        let c = caixa_with_edicao(None);
13799        c.validate_edicao().unwrap();
13800    }
13801
13802    #[test]
13803    fn validate_edicao_accepts_canonical_value() {
13804        // Positive control: the canonical `"2026"` edition every
13805        // existing renderer-side fixture (`caixa-helm`, `caixa-flux`,
13806        // `caixa-mesh`) carries by construction passes the gate.
13807        // Future-introduced sibling editions (`"2027"`, `"2030"`,
13808        // `"2049"`) that match the same 4-digit ASCII decimal year
13809        // shape must also trivially pass — the structural shape
13810        // predicate accepts every well-formed year regardless of
13811        // whether the substrate yet understands the specific value
13812        // (a future known-edition allowlist tightens that).
13813        for ed in ["2026", "2027", "2030", "2049"] {
13814            let c = caixa_with_edicao(Some(ed));
13815            c.validate_edicao()
13816                .unwrap_or_else(|err| panic!("canonical {ed:?} must pass: {err:?}"));
13817        }
13818    }
13819
13820    #[test]
13821    fn validate_edicao_rejects_empty_some() {
13822        // Canonical paste-from-blank-doc footgun. Without this gate
13823        // the empty `Some("")` silently lands as `(:edicao "")` in
13824        // the rendered caixa.lisp and a future renderer-side
13825        // consumer's `Option::unwrap_or_else` (which only fires on
13826        // `None`) skips its fallback. Mirrors the peer
13827        // [`ManifestError::LicencaEmpty`] empty-arm on the sibling
13828        // `Option<String>` Caixa slot.
13829        let c = caixa_with_edicao(Some(""));
13830        let err = c.validate_edicao().unwrap_err();
13831        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
13832    }
13833
13834    #[test]
13835    fn validate_edicao_rejects_free_form_non_year() {
13836        // Free-form non-year footgun: the bare `"x"` / `"latest"` /
13837        // `"nightly"` shapes carry no operational meaning on the
13838        // substrate's build-time edition selector. Until this gate
13839        // landed the bare empty-arm check let every such value
13840        // through and broke far from the source caixa.lisp. Peer
13841        // with the shape-predicate cascade
13842        // `validate_repositorio_rejects_missing_colon_separator`
13843        // establishes past its own empty arm.
13844        for ed in ["x", "latest", "nightly", "stable"] {
13845            let c = caixa_with_edicao(Some(ed));
13846            let err = c.validate_edicao().unwrap_err();
13847            assert!(
13848                matches!(err, ManifestError::EdicaoInvalid { .. }),
13849                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13850            );
13851        }
13852    }
13853
13854    #[test]
13855    fn validate_edicao_rejects_trailing_whitespace() {
13856        // Paste-from-doc whitespace footgun. A trailing space in
13857        // the `:edicao` value would silently break the substrate's
13858        // build-time edition match-table lookup at the rendered
13859        // artifact's edition-selector consumer. The shape predicate
13860        // refuses every whitespace byte by construction (any byte
13861        // outside `0-9` fails `is_ascii_digit`). Peer with
13862        // `validate_repositorio_rejects_whitespace`.
13863        let c = caixa_with_edicao(Some("2026 "));
13864        let err = c.validate_edicao().unwrap_err();
13865        let ManifestError::EdicaoInvalid { edicao, .. } = err else {
13866            panic!("expected EdicaoInvalid, got {err:?}");
13867        };
13868        assert_eq!(edicao, "2026 ");
13869    }
13870
13871    #[test]
13872    fn validate_edicao_rejects_leading_whitespace() {
13873        // Symmetric paste-from-doc whitespace footgun on the leading
13874        // boundary — the gate refuses every shape with a non-digit
13875        // byte by construction.
13876        let c = caixa_with_edicao(Some(" 2026"));
13877        let err = c.validate_edicao().unwrap_err();
13878        assert!(
13879            matches!(err, ManifestError::EdicaoInvalid { .. }),
13880            "got {err:?}",
13881        );
13882    }
13883
13884    #[test]
13885    fn validate_edicao_rejects_control_char() {
13886        // Paste-from-multiline-doc CRLF footgun — control characters
13887        // at the value boundary break the substrate's build-time
13888        // edition-selector parser. Peer with
13889        // `validate_repositorio_rejects_control_char`.
13890        let c = caixa_with_edicao(Some("2026\n"));
13891        let err = c.validate_edicao().unwrap_err();
13892        assert!(
13893            matches!(err, ManifestError::EdicaoInvalid { .. }),
13894            "got {err:?}",
13895        );
13896    }
13897
13898    #[test]
13899    fn validate_edicao_rejects_non_ascii_lookalike() {
13900        // Fullwidth-keyboard look-alike footgun — `"2026"` is
13901        // the U+FF12 U+FF10 U+FF12 U+FF16 sequence (CJK fullwidth
13902        // digits), 4 codepoints but 12 UTF-8 bytes; the substrate's
13903        // edition selector wants an ASCII year, and the gate
13904        // refuses every non-ASCII shape by construction (length in
13905        // bytes is 12 ≠ 4, *and* every byte falls outside
13906        // `is_ascii_digit`'s `0-9` range).
13907        let c = caixa_with_edicao(Some("2026"));
13908        let err = c.validate_edicao().unwrap_err();
13909        assert!(
13910            matches!(err, ManifestError::EdicaoInvalid { .. }),
13911            "got {err:?}",
13912        );
13913    }
13914
13915    #[test]
13916    fn validate_edicao_rejects_version_tag_prefix() {
13917        // Common version-tag idiom footgun — `"v2026"` / `"e2026"`
13918        // / `"r2026"` are familiar shapes from git-tag / Rust
13919        // edition / release-tag conventions that don't apply to
13920        // the year-shaped edition axis. The shape predicate refuses
13921        // every leading non-digit prefix.
13922        for ed in ["v2026", "e2026", "r2026"] {
13923            let c = caixa_with_edicao(Some(ed));
13924            let err = c.validate_edicao().unwrap_err();
13925            assert!(
13926                matches!(err, ManifestError::EdicaoInvalid { .. }),
13927                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13928            );
13929        }
13930    }
13931
13932    #[test]
13933    fn validate_edicao_rejects_decimal_shape() {
13934        // Decimal-shaped pseudo-version footgun — `"2026.1"` /
13935        // `"2026.0"` are familiar shapes from semver / float
13936        // conventions that don't apply to the year-shaped edition
13937        // axis. The shape predicate refuses every non-digit byte
13938        // (`.` falls outside `is_ascii_digit`).
13939        for ed in ["2026.1", "2026.0", "2026.0.1"] {
13940            let c = caixa_with_edicao(Some(ed));
13941            let err = c.validate_edicao().unwrap_err();
13942            assert!(
13943                matches!(err, ManifestError::EdicaoInvalid { .. }),
13944                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13945            );
13946        }
13947    }
13948
13949    #[test]
13950    fn validate_edicao_rejects_wrong_length_numeric() {
13951        // Wrong-length numeric footgun — `"26"` (truncated) /
13952        // `"202"` (truncated) / `"20260"` (extra digit) / `"00026"`
13953        // (zero-padded too wide) all parse as integers but don't
13954        // name a 4-digit year. The shape predicate refuses every
13955        // value whose length isn't exactly 4 bytes.
13956        for ed in ["26", "202", "20260", "00026", "9"] {
13957            let c = caixa_with_edicao(Some(ed));
13958            let err = c.validate_edicao().unwrap_err();
13959            assert!(
13960                matches!(err, ManifestError::EdicaoInvalid { .. }),
13961                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13962            );
13963        }
13964    }
13965
13966    #[test]
13967    fn validate_edicao_empty_takes_precedence_over_shape() {
13968        // Empty-first cascade pin: the empty `Some("")` surfaces
13969        // the narrower `EdicaoEmpty` not the shape-predicate-
13970        // wrapped `EdicaoInvalid`, mirroring the peer
13971        // `validate_repositorio_empty_takes_precedence_over_shape`
13972        // (`RepositorioEmpty` → `RepositorioInvalid`),
13973        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` →
13974        // `VersaoInvalid`, `FonteRepoEmpty` → `FonteRepoInvalid`
13975        // cascades. The shape predicate also refuses the empty
13976        // input (defensively — `s.len() != 4`), but the
13977        // manifest-layer empty arm runs first to surface the
13978        // narrower diagnostic verbatim.
13979        let c = caixa_with_edicao(Some(""));
13980        let err = c.validate_edicao().unwrap_err();
13981        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
13982    }
13983
13984    #[test]
13985    fn validate_edicao_template_passes() {
13986        // Round-trip pin: the bare `Caixa::template` shape (which
13987        // carries `:edicao "2026"` verbatim) passes the gate by
13988        // construction. A future template-shape change that
13989        // introduced `(:edicao "")` or a non-year value would
13990        // surface here as a regression. Mirrors the peer
13991        // `validate_licenca_template_passes` pin.
13992        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13993        c.validate_edicao().unwrap();
13994    }
13995
13996    #[test]
13997    fn validate_edicao_diagnostic_names_offending_slot() {
13998        // Diagnostic-shape pin (peer with
13999        // `validate_licenca_diagnostic_names_offending_slot`): the
14000        // error's Display surfaces the `:edicao` slot name verbatim,
14001        // so a `feira lint` run can render the diagnostic without
14002        // re-parsing and the author can grep their caixa.lisp for
14003        // the offending `:edicao` line.
14004        let c = caixa_with_edicao(Some(""));
14005        let rendered = c.validate_edicao().unwrap_err().to_string();
14006        assert!(
14007            rendered.contains(":edicao"),
14008            "diagnostic must name the offending slot: {rendered}",
14009        );
14010    }
14011
14012    #[test]
14013    fn validate_edicao_invalid_diagnostic_carries_offending_value() {
14014        // Diagnostic-shape pin on the shape-predicate arm (peer
14015        // with `validate_repositorio_diagnostic_carries_offending_value`):
14016        // the error's Display surfaces the offending value + slot
14017        // name verbatim, so a `feira lint` run can render the
14018        // diagnostic without re-parsing and the author can grep
14019        // their caixa.lisp for the offending `:edicao` value.
14020        let c = caixa_with_edicao(Some("v2026"));
14021        let rendered = c.validate_edicao().unwrap_err().to_string();
14022        assert!(
14023            rendered.contains(":edicao"),
14024            "diagnostic must name the offending slot: {rendered}",
14025        );
14026        assert!(
14027            rendered.contains("v2026"),
14028            "diagnostic must quote the offending value: {rendered}",
14029        );
14030    }
14031
14032    // ── Caixa::edicao — outer top-level Option<&str> scalar accessor ──
14033
14034    #[test]
14035    fn edicao_returns_edicao_byte_string_verbatim_across_permutations() {
14036        // The canonical per-`Caixa` `:edicao` language-edition scalar
14037        // pin: [`Caixa::edicao`] must return the `:edicao` typed
14038        // byte-string verbatim as an `Option<&str>`, byte-equal to the
14039        // raw `self.edicao.as_deref()` access across every representative
14040        // value in the accept-set — `None` (the "omit the slot to defer
14041        // to the substrate's default edition" arm every existing
14042        // [`caixa-resolver`] fixture without an `:edicao` line carries),
14043        // `Some("")` (a past-the-guard sentinel that pins the accessor
14044        // doesn't perform a silent `Some("") → None` collapse on the
14045        // empty arm — validate rejects `Some("")` through `EdicaoEmpty`
14046        // but the accessor must ship the raw slot verbatim so a
14047        // validate-time gate regression surfaces at any future edition-
14048        // aware consumer's boundary rather than being silently absorbed
14049        // into the substrate's default edition), `Some("2026")` (the
14050        // canonical 4-digit-ASCII-decimal-year shape every `feira init`
14051        // template scaffolds via [`Caixa::template`] and every
14052        // renderer-side fixture at `caixa-helm/src/lib.rs:978` /
14053        // `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208`
14054        // carries by construction), `Some("2018")` / `Some("2021")` /
14055        // `Some("2024")` (canonical 4-digit-ASCII-decimal-year shapes
14056        // peer with Cargo's `[package] edition` grammar every future-
14057        // introduced sibling to `"2026"` will follow), and eight
14058        // past-the-guard sentinels for the `EdicaoInvalid` refusal cases
14059        // (`Some("2026 ")` trailing-whitespace, `Some(" 2026")` leading-
14060        // whitespace, `Some("2026\n")` embedded-LF, `Some("2026")`
14061        // fullwidth-non-ASCII-lookalike, `Some("v2026")` version-tag-
14062        // prefix, `Some("2026.1")` decimal-shape, `Some("26")` wrong-
14063        // length-numeric, `Some("latest")` free-form-non-year — the
14064        // sentinels pin the accessor doesn't silently absorb the
14065        // refusal cases into a substrate-default-edition fallback).
14066        //
14067        // Fourth and final outer top-level [`Caixa`] `Option<&str>`-
14068        // return scalar accessor pin on the substrate primitive —
14069        // sibling of the peer [`Caixa::licenca`] (6d5bc28),
14070        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
14071        // (3f16e2f) pins that opened the "outer [`Caixa`]
14072        // `Option<&str>` scalar" projection pin pattern this pin folds
14073        // on. Sibling in shape to the peer per-`:placement`
14074        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
14075        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
14076        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
14077        // axes, extended onto the outer top-level [`Caixa`] universal-
14078        // axis surface's last unlifted `Option<String>` slot. Pins
14079        // against a future silent detour that returned an owned
14080        // `Option<String>` (which would type-check but silently
14081        // allocate on every accessor call, breaking the zero-cost
14082        // projection every peer sibling accessor carries), a
14083        // `Some("") → None` collapse (which would silently absorb the
14084        // `EdicaoEmpty` refusal case at the accessor boundary and any
14085        // future edition-aware consumer would silently fall back to
14086        // the substrate's default edition on a struct-literal
14087        // `Caixa { edicao: Some(""), .. }`), or a
14088        // `None → Some("2026")` collapse (which would silently reify
14089        // the substrate's default edition at the accessor boundary
14090        // and every downstream consumer keying off the
14091        // `Option::is_none()` discriminator would lose the "author
14092        // omitted the slot" signal).
14093        for edicao in [
14094            None,
14095            Some(""),
14096            Some("2026"),
14097            Some("2018"),
14098            Some("2021"),
14099            Some("2024"),
14100            Some("2026 "),
14101            Some(" 2026"),
14102            Some("2026\n"),
14103            Some("2026"),
14104            Some("v2026"),
14105            Some("2026.1"),
14106            Some("26"),
14107            Some("latest"),
14108        ] {
14109            let c = caixa_with_edicao(edicao);
14110            assert_eq!(
14111                c.edicao(),
14112                edicao,
14113                "Caixa::edicao must return :edicao verbatim (got {:?}, \
14114                 expected {edicao:?})",
14115                c.edicao(),
14116            );
14117            assert_eq!(
14118                c.edicao(),
14119                c.edicao.as_deref(),
14120                "Caixa::edicao must byte-equal the raw \
14121                 `self.edicao.as_deref()` field access across every \
14122                 value in the Option<&str> accept-set",
14123            );
14124        }
14125    }
14126
14127    #[test]
14128    fn validate_edicao_empty_arm_routes_through_accessor() {
14129        // Composition pin: [`Caixa::validate_edicao`]'s empty-arm gate
14130        // must key off [`Caixa::edicao`], not the raw
14131        // `self.edicao.as_deref()` field access. Structurally: a
14132        // `Caixa { edicao: Some(""), .. }` must surface the
14133        // `EdicaoEmpty` refusal exactly, and a
14134        // `Caixa { edicao: Some("2026"), .. }` (the canonical
14135        // 4-digit-ASCII-decimal-year form) must pass validate. The
14136        // pair jointly pins the accessor + validate-gate composition:
14137        // any future silent detour that had the accessor return `None`
14138        // on the empty arm (a `.filter(|s| !s.is_empty())` collapse)
14139        // would silently absorb the `EdicaoEmpty` refusal at the
14140        // accessor boundary and the validate gate would accept a
14141        // struct-literal `Caixa { edicao: Some(""), .. }` — the
14142        // composition pin catches that at caixa-core build time.
14143        //
14144        // Peer of the [`Caixa::licenca`] (6d5bc28)
14145        // `validate_licenca_empty_arm_routes_through_accessor`,
14146        // [`Caixa::repositorio`] (cc7332d)
14147        // `validate_repositorio_empty_arm_routes_through_accessor`,
14148        // and [`Caixa::descricao`] (3f16e2f)
14149        // `validate_descricao_empty_arm_routes_through_accessor`
14150        // composition pins on the sibling outer top-level [`Caixa`]
14151        // `Option<&str>` universal-axis surface — same "the validate /
14152        // shape-gate predicate must route through the substrate-
14153        // primitive typed dispatch" discipline extended onto the
14154        // fourth and final outer top-level [`Caixa`] universal-axis
14155        // `Option<&str>`-composition surface, closing the accessor-
14156        // composition family.
14157        let c = caixa_with_edicao(Some(""));
14158        assert!(
14159            matches!(c.validate_edicao(), Err(ManifestError::EdicaoEmpty)),
14160            "validate_edicao must reject edicao == Some(\"\") with \
14161             EdicaoEmpty — the accessor and the validate gate must \
14162             route through the same substrate-primitive typed dispatch \
14163             on the :edicao empty arm",
14164        );
14165        let c = caixa_with_edicao(Some("2026"));
14166        assert!(
14167            c.validate_edicao().is_ok(),
14168            "validate_edicao must accept edicao == Some(\"2026\") \
14169             (the canonical 4-digit-ASCII-decimal-year shape)",
14170        );
14171    }
14172
14173    #[test]
14174    fn edicao_projects_option_str_by_borrow() {
14175        // The by-borrow pin: [`Caixa::edicao`] returns
14176        // `Option<&str>` by borrow — the `&str` borrows the underlying
14177        // `String` storage of the `Option<String>` slot and the
14178        // accessor must not allocate a fresh `String` on every call.
14179        // Peer of the [`Caixa::licenca`] (6d5bc28),
14180        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
14181        // (3f16e2f) by-borrow pins on the peer outer top-level
14182        // [`Caixa`] `Option<&str>`-return axes, and of the
14183        // per-`:placement`
14184        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
14185        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
14186        // return axis, extended onto the fourth and final outer top-
14187        // level [`Caixa`] universal-axis `Option<&str>` shape — the
14188        // accessor's returned `&str` must borrow from `&self` (the
14189        // returned reference's lifetime is tied to `&self`), and
14190        // calling the accessor twice on the same [`Caixa`] must yield
14191        // the same `Option<&str>` verbatim (idempotent, no side
14192        // effects on `&self`).
14193        //
14194        // Pins against a future silent detour that returned an owned
14195        // `Option<String>` (which would type-check but silently
14196        // allocate on every call, breaking the zero-cost projection
14197        // every peer sibling accessor carries), or a one-arm-only
14198        // accessor that returned a saturating value on some sentinel
14199        // input (breaking the pass-through invariant the sibling
14200        // required-scalar accessors carry).
14201        for edicao in [None, Some(""), Some("2026"), Some("2018")] {
14202            let c = caixa_with_edicao(edicao);
14203            let first = c.edicao();
14204            let second = c.edicao();
14205            assert_eq!(
14206                first, second,
14207                "Caixa::edicao must be idempotent — two successive \
14208                 calls on the same &self must return the same \
14209                 Option<&str>",
14210            );
14211            assert_eq!(
14212                first, edicao,
14213                "Caixa::edicao must return :edicao verbatim by \
14214                 borrow — got {first:?}, expected {edicao:?}",
14215            );
14216        }
14217    }
14218
14219    #[test]
14220    fn nome_returns_nome_byte_string_verbatim_across_permutations() {
14221        // The canonical per-`Caixa` `:nome` universal-axis DNS-1123-
14222        // label caixa-identity scalar pin: [`Caixa::nome`] must return
14223        // the `:nome` typed `String` verbatim as `&str`, byte-equal to
14224        // the raw field access across every representative value in
14225        // the accept-set — the canonical `"demo"` template baseline
14226        // (the same `feira init`-scaffolded default the sibling
14227        // `validate_nome_accepts_canonical_template` positive-control
14228        // gate pins), plus every sibling per-typed-slot atom accessor's
14229        // canonical positive-arm byte-string (`"catalog"` per
14230        // [`crate::aplicacao::Membro::nome`], `"cart"` per the peer
14231        // per-`:contratos` `:de`, `"hello-rio"` per the canonical
14232        // `caixa-helm`/`caixa-flux` cross-crate integration-test
14233        // fixture, `"checkout"` per the M3 mesh-slot Aplicacao
14234        // canonical example), plus every past-the-guard sentinel for
14235        // the `NomeEmpty` / `NomeInvalid` / `NomeChartNameBudgetExceeded`
14236        // refusal cases (`""`, `"Bad_Name"`, `"a"` × 56 — 56 bytes fits
14237        // the bare DNS-1123 63-byte cap but overflows the joint
14238        // `lareira-<nome>` chart-name budget the sibling
14239        // [`Caixa::validate_nome_chart_name_budget`] gate closes on).
14240        //
14241        // The past-the-guard sentinels pin the accessor doesn't
14242        // silently absorb the refusal cases into a template-derived
14243        // fallback (a future `.nome().is_empty().then(|| "demo")`
14244        // collapse would silently absorb the `NomeEmpty` refusal at
14245        // the accessor boundary and the validate gate would accept a
14246        // struct-literal `Caixa { nome: "".into(), .. }` — the pin
14247        // catches that at caixa-core build time).
14248        //
14249        // First outer top-level [`Caixa`] `&str`-return required-
14250        // scalar accessor pin — opens the "outer [`Caixa`] `&str`
14251        // required-scalar" projection pattern the sibling per-`Caixa`
14252        // `:versao` future lift folds on. Sibling in shape to the peer
14253        // per-`:membros` [`crate::aplicacao::Membro::nome`] (4a32abf)
14254        // required-`String`-carry accessor pin on the sibling per-
14255        // sub-struct required-axis, extended onto the outer top-level
14256        // [`Caixa`] universal-axis required-`String`-carry axis.
14257        for nome in [
14258            "demo",
14259            "catalog",
14260            "cart",
14261            "hello-rio",
14262            "checkout",
14263            "",
14264            "Bad_Name",
14265            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14266        ] {
14267            let c = caixa_with_nome(nome);
14268            assert_eq!(
14269                c.nome(),
14270                nome,
14271                "Caixa::nome must return :nome verbatim (got {}, \
14272                 expected {nome})",
14273                c.nome(),
14274            );
14275            assert_eq!(
14276                c.nome(),
14277                c.nome.as_str(),
14278                "Caixa::nome must byte-equal the raw .nome field \
14279                 access across every value in the String accept-set",
14280            );
14281        }
14282    }
14283
14284    #[test]
14285    fn validate_nome_empty_arm_routes_through_accessor() {
14286        // Composition pin: [`Caixa::validate_nome`]'s empty-arm must
14287        // key off [`Caixa::nome`], not the raw `.nome` field access.
14288        // Structurally: a `Caixa { nome: "".into(), .. }` must surface
14289        // the `NomeEmpty` refusal exactly, and the canonical `"demo"`
14290        // template baseline (the peer positive-arm the sibling
14291        // `validate_nome_accepts_canonical_template` gate carves out)
14292        // must pass validate. The pair jointly pins the accessor +
14293        // validate-gate composition: any future silent detour that
14294        // had the accessor return a fresh `"demo"` on the empty arm
14295        // (a `.nome().is_empty().then(|| "demo")` fallback collapse)
14296        // would silently absorb the `NomeEmpty` refusal at the
14297        // accessor boundary and the validate gate would accept a
14298        // struct-literal `Caixa { nome: "".into(), .. }` — the
14299        // composition pin catches that at caixa-core build time.
14300        //
14301        // Peer of the sibling per-`Caixa`
14302        // `validate_licenca_empty_arm_routes_through_accessor` (6d5bc28)
14303        // / `validate_repositorio_empty_arm_routes_through_accessor`
14304        // (cc7332d) / `validate_descricao_empty_arm_routes_through_accessor`
14305        // (3f16e2f) / `validate_edicao_empty_arm_routes_through_accessor`
14306        // (2641cbd) composition pins on the sibling outer top-level
14307        // [`Caixa`] `Option<&str>` axes — same "the validate /
14308        // shape-gate predicate must route through the substrate-
14309        // primitive typed dispatch" discipline extended onto the peer
14310        // outer top-level [`Caixa`] required-`&str` composition axis.
14311        let c = caixa_with_nome("");
14312        assert!(
14313            matches!(c.validate_nome(), Err(ManifestError::NomeEmpty)),
14314            "validate_nome must reject nome == \"\" with NomeEmpty — \
14315             the accessor and the validate gate must route through the \
14316             same substrate-primitive typed dispatch on the :nome \
14317             empty-arm",
14318        );
14319        let c = caixa_with_nome("demo");
14320        assert!(
14321            c.validate_nome().is_ok(),
14322            "validate_nome must accept nome == \"demo\" (the canonical \
14323             DNS-1123-label template baseline)",
14324        );
14325    }
14326
14327    #[test]
14328    fn nome_projects_str_by_borrow() {
14329        // The by-borrow pin: [`Caixa::nome`] returns `&str` by borrow
14330        // — the `&str` borrows the underlying `String` storage of the
14331        // required `nome` slot and the accessor must not allocate a
14332        // fresh `String` on every call. Peer of the [`Caixa::licenca`]
14333        // (6d5bc28) / [`Caixa::repositorio`] (cc7332d) /
14334        // [`Caixa::descricao`] (3f16e2f) / [`Caixa::edicao`] (2641cbd)
14335        // by-borrow pins on the peer outer top-level [`Caixa`]
14336        // `Option<&str>`-return axes, extended onto the first outer
14337        // top-level [`Caixa`] required-`&str`-return axis — the
14338        // accessor's returned `&str` must borrow from `&self` (the
14339        // returned reference's lifetime is tied to `&self`), and
14340        // calling the accessor twice on the same [`Caixa`] must yield
14341        // the same `&str` verbatim (idempotent, no side effects on
14342        // `&self`).
14343        //
14344        // Pins against a future silent detour that returned an owned
14345        // `String` (which would type-check but silently allocate on
14346        // every call, breaking the zero-cost projection every peer
14347        // sibling accessor carries), an accidental
14348        // `.nome.to_lowercase()` detour that returned a fresh
14349        // allocation through an already-DNS-1123-lowercase-only
14350        // string (breaking a future `const fn` regression), or a
14351        // one-arm-only accessor that returned a canonicalized value
14352        // on some sentinel input (breaking the pass-through invariant
14353        // the sibling required-scalar accessors carry).
14354        for nome in ["demo", "catalog", "hello-rio", "checkout"] {
14355            let c = caixa_with_nome(nome);
14356            let first = c.nome();
14357            let second = c.nome();
14358            assert_eq!(
14359                first, second,
14360                "Caixa::nome must be idempotent — two successive calls \
14361                 on the same &self must return the same &str",
14362            );
14363            assert_eq!(
14364                first, nome,
14365                "Caixa::nome must return :nome verbatim by borrow — \
14366                 got {first}, expected {nome}",
14367            );
14368        }
14369    }
14370
14371    #[test]
14372    fn versao_returns_versao_byte_string_verbatim_across_permutations() {
14373        // The canonical per-`Caixa` `:versao` universal-axis SemVer-2
14374        // pinned-version scalar pin: [`Caixa::versao`] must return the
14375        // `:versao` typed `String` verbatim as `&str`, byte-equal to the
14376        // raw `.versao` field access across every representative value
14377        // in the accept-set — the canonical `"0.1.0"` template baseline
14378        // (the same `feira init`-scaffolded default the sibling
14379        // `validate_versao_accepts_canonical_template` positive-control
14380        // gate pins), plus every canonical SemVer-2 shape the sibling
14381        // `validate_versao_accepts_canonical_forms` positive-arm sweep
14382        // covers (`"0.0.0"`, `"1.0.0"`, `"0.2.0-rc.1"`,
14383        // `"1.0.0-alpha.0"`, `"1.0.0+build.42"`, `"1.0.0-rc.1+build.42"`,
14384        // `"10.20.30"`), plus every past-the-guard sentinel for the
14385        // `VersaoEmpty` / `VersaoInvalid` refusal cases (`""` the empty
14386        // arm, `"v0.1.0"` the git-tag-shape-leak footgun, `"0.1"` the
14387        // missing-patch footgun, `"^0.1"` the requirement-shape-leak
14388        // footgun, `"0.1.0.0"` the four-part-Java-convention footgun,
14389        // `"latest"` the docker-tag-shape footgun — the sentinels pin
14390        // the accessor doesn't silently absorb the refusal cases into a
14391        // template-derived fallback like `"0.1.0"`).
14392        //
14393        // The past-the-guard sentinels pin the accessor doesn't silently
14394        // absorb the refusal cases into a template-derived fallback (a
14395        // future `.versao().is_empty().then(|| "0.1.0")` collapse would
14396        // silently absorb the `VersaoEmpty` refusal at the accessor
14397        // boundary and the validate gate would accept a struct-literal
14398        // `Caixa { versao: "".into(), .. }` — the pin catches that at
14399        // caixa-core build time).
14400        //
14401        // Second outer top-level [`Caixa`] `&str`-return required-scalar
14402        // accessor pin — folds on the "outer [`Caixa`] `&str` required-
14403        // scalar" projection pattern the sibling per-`Caixa`
14404        // [`Caixa::nome`] (e6b7d97) opened. Sibling in shape to the peer
14405        // per-`:membros` [`crate::aplicacao::Membro::versao_requirement`]
14406        // (4127bb6) / per-`:children`
14407        // [`crate::supervisor::ChildSpec::versao_requirement`] (2c053c8)
14408        // / per-`:upgrade-from`
14409        // [`crate::UpgradeFromEntry::prior_versao`] (75d27a8) per-sub-
14410        // struct `:versao`-shaped `&str`-return accessor pins on the
14411        // sibling per-typed-slot version-carrier axes, extended onto the
14412        // second outer top-level [`Caixa`] universal-axis required-
14413        // `String`-carry axis so the two universal-axis identity-
14414        // carrying scalars every `defcaixa` form supplies (`:nome` +
14415        // `:versao`) share the same "one typed dispatch per axis" pin
14416        // discipline.
14417        for versao in [
14418            "0.1.0",
14419            "0.0.0",
14420            "1.0.0",
14421            "0.2.0-rc.1",
14422            "1.0.0-alpha.0",
14423            "1.0.0+build.42",
14424            "1.0.0-rc.1+build.42",
14425            "10.20.30",
14426            "",
14427            "v0.1.0",
14428            "0.1",
14429            "^0.1",
14430            "0.1.0.0",
14431            "latest",
14432        ] {
14433            let c = caixa_with_versao(versao);
14434            assert_eq!(
14435                c.versao(),
14436                versao,
14437                "Caixa::versao must return :versao verbatim (got {}, \
14438                 expected {versao})",
14439                c.versao(),
14440            );
14441            assert_eq!(
14442                c.versao(),
14443                c.versao.as_str(),
14444                "Caixa::versao must byte-equal the raw .versao field \
14445                 access across every value in the String accept-set",
14446            );
14447        }
14448    }
14449
14450    #[test]
14451    fn validate_versao_empty_arm_routes_through_accessor() {
14452        // Composition pin: [`Caixa::validate_versao`]'s empty-arm gate
14453        // must key off [`Caixa::versao`], not the raw `.versao` field
14454        // access. Structurally: a `Caixa { versao: "".into(), .. }` must
14455        // surface the `VersaoEmpty` refusal exactly, and the canonical
14456        // `"0.1.0"` template baseline (the peer positive-arm the sibling
14457        // `validate_versao_accepts_canonical_template` gate carves out)
14458        // must pass validate. The pair jointly pins the accessor +
14459        // validate-gate composition: any future silent detour that had
14460        // the accessor return a fresh `"0.1.0"` on the empty arm
14461        // (a `.versao().is_empty().then(|| "0.1.0")` fallback collapse)
14462        // would silently absorb the `VersaoEmpty` refusal at the
14463        // accessor boundary and the validate gate would accept a
14464        // struct-literal `Caixa { versao: "".into(), .. }` — the
14465        // composition pin catches that at caixa-core build time.
14466        //
14467        // Peer of the sibling per-`Caixa`
14468        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97)
14469        // composition pin on the sibling outer top-level [`Caixa`]
14470        // required-`&str` universal-axis surface — same "the validate /
14471        // shape-gate predicate must route through the substrate-
14472        // primitive typed dispatch" discipline extended onto the peer
14473        // outer top-level [`Caixa`] required-`&str` universal-axis
14474        // pinned-version composition axis, closing the second
14475        // coordinate of the "one canonical typed dispatch per per-Caixa
14476        // required-`&str` universal-axis" discipline.
14477        let c = caixa_with_versao("");
14478        assert!(
14479            matches!(c.validate_versao(), Err(ManifestError::VersaoEmpty)),
14480            "validate_versao must reject versao == \"\" with VersaoEmpty — \
14481             the accessor and the validate gate must route through the \
14482             same substrate-primitive typed dispatch on the :versao \
14483             empty-arm",
14484        );
14485        let c = caixa_with_versao("0.1.0");
14486        assert!(
14487            c.validate_versao().is_ok(),
14488            "validate_versao must accept versao == \"0.1.0\" (the \
14489             canonical SemVer-2 template baseline)",
14490        );
14491    }
14492
14493    #[test]
14494    fn versao_projects_str_by_borrow() {
14495        // The by-borrow pin: [`Caixa::versao`] returns `&str` by borrow
14496        // — the `&str` borrows the underlying `String` storage of the
14497        // required `versao` slot and the accessor must not allocate a
14498        // fresh `String` on every call. Peer of the [`Caixa::nome`]
14499        // (e6b7d97) by-borrow pin on the sibling outer top-level
14500        // [`Caixa`] required-`&str`-return axis, extended onto the
14501        // second outer top-level [`Caixa`] required-`&str`-return
14502        // universal-axis pinned-version surface — the accessor's
14503        // returned `&str` must borrow from `&self` (the returned
14504        // reference's lifetime is tied to `&self`), and calling the
14505        // accessor twice on the same [`Caixa`] must yield the same
14506        // `&str` verbatim (idempotent, no side effects on `&self`).
14507        //
14508        // Pins against a future silent detour that returned an owned
14509        // `String` (which would type-check but silently allocate on
14510        // every call, breaking the zero-cost projection every peer
14511        // sibling accessor carries), an accidental
14512        // `semver::Version::parse(&self.versao).unwrap().to_string()`
14513        // detour that returned a canonicalized fresh allocation through
14514        // an already-canonical byte-string (breaking a future `const fn`
14515        // regression and silently absorbing the `VersaoInvalid` refusal
14516        // at the accessor boundary), or a one-arm-only accessor that
14517        // returned a canonicalized value on some sentinel input
14518        // (breaking the pass-through invariant the sibling required-
14519        // scalar accessors carry).
14520        for versao in ["0.1.0", "1.0.0", "0.2.0-rc.1", "1.0.0+build.42"] {
14521            let c = caixa_with_versao(versao);
14522            let first = c.versao();
14523            let second = c.versao();
14524            assert_eq!(
14525                first, second,
14526                "Caixa::versao must be idempotent — two successive \
14527                 calls on the same &self must return the same &str",
14528            );
14529            assert_eq!(
14530                first, versao,
14531                "Caixa::versao must return :versao verbatim by borrow \
14532                 — got {first}, expected {versao}",
14533            );
14534        }
14535    }
14536
14537    fn caixa_with_kind(kind: CaixaKind) -> Caixa {
14538        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14539        c.kind = kind;
14540        c
14541    }
14542
14543    #[test]
14544    fn kind_returns_kind_variant_verbatim_across_permutations() {
14545        // The canonical per-`Caixa` `:kind` universal-axis closed-set-
14546        // enum discriminant pin: [`Caixa::kind`] must return the `:kind`
14547        // typed [`CaixaKind`] variant verbatim by `Copy`, byte-equal to
14548        // the raw `.kind` field access across every variant in the
14549        // closed accept-set (`Biblioteca` — the library kind that
14550        // exports lisp forms; `Binario` — the nix-built executable kind
14551        // under `exe/`; `Servico` — the wasm-component daemon kind
14552        // under `servicos/`; `Supervisor` — the OTP-shaped hierarchical
14553        // reconciliation kind; `Aplicacao` — the M3 typed-mesh
14554        // composition kind).
14555        //
14556        // Pins against a future silent detour that re-derived the kind
14557        // from a peer axis (an accidental fallback to
14558        // `if !servicos.is_empty() { Servico } else if
14559        // !membros.is_empty() { Aplicacao } else { Biblioteca }`
14560        // collapse that read the code-surface / mesh-slot columns into
14561        // the kind discriminator), a variant remap the operator
14562        // authors on one consumer without the other, or a stale-derive
14563        // detour that substituted [`CaixaKind::Biblioteca`] as the
14564        // default when the field held any other variant (which would
14565        // silently collapse the distinction between "author explicitly
14566        // declared `:kind Servico`" and "author declared any other
14567        // kind" every downstream renderer-dispatch site depends on).
14568        //
14569        // First outer top-level [`Caixa`] `Copy`-return required-enum-
14570        // discriminant accessor pin — opens the "outer [`Caixa`]
14571        // `Copy`-return required-discriminant" projection pattern.
14572        // Sibling in shape to the peer per-`:supervisor`
14573        // [`crate::supervisor::SupervisorSpec::estrategia`] (eafb619),
14574        // per-`:placement` [`crate::aplicacao::Placement::estrategia`]
14575        // (921fe1b), and per-`:children`
14576        // [`crate::supervisor::ChildSpec::restart`] (dfb4a81)
14577        // `Copy`-return closed-set-enum discriminant accessor pins on
14578        // the sibling nested-spec typed-slot discriminator axes,
14579        // extended here to the outer top-level [`Caixa`] universal-
14580        // axis surface.
14581        for kind in [
14582            CaixaKind::Biblioteca,
14583            CaixaKind::Binario,
14584            CaixaKind::Servico,
14585            CaixaKind::Supervisor,
14586            CaixaKind::Aplicacao,
14587        ] {
14588            let c = caixa_with_kind(kind);
14589            assert_eq!(
14590                c.kind(),
14591                kind,
14592                "Caixa::kind must return :kind verbatim (got {:?}, \
14593                 expected {kind:?})",
14594                c.kind(),
14595            );
14596            assert_eq!(
14597                c.kind(),
14598                c.kind,
14599                "Caixa::kind accessor and .kind field access must \
14600                 byte-equal — the accessor is the substrate-primitive \
14601                 typed dispatch every downstream kind-gate consumer \
14602                 must route through",
14603            );
14604        }
14605    }
14606
14607    #[test]
14608    fn require_kind_reads_through_lifted_kind_accessor() {
14609        // Two-consumer coherence pin: the [`crate::render::require_kind`]
14610        // entry-gate predicate (the canonical two-line
14611        // `require_kind(caixa, Servico)?` prelude every per-Servico /
14612        // per-Aplicacao renderer runs at its entry-point) and the
14613        // sibling [`crate::render::KindMismatch`] error carrier's
14614        // `actual:` field (which names the offending caixa's variant
14615        // in the diagnostic) must both key off the lifted accessor, so
14616        // any future rebrand on the typed slot's reader shape lands at
14617        // exactly one place. Pins the two-site coherence by exercising
14618        // every off-diagonal `(actual, expected)` pair across the
14619        // closed accept-set — the `KindMismatch { actual, expected }`
14620        // surfaced on the mismatch arm must byte-equal the pair the
14621        // accessor returns for each side.
14622        //
14623        // Peer of the sibling per-`:placement`
14624        // `validate_placement_reads_through_lifted_estrategia_accessor`
14625        // (921fe1b) two-arm consumer-coherence pin on the M3 mesh-slot
14626        // `Copy`-return discriminant axis — same "the entry-gate
14627        // predicate and the error carrier's `actual:` field must route
14628        // through the substrate-primitive typed dispatch" discipline
14629        // extended onto the outer top-level [`Caixa`] universal-axis
14630        // discriminant surface.
14631        for expected in [
14632            CaixaKind::Biblioteca,
14633            CaixaKind::Binario,
14634            CaixaKind::Servico,
14635            CaixaKind::Supervisor,
14636            CaixaKind::Aplicacao,
14637        ] {
14638            for actual in [
14639                CaixaKind::Biblioteca,
14640                CaixaKind::Binario,
14641                CaixaKind::Servico,
14642                CaixaKind::Supervisor,
14643                CaixaKind::Aplicacao,
14644            ] {
14645                let c = caixa_with_kind(actual);
14646                let result = crate::render::require_kind(&c, expected);
14647                if expected == actual {
14648                    assert!(
14649                        result.is_ok(),
14650                        "require_kind must accept when actual == expected \
14651                         (actual={actual:?}, expected={expected:?})",
14652                    );
14653                } else {
14654                    let err = result.expect_err("require_kind must reject when actual != expected");
14655                    assert_eq!(
14656                        err.actual,
14657                        c.kind(),
14658                        "KindMismatch.actual must byte-equal Caixa::kind() \
14659                         — the error carrier's `actual:` field reads \
14660                         through the lifted accessor",
14661                    );
14662                    assert_eq!(
14663                        err.expected, expected,
14664                        "KindMismatch.expected must byte-equal the \
14665                         expected variant passed to require_kind",
14666                    );
14667                }
14668            }
14669        }
14670    }
14671
14672    #[test]
14673    fn aplicacao_view_kind_gate_routes_through_accessor() {
14674        // Composition pin: [`Caixa::aplicacao_view`]'s kind-gate arm
14675        // must key off [`Caixa::kind`], not the raw `.kind` field
14676        // access. Structurally: a `Caixa { kind: X, .. }` for any
14677        // non-`Aplicacao` variant must fold to `None` on the
14678        // `aplicacao_view` composer (the "kind mismatch → no typed
14679        // view" contract every downstream Aplicacao consumer keys off
14680        // via `?`), and a `Caixa { kind: Aplicacao, .. }` must fold to
14681        // `Some(_)`. The pair jointly pins the accessor + view-gate
14682        // composition: any future silent detour that had the accessor
14683        // return a fresh [`CaixaKind::Aplicacao`] on some sentinel
14684        // input would silently absorb the kind-mismatch case at the
14685        // accessor boundary and every per-Aplicacao renderer would
14686        // silently render a non-Aplicacao caixa's mesh slots — the
14687        // composition pin catches that at caixa-core build time.
14688        //
14689        // Peer of the sibling per-`Caixa`
14690        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97) /
14691        // `validate_versao_empty_arm_routes_through_accessor` (20c0539)
14692        // composition pins on the sibling outer top-level [`Caixa`]
14693        // required-`&str` universal-axis surfaces — same "the
14694        // composer / validate gate must route through the substrate-
14695        // primitive typed dispatch" discipline extended onto the
14696        // outer top-level [`Caixa`] `Copy`-return required-
14697        // discriminant composition axis.
14698        for kind in [
14699            CaixaKind::Biblioteca,
14700            CaixaKind::Binario,
14701            CaixaKind::Servico,
14702            CaixaKind::Supervisor,
14703        ] {
14704            let c = caixa_with_kind(kind);
14705            assert!(
14706                c.aplicacao_view().is_none(),
14707                "aplicacao_view must return None on non-Aplicacao \
14708                 kind {kind:?} — the composer's kind-gate must route \
14709                 through Caixa::kind()",
14710            );
14711        }
14712        let c = caixa_with_kind(CaixaKind::Aplicacao);
14713        assert!(
14714            c.aplicacao_view().is_some(),
14715            "aplicacao_view must return Some on kind Aplicacao — \
14716             the composer's kind-gate must accept the matching arm \
14717             through Caixa::kind()",
14718        );
14719    }
14720
14721    #[test]
14722    fn supervisor_view_kind_gate_routes_through_accessor() {
14723        // Composition pin (mirror of the sibling
14724        // `aplicacao_view_kind_gate_routes_through_accessor` on the
14725        // second `_view` composer): [`Caixa::supervisor_view`]'s kind-
14726        // gate arm must key off [`Caixa::kind`], not the raw `.kind`
14727        // field access. A `Caixa { kind: X, .. }` for any non-
14728        // `Supervisor` variant must fold to `None` on the
14729        // `supervisor_view` composer, and a `Caixa { kind:
14730        // Supervisor, .. }` must fold to `Some(_)`. Same peer
14731        // composition pin discipline on the second `_view` composer
14732        // axis.
14733        for kind in [
14734            CaixaKind::Biblioteca,
14735            CaixaKind::Binario,
14736            CaixaKind::Servico,
14737            CaixaKind::Aplicacao,
14738        ] {
14739            let c = caixa_with_kind(kind);
14740            assert!(
14741                c.supervisor_view().is_none(),
14742                "supervisor_view must return None on non-Supervisor \
14743                 kind {kind:?} — the composer's kind-gate must route \
14744                 through Caixa::kind()",
14745            );
14746        }
14747        let mut c = caixa_with_kind(CaixaKind::Supervisor);
14748        // A Supervisor caixa needs a strategy + at least one child to
14749        // fold to a Some(_) that also validates; the composer itself
14750        // requires only the kind arm, so bare kind flip is enough to
14751        // pin the `Some(_)` return, but we populate the minimum
14752        // supervisor shape so a future strengthening of the composer
14753        // to reject an empty spec doesn't false-positive this pin.
14754        c.estrategia = Some(crate::supervisor::RestartStrategy::OneForOne);
14755        c.children = vec![crate::supervisor::ChildSpec {
14756            caixa: "child".into(),
14757            versao: "^0.1".into(),
14758            restart: crate::supervisor::RestartPolicy::Permanent,
14759        }];
14760        assert!(
14761            c.supervisor_view().is_some(),
14762            "supervisor_view must return Some on kind Supervisor — \
14763             the composer's kind-gate must accept the matching arm \
14764             through Caixa::kind()",
14765        );
14766    }
14767
14768    #[test]
14769    fn kind_projects_by_copy() {
14770        // The by-`Copy` pin: [`Caixa::kind`] returns a fresh
14771        // [`CaixaKind`] by `Copy` — the accessor must not borrow from
14772        // `&self` (the returned value is owned, `Copy`-projected from
14773        // the underlying [`CaixaKind`] storage; two calls on the same
14774        // [`Caixa`] must yield byte-equal values). Peer of the peer
14775        // per-`:placement` `Placement::estrategia` / per-`:supervisor`
14776        // `SupervisorSpec::estrategia` / per-`:children`
14777        // `ChildSpec::restart` `Copy`-return discriminant accessor
14778        // pins on the sibling nested-spec typed-slot discriminator
14779        // axes, extended onto the first outer top-level [`Caixa`]
14780        // required-`Copy`-return axis — pins against a future silent
14781        // detour that returned `&CaixaKind` (which would type-check
14782        // but silently constrain every consumer's callsite to a
14783        // borrow-shaped dispatch, breaking the zero-cost `Copy`
14784        // projection every peer sibling accessor carries).
14785        for kind in [
14786            CaixaKind::Biblioteca,
14787            CaixaKind::Binario,
14788            CaixaKind::Servico,
14789            CaixaKind::Supervisor,
14790            CaixaKind::Aplicacao,
14791        ] {
14792            let c = caixa_with_kind(kind);
14793            let first: CaixaKind = c.kind();
14794            let second: CaixaKind = c.kind();
14795            assert_eq!(
14796                first, second,
14797                "Caixa::kind must be idempotent — two successive \
14798                 calls on the same &self must return the same \
14799                 CaixaKind variant",
14800            );
14801            assert_eq!(
14802                first, kind,
14803                "Caixa::kind must return :kind verbatim by Copy — \
14804                 got {first:?}, expected {kind:?}",
14805            );
14806        }
14807    }
14808
14809    // ── Caixa::autores — outer top-level &[T] slice accessor ──────────
14810
14811    #[test]
14812    fn autores_returns_autores_slice_verbatim_across_permutations() {
14813        // The canonical per-`Caixa` `:autores` universal-axis maintainer-
14814        // name-list slice pin: [`Caixa::autores`] must return the
14815        // `:autores` typed [`Vec<String>`] list verbatim as a
14816        // `&[String]`, byte-equal to the raw `self.autores.as_slice()`
14817        // access across every representative value in the accept-set —
14818        // `[]` (the "no maintainers declared" arm every existing
14819        // fixture without an `:autores` line carries), `[""]` (a past-
14820        // the-guard sentinel that pins the accessor doesn't perform a
14821        // silent `[""] → []` collapse on the empty-entry arm — validate
14822        // rejects `[""]` through `AutorEmpty` but the accessor must
14823        // ship the raw slot verbatim so a validate-time gate regression
14824        // surfaces at the caixa-helm emit boundary rather than being
14825        // silently absorbed into a maintainer-drop), `["pleme-io"]` (the
14826        // canonical single-maintainer form every `feira init` template
14827        // scaffolds), `["alice", "bob"]` (a canonical multi-maintainer
14828        // form), `["alice <alice@example.com>", "bob <bob@example.com>"]`
14829        // (the canonical RFC-5322 `<name> <email>` form the
14830        // `is_chart_maintainer_name_shape` predicate accepts), and
14831        // `["pleme-io", "pleme-io"]` (a past-the-guard duplicate
14832        // sentinel — validate rejects through `AutorDuplicate` but the
14833        // accessor must ship the raw slot verbatim).
14834        //
14835        // First outer top-level [`Caixa`] `&[T]`-return slice accessor
14836        // pin on the substrate primitive — opens the "outer [`Caixa`]
14837        // `&[T]` slice" projection pattern the sibling per-`Caixa`
14838        // `:etiquetas` / `:deps` / `:deps-dev` / `:exe` / `:bibliotecas`
14839        // / `:servicos` / `:upgrade-from` / `:children` future lifts
14840        // fold on. Sibling in shape to the peer per-`:supervisor`
14841        // [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
14842        // per-`:placement` [`crate::aplicacao::Placement::clusters`]
14843        // (a6e18d7), per-`:membros`
14844        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
14845        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
14846        // (0dcc926), and per-`:upgrade-from :instructions`
14847        // [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
14848        // `&[T]`-return slice accessor pins on the sibling per-M2 /
14849        // per-M3 typed-slot list axes, extended onto the outer top-
14850        // level [`Caixa`] universal-axis surface. Pins against a future
14851        // silent detour that returned an owned `Vec<String>` (which
14852        // would type-check but silently clone on every accessor call,
14853        // breaking the zero-cost projection every peer sibling slice
14854        // accessor carries), a `[""] → []` collapse (which would
14855        // silently absorb the `AutorEmpty` refusal case at the accessor
14856        // boundary), or a `["a", "a"] → ["a"]` dedup collapse (which
14857        // would silently absorb the `AutorDuplicate` refusal case at
14858        // the accessor boundary and the caixa-helm `maintainers:` fold
14859        // would silently render a dedupped list on a struct-literal
14860        // `Caixa { autores: vec!["a".into(), "a".into()], .. }`).
14861        for autores in [
14862            vec![],
14863            vec![""],
14864            vec!["pleme-io"],
14865            vec!["alice", "bob"],
14866            vec!["alice <alice@example.com>", "bob <bob@example.com>"],
14867            vec!["pleme-io", "pleme-io"],
14868        ] {
14869            let c = caixa_with_autores(autores.clone());
14870            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
14871            assert_eq!(
14872                c.autores(),
14873                expected.as_slice(),
14874                "Caixa::autores must return :autores verbatim (got {:?}, \
14875                 expected {expected:?})",
14876                c.autores(),
14877            );
14878            assert_eq!(
14879                c.autores(),
14880                c.autores.as_slice(),
14881                "Caixa::autores must byte-equal the raw \
14882                 `self.autores.as_slice()` field access across every \
14883                 value in the Vec<String> accept-set",
14884            );
14885        }
14886    }
14887
14888    #[test]
14889    fn validate_autores_empty_entry_arm_routes_through_accessor() {
14890        // Composition pin: [`Caixa::validate_autores`]'s per-entry
14891        // empty-arm gate must key off [`Caixa::autores`], not the raw
14892        // `&self.autores` field-borrow walk. Structurally: a
14893        // `Caixa { autores: vec!["".into()], .. }` must surface the
14894        // `AutorEmpty` refusal exactly, and a
14895        // `Caixa { autores: vec!["pleme-io".into()], .. }` (the
14896        // canonical single-maintainer form) must pass validate. The
14897        // pair jointly pins the accessor + validate-gate composition:
14898        // any future silent detour that had the accessor return an
14899        // empty slice on the `[""]` arm (a
14900        // `.iter().filter(|s| !s.is_empty()).collect()` collapse)
14901        // would silently absorb the `AutorEmpty` refusal at the
14902        // accessor boundary and the validate gate would accept a
14903        // struct-literal `Caixa { autores: vec!["".into()], .. }` —
14904        // the composition pin catches that at caixa-core build time.
14905        //
14906        // Peer of the per-`Caixa` [`Caixa::validate_licenca`] (6d5bc28)
14907        // accessor-composition pin
14908        // (`validate_licenca_empty_arm_routes_through_accessor`) on the
14909        // sibling `Option<&str>`-composition axis and the
14910        // per-`:politicas :circuit-breaker`
14911        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
14912        // accessor-composition pin
14913        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
14914        // on the sibling required-`u32`-composition axis — same "the
14915        // validate / shape-gate predicate must route through the
14916        // substrate-primitive typed dispatch" discipline extended onto
14917        // the outer top-level [`Caixa`] universal-axis `&[T]`-
14918        // composition surface.
14919        let c = caixa_with_autores(vec![""]);
14920        assert!(
14921            matches!(c.validate_autores(), Err(ManifestError::AutorEmpty)),
14922            "validate_autores must reject autores == vec![\"\"] with \
14923             AutorEmpty — the accessor and the validate gate must \
14924             route through the same substrate-primitive typed dispatch \
14925             on the :autores per-entry empty arm",
14926        );
14927        let c = caixa_with_autores(vec!["pleme-io"]);
14928        assert!(
14929            c.validate_autores().is_ok(),
14930            "validate_autores must accept autores == vec![\"pleme-io\"] \
14931             (the canonical single-maintainer shape every `feira init` \
14932             template scaffolds)",
14933        );
14934    }
14935
14936    #[test]
14937    fn autores_projects_slice_by_borrow() {
14938        // The by-borrow pin: [`Caixa::autores`] returns `&[String]` by
14939        // borrow — the returned slice borrows the underlying
14940        // `Vec<String>` storage of the `:autores` slot and the
14941        // accessor must not clone the backing `Vec` on every call.
14942        // Peer of the per-`:membros`
14943        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36) /
14944        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
14945        // (0dcc926) / per-`:placement`
14946        // [`crate::aplicacao::Placement::clusters`] (a6e18d7) /
14947        // per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
14948        // (bc92bce) by-borrow pins on the sibling per-M2 / per-M3
14949        // typed-slot `&[T]`-return axes, extended onto the outer top-
14950        // level [`Caixa`] universal-axis `&[String]` shape — the
14951        // accessor's returned slice must borrow from `&self` (the
14952        // returned reference's lifetime is tied to `&self`), and
14953        // calling the accessor twice on the same [`Caixa`] must yield
14954        // slices that are pointer-equal (the underlying byte-buffer is
14955        // the storage `Vec`'s allocation, not a fresh copy) as well as
14956        // value-equal (idempotent, no side effects on `&self`).
14957        //
14958        // Pins against a future silent detour that returned an owned
14959        // `Vec<String>` (which would type-check but silently clone on
14960        // every call, breaking the zero-cost projection every peer
14961        // sibling slice accessor carries), a `&Vec<String>` return
14962        // (which would leak the backing `Vec`'s grow/push/reserve
14963        // surface no downstream consumer reaches for), or a one-arm-
14964        // only accessor that returned a saturating value on some
14965        // sentinel input (breaking the pass-through invariant the
14966        // sibling slice accessors carry).
14967        for autores in [
14968            vec![],
14969            vec!["pleme-io"],
14970            vec!["alice", "bob"],
14971            vec!["pleme-io", "pleme-io"],
14972        ] {
14973            let c = caixa_with_autores(autores.clone());
14974            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
14975            let first = c.autores();
14976            let second = c.autores();
14977            assert_eq!(
14978                first, second,
14979                "Caixa::autores must be idempotent — two successive \
14980                 calls on the same &self must return the same \
14981                 &[String]",
14982            );
14983            assert_eq!(
14984                first.as_ptr(),
14985                second.as_ptr(),
14986                "Caixa::autores must borrow the underlying Vec<String> \
14987                 storage — two successive calls must return slices \
14988                 with the same backing pointer (a fresh Vec<String> \
14989                 clone would change the pointer on every call)",
14990            );
14991            assert_eq!(
14992                first,
14993                expected.as_slice(),
14994                "Caixa::autores must return :autores verbatim by \
14995                 borrow — got {first:?}, expected {expected:?}",
14996            );
14997        }
14998    }
14999
15000    // ── Caixa::etiquetas — outer top-level &[T] slice accessor ────────
15001
15002    #[test]
15003    fn etiquetas_returns_etiquetas_slice_verbatim_across_permutations() {
15004        // The canonical per-`Caixa` `:etiquetas` universal-axis
15005        // registry-search-tag-list slice pin: [`Caixa::etiquetas`] must
15006        // return the `:etiquetas` typed [`Vec<String>`] list verbatim
15007        // as a `&[String]`, byte-equal to the raw
15008        // `self.etiquetas.as_slice()` access across every representative
15009        // value in the accept-set — `[]` (the "no tags declared" arm
15010        // every existing fixture without an `:etiquetas` line carries),
15011        // `[""]` (a past-the-guard sentinel that pins the accessor
15012        // doesn't perform a silent `[""] → []` collapse on the empty-
15013        // entry arm — validate rejects `[""]` through `EtiquetaEmpty`
15014        // but the accessor must ship the raw slot verbatim so a
15015        // validate-time gate regression surfaces at the caixa-helm emit
15016        // boundary rather than being silently absorbed into a keyword-
15017        // drop), `["demo"]` (the canonical single-tag form every
15018        // `feira init` template scaffolds), `["example", "aplicacao",
15019        // "mesh", "ecommerce", "demo"]` (the canonical multi-tag form
15020        // the checkout-aplicacao fixture emits), and `["demo", "demo"]`
15021        // (a past-the-guard duplicate sentinel — validate rejects
15022        // through `EtiquetaDuplicate` but the accessor must ship the
15023        // raw slot verbatim so the caixa-helm `BTreeSet::collect` dedup
15024        // at chart-render time isn't silently promoted into the
15025        // accessor boundary and struct-literal
15026        // `Caixa { etiquetas: vec!["demo".into(), "demo".into()], .. }`
15027        // fixtures continue to expose the duplicate at the accessor).
15028        //
15029        // Second outer top-level [`Caixa`] `&[T]`-return slice accessor
15030        // pin on the substrate primitive — folds on the "outer
15031        // [`Caixa`] `&[T]` slice" projection pattern
15032        // `autores_returns_autores_slice_verbatim_across_permutations`
15033        // (b5d813f) opened, sibling in shape and idiom. Pins against a
15034        // future silent detour that returned an owned `Vec<String>`
15035        // (which would type-check but silently clone on every accessor
15036        // call, breaking the zero-cost projection every peer sibling
15037        // slice accessor carries), a `[""] → []` collapse (which would
15038        // silently absorb the `EtiquetaEmpty` refusal case at the
15039        // accessor boundary), or a `["a", "a"] → ["a"]` dedup collapse
15040        // (which would silently absorb the `EtiquetaDuplicate` refusal
15041        // case at the accessor boundary — the caixa-helm chart-render
15042        // `BTreeSet::collect` dedup is downstream of the accessor and
15043        // must not be silently promoted into it).
15044        for etiquetas in [
15045            vec![],
15046            vec![""],
15047            vec!["demo"],
15048            vec!["example", "aplicacao", "mesh", "ecommerce", "demo"],
15049            vec!["demo", "demo"],
15050        ] {
15051            let c = caixa_with_etiquetas(etiquetas.clone());
15052            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
15053            assert_eq!(
15054                c.etiquetas(),
15055                expected.as_slice(),
15056                "Caixa::etiquetas must return :etiquetas verbatim (got \
15057                 {:?}, expected {expected:?})",
15058                c.etiquetas(),
15059            );
15060            assert_eq!(
15061                c.etiquetas(),
15062                c.etiquetas.as_slice(),
15063                "Caixa::etiquetas must byte-equal the raw \
15064                 `self.etiquetas.as_slice()` field access across every \
15065                 value in the Vec<String> accept-set",
15066            );
15067        }
15068    }
15069
15070    #[test]
15071    fn validate_etiquetas_empty_entry_arm_routes_through_accessor() {
15072        // Composition pin: [`Caixa::validate_etiquetas`]'s per-entry
15073        // empty-arm gate must key off [`Caixa::etiquetas`], not the raw
15074        // `&self.etiquetas` field-borrow walk. Structurally: a
15075        // `Caixa { etiquetas: vec!["".into()], .. }` must surface the
15076        // `EtiquetaEmpty` refusal exactly, and a
15077        // `Caixa { etiquetas: vec!["demo".into()], .. }` (the canonical
15078        // single-tag form) must pass validate. The pair jointly pins
15079        // the accessor + validate-gate composition: any future silent
15080        // detour that had the accessor return an empty slice on the
15081        // `[""]` arm (a
15082        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
15083        // silently absorb the `EtiquetaEmpty` refusal at the accessor
15084        // boundary and the validate gate would accept a struct-literal
15085        // `Caixa { etiquetas: vec!["".into()], .. }` — the composition
15086        // pin catches that at caixa-core build time.
15087        //
15088        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
15089        // through_accessor` (b5d813f) accessor-composition pin on the
15090        // sibling `&[T]`-composition axis — same "the validate / shape-
15091        // gate predicate must route through the substrate-primitive
15092        // typed dispatch" discipline extended onto the sibling outer
15093        // top-level [`Caixa`] `&[T]`-composition surface.
15094        let c = caixa_with_etiquetas(vec![""]);
15095        assert!(
15096            matches!(c.validate_etiquetas(), Err(ManifestError::EtiquetaEmpty)),
15097            "validate_etiquetas must reject etiquetas == vec![\"\"] \
15098             with EtiquetaEmpty — the accessor and the validate gate \
15099             must route through the same substrate-primitive typed \
15100             dispatch on the :etiquetas per-entry empty arm",
15101        );
15102        let c = caixa_with_etiquetas(vec!["demo"]);
15103        assert!(
15104            c.validate_etiquetas().is_ok(),
15105            "validate_etiquetas must accept etiquetas == vec![\"demo\"] \
15106             (the canonical single-tag shape every `feira init` \
15107             template scaffolds)",
15108        );
15109    }
15110
15111    #[test]
15112    fn etiquetas_projects_slice_by_borrow() {
15113        // The by-borrow pin: [`Caixa::etiquetas`] returns `&[String]`
15114        // by borrow — the returned slice borrows the underlying
15115        // `Vec<String>` storage of the `:etiquetas` slot and the
15116        // accessor must not clone the backing `Vec` on every call.
15117        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15118        // (b5d813f) by-borrow pin on the sibling outer top-level
15119        // [`Caixa`] `&[String]`-return axis — the accessor's returned
15120        // slice must borrow from `&self` (the returned reference's
15121        // lifetime is tied to `&self`), and calling the accessor twice
15122        // on the same [`Caixa`] must yield slices that are pointer-
15123        // equal (the underlying byte-buffer is the storage `Vec`'s
15124        // allocation, not a fresh copy) as well as value-equal
15125        // (idempotent, no side effects on `&self`).
15126        //
15127        // Pins against a future silent detour that returned an owned
15128        // `Vec<String>` (which would type-check but silently clone on
15129        // every call, breaking the zero-cost projection every peer
15130        // sibling slice accessor carries), a `&Vec<String>` return
15131        // (which would leak the backing `Vec`'s grow/push/reserve
15132        // surface no downstream consumer reaches for), or a one-arm-
15133        // only accessor that returned a saturating value on some
15134        // sentinel input (breaking the pass-through invariant the
15135        // sibling slice accessors carry).
15136        for etiquetas in [
15137            vec![],
15138            vec!["demo"],
15139            vec!["example", "aplicacao", "mesh"],
15140            vec!["demo", "demo"],
15141        ] {
15142            let c = caixa_with_etiquetas(etiquetas.clone());
15143            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
15144            let first = c.etiquetas();
15145            let second = c.etiquetas();
15146            assert_eq!(
15147                first, second,
15148                "Caixa::etiquetas must be idempotent — two successive \
15149                 calls on the same &self must return the same \
15150                 &[String]",
15151            );
15152            assert_eq!(
15153                first.as_ptr(),
15154                second.as_ptr(),
15155                "Caixa::etiquetas must borrow the underlying \
15156                 Vec<String> storage — two successive calls must \
15157                 return slices with the same backing pointer (a fresh \
15158                 Vec<String> clone would change the pointer on every \
15159                 call)",
15160            );
15161            assert_eq!(
15162                first,
15163                expected.as_slice(),
15164                "Caixa::etiquetas must return :etiquetas verbatim by \
15165                 borrow — got {first:?}, expected {expected:?}",
15166            );
15167        }
15168    }
15169
15170    // ── Caixa::bibliotecas — outer top-level &[T] slice accessor ──────
15171
15172    #[test]
15173    fn bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations() {
15174        // The canonical per-`Caixa` `:bibliotecas` universal-axis
15175        // library-source-path-list slice pin: [`Caixa::bibliotecas`]
15176        // must return the `:bibliotecas` typed [`Vec<String>`] list
15177        // verbatim as a `&[String]`, byte-equal to the raw
15178        // `self.bibliotecas.as_slice()` access across every
15179        // representative value in the accept-set — `[]` (the "no
15180        // libraries declared" arm every `:kind` other than `Biblioteca`
15181        // + every `Biblioteca` relying on the canonical
15182        // `lib/<nome>.lisp` implicit-default path carries; the
15183        // layout's [`crate::LayoutInvariants`] `MissingLib` arm-gate
15184        // fires exactly on this empty-slot + `Biblioteca`-kind
15185        // combination), `[""]` (a past-the-guard sentinel that pins
15186        // the accessor doesn't perform a silent `[""] → []` collapse
15187        // on the empty-entry arm — validate rejects `[""]` through
15188        // `CodePathEmpty { slot: ":bibliotecas" }` but the accessor
15189        // must ship the raw slot verbatim so a validate-time gate
15190        // regression surfaces at the `feira build` phase-1 parse
15191        // boundary rather than being silently absorbed into a
15192        // library-drop), `["lib/demo.lisp"]` (the canonical single-
15193        // entry form `Caixa::template` scaffolds and every `feira init`
15194        // template emits), `["lib/demo.lisp", "lib/helpers.lisp"]`
15195        // (the canonical multi-library form the
15196        // `validate_code_paths_accepts_explicit_relative_paths_on_
15197        // every_slot` fixture emits), and `["lib/foo.lisp",
15198        // "lib/foo.lisp"]` (a past-the-guard duplicate sentinel —
15199        // validate rejects through `CodePathDuplicate { slot:
15200        // ":bibliotecas" }` per the per-slot set-not-multiset gate,
15201        // but the accessor must ship the raw slot verbatim so the
15202        // `feira build` `for entry in caixa.bibliotecas()` parse walk
15203        // sees the duplicate at the accessor boundary and struct-
15204        // literal `Caixa { bibliotecas: vec!["lib/foo.lisp".into(),
15205        // "lib/foo.lisp".into()], .. }` fixtures continue to expose
15206        // the duplicate at the accessor).
15207        //
15208        // Third outer top-level [`Caixa`] `&[T]`-return slice accessor
15209        // pin on the substrate primitive — folds on the "outer
15210        // [`Caixa`] `&[T]` slice" projection pattern
15211        // `autores_returns_autores_slice_verbatim_across_permutations`
15212        // (b5d813f) opened and
15213        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15214        // (78c7d3c) folded on, sibling in shape and idiom. Pins
15215        // against a future silent detour that returned an owned
15216        // `Vec<String>` (which would type-check but silently clone on
15217        // every accessor call, breaking the zero-cost projection
15218        // every peer sibling slice accessor carries), a `[""] → []`
15219        // collapse (which would silently absorb the `CodePathEmpty`
15220        // refusal case at the accessor boundary), or a `["lib/foo.lisp",
15221        // "lib/foo.lisp"] → ["lib/foo.lisp"]` dedup collapse (which
15222        // would silently absorb the `CodePathDuplicate` refusal case
15223        // at the accessor boundary — the per-slot set-not-multiset
15224        // gate is downstream of the accessor and must not be silently
15225        // promoted into it).
15226        for bibliotecas in [
15227            vec![],
15228            vec![""],
15229            vec!["lib/demo.lisp"],
15230            vec!["lib/demo.lisp", "lib/helpers.lisp"],
15231            vec!["lib/foo.lisp", "lib/foo.lisp"],
15232        ] {
15233            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
15234            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
15235            assert_eq!(
15236                c.bibliotecas(),
15237                expected.as_slice(),
15238                "Caixa::bibliotecas must return :bibliotecas verbatim \
15239                 (got {:?}, expected {expected:?})",
15240                c.bibliotecas(),
15241            );
15242            assert_eq!(
15243                c.bibliotecas(),
15244                c.bibliotecas.as_slice(),
15245                "Caixa::bibliotecas must byte-equal the raw \
15246                 `self.bibliotecas.as_slice()` field access across \
15247                 every value in the Vec<String> accept-set",
15248            );
15249        }
15250    }
15251
15252    #[test]
15253    fn validate_code_paths_bibliotecas_empty_arm_routes_through_accessor() {
15254        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15255        // empty-arm gate on the `:bibliotecas` slot must key off
15256        // [`Caixa::bibliotecas`], not a divergent raw
15257        // `&self.bibliotecas` field-borrow walk. Structurally: a
15258        // `Caixa { bibliotecas: vec!["".into()], .. }` must surface
15259        // the `CodePathEmpty { slot: ":bibliotecas" }` refusal
15260        // exactly, and a `Caixa { bibliotecas: vec!["lib/demo.lisp".
15261        // into()], .. }` (the canonical single-library form
15262        // `Caixa::template` scaffolds) must pass validate. The pair
15263        // jointly pins the accessor + validate-gate composition: any
15264        // future silent detour that had the accessor return an empty
15265        // slice on the `[""]` arm (a `.iter().filter(|s|
15266        // !s.is_empty()).collect()` collapse) would silently absorb
15267        // the `CodePathEmpty` refusal at the accessor boundary and
15268        // the validate gate would accept a struct-literal
15269        // `Caixa { bibliotecas: vec!["".into()], .. }` — the
15270        // composition pin catches that at caixa-core build time.
15271        //
15272        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
15273        // through_accessor` (b5d813f) and
15274        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15275        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15276        // composition axes — same "the validate / shape-gate
15277        // predicate must route through the substrate-primitive typed
15278        // dispatch" discipline extended onto the sibling outer top-
15279        // level [`Caixa`] `&[T]`-composition surface. Nominally the
15280        // in-tree `validate_code_paths` production body still keys
15281        // off the internal `[(":bibliotecas", &self.bibliotecas,
15282        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15283        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15284        // (the tuple's homogeneous slice-typed shape blocks a per-
15285        // element accessor swap in isolation — a future companion
15286        // lift for `:exe` and `:servicos` on the same outer-`Caixa`
15287        // `&[T]` slice-accessor axis closes that tuple onto the
15288        // triple of typed dispatches as a unit); the composition pin
15289        // catches any future accessor-side silent filter drop against
15290        // that eventual tuple-closure regardless of whether the
15291        // `:bibliotecas` slot is threaded through the accessor or the
15292        // raw field access at the tuple's construction site.
15293        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
15294        assert!(
15295            matches!(
15296                c.validate_code_paths(),
15297                Err(ManifestError::CodePathEmpty {
15298                    slot: ":bibliotecas"
15299                })
15300            ),
15301            "validate_code_paths must reject bibliotecas == vec![\"\"] \
15302             with CodePathEmpty {{ slot: \":bibliotecas\" }} — the \
15303             accessor and the validate gate must route through the \
15304             same substrate-primitive typed dispatch on the \
15305             :bibliotecas per-entry empty arm",
15306        );
15307        let c = caixa_with_code_paths(vec!["lib/demo.lisp"], vec![], vec![]);
15308        assert!(
15309            c.validate_code_paths().is_ok(),
15310            "validate_code_paths must accept bibliotecas == \
15311             vec![\"lib/demo.lisp\"] (the canonical single-library \
15312             shape every `feira init` template scaffolds)",
15313        );
15314    }
15315
15316    #[test]
15317    fn bibliotecas_projects_slice_by_borrow() {
15318        // The by-borrow pin: [`Caixa::bibliotecas`] returns
15319        // `&[String]` by borrow — the returned slice borrows the
15320        // underlying `Vec<String>` storage of the `:bibliotecas` slot
15321        // and the accessor must not clone the backing `Vec` on every
15322        // call. Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15323        // (b5d813f) and `etiquetas_projects_slice_by_borrow` (78c7d3c)
15324        // by-borrow pins on the sibling outer top-level [`Caixa`]
15325        // `&[String]`-return axes — the accessor's returned slice
15326        // must borrow from `&self` (the returned reference's lifetime
15327        // is tied to `&self`), and calling the accessor twice on the
15328        // same [`Caixa`] must yield slices that are pointer-equal
15329        // (the underlying byte-buffer is the storage `Vec`'s
15330        // allocation, not a fresh copy) as well as value-equal
15331        // (idempotent, no side effects on `&self`).
15332        //
15333        // Pins against a future silent detour that returned an owned
15334        // `Vec<String>` (which would type-check but silently clone on
15335        // every call, breaking the zero-cost projection every peer
15336        // sibling slice accessor carries), a `&Vec<String>` return
15337        // (which would leak the backing `Vec`'s grow/push/reserve
15338        // surface no downstream consumer reaches for), or a one-arm-
15339        // only accessor that returned a saturating value on some
15340        // sentinel input (breaking the pass-through invariant the
15341        // sibling slice accessors carry).
15342        for bibliotecas in [
15343            vec![],
15344            vec!["lib/demo.lisp"],
15345            vec!["lib/demo.lisp", "lib/helpers.lisp"],
15346            vec!["lib/foo.lisp", "lib/foo.lisp"],
15347        ] {
15348            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
15349            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
15350            let first = c.bibliotecas();
15351            let second = c.bibliotecas();
15352            assert_eq!(
15353                first, second,
15354                "Caixa::bibliotecas must be idempotent — two \
15355                 successive calls on the same &self must return the \
15356                 same &[String]",
15357            );
15358            assert_eq!(
15359                first.as_ptr(),
15360                second.as_ptr(),
15361                "Caixa::bibliotecas must borrow the underlying \
15362                 Vec<String> storage — two successive calls must \
15363                 return slices with the same backing pointer (a \
15364                 fresh Vec<String> clone would change the pointer on \
15365                 every call)",
15366            );
15367            assert_eq!(
15368                first,
15369                expected.as_slice(),
15370                "Caixa::bibliotecas must return :bibliotecas verbatim \
15371                 by borrow — got {first:?}, expected {expected:?}",
15372            );
15373        }
15374    }
15375
15376    // ── Caixa::exe — outer top-level &[T] slice accessor ──────────────
15377
15378    #[test]
15379    fn exe_returns_exe_slice_verbatim_across_permutations() {
15380        // The canonical per-`Caixa` `:exe` universal-axis
15381        // nix-built-executable-entry-path-list slice pin: [`Caixa::exe`]
15382        // must return the `:exe` typed [`Vec<String>`] list verbatim as
15383        // a `&[String]`, byte-equal to the raw `self.exe.as_slice()`
15384        // access across every representative value in the accept-set —
15385        // `[]` (the "no executable declared" arm every `:kind` other
15386        // than `Binario` carries; the layout's [`crate::LayoutInvariants`]
15387        // `BinarioWithoutExe` arm-gate fires exactly on this empty-slot
15388        // + `Binario`-kind combination), `[""]` (a past-the-guard
15389        // sentinel that pins the accessor doesn't perform a silent
15390        // `[""] → []` collapse on the empty-entry arm — validate rejects
15391        // `[""]` through `CodePathEmpty { slot: ":exe" }` but the
15392        // accessor must ship the raw slot verbatim so a validate-time
15393        // gate regression surfaces at the layout / `feira nix` boundary
15394        // rather than being silently absorbed into an executable-drop),
15395        // `["exe/cli"]` (the canonical single-entry Binario form every
15396        // in-tree `caixa_with_code_paths` positive control uses),
15397        // `["exe/cli", "exe/serve"]` (the canonical multi-executable
15398        // form the `validate_code_paths_accepts_explicit_relative_paths_
15399        // on_every_slot` fixture emits), and `["exe/cli", "exe/cli"]`
15400        // (a past-the-guard duplicate sentinel — validate rejects
15401        // through `CodePathDuplicate { slot: ":exe" }` per the per-slot
15402        // set-not-multiset gate, but the accessor must ship the raw
15403        // slot verbatim so struct-literal `Caixa { exe: vec!["exe/cli".
15404        // into(), "exe/cli".into()], .. }` fixtures continue to expose
15405        // the duplicate at the accessor).
15406        //
15407        // Fourth outer top-level [`Caixa`] `&[T]`-return slice accessor
15408        // pin on the substrate primitive — folds on the "outer
15409        // [`Caixa`] `&[T]` slice" projection pattern
15410        // `autores_returns_autores_slice_verbatim_across_permutations`
15411        // (b5d813f) opened,
15412        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15413        // (78c7d3c) folded on, and
15414        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15415        // (8a36c23) closed the universal-axis text-tag family of.
15416        // Opens the outer-`Caixa` foreign-code-slot `&[T]` sub-family
15417        // the sibling `:servicos` future lift closes onto. Pins against
15418        // a future silent detour that returned an owned `Vec<String>`
15419        // (which would type-check but silently clone on every accessor
15420        // call, breaking the zero-cost projection every peer sibling
15421        // slice accessor carries), a `[""] → []` collapse (which would
15422        // silently absorb the `CodePathEmpty` refusal case at the
15423        // accessor boundary), or an `["exe/cli", "exe/cli"] →
15424        // ["exe/cli"]` dedup collapse (which would silently absorb the
15425        // `CodePathDuplicate` refusal case at the accessor boundary —
15426        // the per-slot set-not-multiset gate is downstream of the
15427        // accessor and must not be silently promoted into it).
15428        for exe in [
15429            vec![],
15430            vec![""],
15431            vec!["exe/cli"],
15432            vec!["exe/cli", "exe/serve"],
15433            vec!["exe/cli", "exe/cli"],
15434        ] {
15435            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
15436            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
15437            assert_eq!(
15438                c.exe(),
15439                expected.as_slice(),
15440                "Caixa::exe must return :exe verbatim (got {:?}, \
15441                 expected {expected:?})",
15442                c.exe(),
15443            );
15444            assert_eq!(
15445                c.exe(),
15446                c.exe.as_slice(),
15447                "Caixa::exe must byte-equal the raw \
15448                 `self.exe.as_slice()` field access across every value \
15449                 in the Vec<String> accept-set",
15450            );
15451        }
15452    }
15453
15454    #[test]
15455    fn validate_code_paths_exe_empty_arm_routes_through_accessor() {
15456        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15457        // empty-arm gate on the `:exe` slot must key off
15458        // [`Caixa::exe`], not a divergent raw `&self.exe` field-borrow
15459        // walk. Structurally: a `Caixa { exe: vec!["".into()], .. }`
15460        // must surface the `CodePathEmpty { slot: ":exe" }` refusal
15461        // exactly, and a `Caixa { exe: vec!["exe/cli".into()], .. }`
15462        // (the canonical single-executable form every in-tree
15463        // `caixa_with_code_paths` positive control uses) must pass
15464        // validate. The pair jointly pins the accessor + validate-gate
15465        // composition: any future silent detour that had the accessor
15466        // return an empty slice on the `[""]` arm (a
15467        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
15468        // silently absorb the `CodePathEmpty` refusal at the accessor
15469        // boundary and the validate gate would accept a struct-literal
15470        // `Caixa { exe: vec!["".into()], .. }` — the composition pin
15471        // catches that at caixa-core build time.
15472        //
15473        // Peer of the per-`Caixa`
15474        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15475        // (8a36c23), `validate_autores_empty_arm_routes_through_accessor`
15476        // (b5d813f), and
15477        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15478        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15479        // composition axes — same "the validate / shape-gate predicate
15480        // must route through the substrate-primitive typed dispatch"
15481        // discipline extended onto the sibling outer top-level [`Caixa`]
15482        // `&[T]`-composition surface. Nominally the in-tree
15483        // `validate_code_paths` production body still keys off the
15484        // internal `[(":bibliotecas", &self.bibliotecas,
15485        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15486        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15487        // (the tuple's homogeneous slice-typed shape blocks a per-
15488        // element accessor swap in isolation — a future companion lift
15489        // for `:servicos` on the same outer-`Caixa` `&[T]` slice-
15490        // accessor axis closes that tuple onto the triple of typed
15491        // dispatches as a unit); the composition pin catches any future
15492        // accessor-side silent filter drop against that eventual tuple-
15493        // closure regardless of whether the `:exe` slot is threaded
15494        // through the accessor or the raw field access at the tuple's
15495        // construction site.
15496        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
15497        assert!(
15498            matches!(
15499                c.validate_code_paths(),
15500                Err(ManifestError::CodePathEmpty { slot: ":exe" })
15501            ),
15502            "validate_code_paths must reject exe == vec![\"\"] \
15503             with CodePathEmpty {{ slot: \":exe\" }} — the \
15504             accessor and the validate gate must route through the \
15505             same substrate-primitive typed dispatch on the \
15506             :exe per-entry empty arm",
15507        );
15508        let c = caixa_with_code_paths(vec![], vec!["exe/cli"], vec![]);
15509        assert!(
15510            c.validate_code_paths().is_ok(),
15511            "validate_code_paths must accept exe == vec![\"exe/cli\"] \
15512             (the canonical single-executable shape every in-tree \
15513             `caixa_with_code_paths` positive control uses)",
15514        );
15515    }
15516
15517    #[test]
15518    fn exe_projects_slice_by_borrow() {
15519        // The by-borrow pin: [`Caixa::exe`] returns `&[String]` by
15520        // borrow — the returned slice borrows the underlying
15521        // `Vec<String>` storage of the `:exe` slot and the accessor
15522        // must not clone the backing `Vec` on every call. Peer of the
15523        // per-`Caixa` `autores_projects_slice_by_borrow` (b5d813f),
15524        // `etiquetas_projects_slice_by_borrow` (78c7d3c), and
15525        // `bibliotecas_projects_slice_by_borrow` (8a36c23) by-borrow
15526        // pins on the sibling outer top-level [`Caixa`] `&[String]`-
15527        // return axes — the accessor's returned slice must borrow from
15528        // `&self` (the returned reference's lifetime is tied to
15529        // `&self`), and calling the accessor twice on the same
15530        // [`Caixa`] must yield slices that are pointer-equal (the
15531        // underlying byte-buffer is the storage `Vec`'s allocation,
15532        // not a fresh copy) as well as value-equal (idempotent, no
15533        // side effects on `&self`).
15534        //
15535        // Pins against a future silent detour that returned an owned
15536        // `Vec<String>` (which would type-check but silently clone on
15537        // every call, breaking the zero-cost projection every peer
15538        // sibling slice accessor carries), a `&Vec<String>` return
15539        // (which would leak the backing `Vec`'s grow/push/reserve
15540        // surface no downstream consumer reaches for), or a one-arm-
15541        // only accessor that returned a saturating value on some
15542        // sentinel input (breaking the pass-through invariant the
15543        // sibling slice accessors carry).
15544        for exe in [
15545            vec![],
15546            vec!["exe/cli"],
15547            vec!["exe/cli", "exe/serve"],
15548            vec!["exe/cli", "exe/cli"],
15549        ] {
15550            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
15551            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
15552            let first = c.exe();
15553            let second = c.exe();
15554            assert_eq!(
15555                first, second,
15556                "Caixa::exe must be idempotent — two successive calls \
15557                 on the same &self must return the same &[String]",
15558            );
15559            assert_eq!(
15560                first.as_ptr(),
15561                second.as_ptr(),
15562                "Caixa::exe must borrow the underlying Vec<String> \
15563                 storage — two successive calls must return slices \
15564                 with the same backing pointer (a fresh Vec<String> \
15565                 clone would change the pointer on every call)",
15566            );
15567            assert_eq!(
15568                first,
15569                expected.as_slice(),
15570                "Caixa::exe must return :exe verbatim by borrow — \
15571                 got {first:?}, expected {expected:?}",
15572            );
15573        }
15574    }
15575
15576    // ── Caixa::servicos — outer top-level &[T] slice accessor ─────────
15577
15578    #[test]
15579    fn servicos_returns_servicos_slice_verbatim_across_permutations() {
15580        // The canonical per-`Caixa` `:servicos` universal-axis
15581        // ComputeUnit-CR-YAML-entry-path-list slice pin:
15582        // [`Caixa::servicos`] must return the `:servicos` typed
15583        // [`Vec<String>`] list verbatim as a `&[String]`, byte-equal to
15584        // the raw `self.servicos.as_slice()` access across every
15585        // representative value in the accept-set — `[]` (the "no
15586        // ComputeUnit-CR declared" arm every `:kind` other than
15587        // `Servico` carries; the layout's [`crate::LayoutInvariants`]
15588        // `ServicoWithoutServicos` arm-gate fires exactly on this
15589        // empty-slot + `Servico`-kind combination), `[""]` (a past-the-
15590        // guard sentinel that pins the accessor doesn't perform a
15591        // silent `[""] → []` collapse on the empty-entry arm — validate
15592        // rejects `[""]` through `CodePathEmpty { slot: ":servicos" }`
15593        // but the accessor must ship the raw slot verbatim so a
15594        // validate-time gate regression surfaces at the layout /
15595        // per-Servico renderer boundary rather than being silently
15596        // absorbed into a component-drop),
15597        // `["servicos/demo.computeunit.yaml"]` (the canonical
15598        // singleton V0-shape every in-tree `caixa_with_code_paths`
15599        // positive control uses; the same shape
15600        // [`crate::require_single_servico`] admits),
15601        // `["servicos/a.computeunit.yaml", "servicos/b.computeunit.
15602        // yaml"]` (a past-the-guard `len != 1` sentinel — the V0
15603        // singularity gate rejects through `ServicoCountMismatch
15604        // { count: 2 }` but the accessor must ship the raw slot
15605        // verbatim so struct-literal `Caixa { servicos: vec![...,
15606        // ...], .. }` fixtures continue to expose the count at the
15607        // accessor), and `["servicos/a.computeunit.yaml",
15608        // "servicos/a.computeunit.yaml"]` (a past-the-guard duplicate
15609        // sentinel — validate rejects through
15610        // `CodePathDuplicate { slot: ":servicos" }` per the per-slot
15611        // set-not-multiset gate, but the accessor must ship the raw
15612        // slot verbatim so struct-literal fixtures continue to expose
15613        // the duplicate at the accessor).
15614        //
15615        // Fifth and final outer top-level [`Caixa`] `&[T]`-return
15616        // slice accessor pin on the substrate primitive — folds on the
15617        // "outer [`Caixa`] `&[T]` slice" projection pattern
15618        // `autores_returns_autores_slice_verbatim_across_permutations`
15619        // (b5d813f) opened,
15620        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15621        // (78c7d3c) folded on,
15622        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15623        // (8a36c23) closed the universal-axis text-tag family of, and
15624        // `exe_returns_exe_slice_verbatim_across_permutations`
15625        // (65d9527) opened the foreign-code-slot sub-family of. Closes
15626        // the outer-`Caixa` foreign-code-slot `&[T]` sub-family — the
15627        // trio of code-surface list slots (`:bibliotecas` + `:exe` +
15628        // `:servicos`) now each carries a substrate-canonical slice
15629        // accessor. Pins against a future silent detour that returned
15630        // an owned `Vec<String>` (which would type-check but silently
15631        // clone on every accessor call, breaking the zero-cost
15632        // projection every peer sibling slice accessor carries), a
15633        // `[""] → []` collapse (which would silently absorb the
15634        // `CodePathEmpty` refusal case at the accessor boundary), an
15635        // `[a, a] → [a]` dedup collapse (which would silently absorb
15636        // the `CodePathDuplicate` refusal case at the accessor
15637        // boundary — the per-slot set-not-multiset gate is downstream
15638        // of the accessor and must not be silently promoted into it),
15639        // or a `[a, b] → [a]` singleton collapse (which would silently
15640        // absorb the V0 `ServicoCountMismatch` refusal case at the
15641        // accessor boundary — the V0 singularity gate is downstream of
15642        // the accessor and must not be silently promoted into it).
15643        for servicos in [
15644            vec![],
15645            vec![""],
15646            vec!["servicos/demo.computeunit.yaml"],
15647            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
15648            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
15649        ] {
15650            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
15651            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
15652            assert_eq!(
15653                c.servicos(),
15654                expected.as_slice(),
15655                "Caixa::servicos must return :servicos verbatim (got \
15656                 {:?}, expected {expected:?})",
15657                c.servicos(),
15658            );
15659            assert_eq!(
15660                c.servicos(),
15661                c.servicos.as_slice(),
15662                "Caixa::servicos must byte-equal the raw \
15663                 `self.servicos.as_slice()` field access across every \
15664                 value in the Vec<String> accept-set",
15665            );
15666        }
15667    }
15668
15669    #[test]
15670    fn validate_code_paths_servicos_empty_arm_routes_through_accessor() {
15671        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15672        // empty-arm gate on the `:servicos` slot must key off
15673        // [`Caixa::servicos`], not a divergent raw `&self.servicos`
15674        // field-borrow walk. Structurally: a `Caixa { servicos:
15675        // vec!["".into()], .. }` must surface the `CodePathEmpty
15676        // { slot: ":servicos" }` refusal exactly, and a `Caixa
15677        // { servicos: vec!["servicos/demo.computeunit.yaml".into()],
15678        // .. }` (the canonical singleton V0-shape every in-tree
15679        // `caixa_with_code_paths` positive control uses) must pass
15680        // validate. The pair jointly pins the accessor + validate-gate
15681        // composition: any future silent detour that had the accessor
15682        // return an empty slice on the `[""]` arm (a `.iter().filter
15683        // (|s| !s.is_empty()).collect()` collapse) would silently
15684        // absorb the `CodePathEmpty` refusal at the accessor boundary
15685        // and the validate gate would accept a struct-literal
15686        // `Caixa { servicos: vec!["".into()], .. }` — the composition
15687        // pin catches that at caixa-core build time.
15688        //
15689        // Peer of the per-`Caixa`
15690        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15691        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
15692        // (65d9527), `validate_autores_empty_arm_routes_through_accessor`
15693        // (b5d813f), and
15694        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15695        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15696        // composition axes — same "the validate / shape-gate predicate
15697        // must route through the substrate-primitive typed dispatch"
15698        // discipline extended onto the sibling outer top-level
15699        // [`Caixa`] `&[T]`-composition surface, closing the trio of
15700        // code-surface accessor-composition pins on the same axis.
15701        // Nominally the in-tree `validate_code_paths` production body
15702        // still keys off the internal
15703        // `[(":bibliotecas", &self.bibliotecas,
15704        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15705        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15706        // (the tuple's homogeneous `&Vec<String>`-typed shape blocks a
15707        // per-element accessor swap in isolation — a future companion
15708        // lift promotes the tuple's element type to `&[String]` and
15709        // threads the triple of typed dispatches through as a unit);
15710        // the composition pin catches any future accessor-side silent
15711        // filter drop against that eventual tuple-closure regardless
15712        // of whether the `:servicos` slot is threaded through the
15713        // accessor or the raw field access at the tuple's construction
15714        // site.
15715        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
15716        assert!(
15717            matches!(
15718                c.validate_code_paths(),
15719                Err(ManifestError::CodePathEmpty { slot: ":servicos" })
15720            ),
15721            "validate_code_paths must reject servicos == vec![\"\"] \
15722             with CodePathEmpty {{ slot: \":servicos\" }} — the \
15723             accessor and the validate gate must route through the \
15724             same substrate-primitive typed dispatch on the \
15725             :servicos per-entry empty arm",
15726        );
15727        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.computeunit.yaml"]);
15728        assert!(
15729            c.validate_code_paths().is_ok(),
15730            "validate_code_paths must accept servicos == \
15731             vec![\"servicos/demo.computeunit.yaml\"] (the canonical \
15732             singleton V0-shape every in-tree `caixa_with_code_paths` \
15733             positive control uses)",
15734        );
15735    }
15736
15737    #[test]
15738    fn servicos_projects_slice_by_borrow() {
15739        // The by-borrow pin: [`Caixa::servicos`] returns `&[String]` by
15740        // borrow — the returned slice borrows the underlying
15741        // `Vec<String>` storage of the `:servicos` slot and the
15742        // accessor must not clone the backing `Vec` on every call.
15743        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15744        // (b5d813f), `etiquetas_projects_slice_by_borrow` (78c7d3c),
15745        // `bibliotecas_projects_slice_by_borrow` (8a36c23), and
15746        // `exe_projects_slice_by_borrow` (65d9527) by-borrow pins on
15747        // the sibling outer top-level [`Caixa`] `&[String]`-return
15748        // axes — the accessor's returned slice must borrow from
15749        // `&self` (the returned reference's lifetime is tied to
15750        // `&self`), and calling the accessor twice on the same
15751        // [`Caixa`] must yield slices that are pointer-equal (the
15752        // underlying byte-buffer is the storage `Vec`'s allocation,
15753        // not a fresh copy) as well as value-equal (idempotent, no
15754        // side effects on `&self`).
15755        //
15756        // Pins against a future silent detour that returned an owned
15757        // `Vec<String>` (which would type-check but silently clone on
15758        // every call, breaking the zero-cost projection every peer
15759        // sibling slice accessor carries), a `&Vec<String>` return
15760        // (which would leak the backing `Vec`'s grow/push/reserve
15761        // surface no downstream consumer reaches for), or a one-arm-
15762        // only accessor that returned a saturating value on some
15763        // sentinel input (breaking the pass-through invariant the
15764        // sibling slice accessors carry).
15765        for servicos in [
15766            vec![],
15767            vec!["servicos/demo.computeunit.yaml"],
15768            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
15769            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
15770        ] {
15771            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
15772            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
15773            let first = c.servicos();
15774            let second = c.servicos();
15775            assert_eq!(
15776                first, second,
15777                "Caixa::servicos must be idempotent — two successive \
15778                 calls on the same &self must return the same &[String]",
15779            );
15780            assert_eq!(
15781                first.as_ptr(),
15782                second.as_ptr(),
15783                "Caixa::servicos must borrow the underlying \
15784                 Vec<String> storage — two successive calls must \
15785                 return slices with the same backing pointer (a fresh \
15786                 Vec<String> clone would change the pointer on every \
15787                 call)",
15788            );
15789            assert_eq!(
15790                first,
15791                expected.as_slice(),
15792                "Caixa::servicos must return :servicos verbatim by \
15793                 borrow — got {first:?}, expected {expected:?}",
15794            );
15795        }
15796    }
15797
15798    // ── Caixa::deps — outer top-level &[Dep] slice accessor ───────────
15799
15800    fn caixa_with_deps(deps: Vec<Dep>) -> Caixa {
15801        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15802        c.deps = deps;
15803        c
15804    }
15805
15806    #[test]
15807    fn deps_returns_deps_slice_verbatim_across_permutations() {
15808        // The canonical per-`Caixa` `:deps` universal-axis runtime-
15809        // dependency-declaration-list slice pin: [`Caixa::deps`] must
15810        // return the `:deps` typed [`Vec<Dep>`] list verbatim as a
15811        // `&[Dep]`, element-equal to the raw `self.deps.as_slice()`
15812        // access across every representative value in the accept-set —
15813        // `[]` (the "no runtime deps declared" arm every existing
15814        // fixture without a `:deps` line carries; the
15815        // [`Caixa::template`] scaffold emits `:deps ()`), a canonical
15816        // single-entry list (the shape most consumer caixas carry), a
15817        // canonical two-entry list (the multi-dep runtime closure), and
15818        // two past-the-guard sentinels — a `[""]`-`:nome` entry
15819        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
15820        // `NomeInvalid` but the accessor must ship the raw slot
15821        // verbatim) and a `[a, a]` duplicate (validate rejects through
15822        // `DuplicateNome { list: ":deps" }` but the accessor must ship
15823        // the raw slot verbatim so struct-literal fixtures continue to
15824        // expose the duplicate at the accessor).
15825        //
15826        // First outer top-level [`Caixa`] `&[Dep]`-return slice accessor
15827        // pin on the substrate primitive — opens the outer-`Caixa`
15828        // dependency-slot `&[Dep]` sub-family the sibling `:deps-dev`
15829        // future lift closes on. Peer of the closed outer-`Caixa`
15830        // foreign-code-slot `&[String]` sub-family
15831        // (`bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15832        // 8a36c23, `exe_returns_exe_slice_verbatim_across_permutations`
15833        // 65d9527, `servicos_returns_servicos_slice_verbatim_across_permutations`
15834        // 611f78b) and the outer-`Caixa` universal-axis text-tag family
15835        // (`autores_returns_autores_slice_verbatim_across_permutations`
15836        // b5d813f, `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15837        // 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice"
15838        // projection pattern onto a novel element-type axis (`Dep`
15839        // composite vs the prior sibling family's `String` scalar).
15840        // Pins against a future silent detour that returned an owned
15841        // `Vec<Dep>` (which would type-check but silently clone on every
15842        // accessor call, breaking the zero-cost projection every peer
15843        // sibling slice accessor carries), a `[""] → []` collapse (which
15844        // would silently absorb the `NomeEmpty` refusal case at the
15845        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
15846        // would silently absorb the `DuplicateNome` refusal case at the
15847        // accessor boundary).
15848        for deps in [
15849            vec![],
15850            vec![Dep::simple("", "^0.1")],
15851            vec![Dep::simple("caixa-teia", "^0.1")],
15852            vec![
15853                Dep::simple("caixa-teia", "^0.1"),
15854                Dep::simple("caixa-core", "^0.1"),
15855            ],
15856            vec![
15857                Dep::simple("caixa-teia", "^0.1"),
15858                Dep::simple("caixa-teia", "^0.2"),
15859            ],
15860        ] {
15861            let c = caixa_with_deps(deps.clone());
15862            assert_eq!(
15863                c.deps(),
15864                deps.as_slice(),
15865                "Caixa::deps must return :deps verbatim (got {:?}, \
15866                 expected {deps:?})",
15867                c.deps(),
15868            );
15869            assert_eq!(
15870                c.deps(),
15871                c.deps.as_slice(),
15872                "Caixa::deps must element-equal the raw \
15873                 `self.deps.as_slice()` field access across every \
15874                 value in the Vec<Dep> accept-set",
15875            );
15876        }
15877    }
15878
15879    #[test]
15880    fn validate_deps_duplicate_arm_routes_through_accessor() {
15881        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps`
15882        // duplicate-`:nome` gate must key off [`Caixa::deps`], not the
15883        // raw `&self.deps` field-borrow walk. Structurally: a `Caixa
15884        // { deps: vec![Dep::simple("d", "^0.1"), Dep::simple("d",
15885        // "^0.2")], .. }` must surface the `DuplicateNome { list:
15886        // ":deps" }` refusal exactly, and a `Caixa { deps: vec![
15887        // Dep::simple("d", "^0.1")], .. }` (the canonical single-entry
15888        // form) must pass validate. The pair jointly pins the accessor +
15889        // validate-gate composition: any future silent detour that had
15890        // the accessor return a dedupped slice on the `[a, a]` arm (a
15891        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
15892        // would silently absorb the `DuplicateNome` refusal at the
15893        // accessor boundary and the validate gate would accept a
15894        // struct-literal `Caixa` carrying the drift — the composition
15895        // pin catches that at caixa-core build time.
15896        //
15897        // Peer of the per-`Caixa`
15898        // `validate_autores_empty_entry_arm_routes_through_accessor`
15899        // (b5d813f), `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15900        // (78c7d3c), `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15901        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
15902        // (65d9527), and `validate_code_paths_servicos_empty_arm_routes_through_accessor`
15903        // (611f78b) accessor-composition pins on the sibling `&[T]`-
15904        // composition axes — same "the validate gate must route through
15905        // the substrate-primitive typed dispatch" discipline extended
15906        // onto the sibling outer top-level [`Caixa`] `&[Dep]`-
15907        // composition surface, opening the outer-`Caixa` dependency-slot
15908        // arm of the composition-pin family.
15909        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
15910        let err = c.validate_deps().unwrap_err();
15911        assert!(
15912            matches!(
15913                err,
15914                DepError::DuplicateNome { ref nome, list } if nome == "d"
15915                    && list == crate::render::DEP_AUTHOR_KEY_DEPS
15916            ),
15917            "validate_deps must reject deps == \
15918             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
15919             DuplicateNome {{ nome: \"d\", list: \":deps\" }} — the \
15920             accessor and the validate gate must route through the \
15921             same substrate-primitive typed dispatch on the :deps \
15922             within-list duplicate arm (got {err:?})",
15923        );
15924        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1")]);
15925        assert!(
15926            c.validate_deps().is_ok(),
15927            "validate_deps must accept deps == vec![Dep(\"d\",\"^0.1\")] \
15928             (the canonical single-entry form)",
15929        );
15930    }
15931
15932    #[test]
15933    fn deps_projects_slice_by_borrow() {
15934        // The by-borrow pin: [`Caixa::deps`] returns `&[Dep]` by borrow
15935        // — the returned slice borrows the underlying `Vec<Dep>` storage
15936        // of the `:deps` slot and the accessor must not clone the
15937        // backing `Vec` on every call. Peer of the per-`Caixa`
15938        // `autores_projects_slice_by_borrow` (b5d813f),
15939        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
15940        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
15941        // `exe_projects_slice_by_borrow` (65d9527), and
15942        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
15943        // on the sibling outer top-level [`Caixa`] `&[String]`-return
15944        // axes — the accessor's returned slice must borrow from `&self`
15945        // (the returned reference's lifetime is tied to `&self`), and
15946        // calling the accessor twice on the same [`Caixa`] must yield
15947        // slices that are pointer-equal (the underlying byte-buffer is
15948        // the storage `Vec`'s allocation, not a fresh copy) as well as
15949        // value-equal (idempotent, no side effects on `&self`).
15950        //
15951        // Pins against a future silent detour that returned an owned
15952        // `Vec<Dep>` (which would type-check but silently clone on
15953        // every call), a `&Vec<Dep>` return (which would leak the
15954        // backing `Vec`'s grow/push/reserve surface no downstream
15955        // consumer reaches for), or a one-arm-only accessor that
15956        // returned a saturating value on some sentinel input.
15957        for deps in [
15958            vec![],
15959            vec![Dep::simple("caixa-teia", "^0.1")],
15960            vec![
15961                Dep::simple("caixa-teia", "^0.1"),
15962                Dep::simple("caixa-core", "^0.1"),
15963            ],
15964        ] {
15965            let c = caixa_with_deps(deps.clone());
15966            let first = c.deps();
15967            let second = c.deps();
15968            assert_eq!(
15969                first, second,
15970                "Caixa::deps must be idempotent — two successive calls \
15971                 on the same &self must return the same &[Dep]",
15972            );
15973            assert_eq!(
15974                first.as_ptr(),
15975                second.as_ptr(),
15976                "Caixa::deps must borrow the underlying Vec<Dep> \
15977                 storage — two successive calls must return slices \
15978                 with the same backing pointer (a fresh Vec<Dep> clone \
15979                 would change the pointer on every call)",
15980            );
15981            assert_eq!(
15982                first,
15983                deps.as_slice(),
15984                "Caixa::deps must return :deps verbatim by borrow — \
15985                 got {first:?}, expected {deps:?}",
15986            );
15987        }
15988    }
15989
15990    // ── Caixa::deps_dev — outer top-level &[Dep] slice accessor ──────
15991
15992    fn caixa_with_deps_dev(deps_dev: Vec<Dep>) -> Caixa {
15993        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15994        c.deps_dev = deps_dev;
15995        c
15996    }
15997
15998    #[test]
15999    fn deps_dev_returns_deps_dev_slice_verbatim_across_permutations() {
16000        // The canonical per-`Caixa` `:deps-dev` universal-axis dev-only-
16001        // dependency-declaration-list slice pin: [`Caixa::deps_dev`]
16002        // must return the `:deps-dev` typed [`Vec<Dep>`] list verbatim as
16003        // a `&[Dep]`, element-equal to the raw `self.deps_dev.as_slice()`
16004        // access across every representative value in the accept-set —
16005        // `[]` (the "no dev deps declared" arm every existing fixture
16006        // without a `:deps-dev` line carries; the [`Caixa::template`]
16007        // scaffold emits `:deps-dev ()`), a canonical single-entry list
16008        // (the shape most consumer caixas carry — a `tatara-check` dev
16009        // pin), a canonical two-entry list (the multi-dev-dep closure),
16010        // and two past-the-guard sentinels — a `[""]`-`:nome` entry
16011        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
16012        // `NomeInvalid` but the accessor must ship the raw slot
16013        // verbatim) and a `[a, a]` duplicate (validate rejects through
16014        // `DuplicateNome { list: ":deps-dev" }` but the accessor must
16015        // ship the raw slot verbatim so struct-literal fixtures continue
16016        // to expose the duplicate at the accessor).
16017        //
16018        // Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor
16019        // pin on the substrate primitive — closes the outer-`Caixa`
16020        // dependency-slot `&[Dep]` sub-family the sibling
16021        // `deps_returns_deps_slice_verbatim_across_permutations`
16022        // (ad34b4e) opened on. Folds the "outer [`Caixa`] `&[Dep]`
16023        // slice" projection pattern onto the sibling dev-dep axis —
16024        // pins against a future silent detour that returned an owned
16025        // `Vec<Dep>` (which would type-check but silently clone on every
16026        // accessor call, breaking the zero-cost projection every peer
16027        // sibling slice accessor carries), a `[""] → []` collapse (which
16028        // would silently absorb the `NomeEmpty` refusal case at the
16029        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
16030        // would silently absorb the `DuplicateNome` refusal case at the
16031        // accessor boundary).
16032        for deps_dev in [
16033            vec![],
16034            vec![Dep::simple("", "^0.1")],
16035            vec![Dep::simple("tatara-check", "^0.1")],
16036            vec![
16037                Dep::simple("tatara-check", "^0.1"),
16038                Dep::simple("caixa-lint", "^0.1"),
16039            ],
16040            vec![
16041                Dep::simple("tatara-check", "^0.1"),
16042                Dep::simple("tatara-check", "^0.2"),
16043            ],
16044        ] {
16045            let c = caixa_with_deps_dev(deps_dev.clone());
16046            assert_eq!(
16047                c.deps_dev(),
16048                deps_dev.as_slice(),
16049                "Caixa::deps_dev must return :deps-dev verbatim (got \
16050                 {:?}, expected {deps_dev:?})",
16051                c.deps_dev(),
16052            );
16053            assert_eq!(
16054                c.deps_dev(),
16055                c.deps_dev.as_slice(),
16056                "Caixa::deps_dev must element-equal the raw \
16057                 `self.deps_dev.as_slice()` field access across every \
16058                 value in the Vec<Dep> accept-set",
16059            );
16060        }
16061    }
16062
16063    #[test]
16064    fn validate_deps_duplicate_deps_dev_arm_routes_through_accessor() {
16065        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps-dev`
16066        // duplicate-`:nome` gate must key off [`Caixa::deps_dev`], not
16067        // the raw `&self.deps_dev` field-borrow walk. Structurally: a
16068        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1"),
16069        // Dep::simple("d", "^0.2")], .. }` must surface the
16070        // `DuplicateNome { list: ":deps-dev" }` refusal exactly, and a
16071        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1")], .. }` (the
16072        // canonical single-entry form) must pass validate. The pair
16073        // jointly pins the accessor + validate-gate composition: any
16074        // future silent detour that had the accessor return a dedupped
16075        // slice on the `[a, a]` arm (a
16076        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
16077        // would silently absorb the `DuplicateNome` refusal at the
16078        // accessor boundary and the validate gate would accept a
16079        // struct-literal `Caixa` carrying the drift — the composition
16080        // pin catches that at caixa-core build time.
16081        //
16082        // Peer of `validate_deps_duplicate_arm_routes_through_accessor`
16083        // (ad34b4e) on the sibling `:deps` axis — same "the validate
16084        // gate must route through the substrate-primitive typed
16085        // dispatch" discipline folded onto the sibling `:deps-dev`
16086        // axis, closing the two-list dep-graph composition-pin family.
16087        // The `:deps-dev` diagnostic must carry the
16088        // `DEP_AUTHOR_KEY_DEPS_DEV` list-tag (not
16089        // `DEP_AUTHOR_KEY_DEPS`) so the emitted error names the
16090        // offending list unambiguously.
16091        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
16092        let err = c.validate_deps().unwrap_err();
16093        assert!(
16094            matches!(
16095                err,
16096                DepError::DuplicateNome { ref nome, list } if nome == "d"
16097                    && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
16098            ),
16099            "validate_deps must reject deps_dev == \
16100             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
16101             DuplicateNome {{ nome: \"d\", list: \":deps-dev\" }} — the \
16102             accessor and the validate gate must route through the \
16103             same substrate-primitive typed dispatch on the :deps-dev \
16104             within-list duplicate arm (got {err:?})",
16105        );
16106        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1")]);
16107        assert!(
16108            c.validate_deps().is_ok(),
16109            "validate_deps must accept deps_dev == \
16110             vec![Dep(\"d\",\"^0.1\")] (the canonical single-entry form)",
16111        );
16112    }
16113
16114    #[test]
16115    fn deps_dev_projects_slice_by_borrow() {
16116        // The by-borrow pin: [`Caixa::deps_dev`] returns `&[Dep]` by
16117        // borrow — the returned slice borrows the underlying `Vec<Dep>`
16118        // storage of the `:deps-dev` slot and the accessor must not
16119        // clone the backing `Vec` on every call. Peer of
16120        // `deps_projects_slice_by_borrow` (ad34b4e) on the sibling
16121        // `:deps` axis, and of the per-`Caixa`
16122        // `autores_projects_slice_by_borrow` (b5d813f),
16123        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
16124        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
16125        // `exe_projects_slice_by_borrow` (65d9527), and
16126        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
16127        // on the sibling outer top-level [`Caixa`] `&[String]`-return
16128        // axes — the accessor's returned slice must borrow from `&self`
16129        // (the returned reference's lifetime is tied to `&self`), and
16130        // calling the accessor twice on the same [`Caixa`] must yield
16131        // slices that are pointer-equal (the underlying byte-buffer is
16132        // the storage `Vec`'s allocation, not a fresh copy) as well as
16133        // value-equal (idempotent, no side effects on `&self`).
16134        //
16135        // Pins against a future silent detour that returned an owned
16136        // `Vec<Dep>` (which would type-check but silently clone on
16137        // every call), a `&Vec<Dep>` return (which would leak the
16138        // backing `Vec`'s grow/push/reserve surface no downstream
16139        // consumer reaches for), or a one-arm-only accessor that
16140        // returned a saturating value on some sentinel input.
16141        for deps_dev in [
16142            vec![],
16143            vec![Dep::simple("tatara-check", "^0.1")],
16144            vec![
16145                Dep::simple("tatara-check", "^0.1"),
16146                Dep::simple("caixa-lint", "^0.1"),
16147            ],
16148        ] {
16149            let c = caixa_with_deps_dev(deps_dev.clone());
16150            let first = c.deps_dev();
16151            let second = c.deps_dev();
16152            assert_eq!(
16153                first, second,
16154                "Caixa::deps_dev must be idempotent — two successive \
16155                 calls on the same &self must return the same &[Dep]",
16156            );
16157            assert_eq!(
16158                first.as_ptr(),
16159                second.as_ptr(),
16160                "Caixa::deps_dev must borrow the underlying Vec<Dep> \
16161                 storage — two successive calls must return slices \
16162                 with the same backing pointer (a fresh Vec<Dep> clone \
16163                 would change the pointer on every call)",
16164            );
16165            assert_eq!(
16166                first,
16167                deps_dev.as_slice(),
16168                "Caixa::deps_dev must return :deps-dev verbatim by \
16169                 borrow — got {first:?}, expected {deps_dev:?}",
16170            );
16171        }
16172    }
16173
16174    // ── Caixa::limits — outer top-level Option<&LimitsSpec> composite-reference accessor ──
16175
16176    fn caixa_with_limits(limits: Option<crate::LimitsSpec>) -> Caixa {
16177        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16178        c.limits = limits;
16179        c
16180    }
16181
16182    #[test]
16183    fn limits_returns_limits_option_ref_verbatim_across_permutations() {
16184        // The canonical per-`Caixa` `:limits` M2 typed-slot outer-
16185        // composite optional-composite-reference-shape pin:
16186        // [`Caixa::limits`] must return the `:limits` typed
16187        // `Option<LimitsSpec>` verbatim as an `Option<&LimitsSpec>`
16188        // reference over the same backing storage the raw
16189        // `self.limits.as_ref()` field access borrows from, byte-equal
16190        // across every representative fixture in the accept-set — the
16191        // author-omitted `None` shape (the "engine-default applies"
16192        // partition every downstream Servico M2 overlay emitter treats
16193        // as "emit nothing"), the empty-composite `Some(LimitsSpec {
16194        // .. default })` shape ([`LimitsSpec::is_empty`] holds — every
16195        // per-axis cap is `None`, so the peer M2 overlay emitter's
16196        // `.is_empty()`-gated projection still emits nothing but the
16197        // outer presence-bit is `Some`, so [`Caixa::declared_servico_slots`]
16198        // still pushes the `M2_AUTHOR_KEY_LIMITS` label), a single-axis
16199        // fixture (only `:memory` set — the canonical shape most
16200        // memory-heavy Servicos carry), and a fully-populated composite
16201        // (every per-axis cap set — the canonical shape a
16202        // sandboxed-by-default Servico carries).
16203        //
16204        // Pins against a future silent detour that returned a fresh-
16205        // cloned [`LimitsSpec`] copy (which would type-check via the
16206        // `Clone` impl but silently break every downstream caller that
16207        // relied on the reference sharing the composite's backing
16208        // identity), a reference to an operator-resolved overlay (the
16209        // future per-cluster `:limits-overrides` slot — its resolution
16210        // must land at exactly this accessor body, not silently divert
16211        // the raw slot away from a second consumer), a
16212        // `None` → `Some(LimitsSpec::default)` cluster-default
16213        // projection (which would collapse the load-bearing
16214        // "author-omitted `:limits` ⇒ engine-default applies" partition
16215        // the peer [`crate::render::servico_m2_overlay`] emitter and
16216        // the peer [`Caixa::declared_servico_slots`] enumerator both
16217        // read), or an axis-shuffled projection (a future detour that
16218        // swapped `memory` and `fuel` through the accessor would
16219        // silently split the paired [`crate::StandardLayout::verify`]
16220        // per-`:limits` shape gate's traversal input from the peer
16221        // `servico_m2_overlay` emitter's projection input).
16222        //
16223        // First outer top-level [`Caixa`] `Option<&Composite>`-return
16224        // composite-reference accessor pin on the substrate primitive
16225        // — opens the outer-`Caixa` `Option<&Composite>` composite-
16226        // reference projection pattern the sibling `:behavior`
16227        // [`crate::BehaviorSpec`] / `:politicas`
16228        // [`crate::aplicacao::MeshPolicy`] / `:placement`
16229        // [`crate::aplicacao::Placement`] / `:entrada`
16230        // [`crate::aplicacao::Entrada`] future outer-composite lifts
16231        // fold on. Peer of the closed M3 outer-composite family the
16232        // sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
16233        // [`crate::AplicacaoSpec::placement`] (9abb8f0) /
16234        // [`crate::AplicacaoSpec::entrada`] (d32111c) composite-
16235        // reference accessor pins already carry on the outer
16236        // [`crate::AplicacaoSpec`] altitude — extends the outer-
16237        // accessor byte-equal-projection discipline onto the outer
16238        // top-level [`Caixa`] M2 Servico-runtime slot altitude.
16239        use crate::LimitsSpec;
16240        use std::time::Duration;
16241        let fixtures: Vec<Option<LimitsSpec>> = vec![
16242            None,
16243            Some(LimitsSpec::default()),
16244            Some(LimitsSpec {
16245                memory: Some(64 * 1024 * 1024),
16246                ..Default::default()
16247            }),
16248            Some(LimitsSpec {
16249                memory: Some(64 * 1024 * 1024),
16250                fuel: Some(1_000_000),
16251                wall_clock: Some(Duration::from_secs(30)),
16252                cpu: Some(500),
16253            }),
16254        ];
16255        for limits in fixtures {
16256            let c = caixa_with_limits(limits);
16257            assert_eq!(
16258                c.limits(),
16259                limits.as_ref(),
16260                "Caixa::limits must return :limits verbatim (got {:?}, \
16261                 expected {:?})",
16262                c.limits(),
16263                limits.as_ref(),
16264            );
16265            match (c.limits(), c.limits.as_ref()) {
16266                (Some(a), Some(b)) => assert!(
16267                    std::ptr::eq(a, b),
16268                    "Caixa::limits accessor and self.limits.as_ref() \
16269                     field access must borrow the same backing storage \
16270                     — the accessor is the substrate-primitive typed \
16271                     dispatch every downstream Servico-M2-overlay \
16272                     composite consumer must route through, and a \
16273                     reference-identity split would silently break \
16274                     every consumer that relied on the borrow sharing \
16275                     the composite's storage",
16276                ),
16277                (None, None) => {}
16278                _ => panic!(
16279                    "Caixa::limits presence bit must byte-equal \
16280                     self.limits.is_some() — a presence-bit drift would \
16281                     silently split the paired StandardLayout::verify \
16282                     per-`:limits` shape gate's traversal head from \
16283                     the peer render::servico_m2_overlay M2 overlay \
16284                     emitter's traversal head from the peer \
16285                     Caixa::declared_servico_slots M2 declared-slot \
16286                     enumerator's presence probe",
16287                ),
16288            }
16289            assert_eq!(
16290                c.limits().is_some(),
16291                c.limits.is_some(),
16292                "Caixa::limits().is_some() must byte-equal \
16293                 self.limits.is_some() — a presence-bit drift would \
16294                 silently split every downstream Option<&LimitsSpec> \
16295                 consumer's partition on the engine-default arm",
16296            );
16297        }
16298    }
16299
16300    #[test]
16301    fn declared_servico_slots_limits_arm_routes_through_accessor() {
16302        // Composition pin: [`Caixa::declared_servico_slots`]'s
16303        // `:limits` presence-probe arm must key off [`Caixa::limits`],
16304        // not the raw `self.limits.is_some()` field-probe. Structurally:
16305        // a `Caixa { limits: Some(LimitsSpec::default()), .. }` must
16306        // still push `M2_AUTHOR_KEY_LIMITS` onto the declared-slot list
16307        // (the presence bit is `Some`, so the M2 kind-coherence gate
16308        // must surface the slot as "declared" even when every per-axis
16309        // cap is unset), and a `Caixa { limits: None, .. }` must NOT
16310        // push the label (the "author omitted the slot entirely"
16311        // partition). The pair jointly pins the accessor + declared-
16312        // slot enumerator composition: any future silent detour that
16313        // had the accessor collapse `Some(LimitsSpec::default())` to
16314        // `None` (a `.filter(|l| !l.is_empty())` projection) would
16315        // silently absorb the "declared but empty" arm at the
16316        // accessor boundary and the [`crate::LayoutError::ServicoSlotsOnNonServico`]
16317        // kind-coherence gate would silently accept a
16318        // struct-literal `Caixa` carrying the drift.
16319        //
16320        // Peer of the sibling per-`Caixa`
16321        // `validate_deps_duplicate_arm_routes_through_accessor` (ad34b4e)
16322        // and `validate_deps_duplicate_deps_dev_arm_routes_through_accessor`
16323        // (f7fd81e) accessor-composition pins on the sibling `:deps` /
16324        // `:deps-dev` outer-`&[Dep]`-composition axes — same "the
16325        // enumerator gate must route through the substrate-primitive
16326        // typed dispatch" discipline extended onto the outer top-level
16327        // [`Caixa`] `Option<&LimitsSpec>`-composition surface, opening
16328        // the outer-`Caixa` M2 Servico-runtime-slot arm of the
16329        // composition-pin family.
16330        use crate::LimitsSpec;
16331        let c = caixa_with_limits(Some(LimitsSpec::default()));
16332        let slots = c.declared_servico_slots();
16333        assert!(
16334            slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
16335            "declared_servico_slots must push M2_AUTHOR_KEY_LIMITS \
16336             when `:limits` is Some (even for LimitsSpec::default()) \
16337             — the accessor and the enumerator gate must route through \
16338             the same substrate-primitive typed dispatch on the outer \
16339             :limits presence bit (got slots={slots:?})",
16340        );
16341        let c = caixa_with_limits(None);
16342        let slots = c.declared_servico_slots();
16343        assert!(
16344            !slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
16345            "declared_servico_slots must NOT push M2_AUTHOR_KEY_LIMITS \
16346             when `:limits` is None — the author-omitted arm must \
16347             route through the accessor's None-return unchanged (got \
16348             slots={slots:?})",
16349        );
16350    }
16351
16352    #[test]
16353    fn servico_m2_overlay_limits_arm_routes_through_accessor() {
16354        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16355        // per-`:limits` M2 overlay emit arm must key off
16356        // [`Caixa::limits`], not the raw `&caixa.limits` field-borrow.
16357        // Structurally: a `Caixa { limits: Some(LimitsSpec { memory:
16358        // Some(64 MiB), .. default }), .. }` must surface the
16359        // `M2_KEY_LIMITS` key with the per-axis
16360        // `memory: "64MiB"` sub-mapping in the overlay, a `Caixa {
16361        // limits: Some(LimitsSpec::default()), .. }` must omit the
16362        // key entirely (the `.is_empty()`-gated inner arm elides an
16363        // empty composite even when the outer presence bit is `Some`),
16364        // and a `Caixa { limits: None, .. }` must also omit the key
16365        // (the "author omitted the slot entirely" partition). The
16366        // three-fixture family jointly pins the accessor + M2 overlay
16367        // emitter composition: any future silent detour that had the
16368        // accessor return a fresh-cloned copy on the `Some` arm (a
16369        // `LimitsSpec::clone()` projection) would silently break the
16370        // reference-identity pin the peer per-axis
16371        // `serde_yaml::to_value(limits)` projection reads from.
16372        use crate::LimitsSpec;
16373        use crate::render::{M2_KEY_LIMITS, servico_m2_overlay};
16374        let c = caixa_with_limits(Some(LimitsSpec {
16375            memory: Some(64 * 1024 * 1024),
16376            ..Default::default()
16377        }));
16378        let overlay = servico_m2_overlay(&c).unwrap();
16379        assert!(
16380            overlay.contains_key(M2_KEY_LIMITS),
16381            "servico_m2_overlay must surface M2_KEY_LIMITS when \
16382             `:limits` carries a non-empty composite — the accessor \
16383             and the M2 overlay emitter must route through the same \
16384             substrate-primitive typed dispatch on the outer :limits \
16385             composite (got overlay={overlay:?})",
16386        );
16387        let c = caixa_with_limits(Some(LimitsSpec::default()));
16388        let overlay = servico_m2_overlay(&c).unwrap();
16389        assert!(
16390            !overlay.contains_key(M2_KEY_LIMITS),
16391            "servico_m2_overlay must omit M2_KEY_LIMITS when \
16392             `:limits` is Some(LimitsSpec::default()) — the empty \
16393             composite's `.is_empty()`-gated inner arm must elide \
16394             the key regardless of the outer presence bit (got \
16395             overlay={overlay:?})",
16396        );
16397        let c = caixa_with_limits(None);
16398        let overlay = servico_m2_overlay(&c).unwrap();
16399        assert!(
16400            !overlay.contains_key(M2_KEY_LIMITS),
16401            "servico_m2_overlay must omit M2_KEY_LIMITS when \
16402             `:limits` is None — the author-omitted arm must route \
16403             through the accessor's None-return unchanged (got \
16404             overlay={overlay:?})",
16405        );
16406    }
16407
16408    #[test]
16409    fn limits_projects_option_ref_by_borrow() {
16410        // The by-borrow pin: [`Caixa::limits`] returns
16411        // `Option<&LimitsSpec>` by borrow — the returned reference
16412        // borrows the underlying `Option<LimitsSpec>` storage of the
16413        // `:limits` slot and the accessor must not clone the backing
16414        // composite on every call. Peer of the sibling
16415        // `deps_projects_slice_by_borrow` (ad34b4e) /
16416        // `deps_dev_projects_slice_by_borrow` (f7fd81e) by-borrow pins
16417        // on the outer top-level [`Caixa`] `&[Dep]`-return axes —
16418        // extended here to the outer [`Caixa`] `Option<&Composite>`-
16419        // return axis: the accessor's returned reference must borrow
16420        // from `&self` (the returned reference's lifetime is tied to
16421        // `&self`), and calling the accessor twice on the same
16422        // [`Caixa`] must yield references that are pointer-equal (the
16423        // underlying byte-buffer is the storage `LimitsSpec`'s
16424        // allocation, not a fresh copy) as well as value-equal
16425        // (idempotent, no side effects on `&self`).
16426        //
16427        // Pins against a future silent detour that returned an owned
16428        // `LimitsSpec` (which would type-check via the `Clone` impl
16429        // but silently clone on every call), a `&LimitsSpec` panic-
16430        // return on the `None` arm (which would collapse the load-
16431        // bearing `Option` presence-bit into a runtime panic), or a
16432        // one-arm-only accessor that returned a saturating composite
16433        // on some sentinel input.
16434        use crate::LimitsSpec;
16435        use std::time::Duration;
16436        for limits in [
16437            Some(LimitsSpec::default()),
16438            Some(LimitsSpec {
16439                memory: Some(64 * 1024 * 1024),
16440                fuel: Some(1_000_000),
16441                wall_clock: Some(Duration::from_secs(30)),
16442                cpu: Some(500),
16443            }),
16444        ] {
16445            let c = caixa_with_limits(limits);
16446            let first = c.limits().unwrap();
16447            let second = c.limits().unwrap();
16448            assert_eq!(
16449                first, second,
16450                "Caixa::limits must be idempotent — two successive \
16451                 calls on the same &self must return the same \
16452                 &LimitsSpec",
16453            );
16454            assert!(
16455                std::ptr::eq(first, second),
16456                "Caixa::limits must borrow the underlying \
16457                 Option<LimitsSpec> storage — two successive calls \
16458                 must return references with the same backing pointer \
16459                 (a fresh LimitsSpec clone would change the pointer \
16460                 on every call)",
16461            );
16462            assert_eq!(
16463                Some(first),
16464                limits.as_ref(),
16465                "Caixa::limits must return :limits verbatim by borrow \
16466                 — got {first:?}, expected {:?}",
16467                limits.as_ref(),
16468            );
16469        }
16470        let c = caixa_with_limits(None);
16471        assert!(
16472            c.limits().is_none(),
16473            "Caixa::limits must return None when :limits is absent — \
16474             the author-omitted arm must project through the \
16475             accessor's Option::None unchanged",
16476        );
16477    }
16478
16479    // ── Caixa::behavior — outer top-level Option<&BehaviorSpec> composite-reference accessor ──
16480
16481    fn caixa_with_behavior(behavior: Option<crate::BehaviorSpec>) -> Caixa {
16482        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16483        c.behavior = behavior;
16484        c
16485    }
16486
16487    #[test]
16488    fn behavior_returns_behavior_option_ref_verbatim_across_permutations() {
16489        // The canonical per-`Caixa` `:behavior` M2 typed-slot outer-
16490        // composite optional-composite-reference-shape pin:
16491        // [`Caixa::behavior`] must return the `:behavior` typed
16492        // `Option<BehaviorSpec>` verbatim as an `Option<&BehaviorSpec>`
16493        // reference over the same backing storage the raw
16494        // `self.behavior.as_ref()` field access borrows from, byte-equal
16495        // across every representative fixture in the accept-set — the
16496        // author-omitted `None` shape (the "runtime-default applies"
16497        // partition every downstream Servico M2 overlay emitter treats
16498        // as "emit nothing"), the empty-composite `Some(BehaviorSpec {
16499        // .. default })` shape ([`BehaviorSpec::is_empty`] holds —
16500        // every per-callback path is `None`, so the peer M2 overlay
16501        // emitter's `.is_empty()`-gated projection still emits nothing
16502        // but the outer presence-bit is `Some`, so
16503        // [`Caixa::declared_servico_slots`] still pushes the
16504        // `M2_AUTHOR_KEY_BEHAVIOR` label), a single-callback fixture
16505        // (only `:on-state-change` set — the canonical shape a caixa
16506        // that only wires the hot-upgrade migration path carries), and
16507        // a fully-populated composite (every per-callback path set —
16508        // the canonical shape a fully-instrumented gen_server-shaped
16509        // Servico carries).
16510        //
16511        // Peer of the sibling
16512        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16513        // (b2bd9d7) opening fixture-family + reference-identity +
16514        // presence-bit tetrad pin on the outer top-level [`Caixa`]
16515        // `Option<&Composite>`-return sub-family — extended here to the
16516        // second axis of that sub-family so both of the currently-lifted
16517        // M2 Servico-runtime `Option<&Composite>` slots (`:limits` /
16518        // `:behavior`) carry the same "byte-equal, borrow-shared,
16519        // presence-bit-preserved" outer-accessor discipline.
16520        //
16521        // Pins against a future silent detour that returned a fresh-
16522        // cloned [`crate::BehaviorSpec`] copy (which would type-check
16523        // via the `Clone` impl but silently break every downstream
16524        // caller that relied on the reference sharing the composite's
16525        // backing identity), a reference to an operator-resolved
16526        // overlay (a future per-cluster `:behavior-overrides` slot —
16527        // its resolution must land at exactly this accessor body, not
16528        // silently divert the raw slot away from a second consumer), a
16529        // `None` → `Some(BehaviorSpec::default)` cluster-default
16530        // projection (which would collapse the load-bearing
16531        // "author-omitted `:behavior` ⇒ runtime-default applies"
16532        // partition the peer [`crate::render::servico_m2_overlay`]
16533        // emitter, the peer [`Caixa::declared_servico_slots`]
16534        // enumerator, and the cross-slot
16535        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
16536        // gate all read), or a callback-shuffled projection (a future
16537        // detour that swapped `on_init` and `on_terminate` through the
16538        // accessor would silently split the paired
16539        // [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
16540        // traversal input from the peer `servico_m2_overlay` emitter's
16541        // projection input from the cross-slot `:state-change`
16542        // composition gate's traversal input).
16543        use crate::BehaviorSpec;
16544        use std::path::PathBuf;
16545        let fixtures: Vec<Option<BehaviorSpec>> = vec![
16546            None,
16547            Some(BehaviorSpec::default()),
16548            Some(BehaviorSpec {
16549                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16550                ..Default::default()
16551            }),
16552            Some(BehaviorSpec {
16553                on_init: Some(PathBuf::from("lib/init.lisp")),
16554                on_call: Some(PathBuf::from("lib/handlers.lisp")),
16555                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
16556                on_info: Some(PathBuf::from("lib/handlers.lisp")),
16557                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16558                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
16559            }),
16560        ];
16561        for behavior in fixtures {
16562            let c = caixa_with_behavior(behavior.clone());
16563            assert_eq!(
16564                c.behavior(),
16565                behavior.as_ref(),
16566                "Caixa::behavior must return :behavior verbatim (got \
16567                 {:?}, expected {:?})",
16568                c.behavior(),
16569                behavior.as_ref(),
16570            );
16571            match (c.behavior(), c.behavior.as_ref()) {
16572                (Some(a), Some(b)) => assert!(
16573                    std::ptr::eq(a, b),
16574                    "Caixa::behavior accessor and self.behavior.as_ref() \
16575                     field access must borrow the same backing storage \
16576                     — the accessor is the substrate-primitive typed \
16577                     dispatch every downstream Servico-M2-overlay \
16578                     composite consumer must route through, and a \
16579                     reference-identity split would silently break \
16580                     every consumer that relied on the borrow sharing \
16581                     the composite's storage",
16582                ),
16583                (None, None) => {}
16584                _ => panic!(
16585                    "Caixa::behavior presence bit must byte-equal \
16586                     self.behavior.is_some() — a presence-bit drift \
16587                     would silently split the paired \
16588                     StandardLayout::verify per-`:behavior` shape \
16589                     gate's traversal head from the peer \
16590                     render::servico_m2_overlay M2 overlay emitter's \
16591                     traversal head from the cross-slot \
16592                     validate_upgrade_from_against_behavior \
16593                     composition gate's traversal head from the peer \
16594                     Caixa::declared_servico_slots M2 declared-slot \
16595                     enumerator's presence probe",
16596                ),
16597            }
16598            assert_eq!(
16599                c.behavior().is_some(),
16600                c.behavior.is_some(),
16601                "Caixa::behavior().is_some() must byte-equal \
16602                 self.behavior.is_some() — a presence-bit drift would \
16603                 silently split every downstream Option<&BehaviorSpec> \
16604                 consumer's partition on the runtime-default arm",
16605            );
16606        }
16607    }
16608
16609    #[test]
16610    fn declared_servico_slots_behavior_arm_routes_through_accessor() {
16611        // Composition pin: [`Caixa::declared_servico_slots`]'s
16612        // `:behavior` presence-probe arm must key off
16613        // [`Caixa::behavior`], not the raw `self.behavior.is_some()`
16614        // field-probe. Structurally: a `Caixa { behavior:
16615        // Some(BehaviorSpec::default()), .. }` must still push
16616        // `M2_AUTHOR_KEY_BEHAVIOR` onto the declared-slot list (the
16617        // presence bit is `Some`, so the M2 kind-coherence gate must
16618        // surface the slot as "declared" even when every per-callback
16619        // path is unset), and a `Caixa { behavior: None, .. }` must
16620        // NOT push the label (the "author omitted the slot entirely"
16621        // partition). The pair jointly pins the accessor + declared-
16622        // slot enumerator composition: any future silent detour that
16623        // had the accessor collapse `Some(BehaviorSpec::default())`
16624        // to `None` (a `.filter(|b| !b.is_empty())` projection) would
16625        // silently absorb the "declared but empty" arm at the
16626        // accessor boundary and the
16627        // [`crate::LayoutError::ServicoSlotsOnNonServico`]
16628        // kind-coherence gate would silently accept a struct-literal
16629        // `Caixa` carrying the drift.
16630        //
16631        // Peer of the sibling
16632        // `declared_servico_slots_limits_arm_routes_through_accessor`
16633        // (b2bd9d7) composition pin on the sibling `:limits` outer-
16634        // `Option<&LimitsSpec>` arm of the same
16635        // [`Caixa::declared_servico_slots`] M2 declared-slot
16636        // enumerator's traversal — same "the enumerator gate must
16637        // route through the substrate-primitive typed dispatch"
16638        // discipline extended onto the outer top-level [`Caixa`]
16639        // `Option<&BehaviorSpec>`-composition surface.
16640        use crate::BehaviorSpec;
16641        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
16642        let slots = c.declared_servico_slots();
16643        assert!(
16644            slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
16645            "declared_servico_slots must push M2_AUTHOR_KEY_BEHAVIOR \
16646             when `:behavior` is Some (even for BehaviorSpec::default()) \
16647             — the accessor and the enumerator gate must route through \
16648             the same substrate-primitive typed dispatch on the outer \
16649             :behavior presence bit (got slots={slots:?})",
16650        );
16651        let c = caixa_with_behavior(None);
16652        let slots = c.declared_servico_slots();
16653        assert!(
16654            !slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
16655            "declared_servico_slots must NOT push M2_AUTHOR_KEY_BEHAVIOR \
16656             when `:behavior` is None — the author-omitted arm must \
16657             route through the accessor's None-return unchanged (got \
16658             slots={slots:?})",
16659        );
16660    }
16661
16662    #[test]
16663    fn servico_m2_overlay_behavior_arm_routes_through_accessor() {
16664        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16665        // per-`:behavior` M2 overlay emit arm must key off
16666        // [`Caixa::behavior`], not the raw `&caixa.behavior`
16667        // field-borrow. Structurally: a `Caixa { behavior:
16668        // Some(BehaviorSpec { on_state_change: Some(...), .. default
16669        // }), .. }` must surface the `M2_KEY_BEHAVIOR` key with the
16670        // per-callback `onStateChange` sub-mapping in the overlay, a
16671        // `Caixa { behavior: Some(BehaviorSpec::default()), .. }`
16672        // must omit the key entirely (the `.is_empty()`-gated inner
16673        // arm elides an empty composite even when the outer presence
16674        // bit is `Some`), and a `Caixa { behavior: None, .. }` must
16675        // also omit the key (the "author omitted the slot entirely"
16676        // partition). The three-fixture family jointly pins the
16677        // accessor + M2 overlay emitter composition: any future
16678        // silent detour that had the accessor return a fresh-cloned
16679        // copy on the `Some` arm (a `BehaviorSpec::clone()`
16680        // projection) would silently break the reference-identity
16681        // pin the peer per-callback `serde_yaml::to_value(behavior)`
16682        // projection reads from.
16683        //
16684        // Peer of the sibling
16685        // `servico_m2_overlay_limits_arm_routes_through_accessor`
16686        // (b2bd9d7) composition pin on the sibling `:limits` outer-
16687        // `Option<&LimitsSpec>` arm of the same
16688        // [`crate::render::servico_m2_overlay`] M2 overlay emitter's
16689        // traversal — same "the emitter must route through the
16690        // substrate-primitive typed dispatch on the outer composite"
16691        // discipline extended onto the outer top-level [`Caixa`]
16692        // `Option<&BehaviorSpec>`-composition surface.
16693        use crate::BehaviorSpec;
16694        use crate::render::{M2_KEY_BEHAVIOR, servico_m2_overlay};
16695        use std::path::PathBuf;
16696        let c = caixa_with_behavior(Some(BehaviorSpec {
16697            on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16698            ..Default::default()
16699        }));
16700        let overlay = servico_m2_overlay(&c).unwrap();
16701        assert!(
16702            overlay.contains_key(M2_KEY_BEHAVIOR),
16703            "servico_m2_overlay must surface M2_KEY_BEHAVIOR when \
16704             `:behavior` carries a non-empty composite — the accessor \
16705             and the M2 overlay emitter must route through the same \
16706             substrate-primitive typed dispatch on the outer :behavior \
16707             composite (got overlay={overlay:?})",
16708        );
16709        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
16710        let overlay = servico_m2_overlay(&c).unwrap();
16711        assert!(
16712            !overlay.contains_key(M2_KEY_BEHAVIOR),
16713            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
16714             `:behavior` is Some(BehaviorSpec::default()) — the empty \
16715             composite's `.is_empty()`-gated inner arm must elide the \
16716             key regardless of the outer presence bit (got \
16717             overlay={overlay:?})",
16718        );
16719        let c = caixa_with_behavior(None);
16720        let overlay = servico_m2_overlay(&c).unwrap();
16721        assert!(
16722            !overlay.contains_key(M2_KEY_BEHAVIOR),
16723            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
16724             `:behavior` is None — the author-omitted arm must route \
16725             through the accessor's None-return unchanged (got \
16726             overlay={overlay:?})",
16727        );
16728    }
16729
16730    #[test]
16731    fn behavior_projects_option_ref_by_borrow() {
16732        // The by-borrow pin: [`Caixa::behavior`] returns
16733        // `Option<&BehaviorSpec>` by borrow — the returned reference
16734        // borrows the underlying `Option<BehaviorSpec>` storage of the
16735        // `:behavior` slot and the accessor must not clone the backing
16736        // composite on every call. Peer of the sibling
16737        // `limits_projects_option_ref_by_borrow` (b2bd9d7) by-borrow
16738        // pin on the outer top-level [`Caixa`] `Option<&Composite>`-
16739        // return sub-family — extended here to the second axis of the
16740        // same sub-family: the accessor's returned reference must
16741        // borrow from `&self` (the returned reference's lifetime is
16742        // tied to `&self`), and calling the accessor twice on the same
16743        // [`Caixa`] must yield references that are pointer-equal (the
16744        // underlying byte-buffer is the storage `BehaviorSpec`'s
16745        // allocation, not a fresh copy) as well as value-equal
16746        // (idempotent, no side effects on `&self`).
16747        //
16748        // Pins against a future silent detour that returned an owned
16749        // `BehaviorSpec` (which would type-check via the `Clone` impl
16750        // but silently clone on every call), a `&BehaviorSpec` panic-
16751        // return on the `None` arm (which would collapse the load-
16752        // bearing `Option` presence-bit into a runtime panic), or a
16753        // one-arm-only accessor that returned a saturating composite
16754        // on some sentinel input.
16755        use crate::BehaviorSpec;
16756        use std::path::PathBuf;
16757        for behavior in [
16758            Some(BehaviorSpec::default()),
16759            Some(BehaviorSpec {
16760                on_init: Some(PathBuf::from("lib/init.lisp")),
16761                on_call: Some(PathBuf::from("lib/handlers.lisp")),
16762                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
16763                on_info: Some(PathBuf::from("lib/handlers.lisp")),
16764                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16765                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
16766            }),
16767        ] {
16768            let c = caixa_with_behavior(behavior.clone());
16769            let first = c.behavior().unwrap();
16770            let second = c.behavior().unwrap();
16771            assert_eq!(
16772                first, second,
16773                "Caixa::behavior must be idempotent — two successive \
16774                 calls on the same &self must return the same \
16775                 &BehaviorSpec",
16776            );
16777            assert!(
16778                std::ptr::eq(first, second),
16779                "Caixa::behavior must borrow the underlying \
16780                 Option<BehaviorSpec> storage — two successive calls \
16781                 must return references with the same backing pointer \
16782                 (a fresh BehaviorSpec clone would change the pointer \
16783                 on every call)",
16784            );
16785            assert_eq!(
16786                Some(first),
16787                behavior.as_ref(),
16788                "Caixa::behavior must return :behavior verbatim by \
16789                 borrow — got {first:?}, expected {:?}",
16790                behavior.as_ref(),
16791            );
16792        }
16793        let c = caixa_with_behavior(None);
16794        assert!(
16795            c.behavior().is_none(),
16796            "Caixa::behavior must return None when :behavior is absent \
16797             — the author-omitted arm must project through the \
16798             accessor's Option::None unchanged",
16799        );
16800    }
16801
16802    // ── Caixa::politicas — outer top-level Option<&MeshPolicy> composite-reference accessor ──
16803
16804    fn caixa_aplicacao_with_politicas(politicas: Option<crate::aplicacao::MeshPolicy>) -> Caixa {
16805        use crate::aplicacao::{Membro, WitContract};
16806        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16807        c.kind = CaixaKind::Aplicacao;
16808        c.membros = vec![Membro {
16809            caixa: "a".into(),
16810            versao: "^0.1".into(),
16811        }];
16812        c.contratos = vec![WitContract {
16813            de: "a".into(),
16814            para: "a".into(),
16815            wit: "wasi:http/proxy".into(),
16816            endpoint: Some("/x".into()),
16817            subject: None,
16818            slot: None,
16819        }];
16820        c.politicas = politicas;
16821        c
16822    }
16823
16824    #[test]
16825    fn politicas_returns_politicas_option_ref_verbatim_across_permutations() {
16826        // The canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
16827        // composite optional-composite-reference-shape pin:
16828        // [`Caixa::politicas`] must return the `:politicas` typed
16829        // `Option<MeshPolicy>` verbatim as an `Option<&MeshPolicy>`
16830        // reference over the same backing storage the raw
16831        // `self.politicas.as_ref()` field access borrows from,
16832        // byte-equal across every representative fixture in the
16833        // accept-set — the author-omitted `None` shape (the "cluster-
16834        // default applies" partition every downstream mesh-artifact
16835        // emitter treats as "emit no `:politicas` overlay"), the
16836        // empty-composite `Some(MeshPolicy { .. default })` shape
16837        // ([`crate::aplicacao::MeshPolicy::is_empty`] holds — every
16838        // per-axis mesh-policy scalar is `None`, so the peer inner
16839        // [`crate::AplicacaoSpec::politicas`] `.is_empty()`-gated
16840        // caixa-mesh overlay elides every per-axis emit but the outer
16841        // presence-bit is `Some`, so [`Caixa::declared_mesh_slots`]
16842        // still pushes the `M3_AUTHOR_KEY_POLITICAS` label), a
16843        // single-axis fixture (only `:timeout` set — the canonical
16844        // shape a latency-sensitive Aplicacao carries), and a
16845        // fully-populated composite (every per-axis mesh-policy
16846        // scalar set — the canonical shape a fully-governed
16847        // Aplicacao carries).
16848        //
16849        // Pins against a future silent detour that returned a fresh-
16850        // cloned [`crate::aplicacao::MeshPolicy`] copy (which would
16851        // type-check via the `Clone` impl but silently break every
16852        // downstream caller that relied on the reference sharing the
16853        // composite's backing identity), a reference to an operator-
16854        // resolved overlay (the future per-cluster
16855        // `:politicas-overrides` slot — its resolution must land at
16856        // exactly this accessor body, not silently divert the raw
16857        // slot away from the peer [`Caixa::declared_mesh_slots`]
16858        // enumerator's presence probe), a
16859        // `None` → `Some(MeshPolicy::default)` cluster-default
16860        // projection (which would collapse the load-bearing
16861        // "author-omitted `:politicas` ⇒ cluster-default applies"
16862        // partition the peer [`Caixa::declared_mesh_slots`]
16863        // enumerator and the peer [`Caixa::aplicacao_view`]
16864        // Aplicacao-composition seed both read), or an axis-shuffled
16865        // projection (a future detour that swapped `timeout` and
16866        // `retries` through the accessor would silently split the
16867        // paired [`Caixa::aplicacao_view`] seed's fold input from the
16868        // sibling M3 mesh-artifact emitter's projection input).
16869        //
16870        // Third outer top-level [`Caixa`] `Option<&Composite>`-return
16871        // composite-reference accessor pin on the substrate primitive
16872        // — peer of the sibling
16873        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16874        // (b2bd9d7) and
16875        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
16876        // (35d8b52) opening tetrad pins on the outer top-level
16877        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
16878        // here to the first of the three M3 mesh-slot axes so the
16879        // opening third of the outer `Option<&Composite>` sub-family
16880        // carries the same "byte-equal, borrow-shared, presence-bit-
16881        // preserved" outer-accessor discipline.
16882        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
16883        use std::time::Duration;
16884        let fixtures: Vec<Option<MeshPolicy>> = vec![
16885            None,
16886            Some(MeshPolicy::default()),
16887            Some(MeshPolicy {
16888                timeout: Some(Duration::from_secs(30)),
16889                ..Default::default()
16890            }),
16891            Some(MeshPolicy {
16892                timeout: Some(Duration::from_secs(30)),
16893                retries: Some(3),
16894                circuit_breaker: Some(CircuitBreaker {
16895                    max_failures: 5,
16896                    window: Duration::from_secs(60),
16897                }),
16898                mtls_required: Some(true),
16899                rate_limit: Some(RateLimit {
16900                    rate: 100,
16901                    window: Duration::from_secs(1),
16902                }),
16903            }),
16904        ];
16905        for politicas in fixtures {
16906            let c = caixa_aplicacao_with_politicas(politicas.clone());
16907            assert_eq!(
16908                c.politicas(),
16909                politicas.as_ref(),
16910                "Caixa::politicas must return :politicas verbatim (got \
16911                 {:?}, expected {:?})",
16912                c.politicas(),
16913                politicas.as_ref(),
16914            );
16915            match (c.politicas(), c.politicas.as_ref()) {
16916                (Some(a), Some(b)) => assert!(
16917                    std::ptr::eq(a, b),
16918                    "Caixa::politicas accessor and self.politicas.as_ref() \
16919                     field access must borrow the same backing storage \
16920                     — the accessor is the substrate-primitive typed \
16921                     dispatch every downstream Aplicacao-mesh-overlay \
16922                     composite consumer must route through, and a \
16923                     reference-identity split would silently break \
16924                     every consumer that relied on the borrow sharing \
16925                     the composite's storage",
16926                ),
16927                (None, None) => {}
16928                _ => panic!(
16929                    "Caixa::politicas presence bit must byte-equal \
16930                     self.politicas.is_some() — a presence-bit drift \
16931                     would silently split the paired \
16932                     Caixa::aplicacao_view Aplicacao-composition seed's \
16933                     traversal head from the peer \
16934                     Caixa::declared_mesh_slots M3 declared-slot \
16935                     enumerator's presence probe",
16936                ),
16937            }
16938            assert_eq!(
16939                c.politicas().is_some(),
16940                c.politicas.is_some(),
16941                "Caixa::politicas().is_some() must byte-equal \
16942                 self.politicas.is_some() — a presence-bit drift would \
16943                 silently split every downstream Option<&MeshPolicy> \
16944                 consumer's partition on the cluster-default arm",
16945            );
16946        }
16947    }
16948
16949    #[test]
16950    fn declared_mesh_slots_politicas_arm_routes_through_accessor() {
16951        // Composition pin: [`Caixa::declared_mesh_slots`]'s
16952        // `:politicas` presence-probe arm must key off
16953        // [`Caixa::politicas`], not the raw `self.politicas.is_some()`
16954        // field-probe. Structurally: a `Caixa { politicas:
16955        // Some(MeshPolicy::default()), .. }` must still push
16956        // `M3_AUTHOR_KEY_POLITICAS` onto the declared-slot list (the
16957        // presence bit is `Some`, so the M3 kind-coherence gate must
16958        // surface the slot as "declared" even when every per-axis
16959        // scalar is unset), and a `Caixa { politicas: None, .. }` must
16960        // NOT push the label (the "author omitted the slot entirely"
16961        // partition). The pair jointly pins the accessor + declared-
16962        // slot enumerator composition: any future silent detour that
16963        // had the accessor collapse `Some(MeshPolicy::default())` to
16964        // `None` (a `.filter(|p| !p.is_empty())` projection) would
16965        // silently absorb the "declared but empty" arm at the
16966        // accessor boundary and the
16967        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
16968        // coherence gate would silently accept a struct-literal
16969        // `Caixa` carrying the drift.
16970        //
16971        // Peer of the sibling
16972        // `declared_servico_slots_limits_arm_routes_through_accessor`
16973        // (b2bd9d7) and
16974        // `declared_servico_slots_behavior_arm_routes_through_accessor`
16975        // (35d8b52) composition pins on the sibling `:limits` /
16976        // `:behavior` outer-`Option<&Composite>` arms of the peer
16977        // [`Caixa::declared_servico_slots`] M2 declared-slot
16978        // enumerator's traversal — same "the enumerator gate must
16979        // route through the substrate-primitive typed dispatch"
16980        // discipline extended onto the outer top-level [`Caixa`] M3
16981        // mesh-slot family so the [`Caixa::declared_mesh_slots`]
16982        // enumerator carries the same routing invariant as its M2
16983        // sibling.
16984        use crate::aplicacao::MeshPolicy;
16985        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
16986        let slots = c.declared_mesh_slots();
16987        assert!(
16988            slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
16989            "declared_mesh_slots must push M3_AUTHOR_KEY_POLITICAS \
16990             when `:politicas` is Some (even for MeshPolicy::default()) \
16991             — the accessor and the enumerator gate must route through \
16992             the same substrate-primitive typed dispatch on the outer \
16993             :politicas presence bit (got slots={slots:?})",
16994        );
16995        let c = caixa_aplicacao_with_politicas(None);
16996        let slots = c.declared_mesh_slots();
16997        assert!(
16998            !slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
16999            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_POLITICAS \
17000             when `:politicas` is None — the author-omitted arm must \
17001             route through the accessor's None-return unchanged (got \
17002             slots={slots:?})",
17003        );
17004    }
17005
17006    #[test]
17007    fn aplicacao_view_politicas_arm_folds_through_accessor() {
17008        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:politicas`
17009        // Aplicacao-composition seed must fold through
17010        // [`Caixa::politicas`], not the raw
17011        // `self.politicas.clone().unwrap_or_default()` field-borrow.
17012        // Structurally: a `Caixa { politicas: Some(MeshPolicy {
17013        // timeout: Some(30s), .. default }), kind: Aplicacao, .. }`
17014        // must surface a projected [`crate::AplicacaoSpec`] whose
17015        // `politicas().timeout()` field byte-equals the outer
17016        // composite's `timeout` scalar (the fold must project the
17017        // authored composite verbatim), a `Caixa { politicas:
17018        // Some(MeshPolicy::default()), kind: Aplicacao, .. }` must
17019        // surface an [`crate::AplicacaoSpec`] whose `politicas()`
17020        // byte-equals [`crate::aplicacao::MeshPolicy::default`] (the
17021        // fold's empty-composite arm collapses to the same default the
17022        // author-omitted arm does), and a `Caixa { politicas: None,
17023        // kind: Aplicacao, .. }` must surface an
17024        // [`crate::AplicacaoSpec`] whose `politicas()` byte-equals
17025        // [`crate::aplicacao::MeshPolicy::default`] (the "author
17026        // omitted the slot entirely" arm folds through the
17027        // `unwrap_or_default` onto the cluster-default). The triad
17028        // jointly pins the accessor + Aplicacao-composition seed
17029        // composition: any future silent detour that had the accessor
17030        // divert the raw slot away from the seed's fold (an operator-
17031        // resolved overlay's default-fold arm silently differing from
17032        // the raw slot's default-fold arm) would silently split the
17033        // build-time mesh-artifact emission gate from the caixa-mesh
17034        // renderer's Aplicacao-view input at the composition boundary.
17035        use crate::aplicacao::MeshPolicy;
17036        use std::time::Duration;
17037        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy {
17038            timeout: Some(Duration::from_secs(30)),
17039            ..Default::default()
17040        }));
17041        let view = c.aplicacao_view().unwrap();
17042        assert_eq!(
17043            view.politicas().timeout(),
17044            Some(Duration::from_secs(30)),
17045            "Caixa::aplicacao_view must fold the authored :politicas \
17046             :timeout scalar through the accessor verbatim onto the \
17047             projected AplicacaoSpec — a future silent detour at the \
17048             seed's fold arm would surface here as a projected-scalar \
17049             drift (got {:?})",
17050            view.politicas().timeout(),
17051        );
17052        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
17053        let view = c.aplicacao_view().unwrap();
17054        assert_eq!(
17055            view.politicas(),
17056            &MeshPolicy::default(),
17057            "Caixa::aplicacao_view must fold Some(MeshPolicy::default()) \
17058             through the accessor onto MeshPolicy::default — the empty- \
17059             composite arm collapses to the same default the author- \
17060             omitted arm does (got {:?})",
17061            view.politicas(),
17062        );
17063        let c = caixa_aplicacao_with_politicas(None);
17064        let view = c.aplicacao_view().unwrap();
17065        assert_eq!(
17066            view.politicas(),
17067            &MeshPolicy::default(),
17068            "Caixa::aplicacao_view must fold None through the accessor's \
17069             unwrap_or_default onto MeshPolicy::default — the author- \
17070             omitted arm must route through the accessor's None-return \
17071             unchanged (got {:?})",
17072            view.politicas(),
17073        );
17074    }
17075
17076    #[test]
17077    fn politicas_projects_option_ref_by_borrow() {
17078        // The by-borrow pin: [`Caixa::politicas`] returns
17079        // `Option<&MeshPolicy>` by borrow — the returned reference
17080        // borrows the underlying `Option<MeshPolicy>` storage of the
17081        // `:politicas` slot and the accessor must not clone the
17082        // backing composite on every call. Peer of the sibling
17083        // `limits_projects_option_ref_by_borrow` (b2bd9d7) and
17084        // `behavior_projects_option_ref_by_borrow` (35d8b52) by-borrow
17085        // pins on the outer top-level [`Caixa`]
17086        // `Option<&Composite>`-return sub-family — extended here to
17087        // the third axis of the same sub-family: the accessor's
17088        // returned reference must borrow from `&self` (the returned
17089        // reference's lifetime is tied to `&self`), and calling the
17090        // accessor twice on the same [`Caixa`] must yield references
17091        // that are pointer-equal (the underlying byte-buffer is the
17092        // storage `MeshPolicy`'s allocation, not a fresh copy) as
17093        // well as value-equal (idempotent, no side effects on
17094        // `&self`).
17095        //
17096        // Pins against a future silent detour that returned an owned
17097        // `MeshPolicy` (which would type-check via the `Clone` impl
17098        // but silently clone on every call), a `&MeshPolicy` panic-
17099        // return on the `None` arm (which would collapse the load-
17100        // bearing `Option` presence-bit into a runtime panic), or a
17101        // one-arm-only accessor that returned a saturating composite
17102        // on some sentinel input.
17103        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
17104        use std::time::Duration;
17105        for politicas in [
17106            Some(MeshPolicy::default()),
17107            Some(MeshPolicy {
17108                timeout: Some(Duration::from_secs(30)),
17109                retries: Some(3),
17110                circuit_breaker: Some(CircuitBreaker {
17111                    max_failures: 5,
17112                    window: Duration::from_secs(60),
17113                }),
17114                mtls_required: Some(true),
17115                rate_limit: Some(RateLimit {
17116                    rate: 100,
17117                    window: Duration::from_secs(1),
17118                }),
17119            }),
17120        ] {
17121            let c = caixa_aplicacao_with_politicas(politicas.clone());
17122            let first = c.politicas().unwrap();
17123            let second = c.politicas().unwrap();
17124            assert_eq!(
17125                first, second,
17126                "Caixa::politicas must be idempotent — two successive \
17127                 calls on the same &self must return the same \
17128                 &MeshPolicy",
17129            );
17130            assert!(
17131                std::ptr::eq(first, second),
17132                "Caixa::politicas must borrow the underlying \
17133                 Option<MeshPolicy> storage — two successive calls \
17134                 must return references with the same backing pointer \
17135                 (a fresh MeshPolicy clone would change the pointer on \
17136                 every call)",
17137            );
17138            assert_eq!(
17139                Some(first),
17140                politicas.as_ref(),
17141                "Caixa::politicas must return :politicas verbatim by \
17142                 borrow — got {first:?}, expected {:?}",
17143                politicas.as_ref(),
17144            );
17145        }
17146        let c = caixa_aplicacao_with_politicas(None);
17147        assert!(
17148            c.politicas().is_none(),
17149            "Caixa::politicas must return None when :politicas is \
17150             absent — the author-omitted arm must project through the \
17151             accessor's Option::None unchanged",
17152        );
17153    }
17154
17155    // ── Caixa::placement — outer top-level Option<&Placement> composite-reference accessor ──
17156
17157    fn caixa_aplicacao_with_placement(placement: Option<crate::aplicacao::Placement>) -> Caixa {
17158        use crate::aplicacao::{Membro, WitContract};
17159        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17160        c.kind = CaixaKind::Aplicacao;
17161        c.membros = vec![Membro {
17162            caixa: "a".into(),
17163            versao: "^0.1".into(),
17164        }];
17165        c.contratos = vec![WitContract {
17166            de: "a".into(),
17167            para: "a".into(),
17168            wit: "wasi:http/proxy".into(),
17169            endpoint: Some("/x".into()),
17170            subject: None,
17171            slot: None,
17172        }];
17173        c.placement = placement;
17174        c
17175    }
17176
17177    #[test]
17178    fn placement_returns_placement_option_ref_verbatim_across_permutations() {
17179        // The canonical per-`Caixa` `:placement` M3 mesh-slot outer-
17180        // composite optional-composite-reference-shape pin:
17181        // [`Caixa::placement`] must return the `:placement` typed
17182        // `Option<Placement>` verbatim as an `Option<&Placement>`
17183        // reference over the same backing storage the raw
17184        // `self.placement.as_ref()` field access borrows from,
17185        // byte-equal across every representative fixture in the
17186        // accept-set — the author-omitted `None` shape (the
17187        // "cluster-default applies" partition every downstream mesh-
17188        // artifact emitter treats as "emit no `:placement` overlay"),
17189        // the empty-composite `Some(Placement { .. default })` shape
17190        // (`estrategia: SingleNode`, empty clusters, no shard-key /
17191        // affinity — the outer presence-bit is `Some` so
17192        // [`Caixa::declared_mesh_slots`] still pushes the
17193        // `M3_AUTHOR_KEY_PLACEMENT` label), a single-axis
17194        // `Replicated`-on-two-clusters fixture (the canonical shape a
17195        // stateless HTTP Aplicacao carries), and a fully-populated
17196        // `Sharded`-with-shard-key-and-affinity fixture (the canonical
17197        // shape a stateful Akka-style cluster-sharding Aplicacao
17198        // carries).
17199        //
17200        // Pins against a future silent detour that returned a fresh-
17201        // cloned [`crate::aplicacao::Placement`] copy (which would
17202        // type-check via the `Clone` impl but silently break every
17203        // downstream caller that relied on the reference sharing the
17204        // composite's backing identity), a reference to an operator-
17205        // resolved overlay (the future per-cluster
17206        // `:placement-overrides` slot — its resolution must land at
17207        // exactly this accessor body, not silently divert the raw
17208        // slot away from the peer [`Caixa::declared_mesh_slots`]
17209        // enumerator's presence probe), a `None` →
17210        // `Some(Placement::default)` cluster-default projection (which
17211        // would collapse the load-bearing "author-omitted `:placement`
17212        // ⇒ cluster-default applies" partition the peer
17213        // [`Caixa::declared_mesh_slots`] enumerator and the peer
17214        // [`Caixa::aplicacao_view`] Aplicacao-composition seed both
17215        // read), or an axis-shuffled projection (a future detour that
17216        // swapped `clusters` and `affinity` through the accessor would
17217        // silently split the paired [`Caixa::aplicacao_view`] seed's
17218        // fold input from the sibling M3 mesh-artifact emitter's
17219        // projection input).
17220        //
17221        // Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
17222        // composite-reference accessor pin on the substrate primitive
17223        // — peer of the sibling
17224        // `limits_returns_limits_option_ref_verbatim_across_permutations`
17225        // (b2bd9d7),
17226        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
17227        // (35d8b52), and
17228        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
17229        // (5d23d29) opening triad pins on the outer top-level
17230        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
17231        // here to the second of the three M3 mesh-slot axes so the
17232        // opening four-fifths of the outer `Option<&Composite>` sub-
17233        // family carries the same "byte-equal, borrow-shared,
17234        // presence-bit-preserved" outer-accessor discipline.
17235        use crate::aplicacao::{Placement, PlacementStrategy};
17236        let fixtures: Vec<Option<Placement>> = vec![
17237            None,
17238            Some(Placement::default()),
17239            Some(Placement {
17240                estrategia: PlacementStrategy::Replicated,
17241                clusters: vec!["rio".into(), "sao-paulo".into()],
17242                affinity: None,
17243                shard_key: None,
17244            }),
17245            Some(Placement {
17246                estrategia: PlacementStrategy::Sharded,
17247                clusters: vec!["rio".into(), "sao-paulo".into(), "brasilia".into()],
17248                affinity: Some("data-locality".into()),
17249                shard_key: Some("$tenantId".into()),
17250            }),
17251        ];
17252        for placement in fixtures {
17253            let c = caixa_aplicacao_with_placement(placement.clone());
17254            assert_eq!(
17255                c.placement(),
17256                placement.as_ref(),
17257                "Caixa::placement must return :placement verbatim (got \
17258                 {:?}, expected {:?})",
17259                c.placement(),
17260                placement.as_ref(),
17261            );
17262            match (c.placement(), c.placement.as_ref()) {
17263                (Some(a), Some(b)) => assert!(
17264                    std::ptr::eq(a, b),
17265                    "Caixa::placement accessor and self.placement.as_ref() \
17266                     field access must borrow the same backing storage \
17267                     — the accessor is the substrate-primitive typed \
17268                     dispatch every downstream Aplicacao-distribution- \
17269                     overlay composite consumer must route through, and \
17270                     a reference-identity split would silently break \
17271                     every consumer that relied on the borrow sharing \
17272                     the composite's storage",
17273                ),
17274                (None, None) => {}
17275                _ => panic!(
17276                    "Caixa::placement presence bit must byte-equal \
17277                     self.placement.is_some() — a presence-bit drift \
17278                     would silently split the paired \
17279                     Caixa::aplicacao_view Aplicacao-composition seed's \
17280                     traversal head from the peer \
17281                     Caixa::declared_mesh_slots M3 declared-slot \
17282                     enumerator's presence probe",
17283                ),
17284            }
17285            assert_eq!(
17286                c.placement().is_some(),
17287                c.placement.is_some(),
17288                "Caixa::placement().is_some() must byte-equal \
17289                 self.placement.is_some() — a presence-bit drift would \
17290                 silently split every downstream Option<&Placement> \
17291                 consumer's partition on the cluster-default arm",
17292            );
17293        }
17294    }
17295
17296    #[test]
17297    fn declared_mesh_slots_placement_arm_routes_through_accessor() {
17298        // Composition pin: [`Caixa::declared_mesh_slots`]'s
17299        // `:placement` presence-probe arm must key off
17300        // [`Caixa::placement`], not the raw `self.placement.is_some()`
17301        // field-probe. Structurally: a `Caixa { placement:
17302        // Some(Placement::default()), .. }` must still push
17303        // `M3_AUTHOR_KEY_PLACEMENT` onto the declared-slot list (the
17304        // presence bit is `Some`, so the M3 kind-coherence gate must
17305        // surface the slot as "declared" even when every per-axis
17306        // scalar defers to the cluster-default arm), and a `Caixa {
17307        // placement: None, .. }` must NOT push the label (the "author
17308        // omitted the slot entirely" partition). The pair jointly pins
17309        // the accessor + declared-slot enumerator composition: any
17310        // future silent detour that had the accessor collapse
17311        // `Some(Placement::default())` to `None` (a `.filter(|p|
17312        // p.clusters().is_empty().not())` projection) would silently
17313        // absorb the "declared but empty" arm at the accessor boundary
17314        // and the [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
17315        // kind-coherence gate would silently accept a struct-literal
17316        // `Caixa` carrying the drift.
17317        //
17318        // Peer of the sibling
17319        // `declared_servico_slots_limits_arm_routes_through_accessor`
17320        // (b2bd9d7),
17321        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17322        // (35d8b52), and
17323        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
17324        // (5d23d29) composition pins on the sibling `:limits` /
17325        // `:behavior` / `:politicas` outer-`Option<&Composite>` arms
17326        // — same "the enumerator gate must route through the
17327        // substrate-primitive typed dispatch" discipline extended onto
17328        // the second of the three M3 mesh-slot axes so the
17329        // [`Caixa::declared_mesh_slots`] enumerator carries the same
17330        // routing invariant on the `:placement` arm as the peer
17331        // `:politicas` arm.
17332        use crate::aplicacao::Placement;
17333        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
17334        let slots = c.declared_mesh_slots();
17335        assert!(
17336            slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
17337            "declared_mesh_slots must push M3_AUTHOR_KEY_PLACEMENT \
17338             when `:placement` is Some (even for Placement::default()) \
17339             — the accessor and the enumerator gate must route through \
17340             the same substrate-primitive typed dispatch on the outer \
17341             :placement presence bit (got slots={slots:?})",
17342        );
17343        let c = caixa_aplicacao_with_placement(None);
17344        let slots = c.declared_mesh_slots();
17345        assert!(
17346            !slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
17347            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_PLACEMENT \
17348             when `:placement` is None — the author-omitted arm must \
17349             route through the accessor's None-return unchanged (got \
17350             slots={slots:?})",
17351        );
17352    }
17353
17354    #[test]
17355    fn aplicacao_view_placement_arm_folds_through_accessor() {
17356        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:placement`
17357        // Aplicacao-composition seed must fold through
17358        // [`Caixa::placement`], not the raw
17359        // `self.placement.clone().unwrap_or_default()` field-borrow.
17360        // Structurally: a `Caixa { placement: Some(Placement {
17361        // estrategia: Replicated, clusters: ["rio"], .. default }),
17362        // kind: Aplicacao, .. }` must surface a projected
17363        // [`crate::AplicacaoSpec`] whose `placement().estrategia()` +
17364        // `placement().clusters()` byte-equal the outer composite's
17365        // authored values (the fold must project the authored
17366        // composite verbatim), a `Caixa { placement:
17367        // Some(Placement::default()), kind: Aplicacao, .. }` must
17368        // surface an [`crate::AplicacaoSpec`] whose `placement()`
17369        // byte-equals [`crate::aplicacao::Placement::default`] (the
17370        // fold's empty-composite arm collapses to the same default
17371        // the author-omitted arm does), and a `Caixa { placement:
17372        // None, kind: Aplicacao, .. }` must surface an
17373        // [`crate::AplicacaoSpec`] whose `placement()` byte-equals
17374        // [`crate::aplicacao::Placement::default`] (the "author
17375        // omitted the slot entirely" arm folds through the
17376        // `unwrap_or_default` onto the cluster-default). The triad
17377        // jointly pins the accessor + Aplicacao-composition seed
17378        // composition: any future silent detour that had the accessor
17379        // divert the raw slot away from the seed's fold (an operator-
17380        // resolved overlay's default-fold arm silently differing from
17381        // the raw slot's default-fold arm) would silently split the
17382        // build-time distribution-artifact emission gate from the
17383        // caixa-mesh renderer's Aplicacao-view input at the
17384        // composition boundary.
17385        use crate::aplicacao::{Placement, PlacementStrategy};
17386        let c = caixa_aplicacao_with_placement(Some(Placement {
17387            estrategia: PlacementStrategy::Replicated,
17388            clusters: vec!["rio".into()],
17389            affinity: None,
17390            shard_key: None,
17391        }));
17392        let view = c.aplicacao_view().unwrap();
17393        assert_eq!(
17394            view.placement().estrategia(),
17395            PlacementStrategy::Replicated,
17396            "Caixa::aplicacao_view must fold the authored :placement \
17397             :estrategia scalar through the accessor verbatim onto the \
17398             projected AplicacaoSpec — a future silent detour at the \
17399             seed's fold arm would surface here as a projected-scalar \
17400             drift (got {:?})",
17401            view.placement().estrategia(),
17402        );
17403        assert_eq!(
17404            view.placement().clusters(),
17405            &["rio"],
17406            "Caixa::aplicacao_view must fold the authored :placement \
17407             :clusters list through the accessor verbatim onto the \
17408             projected AplicacaoSpec — a future silent detour at the \
17409             seed's fold arm would surface here as a projected-list \
17410             drift (got {:?})",
17411            view.placement().clusters(),
17412        );
17413        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
17414        let view = c.aplicacao_view().unwrap();
17415        assert_eq!(
17416            view.placement(),
17417            &Placement::default(),
17418            "Caixa::aplicacao_view must fold Some(Placement::default()) \
17419             through the accessor onto Placement::default — the empty- \
17420             composite arm collapses to the same default the author- \
17421             omitted arm does (got {:?})",
17422            view.placement(),
17423        );
17424        let c = caixa_aplicacao_with_placement(None);
17425        let view = c.aplicacao_view().unwrap();
17426        assert_eq!(
17427            view.placement(),
17428            &Placement::default(),
17429            "Caixa::aplicacao_view must fold None through the accessor's \
17430             unwrap_or_default onto Placement::default — the author- \
17431             omitted arm must route through the accessor's None-return \
17432             unchanged (got {:?})",
17433            view.placement(),
17434        );
17435    }
17436
17437    #[test]
17438    fn placement_projects_option_ref_by_borrow() {
17439        // The by-borrow pin: [`Caixa::placement`] returns
17440        // `Option<&Placement>` by borrow — the returned reference
17441        // borrows the underlying `Option<Placement>` storage of the
17442        // `:placement` slot and the accessor must not clone the
17443        // backing composite on every call. Peer of the sibling
17444        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
17445        // `behavior_projects_option_ref_by_borrow` (35d8b52), and
17446        // `politicas_projects_option_ref_by_borrow` (5d23d29) by-borrow
17447        // pins on the outer top-level [`Caixa`]
17448        // `Option<&Composite>`-return sub-family — extended here to
17449        // the fourth axis of the same sub-family: the accessor's
17450        // returned reference must borrow from `&self` (the returned
17451        // reference's lifetime is tied to `&self`), and calling the
17452        // accessor twice on the same [`Caixa`] must yield references
17453        // that are pointer-equal (the underlying byte-buffer is the
17454        // storage `Placement`'s allocation, not a fresh copy) as well
17455        // as value-equal (idempotent, no side effects on `&self`).
17456        //
17457        // Pins against a future silent detour that returned an owned
17458        // `Placement` (which would type-check via the `Clone` impl
17459        // but silently clone on every call), a `&Placement` panic-
17460        // return on the `None` arm (which would collapse the load-
17461        // bearing `Option` presence-bit into a runtime panic), or a
17462        // one-arm-only accessor that returned a saturating composite
17463        // on some sentinel input.
17464        use crate::aplicacao::{Placement, PlacementStrategy};
17465        for placement in [
17466            Some(Placement::default()),
17467            Some(Placement {
17468                estrategia: PlacementStrategy::Sharded,
17469                clusters: vec!["rio".into(), "sao-paulo".into()],
17470                affinity: Some("data-locality".into()),
17471                shard_key: Some("$tenantId".into()),
17472            }),
17473        ] {
17474            let c = caixa_aplicacao_with_placement(placement.clone());
17475            let first = c.placement().unwrap();
17476            let second = c.placement().unwrap();
17477            assert_eq!(
17478                first, second,
17479                "Caixa::placement must be idempotent — two successive \
17480                 calls on the same &self must return the same \
17481                 &Placement",
17482            );
17483            assert!(
17484                std::ptr::eq(first, second),
17485                "Caixa::placement must borrow the underlying \
17486                 Option<Placement> storage — two successive calls \
17487                 must return references with the same backing pointer \
17488                 (a fresh Placement clone would change the pointer on \
17489                 every call)",
17490            );
17491            assert_eq!(
17492                Some(first),
17493                placement.as_ref(),
17494                "Caixa::placement must return :placement verbatim by \
17495                 borrow — got {first:?}, expected {:?}",
17496                placement.as_ref(),
17497            );
17498        }
17499        let c = caixa_aplicacao_with_placement(None);
17500        assert!(
17501            c.placement().is_none(),
17502            "Caixa::placement must return None when :placement is \
17503             absent — the author-omitted arm must project through the \
17504             accessor's Option::None unchanged",
17505        );
17506    }
17507
17508    // ── Caixa::entrada — outer top-level Option<&Entrada> composite-reference accessor ──
17509
17510    fn caixa_aplicacao_with_entrada(entrada: Option<crate::aplicacao::Entrada>) -> Caixa {
17511        use crate::aplicacao::{Membro, WitContract};
17512        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17513        c.kind = CaixaKind::Aplicacao;
17514        c.membros = vec![Membro {
17515            caixa: "a".into(),
17516            versao: "^0.1".into(),
17517        }];
17518        c.contratos = vec![WitContract {
17519            de: "a".into(),
17520            para: "a".into(),
17521            wit: "wasi:http/proxy".into(),
17522            endpoint: Some("/x".into()),
17523            subject: None,
17524            slot: None,
17525        }];
17526        c.entrada = entrada;
17527        c
17528    }
17529
17530    #[test]
17531    fn entrada_returns_entrada_option_ref_verbatim_across_permutations() {
17532        // The canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
17533        // composite optional-composite-reference-shape pin:
17534        // [`Caixa::entrada`] must return the `:entrada` typed
17535        // `Option<Entrada>` verbatim as an `Option<&Entrada>`
17536        // reference over the same backing storage the raw
17537        // `self.entrada.as_ref()` field access borrows from,
17538        // byte-equal across every representative fixture in the
17539        // accept-set — the author-omitted `None` shape (the
17540        // "cluster-internal Aplicacao" partition every downstream
17541        // Gateway-API emitter treats as "emit no listener + no
17542        // HTTPRoute"), a bare-`host`/`para` minimum-composite fixture
17543        // (empty `paths` — the resolved-paths fallback the peer
17544        // [`crate::aplicacao::Entrada::resolved_paths`] cascade folds
17545        // onto the substrate catch-all), and a fully-populated
17546        // multi-path-with-non-default-port fixture (the canonical
17547        // shape a public HTTP Aplicacao carries).
17548        //
17549        // Pins against a future silent detour that returned a fresh-
17550        // cloned [`crate::aplicacao::Entrada`] copy (which would
17551        // type-check via the `Clone` impl but silently break every
17552        // downstream caller that relied on the reference sharing the
17553        // composite's backing identity), a reference to an operator-
17554        // resolved overlay (the future per-cluster
17555        // `:entrada-overrides` slot — its resolution must land at
17556        // exactly this accessor body, not silently divert the raw
17557        // slot away from the peer [`Caixa::declared_mesh_slots`]
17558        // enumerator's presence probe), or an axis-shuffled projection
17559        // (a future detour that swapped `host` and `para` through the
17560        // accessor would silently split the paired
17561        // [`Caixa::aplicacao_view`] seed's forward input from the
17562        // sibling M3 gateway-artifact emitter's projection input).
17563        //
17564        // Fifth and final outer top-level [`Caixa`]
17565        // `Option<&Composite>`-return composite-reference accessor pin
17566        // on the substrate primitive — peer of the sibling
17567        // `limits_returns_limits_option_ref_verbatim_across_permutations`
17568        // (b2bd9d7),
17569        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
17570        // (35d8b52),
17571        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
17572        // (5d23d29), and
17573        // `placement_returns_placement_option_ref_verbatim_across_permutations`
17574        // (4fb8074) opening tetrad pins on the outer top-level
17575        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
17576        // here to the third and final M3 mesh-slot axis so the closed
17577        // outer `Option<&Composite>` sub-family carries the same
17578        // "byte-equal, borrow-shared, presence-bit-preserved" outer-
17579        // accessor discipline across all five arms.
17580        use crate::aplicacao::Entrada;
17581        let fixtures: Vec<Option<Entrada>> = vec![
17582            None,
17583            Some(Entrada {
17584                host: "checkout.quero.cloud".into(),
17585                para: "gateway".into(),
17586                paths: Vec::new(),
17587                port: crate::DEFAULT_SERVICO_PORT,
17588            }),
17589            Some(Entrada {
17590                host: "api.pleme.io".into(),
17591                para: "public-api".into(),
17592                paths: vec!["/v1".into(), "/v2".into()],
17593                port: 8080,
17594            }),
17595        ];
17596        for entrada in fixtures {
17597            let c = caixa_aplicacao_with_entrada(entrada.clone());
17598            assert_eq!(
17599                c.entrada(),
17600                entrada.as_ref(),
17601                "Caixa::entrada must return :entrada verbatim (got \
17602                 {:?}, expected {:?})",
17603                c.entrada(),
17604                entrada.as_ref(),
17605            );
17606            match (c.entrada(), c.entrada.as_ref()) {
17607                (Some(a), Some(b)) => assert!(
17608                    std::ptr::eq(a, b),
17609                    "Caixa::entrada accessor and self.entrada.as_ref() \
17610                     field access must borrow the same backing storage \
17611                     — the accessor is the substrate-primitive typed \
17612                     dispatch every downstream Aplicacao-external- \
17613                     gateway composite consumer must route through, and \
17614                     a reference-identity split would silently break \
17615                     every consumer that relied on the borrow sharing \
17616                     the composite's storage",
17617                ),
17618                (None, None) => {}
17619                _ => panic!(
17620                    "Caixa::entrada presence bit must byte-equal \
17621                     self.entrada.is_some() — a presence-bit drift \
17622                     would silently split the paired \
17623                     Caixa::aplicacao_view Aplicacao-composition seed's \
17624                     traversal head from the peer \
17625                     Caixa::declared_mesh_slots M3 declared-slot \
17626                     enumerator's presence probe",
17627                ),
17628            }
17629            assert_eq!(
17630                c.entrada().is_some(),
17631                c.entrada.is_some(),
17632                "Caixa::entrada().is_some() must byte-equal \
17633                 self.entrada.is_some() — a presence-bit drift would \
17634                 silently split every downstream Option<&Entrada> \
17635                 consumer's partition on the cluster-internal arm",
17636            );
17637        }
17638    }
17639
17640    #[test]
17641    fn declared_mesh_slots_entrada_arm_routes_through_accessor() {
17642        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:entrada`
17643        // presence-probe arm must key off [`Caixa::entrada`], not the
17644        // raw `self.entrada.is_some()` field-probe. Structurally: a
17645        // `Caixa { entrada: Some(Entrada { host: "...", para: "...",
17646        // paths: [], port: DEFAULT_SERVICO_PORT }), .. }` must push
17647        // `M3_AUTHOR_KEY_ENTRADA` onto the declared-slot list (the
17648        // presence bit is `Some`, so the M3 kind-coherence gate must
17649        // surface the slot as "declared" even when every per-axis
17650        // scalar defers to the substrate catch-all / default port),
17651        // and a `Caixa { entrada: None, .. }` must NOT push the label
17652        // (the "author omitted the slot entirely" partition). The pair
17653        // jointly pins the accessor + declared-slot enumerator
17654        // composition: any future silent detour that had the accessor
17655        // collapse `Some(Entrada { paths: [], .. })` to `None` (a
17656        // `.filter(|e| !e.paths.is_empty())` projection) would silently
17657        // absorb the "declared but empty-paths" arm at the accessor
17658        // boundary and the
17659        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
17660        // coherence gate would silently accept a struct-literal
17661        // `Caixa` carrying the drift.
17662        //
17663        // Peer of the sibling
17664        // `declared_servico_slots_limits_arm_routes_through_accessor`
17665        // (b2bd9d7),
17666        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17667        // (35d8b52),
17668        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
17669        // (5d23d29), and
17670        // `declared_mesh_slots_placement_arm_routes_through_accessor`
17671        // (4fb8074) composition pins on the sibling `:limits` /
17672        // `:behavior` / `:politicas` / `:placement` outer-
17673        // `Option<&Composite>` arms — same "the enumerator gate must
17674        // route through the substrate-primitive typed dispatch"
17675        // discipline extended onto the third and final M3 mesh-slot
17676        // axis so the [`Caixa::declared_mesh_slots`] enumerator now
17677        // carries the routing invariant on every M3 mesh-slot arm.
17678        use crate::aplicacao::Entrada;
17679        let c = caixa_aplicacao_with_entrada(Some(Entrada {
17680            host: "checkout.quero.cloud".into(),
17681            para: "gateway".into(),
17682            paths: Vec::new(),
17683            port: crate::DEFAULT_SERVICO_PORT,
17684        }));
17685        let slots = c.declared_mesh_slots();
17686        assert!(
17687            slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
17688            "declared_mesh_slots must push M3_AUTHOR_KEY_ENTRADA when \
17689             `:entrada` is Some (even for empty-paths / default-port) \
17690             — the accessor and the enumerator gate must route through \
17691             the same substrate-primitive typed dispatch on the outer \
17692             :entrada presence bit (got slots={slots:?})",
17693        );
17694        let c = caixa_aplicacao_with_entrada(None);
17695        let slots = c.declared_mesh_slots();
17696        assert!(
17697            !slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
17698            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_ENTRADA \
17699             when `:entrada` is None — the author-omitted arm must \
17700             route through the accessor's None-return unchanged (got \
17701             slots={slots:?})",
17702        );
17703    }
17704
17705    #[test]
17706    fn aplicacao_view_entrada_arm_folds_through_accessor() {
17707        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:entrada`
17708        // Aplicacao-composition seed must fold through
17709        // [`Caixa::entrada`], not the raw `self.entrada.clone()` field-
17710        // borrow. Structurally: a `Caixa { entrada: Some(Entrada {
17711        // host: "api.pleme.io", para: "public-api", paths: ["/v1"],
17712        // port: 8080 }), kind: Aplicacao, .. }` must surface a projected
17713        // [`crate::AplicacaoSpec`] whose `entrada().unwrap()` byte-
17714        // equals the outer composite's authored value (the fold must
17715        // project the authored composite verbatim), and a `Caixa {
17716        // entrada: None, kind: Aplicacao, .. }` must surface an
17717        // [`crate::AplicacaoSpec`] whose `entrada()` is `None` (the
17718        // "author omitted the slot entirely" arm folds through the
17719        // accessor's `Option::cloned` onto the same `None` presence
17720        // bit — unlike the peer `:politicas` / `:placement` arms
17721        // `:entrada` has no cluster-default fold, the omitted arm
17722        // stays omitted). The pair jointly pins the accessor +
17723        // Aplicacao-composition seed composition: any future silent
17724        // detour that had the accessor divert the raw slot away from
17725        // the seed's fold (an operator-resolved overlay's forward arm
17726        // silently differing from the raw slot's forward arm) would
17727        // silently split the build-time gateway-artifact emission gate
17728        // from the caixa-mesh renderer's Aplicacao-view input at the
17729        // composition boundary.
17730        use crate::aplicacao::Entrada;
17731        let authored = Entrada {
17732            host: "api.pleme.io".into(),
17733            para: "public-api".into(),
17734            paths: vec!["/v1".into()],
17735            port: 8080,
17736        };
17737        let c = caixa_aplicacao_with_entrada(Some(authored.clone()));
17738        let view = c.aplicacao_view().unwrap();
17739        assert_eq!(
17740            view.entrada(),
17741            Some(&authored),
17742            "Caixa::aplicacao_view must fold the authored :entrada \
17743             composite through the accessor verbatim onto the \
17744             projected AplicacaoSpec — a future silent detour at the \
17745             seed's fold arm would surface here as a projected- \
17746             composite drift (got {:?})",
17747            view.entrada(),
17748        );
17749        let c = caixa_aplicacao_with_entrada(None);
17750        let view = c.aplicacao_view().unwrap();
17751        assert!(
17752            view.entrada().is_none(),
17753            "Caixa::aplicacao_view must fold None through the \
17754             accessor's Option::cloned onto None — the author- \
17755             omitted arm must route through the accessor's None-return \
17756             unchanged (got {:?})",
17757            view.entrada(),
17758        );
17759    }
17760
17761    #[test]
17762    fn entrada_projects_option_ref_by_borrow() {
17763        // The by-borrow pin: [`Caixa::entrada`] returns
17764        // `Option<&Entrada>` by borrow — the returned reference
17765        // borrows the underlying `Option<Entrada>` storage of the
17766        // `:entrada` slot and the accessor must not clone the backing
17767        // composite on every call. Peer of the sibling
17768        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
17769        // `behavior_projects_option_ref_by_borrow` (35d8b52),
17770        // `politicas_projects_option_ref_by_borrow` (5d23d29), and
17771        // `placement_projects_option_ref_by_borrow` (4fb8074) by-
17772        // borrow pins on the outer top-level [`Caixa`]
17773        // `Option<&Composite>`-return sub-family — extended here to
17774        // the fifth and final axis of the same sub-family, closing
17775        // the discipline: the accessor's returned reference must
17776        // borrow from `&self` (the returned reference's lifetime is
17777        // tied to `&self`), and calling the accessor twice on the
17778        // same [`Caixa`] must yield references that are pointer-equal
17779        // (the underlying byte-buffer is the storage `Entrada`'s
17780        // allocation, not a fresh copy) as well as value-equal
17781        // (idempotent, no side effects on `&self`).
17782        //
17783        // Pins against a future silent detour that returned an owned
17784        // `Entrada` (which would type-check via the `Clone` impl but
17785        // silently clone on every call), a `&Entrada` panic-return on
17786        // the `None` arm (which would collapse the load-bearing
17787        // `Option` presence-bit into a runtime panic), or a one-arm-
17788        // only accessor that returned a saturating composite on some
17789        // sentinel input.
17790        use crate::aplicacao::Entrada;
17791        for entrada in [
17792            Some(Entrada {
17793                host: "checkout.quero.cloud".into(),
17794                para: "gateway".into(),
17795                paths: Vec::new(),
17796                port: crate::DEFAULT_SERVICO_PORT,
17797            }),
17798            Some(Entrada {
17799                host: "api.pleme.io".into(),
17800                para: "public-api".into(),
17801                paths: vec!["/v1".into(), "/v2".into()],
17802                port: 8080,
17803            }),
17804        ] {
17805            let c = caixa_aplicacao_with_entrada(entrada.clone());
17806            let first = c.entrada().unwrap();
17807            let second = c.entrada().unwrap();
17808            assert_eq!(
17809                first, second,
17810                "Caixa::entrada must be idempotent — two successive \
17811                 calls on the same &self must return the same &Entrada",
17812            );
17813            assert!(
17814                std::ptr::eq(first, second),
17815                "Caixa::entrada must borrow the underlying \
17816                 Option<Entrada> storage — two successive calls must \
17817                 return references with the same backing pointer (a \
17818                 fresh Entrada clone would change the pointer on every \
17819                 call)",
17820            );
17821            assert_eq!(
17822                Some(first),
17823                entrada.as_ref(),
17824                "Caixa::entrada must return :entrada verbatim by \
17825                 borrow — got {first:?}, expected {:?}",
17826                entrada.as_ref(),
17827            );
17828        }
17829        let c = caixa_aplicacao_with_entrada(None);
17830        assert!(
17831            c.entrada().is_none(),
17832            "Caixa::entrada must return None when :entrada is absent \
17833             — the author-omitted arm must project through the \
17834             accessor's Option::None unchanged",
17835        );
17836    }
17837
17838    // ── Caixa::estrategia — outer top-level Option<RestartStrategy> flat-spread supervisor-tree accessor ──
17839
17840    fn caixa_with_estrategia(estrategia: Option<crate::supervisor::RestartStrategy>) -> Caixa {
17841        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17842        c.estrategia = estrategia;
17843        c
17844    }
17845
17846    #[test]
17847    fn estrategia_returns_estrategia_option_verbatim_across_permutations() {
17848        // The canonical per-`Caixa` `:estrategia` M2 supervisor-tree-slot
17849        // flat-spread `Option<RestartStrategy>`-return `Copy`-composite-
17850        // enum-arm scalar shape pin: [`Caixa::estrategia`] must return
17851        // the `:estrategia` typed `Option<crate::supervisor::RestartStrategy>`
17852        // verbatim as an `Option<RestartStrategy>` `Copy`-projected value
17853        // over the same discriminant the raw `self.estrategia` field
17854        // access carries, byte-equal across every representative fixture
17855        // in the accept-set — the author-omitted `None` shape (the
17856        // "defer to [`RestartStrategy::default`] through the
17857        // [`Self::supervisor_view`] `unwrap_or_default()` fold" partition
17858        // every non-`Supervisor`-kind `defcaixa` carries by
17859        // `#[serde(default)]`), and each of the four closed-set variants
17860        // [`RestartStrategy::OneForOne`] / [`RestartStrategy::OneForAll`]
17861        // / [`RestartStrategy::RestForOne`] /
17862        // [`RestartStrategy::SimpleOneForOne`] the author-declared arm
17863        // partitions on.
17864        //
17865        // Pins against a future silent detour that re-derived the
17866        // strategy from a peer axis (an accidental fallback to
17867        // `if children.is_empty() { SimpleOneForOne } else { OneForOne }`
17868        // collapse that read the outer `:children` list-length axis into
17869        // the strategy discriminator at the accessor boundary), a
17870        // stale-derive detour that substituted [`RestartStrategy::default`]
17871        // when the outer `Option` held `None` (which would silently
17872        // collapse the load-bearing "author explicitly declared
17873        // `:estrategia OneForOne`" vs "author omitted the slot and
17874        // inherited the default" partition the [`Self::declared_supervisor_slots`]
17875        // presence-probe reads — the enumerator gate would still push
17876        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` on the omitted arm, silently
17877        // splitting the paired [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
17878        // kind-coherence gate's traversal head from the
17879        // [`Self::supervisor_view`] `unwrap_or_default()` fold's
17880        // composition head), a reference to an operator-resolved overlay
17881        // (the future per-cluster `:estrategia-overrides` slot — its
17882        // resolution must land at exactly this accessor body, not
17883        // silently divert the raw slot away from a second consumer), or
17884        // an axis-remap projection (a future detour that mapped
17885        // `OneForAll` through the accessor onto `OneForOne` would
17886        // silently split every downstream sibling-restart-strategy
17887        // consumer's per-arm fan-out).
17888        //
17889        // First outer top-level [`Caixa`] `Option<Copy>`-return
17890        // supervisor-tree-slot flat-spread accessor pin on the substrate
17891        // primitive — opens the outer-`Caixa` `Option<Copy>` flat-spread
17892        // projection pattern the sibling per-`Caixa` `:max-restarts` /
17893        // `:restart-window` future outer-scalar pins fold on. Peer of
17894        // the inner-altitude
17895        // `supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
17896        // (eafb619) pin on the post-composition [`SupervisorSpec`]
17897        // altitude — same "the substrate-primitive accessor must byte-
17898        // equal the raw field access verbatim across every author-
17899        // declared value" discipline extended onto the pre-composition
17900        // outer author-surface [`Caixa`] altitude. Peer of the closed
17901        // outer-`Caixa` `Option<&Composite>` composite-reference family
17902        // the sibling `limits` / `behavior` / `politicas` / `placement` /
17903        // `entrada`
17904        // `..._returns_..._option_ref_verbatim_across_permutations` pins
17905        // already carry on the outer `Option<&Composite>` altitude.
17906        use crate::supervisor::RestartStrategy;
17907        let fixtures: Vec<Option<RestartStrategy>> = vec![
17908            None,
17909            Some(RestartStrategy::OneForOne),
17910            Some(RestartStrategy::OneForAll),
17911            Some(RestartStrategy::RestForOne),
17912            Some(RestartStrategy::SimpleOneForOne),
17913        ];
17914        for estrategia in fixtures {
17915            let c = caixa_with_estrategia(estrategia);
17916            assert_eq!(
17917                c.estrategia(),
17918                estrategia,
17919                "Caixa::estrategia must return :estrategia verbatim (got \
17920                 {:?}, expected {:?})",
17921                c.estrategia(),
17922                estrategia,
17923            );
17924            assert_eq!(
17925                c.estrategia(),
17926                c.estrategia,
17927                "Caixa::estrategia accessor and self.estrategia field \
17928                 access must byte-equal — the accessor is the substrate-\
17929                 primitive typed dispatch every downstream supervisor-\
17930                 tree flat-spread consumer must route through, and a \
17931                 discriminant split would silently break every consumer \
17932                 that relied on the accessor sharing the field's own \
17933                 Option<Copy> shape",
17934            );
17935            assert_eq!(
17936                c.estrategia().is_some(),
17937                c.estrategia.is_some(),
17938                "Caixa::estrategia().is_some() must byte-equal \
17939                 self.estrategia.is_some() — a presence-bit drift would \
17940                 silently split the paired Caixa::declared_supervisor_slots \
17941                 presence-probe arm from the Caixa::supervisor_view \
17942                 unwrap_or_default() fold's composition input",
17943            );
17944        }
17945    }
17946
17947    #[test]
17948    fn declared_supervisor_slots_estrategia_arm_routes_through_accessor() {
17949        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
17950        // `:estrategia` presence-probe arm must key off
17951        // [`Caixa::estrategia`], not the raw `self.estrategia.is_some()`
17952        // field-probe. Structurally: every `Caixa { estrategia:
17953        // Some(RestartStrategy::_), .. }` variant must push
17954        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` onto the declared-slot list
17955        // (the presence bit is `Some` for every closed-set variant, so
17956        // the M2 supervisor-tree kind-coherence gate must surface the
17957        // slot as "declared" regardless of which variant the author
17958        // picked), and a `Caixa { estrategia: None, .. }` must NOT push
17959        // the label (the "author omitted the slot entirely, deferring
17960        // to [`RestartStrategy::default`] through the supervisor_view
17961        // fold" partition). The pair jointly pins the accessor +
17962        // declared-slot enumerator composition: any future silent detour
17963        // that had the accessor collapse `Some(RestartStrategy::default())`
17964        // to `None` (a `.filter(|e| *e != RestartStrategy::default())`
17965        // projection) would silently absorb the "declared but default-
17966        // valued" arm at the accessor boundary and the
17967        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
17968        // coherence gate would silently accept a struct-literal `Caixa`
17969        // carrying the drift.
17970        //
17971        // Peer of the sibling per-`Caixa`
17972        // `declared_servico_slots_limits_arm_routes_through_accessor`
17973        // (b2bd9d7) accessor-composition pin on the sibling outer-`Caixa`
17974        // `Option<&LimitsSpec>` composition axis — same "the enumerator
17975        // gate must route through the substrate-primitive typed
17976        // dispatch" discipline extended onto the flat-spread M2
17977        // supervisor-tree `Option<RestartStrategy>`-composition surface,
17978        // opening the outer-`Caixa` supervisor-tree-slot arm of the
17979        // composition-pin family.
17980        use crate::supervisor::RestartStrategy;
17981        for estrategia in [
17982            RestartStrategy::OneForOne,
17983            RestartStrategy::OneForAll,
17984            RestartStrategy::RestForOne,
17985            RestartStrategy::SimpleOneForOne,
17986        ] {
17987            let c = caixa_with_estrategia(Some(estrategia));
17988            let slots = c.declared_supervisor_slots();
17989            assert!(
17990                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
17991                "declared_supervisor_slots must push \
17992                 SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is \
17993                 Some({estrategia:?}) — the accessor and the enumerator \
17994                 gate must route through the same substrate-primitive \
17995                 typed dispatch on the outer :estrategia presence bit \
17996                 (got slots={slots:?})",
17997            );
17998        }
17999        let c = caixa_with_estrategia(None);
18000        let slots = c.declared_supervisor_slots();
18001        assert!(
18002            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
18003            "declared_supervisor_slots must NOT push \
18004             SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is None \
18005             — the author-omitted arm must route through the accessor's \
18006             None-return unchanged (got slots={slots:?})",
18007        );
18008    }
18009
18010    #[test]
18011    fn supervisor_view_estrategia_arm_routes_through_accessor() {
18012        // Composition pin: [`Caixa::supervisor_view`]'s per-`:estrategia`
18013        // [`SupervisorSpec`] construction arm must key off
18014        // [`Caixa::estrategia`]'s `unwrap_or_default()` fold, not the raw
18015        // `self.estrategia.unwrap_or_default()` field-fold. Structurally:
18016        // for every `:kind Supervisor` `Caixa` carrying an author-
18017        // declared `Some(RestartStrategy::_)` variant, the composed
18018        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal the
18019        // outer accessor's declared variant unchanged; and for a
18020        // `:kind Supervisor` `Caixa` carrying `None`, the composed
18021        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal
18022        // [`RestartStrategy::default`] (the [`RestartStrategy::OneForOne`]
18023        // arm the flat-spread `unwrap_or_default()` fold projects to on
18024        // the author-omitted arm — this is the *composition* between the
18025        // outer `Option<RestartStrategy>` accessor's presence-bit
18026        // surface and the inner post-composition non-`Option`
18027        // [`SupervisorSpec::estrategia`] altitude). The pair jointly
18028        // pins the accessor + supervisor_view composition: any future
18029        // silent detour that had the accessor promote `None` to
18030        // `Some(RestartStrategy::default())` (a `.or_else(|| Some(RestartStrategy::default()))`
18031        // projection) would silently collapse the two arms into one at
18032        // the accessor boundary and the [`Self::declared_supervisor_slots`]
18033        // presence probe would silently drift from the composition site.
18034        //
18035        // Peer of the sibling M2 supervisor-slot post-composition
18036        // `validate_reads_through_lifted_estrategia_accessor` (eafb619)
18037        // pin on the [`SupervisorSpec::validate`] altitude — this pin
18038        // extends that inner-altitude accessor-routing discipline onto
18039        // the pre-composition outer author-surface [`Caixa`] altitude,
18040        // pinning the composition edge between the flat-spread outer
18041        // `Option<RestartStrategy>` and the composed [`SupervisorSpec`]
18042        // `RestartStrategy` axes.
18043        use crate::CaixaKind;
18044        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
18045        for estrategia in [
18046            RestartStrategy::OneForOne,
18047            RestartStrategy::OneForAll,
18048            RestartStrategy::RestForOne,
18049            RestartStrategy::SimpleOneForOne,
18050        ] {
18051            let mut c = caixa_with_estrategia(Some(estrategia));
18052            c.kind = CaixaKind::Supervisor;
18053            // Route the `SimpleOneForOne ↔ non-SimpleOneForOne` fixture-
18054            // shape partition through the [`gen_platform::IsVariant`]
18055            // derive-generated
18056            // [`RestartStrategy::is_simple_one_for_one`] predicate rather
18057            // than the raw `matches!(estrategia, RestartStrategy::
18058            // SimpleOneForOne)` open-coded pattern-match — same closed-
18059            // set-typed-enum arm-discriminator dispatch discipline the
18060            // sibling [`crate::upgrade::UpgradeInstruction::is_restart`]
18061            // convergence (915a934) extended onto its two paired positive
18062            // / negated `matches!` sites and the peer
18063            // [`crate::aplicacao::PlacementStrategy`] `IsVariant`-derived
18064            // predicate convergence (766ec63) extended onto the M3 mesh-
18065            // slot per-`:placement` distribution-strategy discriminator
18066            // axis. See the sibling `supervisor::tests::
18067            // round_trip_all_strategies` and
18068            // `supervisor::tests::supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
18069            // fixtures — the three sites (all test-only,
18070            // acknowledged in 915a934's Prior-commits footnote as the
18071            // outstanding follow-up) now consult one typed dispatch on
18072            // the substrate primitive.
18073            c.children = if estrategia.is_simple_one_for_one() {
18074                Vec::new()
18075            } else {
18076                vec![ChildSpec {
18077                    caixa: "worker".into(),
18078                    versao: "^0.1".into(),
18079                    restart: RestartPolicy::Permanent,
18080                }]
18081            };
18082            let view = c.supervisor_view().expect(
18083                "supervisor_view must materialize a SupervisorSpec for a \
18084                 :kind Supervisor Caixa carrying a Some(:estrategia) slot",
18085            );
18086            assert_eq!(
18087                view.estrategia(),
18088                c.estrategia().unwrap(),
18089                "supervisor_view must carry the outer Caixa::estrategia() \
18090                 declared variant onto the composed SupervisorSpec.estrategia \
18091                 field verbatim on the Some arm (got {:?}, expected {:?})",
18092                view.estrategia(),
18093                c.estrategia().unwrap(),
18094            );
18095        }
18096        // The author-omitted arm: outer `None` → composed
18097        // `RestartStrategy::default()` through the flat-spread
18098        // `unwrap_or_default()` fold.
18099        let mut c = caixa_with_estrategia(None);
18100        c.kind = CaixaKind::Supervisor;
18101        // Populate children so the sibling supervisor slots are coherent
18102        // for the [`Self::supervisor_view`] projection; the `:estrategia`
18103        // arm still defers to [`RestartStrategy::default`] on the
18104        // author-omitted arm even when the sibling slots carry values.
18105        c.children = vec![ChildSpec {
18106            caixa: "worker".into(),
18107            versao: "^0.1".into(),
18108            restart: RestartPolicy::Permanent,
18109        }];
18110        let view = c.supervisor_view().expect(
18111            "supervisor_view must materialize a SupervisorSpec for a \
18112             :kind Supervisor Caixa carrying a None `:estrategia` slot",
18113        );
18114        assert_eq!(
18115            view.estrategia(),
18116            RestartStrategy::default(),
18117            "supervisor_view must project the outer Caixa::estrategia() \
18118             None arm onto RestartStrategy::default() through the flat-\
18119             spread unwrap_or_default() fold (got {:?}, expected {:?})",
18120            view.estrategia(),
18121            RestartStrategy::default(),
18122        );
18123        assert!(
18124            c.estrategia().is_none(),
18125            "Caixa::estrategia() must remain None on the author-omitted \
18126             arm — the supervisor_view fold must not mutate the outer \
18127             flat-spread presence bit",
18128        );
18129    }
18130
18131    #[test]
18132    fn estrategia_projects_option_by_copy() {
18133        // The by-`Copy` pin: [`Caixa::estrategia`] returns
18134        // `Option<RestartStrategy>` by value (`RestartStrategy: Copy`) —
18135        // the accessor does not borrow `&self` past the call (no
18136        // lifetime on the return type), and calling the accessor twice
18137        // on the same [`Caixa`] must yield discriminant-equal values
18138        // (idempotent, no side effects on `&self`). Peer of the sibling
18139        // outer-`Caixa` `Option<&Composite>` by-borrow
18140        // `limits_projects_option_ref_by_borrow` (b2bd9d7) /
18141        // `behavior_projects_option_ref_by_borrow` (35d8b52) /
18142        // `politicas_projects_option_ref_by_borrow` (5d23d29) /
18143        // `placement_projects_option_ref_by_borrow` (4fb8074) /
18144        // `entrada_projects_option_ref_by_borrow` (e4128e4) by-borrow
18145        // pins on the outer-`Caixa` `Option<&Composite>`-return axes —
18146        // extended here to the outer-`Caixa` `Option<Copy>`-return
18147        // flat-spread axis. The `Copy` discipline replaces the pointer-
18148        // equality claim the by-borrow siblings pin (a fresh `Copy` of a
18149        // `Copy` discriminant is definitionally the same discriminant, so
18150        // the axis reduces to discriminant equality).
18151        //
18152        // Pins against a future silent detour that returned a fresh
18153        // `Option<&RestartStrategy>` (which would type-check but silently
18154        // introduce a borrow of `&self` past the call, collapsing the
18155        // load-bearing "no lifetime on the return type" `Copy` projection
18156        // the flat-spread axis's `Option<Copy>` shape carries), a stale-
18157        // read side effect that flipped the outer discriminant on
18158        // successive calls, or an axis-remap projection that returned a
18159        // different variant than the field storage.
18160        use crate::supervisor::RestartStrategy;
18161        for estrategia in [
18162            Some(RestartStrategy::OneForOne),
18163            Some(RestartStrategy::OneForAll),
18164            Some(RestartStrategy::RestForOne),
18165            Some(RestartStrategy::SimpleOneForOne),
18166        ] {
18167            let c = caixa_with_estrategia(estrategia);
18168            let first = c.estrategia();
18169            let second = c.estrategia();
18170            assert_eq!(
18171                first, second,
18172                "Caixa::estrategia must be idempotent — two successive \
18173                 calls on the same &self must return the same \
18174                 Option<RestartStrategy>",
18175            );
18176            assert_eq!(
18177                first, estrategia,
18178                "Caixa::estrategia must return :estrategia verbatim by \
18179                 Copy — got {first:?}, expected {estrategia:?}",
18180            );
18181        }
18182        let c = caixa_with_estrategia(None);
18183        assert!(
18184            c.estrategia().is_none(),
18185            "Caixa::estrategia must return None when :estrategia is \
18186             absent — the author-omitted arm must project through the \
18187             accessor's Option::None unchanged",
18188        );
18189    }
18190
18191    // ── Caixa::max_restarts / Caixa::restart_window —
18192    //    outer top-level M2 supervisor-tree-slot flat-spread accessors
18193    //    (Option<u32> / Option<&str>) folding on the ed04d3c
18194    //    Caixa::estrategia Option<Copy> sub-family ─────────────────────
18195
18196    fn caixa_with_max_restarts(max_restarts: Option<u32>) -> Caixa {
18197        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18198        c.max_restarts = max_restarts;
18199        c
18200    }
18201
18202    fn caixa_supervisor_with_max_restarts_and_window(
18203        max_restarts: Option<u32>,
18204        restart_window: Option<&str>,
18205    ) -> Caixa {
18206        use crate::CaixaKind;
18207        use crate::supervisor::{ChildSpec, RestartPolicy};
18208        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
18209        c.kind = CaixaKind::Supervisor;
18210        c.max_restarts = max_restarts;
18211        c.restart_window = restart_window.map(str::to_string);
18212        c.children = vec![ChildSpec {
18213            caixa: "worker".into(),
18214            versao: "^0.1".into(),
18215            restart: RestartPolicy::Permanent,
18216        }];
18217        c
18218    }
18219
18220    #[test]
18221    fn max_restarts_returns_max_restarts_option_verbatim_across_permutations() {
18222        // Value-shape pin: [`Caixa::max_restarts`] returns the
18223        // `:max-restarts` typed `Option<u32>` verbatim, `Copy`-projected
18224        // from the typed slot's own storage, byte-equal across the
18225        // author-omitted `None` arm (the "defer to the
18226        // [`Self::supervisor_view`] `unwrap_or(5)` OTP-canonical
18227        // `{intensity, 5, 60}` default" partition every
18228        // non-`Supervisor`-kind caixa carries by `#[serde(default)]`)
18229        // and each of the representative fixtures in the accept-set —
18230        // `0` (the zero-floor arm the peer
18231        // [`crate::supervisor::SupervisorSpec::validate`]
18232        // [`crate::SupervisorError::ZeroMaxRestarts`] gate refuses on
18233        // the post-composition altitude — the accessor must ship the
18234        // raw slot verbatim so struct-literal fixtures continue to
18235        // expose the zero at the accessor boundary), the OTP-canonical
18236        // `5` default (`{intensity, 5, 60}` worker-supervisor from
18237        // Learn You Some Erlang), `1000` (the
18238        // [`SUPERVISOR_MAX_RESTARTS_MAX`] cap the peer post-composition
18239        // upper-bound gate accepts on the boundary), `u32::MAX` (a
18240        // past-the-cap sentinel that the substrate-primitive accessor
18241        // must still ship verbatim). Second outer top-level
18242        // [`Caixa`] `Option<Copy>`-return supervisor-tree flat-spread
18243        // pin — folds on the sibling
18244        // `estrategia_returns_estrategia_option_verbatim_across_permutations`
18245        // (ed04d3c) pin's `Option<Copy>` shape, extending the sub-family
18246        // onto the sibling `Option<u32>` restart-budget-count arm.
18247        let fixtures: Vec<Option<u32>> = vec![None, Some(0), Some(5), Some(1000), Some(u32::MAX)];
18248        for max_restarts in fixtures {
18249            let c = caixa_with_max_restarts(max_restarts);
18250            assert_eq!(
18251                c.max_restarts(),
18252                max_restarts,
18253                "Caixa::max_restarts must return :max-restarts verbatim \
18254                 (got {:?}, expected {max_restarts:?})",
18255                c.max_restarts(),
18256            );
18257            assert_eq!(
18258                c.max_restarts(),
18259                c.max_restarts,
18260                "Caixa::max_restarts accessor and self.max_restarts \
18261                 field access must byte-equal — a presence-bit or count \
18262                 drift would silently split the paired \
18263                 Caixa::declared_supervisor_slots presence-probe arm \
18264                 from the Caixa::supervisor_view unwrap_or(5) fold's \
18265                 composition input",
18266            );
18267        }
18268    }
18269
18270    #[test]
18271    fn max_restarts_projects_option_by_copy() {
18272        // The by-`Copy` pin: [`Caixa::max_restarts`] returns
18273        // `Option<u32>` by value (`u32: Copy`) — the accessor does not
18274        // borrow `&self` past the call (no lifetime on the return type),
18275        // and calling the accessor twice on the same [`Caixa`] must
18276        // yield equal values (idempotent, no side effects). Peer of the
18277        // sibling `estrategia_projects_option_by_copy` (ed04d3c) pin on
18278        // the outer-`Caixa` `Option<Copy>`-return flat-spread axis.
18279        for max_restarts in [Some(0u32), Some(5), Some(1000), Some(u32::MAX), None] {
18280            let c = caixa_with_max_restarts(max_restarts);
18281            let first = c.max_restarts();
18282            let second = c.max_restarts();
18283            assert_eq!(
18284                first, second,
18285                "Caixa::max_restarts must be idempotent — two successive \
18286                 calls on the same &self must return the same Option<u32>",
18287            );
18288            assert_eq!(
18289                first, max_restarts,
18290                "Caixa::max_restarts must return :max-restarts verbatim \
18291                 by Copy — got {first:?}, expected {max_restarts:?}",
18292            );
18293        }
18294    }
18295
18296    #[test]
18297    fn declared_supervisor_slots_max_restarts_arm_routes_through_accessor() {
18298        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
18299        // `:max-restarts` presence-probe arm must key off
18300        // [`Caixa::max_restarts`], not the raw
18301        // `self.max_restarts.is_some()` field-probe. Structurally: every
18302        // `Caixa { max_restarts: Some(_), .. }` variant must push
18303        // `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS` onto the declared-slot
18304        // list (the presence bit is `Some` for every representative
18305        // count, so the M2 kind-coherence gate must surface the slot as
18306        // "declared"), and a `Caixa { max_restarts: None, .. }` must
18307        // NOT push the label. Peer of the sibling
18308        // `declared_supervisor_slots_estrategia_arm_routes_through_accessor`
18309        // (ed04d3c) composition pin — same routing-through-accessor
18310        // discipline extended onto the sibling flat-spread `Option<u32>`
18311        // arm.
18312        for max_restarts in [0u32, 5, 1000, u32::MAX] {
18313            let c = caixa_with_max_restarts(Some(max_restarts));
18314            let slots = c.declared_supervisor_slots();
18315            assert!(
18316                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
18317                "declared_supervisor_slots must push \
18318                 SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` \
18319                 is Some({max_restarts}) — the accessor and the \
18320                 enumerator gate must route through the same \
18321                 substrate-primitive typed dispatch on the outer \
18322                 :max-restarts presence bit (got slots={slots:?})",
18323            );
18324        }
18325        let c = caixa_with_max_restarts(None);
18326        let slots = c.declared_supervisor_slots();
18327        assert!(
18328            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
18329            "declared_supervisor_slots must NOT push \
18330             SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` is \
18331             None — the author-omitted arm must route through the \
18332             accessor's None-return unchanged (got slots={slots:?})",
18333        );
18334    }
18335
18336    #[test]
18337    fn supervisor_view_max_restarts_arm_routes_through_accessor() {
18338        // Composition pin: [`Caixa::supervisor_view`]'s per-`:max-restarts`
18339        // [`SupervisorSpec`] construction arm must key off
18340        // [`Caixa::max_restarts`]'s `unwrap_or(5)` fold, not the raw
18341        // `self.max_restarts.unwrap_or(5)` field-fold. Structurally: for
18342        // every `:kind Supervisor` `Caixa` carrying an author-declared
18343        // `Some(n)`, the composed [`SupervisorSpec`]'s `.max_restarts()`
18344        // must byte-equal `n`; and for a `:kind Supervisor` `Caixa`
18345        // carrying `None`, the composed [`SupervisorSpec`]'s
18346        // `.max_restarts()` must byte-equal the OTP-canonical `5`. Peer
18347        // of the sibling
18348        // `supervisor_view_estrategia_arm_routes_through_accessor`
18349        // (ed04d3c) composition pin.
18350        for max_restarts in [1u32, 5, 1000] {
18351            let c = caixa_supervisor_with_max_restarts_and_window(Some(max_restarts), None);
18352            let view = c.supervisor_view().expect(
18353                "supervisor_view must materialize a SupervisorSpec for a \
18354                 :kind Supervisor Caixa carrying a Some(:max-restarts)",
18355            );
18356            assert_eq!(
18357                view.max_restarts(),
18358                max_restarts,
18359                "supervisor_view must carry the outer \
18360                 Caixa::max_restarts() Some arm onto the composed \
18361                 SupervisorSpec.max_restarts field verbatim (got {}, \
18362                 expected {max_restarts})",
18363                view.max_restarts(),
18364            );
18365        }
18366        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18367        let view = c.supervisor_view().expect(
18368            "supervisor_view must materialize a SupervisorSpec for a \
18369             :kind Supervisor Caixa carrying a None :max-restarts",
18370        );
18371        assert_eq!(
18372            view.max_restarts(),
18373            5,
18374            "supervisor_view must project the outer \
18375             Caixa::max_restarts() None arm onto the OTP-canonical \
18376             {{intensity, 5, 60}} default (5) through the flat-spread \
18377             unwrap_or(5) fold (got {})",
18378            view.max_restarts(),
18379        );
18380        assert!(
18381            c.max_restarts().is_none(),
18382            "Caixa::max_restarts() must remain None on the author-\
18383             omitted arm — the supervisor_view fold must not mutate \
18384             the outer flat-spread presence bit",
18385        );
18386    }
18387
18388    #[test]
18389    fn supervisor_view_estrategia_fallback_routes_through_lifted_default() {
18390        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
18391        // `:estrategia` arm must degrade onto the substrate-canonical
18392        // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
18393        // `pub const` — the Erlang/OTP-canonical `one_for_one` strategy
18394        // half of Learn You Some Erlang's `{one_for_one, intensity, 5, 60}`
18395        // worker-supervisor default — rather than the transitively-
18396        // derived [`crate::supervisor::RestartStrategy::default`] route
18397        // the prior `.unwrap_or_default()` fold reached for. Prior to the
18398        // lift the composition site carried `.unwrap_or_default()` with
18399        // no compile-time link back to the shared OTP-canonical strategy
18400        // default that the paired [`crate::supervisor::Default for
18401        // RestartStrategy`] impl and the [`crate::supervisor::Default for
18402        // SupervisorSpec`] impl's struct-literal `estrategia` field both
18403        // (now) route through the same lifted constant — so a future
18404        // rebrand of the OTP-canonical strategy default (an OTP
18405        // `rest_for_one` widening once the substrate discovers startup-
18406        // order-coupled child cohorts as the more common worker-
18407        // supervisor shape, a per-cluster overlay the operator pins
18408        // through the MESH-COMPOSITION §III.2 supervision-canary
18409        // `:estrategia-overrides` roadmap slot) would have had to migrate
18410        // the paired `MaxIntensity` + `Period` halves through the lifted
18411        // constants and the `one_for_one` half through a
18412        // `RestartStrategy::default()` route in lockstep or a
18413        // `:kind Supervisor` caixa carrying an author-omitted
18414        // `:estrategia` slot would silently resolve to a `SupervisorSpec`
18415        // whose `estrategia` disagreed with the paired
18416        // `SupervisorSpec::default()` view. Byte-parity against the
18417        // lifted constant closes the split. Peer of the sibling
18418        // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
18419        // composition pin on the paired `MaxIntensity` half + the
18420        // [`crate::supervisor::restart_strategy_default_routes_through_lifted_default`]
18421        // + [`crate::supervisor::supervisor_spec_default_estrategia_routes_through_lifted_default`]
18422        // pins on the sibling entry points onto the shared substrate
18423        // constant.
18424        use crate::CaixaKind;
18425        use crate::supervisor::{ChildSpec, RestartPolicy};
18426        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
18427        c.kind = CaixaKind::Supervisor;
18428        c.estrategia = None;
18429        c.children = vec![ChildSpec {
18430            caixa: "worker".into(),
18431            versao: "^0.1".into(),
18432            restart: RestartPolicy::Permanent,
18433        }];
18434        let view = c.supervisor_view().expect(
18435            "supervisor_view must materialize a SupervisorSpec for a \
18436             :kind Supervisor Caixa carrying a None :estrategia",
18437        );
18438        assert_eq!(
18439            view.estrategia(),
18440            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
18441            "supervisor_view must degrade the outer \
18442             Caixa::estrategia() None arm onto the lifted \
18443             SUPERVISOR_ESTRATEGIA_DEFAULT typed pub const (got {:?}, \
18444             expected {:?})",
18445            view.estrategia(),
18446            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
18447        );
18448    }
18449
18450    #[test]
18451    fn supervisor_view_max_restarts_fallback_routes_through_lifted_default() {
18452        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
18453        // `:max-restarts` arm must degrade onto the substrate-canonical
18454        // [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`] typed
18455        // `pub const` — the Erlang/OTP-canonical `{intensity, 5, 60}`
18456        // `MaxIntensity` default — rather than a raw `5` literal. Prior
18457        // to the lift the composition site carried an inline
18458        // `.unwrap_or(5)` with no compile-time link back to the shared
18459        // OTP-canonical default that the serde-side
18460        // `#[serde(default = "default_max_restarts")]` wire-format arm
18461        // and the [`Default for crate::supervisor::SupervisorSpec`]
18462        // struct-literal default arm both key off — so a future rebrand
18463        // of the OTP-canonical default (Elixir's `Supervisor` `3`
18464        // default, a per-cluster overlay the operator pins through the
18465        // MESH-COMPOSITION §III.2 supervision-canary
18466        // `:supervisor :max-restarts-overrides` roadmap slot) would
18467        // have had to be threaded through both the serde-side helper
18468        // and this view-construction arm in lockstep or a `:kind
18469        // Supervisor` caixa carrying `:max-restarts ()` would silently
18470        // resolve to a `SupervisorSpec` whose `max_restarts` disagreed
18471        // with the same fixture's serde-side `SupervisorSpec` view (an
18472        // author-omitted slot round-tripping through
18473        // `SupervisorSpec::default()` to the lifted constant, then
18474        // splitting to a stale literal past `supervisor_view`).
18475        // Byte-parity against the lifted constant closes the split.
18476        // Peer of the sibling
18477        // [`crate::supervisor::default_max_restarts_helper_routes_through_lifted_default`]
18478        // + [`crate::supervisor::supervisor_spec_default_max_restarts_routes_through_lifted_default`]
18479        // composition pins that close the same routing on the two
18480        // sibling entry points onto the shared substrate constant.
18481        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18482        let view = c.supervisor_view().expect(
18483            "supervisor_view must materialize a SupervisorSpec for a \
18484             :kind Supervisor Caixa carrying a None :max-restarts",
18485        );
18486        assert_eq!(
18487            view.max_restarts(),
18488            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
18489            "supervisor_view must degrade the outer \
18490             Caixa::max_restarts() None arm onto the lifted \
18491             SUPERVISOR_MAX_RESTARTS_DEFAULT typed pub const (got {}, \
18492             expected {})",
18493            view.max_restarts(),
18494            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
18495        );
18496    }
18497
18498    #[test]
18499    fn restart_window_returns_restart_window_option_verbatim_across_permutations() {
18500        // Value-shape pin: [`Caixa::restart_window`] returns the
18501        // `:restart-window` typed `Option<String>` verbatim as an
18502        // `Option<&str>`, borrowed from the typed slot's own storage,
18503        // byte-equal across the author-omitted `None` arm and each of
18504        // the representative fixtures in the accept-set — the canonical
18505        // `"60s"` from `{intensity, 5, 60}`, the sibling
18506        // canonical-magnitude forms (`"5m"` / `"1h"` / `"500ms"` / `"30"`
18507        // / `"0s"`) the shared codec's positive-set sweep pin covers,
18508        // plus a past-the-guard sentinel (`"1.5s"` — the fractional-
18509        // seconds drift the sibling [`Self::validate_restart_window`]
18510        // gate refuses; the accessor must ship the raw slot verbatim
18511        // so struct-literal fixtures continue to expose the drift at
18512        // the accessor boundary). Third outer top-level [`Caixa`]
18513        // supervisor-tree flat-spread pin — extends the sub-family onto
18514        // the sibling `Option<&str>` raw-duration-string arm.
18515        for window in [
18516            None,
18517            Some("60s"),
18518            Some("5m"),
18519            Some("1h"),
18520            Some("500ms"),
18521            Some("1.5s"),
18522            Some(""),
18523        ] {
18524            let c = caixa_with_restart_window(window);
18525            assert_eq!(
18526                c.restart_window(),
18527                window,
18528                "Caixa::restart_window must return :restart-window \
18529                 verbatim as Option<&str> (got {:?}, expected {window:?})",
18530                c.restart_window(),
18531            );
18532            assert_eq!(
18533                c.restart_window(),
18534                c.restart_window.as_deref(),
18535                "Caixa::restart_window accessor and \
18536                 self.restart_window.as_deref() field access must \
18537                 byte-equal — a byte-level drift would silently split \
18538                 the paired Caixa::declared_supervisor_slots \
18539                 presence-probe arm from the \
18540                 Caixa::validate_restart_window shared-codec gate and \
18541                 the Caixa::supervisor_view soft-swallowing fold",
18542            );
18543        }
18544    }
18545
18546    #[test]
18547    fn restart_window_projects_slice_by_borrow() {
18548        // The by-borrow pin: [`Caixa::restart_window`] returns
18549        // `Option<&str>` by borrow — the returned string slice borrows
18550        // the underlying `Option<String>` storage of the `:restart-window`
18551        // slot and the accessor must not clone on every call. Peer of
18552        // the sibling outer top-level [`Caixa`] `Option<&str>`-return
18553        // by-borrow pins on the universal-axis scalar family
18554        // (`licenca_projects_option_ref_by_borrow` /
18555        // `descricao_projects_option_ref_by_borrow` and siblings) —
18556        // extended onto the M2 supervisor-tree flat-spread
18557        // `Option<&str>` raw-duration-string axis.
18558        for window in [None, Some("60s"), Some("5m"), Some("")] {
18559            let c = caixa_with_restart_window(window);
18560            let first = c.restart_window();
18561            let second = c.restart_window();
18562            assert_eq!(
18563                first, second,
18564                "Caixa::restart_window must be idempotent — two \
18565                 successive calls on the same &self must return the \
18566                 same Option<&str>",
18567            );
18568            if let (Some(a), Some(b)) = (first, second) {
18569                assert_eq!(
18570                    a.as_ptr(),
18571                    b.as_ptr(),
18572                    "Caixa::restart_window must borrow the underlying \
18573                     String storage — two successive Some-arm calls must \
18574                     return slices with the same backing pointer (a fresh \
18575                     String clone would change the pointer on every call)",
18576                );
18577            }
18578            assert_eq!(
18579                first, window,
18580                "Caixa::restart_window must return :restart-window \
18581                 verbatim by borrow — got {first:?}, expected {window:?}",
18582            );
18583        }
18584    }
18585
18586    #[test]
18587    fn declared_supervisor_slots_restart_window_arm_routes_through_accessor() {
18588        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
18589        // `:restart-window` presence-probe arm must key off
18590        // [`Caixa::restart_window`], not the raw
18591        // `self.restart_window.is_some()` field-probe. Structurally:
18592        // every `Caixa { restart_window: Some(_), .. }` must push
18593        // `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` onto the declared-slot
18594        // list, and a `Caixa { restart_window: None, .. }` must NOT
18595        // push the label. Peer of the sibling
18596        // `declared_supervisor_slots_max_restarts_arm_routes_through_accessor`
18597        // routing pin.
18598        for window in ["60s", "5m", "1h", "500ms", "1.5s", ""] {
18599            let c = caixa_with_restart_window(Some(window));
18600            let slots = c.declared_supervisor_slots();
18601            assert!(
18602                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
18603                "declared_supervisor_slots must push \
18604                 SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when \
18605                 `:restart-window` is Some({window:?}) — the accessor \
18606                 and the enumerator gate must route through the same \
18607                 substrate-primitive typed dispatch on the outer \
18608                 :restart-window presence bit (got slots={slots:?})",
18609            );
18610        }
18611        let c = caixa_with_restart_window(None);
18612        let slots = c.declared_supervisor_slots();
18613        assert!(
18614            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
18615            "declared_supervisor_slots must NOT push \
18616             SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when `:restart-window` \
18617             is None — the author-omitted arm must route through the \
18618             accessor's None-return unchanged (got slots={slots:?})",
18619        );
18620    }
18621
18622    #[test]
18623    fn validate_restart_window_arm_routes_through_accessor() {
18624        // Composition pin: [`Caixa::validate_restart_window`]'s
18625        // shared-codec fold arm must key off [`Caixa::restart_window`],
18626        // not the raw `self.restart_window.as_deref()` field-projection.
18627        // Structurally: (1) `None` → `Ok(())` (the "omit the slot to
18628        // express no reset" canonical shape); (2) a canonical `Some`
18629        // arm (`"60s"`) → `Ok(())`; (3) a codec-rejected `Some` arm
18630        // (`"1.5s"`) → `Err(RestartWindowMalformed { restart_window,
18631        // .. })` carrying the offending raw string verbatim. The three
18632        // arms jointly pin that the validator's raw-string binding is
18633        // the accessor's return, not a peer projection — any future
18634        // silent detour that had the accessor collapse `Some("")` to
18635        // `None` would silently absorb the empty-after-trim refusal
18636        // case at the accessor boundary.
18637        caixa_with_restart_window(None)
18638            .validate_restart_window()
18639            .expect("None :restart-window must validate through the accessor");
18640        caixa_with_restart_window(Some("60s"))
18641            .validate_restart_window()
18642            .expect("canonical :restart-window \"60s\" must validate through the accessor");
18643        let err = caixa_with_restart_window(Some("1.5s"))
18644            .validate_restart_window()
18645            .expect_err("fractional-seconds :restart-window must fail through the accessor");
18646        assert!(
18647            matches!(
18648                err,
18649                ManifestError::RestartWindowMalformed { ref restart_window, .. }
18650                    if restart_window == "1.5s"
18651            ),
18652            "validator must carry the offending raw string verbatim \
18653             from the accessor's borrowed &str (got {err:?})",
18654        );
18655    }
18656
18657    #[test]
18658    fn supervisor_view_restart_window_arm_routes_through_accessor() {
18659        // Composition pin: [`Caixa::supervisor_view`]'s
18660        // per-`:restart-window` [`SupervisorSpec`] construction arm
18661        // must key off [`Caixa::restart_window`]'s soft-swallowing
18662        // `.and_then(|s| duration_codec::parse(s).ok())` fold, not the
18663        // raw `self.restart_window.as_deref().and_then(…)` field-fold.
18664        // Structurally: (1) `None` → `SupervisorSpec.restart_window ==
18665        // None` (the "never reset" sentinel); (2) canonical `Some("60s")`
18666        // → `SupervisorSpec.restart_window == Some(Duration::from_secs(60))`
18667        // (the shared codec's canonical parse); (3) codec-rejected
18668        // `Some("1.5s")` → `SupervisorSpec.restart_window == None`
18669        // (the soft-swallow preserving the view's best-effort shape).
18670        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18671        let view = c.supervisor_view().expect("Supervisor kind has a view");
18672        assert_eq!(
18673            view.restart_window(),
18674            None,
18675            "supervisor_view must project outer None :restart-window \
18676             onto None on the composed SupervisorSpec (never-reset \
18677             sentinel) through the accessor's None-return unchanged",
18678        );
18679
18680        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("60s"));
18681        let view = c.supervisor_view().expect("Supervisor kind has a view");
18682        assert_eq!(
18683            view.restart_window(),
18684            Some(std::time::Duration::from_secs(60)),
18685            "supervisor_view must fold outer Some(\"60s\") through the \
18686             shared duration_codec into Duration::from_secs(60) on the \
18687             composed SupervisorSpec (accessor's Some(&str) → codec \
18688             parse → Some(Duration))",
18689        );
18690
18691        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("1.5s"));
18692        let view = c.supervisor_view().expect("Supervisor kind has a view");
18693        assert_eq!(
18694            view.restart_window(),
18695            None,
18696            "supervisor_view must soft-swallow the shared-codec parse \
18697             failure to None (the view's best-effort shape the sibling \
18698             manifest-level validate_restart_window surfaces as \
18699             RestartWindowMalformed); the accessor's raw-string return \
18700             is the single input every downstream consumer keys off",
18701        );
18702    }
18703
18704    // ── Caixa::upgrade_from — outer top-level &[UpgradeFromEntry] composite-slice accessor ──
18705
18706    fn caixa_with_upgrade_from(upgrade_from: Vec<crate::upgrade::UpgradeFromEntry>) -> Caixa {
18707        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18708        c.upgrade_from = upgrade_from;
18709        c
18710    }
18711
18712    #[test]
18713    fn upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations() {
18714        // The canonical per-`Caixa` `:upgrade-from` M2 typed-slot
18715        // outer-composite `&[UpgradeFromEntry]`-return slice-shape
18716        // pin: [`Caixa::upgrade_from`] must return the `:upgrade-from`
18717        // typed `Vec<UpgradeFromEntry>` verbatim as a
18718        // `&[UpgradeFromEntry]` slice-view over the same backing
18719        // buffer the raw `self.upgrade_from.as_slice()` field access
18720        // borrows from, element-equal across every representative
18721        // fixture in the accept-set — `[]` (the "no hot-upgrade path
18722        // declared" arm every `defcaixa` without an `:upgrade-from`
18723        // block carries; `#[serde(default)]` folds an omitted slot
18724        // onto `Vec::new()`), a canonical single-entry `Restart`
18725        // fixture (the shape most Servicos carry — a single prior
18726        // version with the fallback strategy), a canonical multi-
18727        // entry list carrying every typed instruction variant
18728        // (`LoadModule` / `StateChange` / `SoftPurge` / `Purge` /
18729        // `Restart`), and a past-the-guard sentinel — a duplicate-
18730        // `:from` `[(0.1.0, Restart), (0.1.0, Restart)]` entry pair
18731        // ([`crate::upgrade::validate_upgrade_from`] rejects through
18732        // `DuplicateFrom { from: "0.1.0" }` but the accessor must
18733        // ship the raw slot verbatim so struct-literal fixtures
18734        // continue to expose the duplicate at the accessor boundary).
18735        //
18736        // Pins against a future silent detour that returned an owned
18737        // `Vec<UpgradeFromEntry>` (which would type-check but silently
18738        // clone on every accessor call, breaking the zero-cost
18739        // projection every peer sibling slice accessor carries), a
18740        // `[dup, dup] → [dup]` dedup collapse (which would silently
18741        // absorb the `DuplicateFrom` refusal case at the accessor
18742        // boundary and the [`crate::StandardLayout::verify`] cross-
18743        // entry gate would silently accept a struct-literal `Caixa`
18744        // carrying the drift), a reference to an operator-resolved
18745        // overlay (the future per-cluster `:upgrade-overrides` slot
18746        // — its resolution must land at exactly this accessor body,
18747        // not silently divert the raw slot away from a second
18748        // consumer), or an axis-shuffled projection (a future detour
18749        // that reordered entries through the accessor would silently
18750        // split the paired [`crate::StandardLayout::verify`] per-
18751        // `:upgrade-from` shape gate's traversal input from the peer
18752        // [`crate::render::servico_m2_overlay`] emitter's projection
18753        // input, since the operator's hot-upgrade dispatch matches
18754        // per-`:from` and axis reordering would silently split the
18755        // per-entry script-path existence probe's iteration order
18756        // from the M2 overlay emitter's serialized-entry order).
18757        //
18758        // First outer top-level [`Caixa`] `&[Composite]`-return
18759        // slice accessor pin on the substrate primitive for M2 / M3
18760        // typed-slot vec-carry axes — opens the outer-`Caixa`
18761        // `&[Composite]` composite-slice projection pattern the
18762        // sibling `:children` [`crate::supervisor::ChildSpec`] /
18763        // `:membros` [`crate::aplicacao::Membro`] / `:contratos`
18764        // [`crate::aplicacao::WitContract`] future outer-composite-
18765        // slice pins fold on. Peer of the closed outer-`Caixa`
18766        // scalar `Option<&Composite>` composite-reference family the
18767        // sibling `limits` / `behavior` / `politicas` / `placement`
18768        // / `entrada` `..._returns_..._option_ref_verbatim_across_
18769        // permutations` pins closed (b2bd9d7 → e4128e4) — extends
18770        // the "byte-equal, borrow-shared" outer-accessor discipline
18771        // onto the outer-`Caixa` `&[Composite]` vec-carry altitude.
18772        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18773        let fixtures: Vec<Vec<UpgradeFromEntry>> = vec![
18774            vec![],
18775            vec![UpgradeFromEntry {
18776                from: "0.0.1".into(),
18777                instructions: vec![UpgradeInstruction::Restart],
18778            }],
18779            vec![
18780                UpgradeFromEntry {
18781                    from: "0.0.1".into(),
18782                    instructions: vec![
18783                        UpgradeInstruction::LoadModule {
18784                            module: "demo".into(),
18785                        },
18786                        UpgradeInstruction::SoftPurge {
18787                            module: "demo".into(),
18788                        },
18789                    ],
18790                },
18791                UpgradeFromEntry {
18792                    from: "0.0.2".into(),
18793                    instructions: vec![
18794                        UpgradeInstruction::StateChange {
18795                            script: "servicos/upgrade.lisp".into(),
18796                        },
18797                        UpgradeInstruction::Purge {
18798                            module: "demo".into(),
18799                        },
18800                        UpgradeInstruction::Restart,
18801                    ],
18802                },
18803            ],
18804            vec![
18805                UpgradeFromEntry {
18806                    from: "0.1.0".into(),
18807                    instructions: vec![UpgradeInstruction::Restart],
18808                },
18809                UpgradeFromEntry {
18810                    from: "0.1.0".into(),
18811                    instructions: vec![UpgradeInstruction::Restart],
18812                },
18813            ],
18814        ];
18815        for upgrade_from in fixtures {
18816            let c = caixa_with_upgrade_from(upgrade_from.clone());
18817            assert_eq!(
18818                c.upgrade_from(),
18819                upgrade_from.as_slice(),
18820                "Caixa::upgrade_from must return :upgrade-from \
18821                 verbatim (got {:?}, expected {upgrade_from:?})",
18822                c.upgrade_from(),
18823            );
18824            assert_eq!(
18825                c.upgrade_from(),
18826                c.upgrade_from.as_slice(),
18827                "Caixa::upgrade_from must element-equal the raw \
18828                 `self.upgrade_from.as_slice()` field access across \
18829                 every value in the Vec<UpgradeFromEntry> accept-set",
18830            );
18831            assert_eq!(
18832                c.upgrade_from().is_empty(),
18833                c.upgrade_from.is_empty(),
18834                "Caixa::upgrade_from().is_empty() must byte-equal \
18835                 self.upgrade_from.is_empty() — a presence-bit drift \
18836                 would silently split the paired \
18837                 Caixa::declared_servico_slots M2 declared-slot \
18838                 enumerator's presence probe from the peer \
18839                 crate::render::servico_m2_overlay M2 overlay \
18840                 emitter's presence gate",
18841            );
18842        }
18843    }
18844
18845    #[test]
18846    fn declared_servico_slots_upgrade_from_arm_routes_through_accessor() {
18847        // Composition pin: [`Caixa::declared_servico_slots`]'s
18848        // `:upgrade-from` presence-probe arm must key off
18849        // [`Caixa::upgrade_from`], not the raw
18850        // `self.upgrade_from.is_empty()` field-probe. Structurally: a
18851        // `Caixa { upgrade_from: vec![UpgradeFromEntry { from: "0.0.1",
18852        // instructions: vec![Restart] }], .. }` must push
18853        // `M2_AUTHOR_KEY_UPGRADE_FROM` onto the declared-slot list
18854        // (the presence bit is non-empty, so the M2 kind-coherence
18855        // gate must surface the slot as "declared"), and a `Caixa {
18856        // upgrade_from: vec![], .. }` must NOT push the label (the
18857        // "author omitted the slot entirely" arm — the empty-slice
18858        // partition the serde-default folds onto). The pair jointly
18859        // pins the accessor + declared-slot enumerator composition:
18860        // any future silent detour that had the accessor collapse
18861        // `[Restart]` to `[]` (a `.filter(|e| !e.instructions.
18862        // is_empty())` projection) would silently absorb the
18863        // "declared but degenerate" arm at the accessor boundary and
18864        // the [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-
18865        // coherence gate would silently accept a struct-literal
18866        // `Caixa` carrying the drift.
18867        //
18868        // Peer of the sibling
18869        // `declared_servico_slots_limits_arm_routes_through_accessor`
18870        // (b2bd9d7) and
18871        // `declared_servico_slots_behavior_arm_routes_through_accessor`
18872        // (35d8b52) composition pins on the sibling `:limits` /
18873        // `:behavior` outer-`Option<&Composite>` arms — same "the
18874        // enumerator gate must route through the substrate-primitive
18875        // typed dispatch" discipline extended onto the third M2
18876        // Servico-runtime slot axis, closing the enumerator's routing
18877        // invariant on every M2 arm.
18878        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18879        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
18880            from: "0.0.1".into(),
18881            instructions: vec![UpgradeInstruction::Restart],
18882        }]);
18883        let slots = c.declared_servico_slots();
18884        assert!(
18885            slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
18886            "declared_servico_slots must push \
18887             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
18888             non-empty — the accessor and the enumerator gate must \
18889             route through the same substrate-primitive typed \
18890             dispatch on the outer :upgrade-from presence bit (got \
18891             slots={slots:?})",
18892        );
18893        let c = caixa_with_upgrade_from(vec![]);
18894        let slots = c.declared_servico_slots();
18895        assert!(
18896            !slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
18897            "declared_servico_slots must NOT push \
18898             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
18899             empty — the author-omitted arm must route through the \
18900             accessor's empty-slice return unchanged (got \
18901             slots={slots:?})",
18902        );
18903    }
18904
18905    #[test]
18906    fn servico_m2_overlay_upgrade_from_arm_routes_through_accessor() {
18907        // Composition pin: [`crate::render::servico_m2_overlay`]'s
18908        // per-`:upgrade-from` M2 overlay emit arm must key off
18909        // [`Caixa::upgrade_from`], not the raw
18910        // `!caixa.upgrade_from.is_empty()` presence gate + the
18911        // `serde_yaml::to_value(&caixa.upgrade_from)` projection.
18912        // Structurally: a `Caixa { upgrade_from: vec![UpgradeFromEntry
18913        // { from: "0.0.1", instructions: vec![Restart] }], .. }` must
18914        // surface the `M2_KEY_UPGRADE_FROM` key with a per-entry
18915        // sequence in the overlay (the emitter fans onto the serde
18916        // slice-serialization), and a `Caixa { upgrade_from: vec![],
18917        // .. }` must omit the key entirely (the empty-slice
18918        // partition — the `!.is_empty()` outer gate elides the key
18919        // when the author omitted the slot). The pair jointly pins
18920        // the accessor + M2 overlay emitter composition: any future
18921        // silent detour that had the accessor return a fresh-cloned
18922        // `Vec<UpgradeFromEntry>` copy would silently break the
18923        // reference-identity pin the peer per-entry
18924        // `serde_yaml::to_value(caixa.upgrade_from())` projection
18925        // reads from — the projection would clone once per accessor
18926        // call instead of borrowing the storage buffer verbatim.
18927        //
18928        // Peer of the sibling
18929        // `servico_m2_overlay_limits_arm_routes_through_accessor`
18930        // (b2bd9d7) and
18931        // `servico_m2_overlay_behavior_arm_routes_through_accessor`
18932        // (35d8b52) composition pins on the sibling `:limits` /
18933        // `:behavior` outer-`Option<&Composite>` arms — same "the
18934        // M2 overlay emitter must route through the substrate-
18935        // primitive typed dispatch" discipline extended onto the
18936        // third M2 Servico-runtime slot axis, closing the overlay
18937        // emitter's routing invariant on every M2 arm.
18938        use crate::render::{M2_KEY_UPGRADE_FROM, servico_m2_overlay};
18939        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18940        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
18941            from: "0.0.1".into(),
18942            instructions: vec![UpgradeInstruction::Restart],
18943        }]);
18944        let overlay = servico_m2_overlay(&c).unwrap();
18945        assert!(
18946            overlay.contains_key(M2_KEY_UPGRADE_FROM),
18947            "servico_m2_overlay must surface M2_KEY_UPGRADE_FROM when \
18948             `:upgrade-from` is non-empty — the accessor and the M2 \
18949             overlay emitter must route through the same substrate- \
18950             primitive typed dispatch on the outer :upgrade-from \
18951             slice (got overlay={overlay:?})",
18952        );
18953        let c = caixa_with_upgrade_from(vec![]);
18954        let overlay = servico_m2_overlay(&c).unwrap();
18955        assert!(
18956            !overlay.contains_key(M2_KEY_UPGRADE_FROM),
18957            "servico_m2_overlay must omit M2_KEY_UPGRADE_FROM when \
18958             `:upgrade-from` is empty — the empty-slice partition \
18959             must route through the accessor's empty-slice return \
18960             unchanged (got overlay={overlay:?})",
18961        );
18962    }
18963
18964    #[test]
18965    fn upgrade_from_projects_slice_by_borrow() {
18966        // The by-borrow pin: [`Caixa::upgrade_from`] returns
18967        // `&[UpgradeFromEntry]` by borrow — the returned slice
18968        // borrows the underlying `Vec<UpgradeFromEntry>` storage of
18969        // the `:upgrade-from` slot and the accessor must not clone
18970        // the backing `Vec` on every call. Peer of the sibling
18971        // outer top-level [`Caixa`] `&[T]`-return by-borrow pins
18972        // (`autores_projects_slice_by_borrow` b5d813f,
18973        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
18974        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
18975        // `exe_projects_slice_by_borrow` 65d9527,
18976        // `servicos_projects_slice_by_borrow` 611f78b,
18977        // `deps_projects_slice_by_borrow` ad34b4e,
18978        // `deps_dev_projects_slice_by_borrow` f7fd81e) on the
18979        // sibling outer top-level [`Caixa`] scalar-element `&[T]`
18980        // axes — extended here to the first outer-`Caixa`
18981        // composite-element `&[Composite]` axis: the accessor's
18982        // returned slice must borrow from `&self` (the returned
18983        // reference's lifetime is tied to `&self`), and calling the
18984        // accessor twice on the same [`Caixa`] must yield slices
18985        // that are pointer-equal (the underlying byte-buffer is the
18986        // storage `Vec`'s allocation, not a fresh copy) as well as
18987        // value-equal (idempotent, no side effects on `&self`).
18988        //
18989        // Pins against a future silent detour that returned an owned
18990        // `Vec<UpgradeFromEntry>` (which would type-check but
18991        // silently clone on every call), a `&Vec<UpgradeFromEntry>`
18992        // return (which would leak the backing `Vec`'s
18993        // grow/push/reserve surface no downstream consumer reaches
18994        // for), or a one-arm-only accessor that returned a
18995        // saturating value on some sentinel input.
18996        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18997        for upgrade_from in [
18998            vec![],
18999            vec![UpgradeFromEntry {
19000                from: "0.0.1".into(),
19001                instructions: vec![UpgradeInstruction::Restart],
19002            }],
19003            vec![
19004                UpgradeFromEntry {
19005                    from: "0.0.1".into(),
19006                    instructions: vec![UpgradeInstruction::Restart],
19007                },
19008                UpgradeFromEntry {
19009                    from: "0.0.2".into(),
19010                    instructions: vec![UpgradeInstruction::SoftPurge {
19011                        module: "demo".into(),
19012                    }],
19013                },
19014            ],
19015        ] {
19016            let c = caixa_with_upgrade_from(upgrade_from.clone());
19017            let first = c.upgrade_from();
19018            let second = c.upgrade_from();
19019            assert_eq!(
19020                first, second,
19021                "Caixa::upgrade_from must be idempotent — two \
19022                 successive calls on the same &self must return the \
19023                 same &[UpgradeFromEntry]",
19024            );
19025            assert_eq!(
19026                first.as_ptr(),
19027                second.as_ptr(),
19028                "Caixa::upgrade_from must borrow the underlying \
19029                 Vec<UpgradeFromEntry> storage — two successive calls \
19030                 must return slices with the same backing pointer (a \
19031                 fresh Vec<UpgradeFromEntry> clone would change the \
19032                 pointer on every call)",
19033            );
19034            assert_eq!(
19035                first,
19036                upgrade_from.as_slice(),
19037                "Caixa::upgrade_from must return :upgrade-from \
19038                 verbatim by borrow — got {first:?}, expected \
19039                 {upgrade_from:?}",
19040            );
19041        }
19042    }
19043
19044    // ── Caixa::children — outer top-level &[ChildSpec] composite-slice accessor ──
19045
19046    fn caixa_with_children(children: Vec<crate::supervisor::ChildSpec>) -> Caixa {
19047        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19048        c.children = children;
19049        c
19050    }
19051
19052    #[test]
19053    fn children_returns_children_slice_verbatim_across_permutations() {
19054        // The canonical per-`Caixa` `:children` M2 supervisor-tree-slot
19055        // outer-composite `&[ChildSpec]`-return slice-shape pin:
19056        // [`Caixa::children`] must return the `:children` typed
19057        // `Vec<ChildSpec>` verbatim as a `&[ChildSpec]` slice-view over
19058        // the same backing buffer the raw `self.children.as_slice()`
19059        // field access borrows from, element-equal across every
19060        // representative fixture in the accept-set — `[]` (the "no
19061        // static children declared" arm every non-`Supervisor`-kind
19062        // `defcaixa` carries by `#[serde(default)]` and every
19063        // `SimpleOneForOne` supervisor carries by cross-slot refusal),
19064        // a canonical single-child `Permanent` fixture (the shape
19065        // most `OneForOne` supervisors carry — a single long-running
19066        // worker child), a canonical multi-child list carrying every
19067        // typed restart-policy variant (`Permanent` / `Transient` /
19068        // `Temporary`), and a past-the-guard sentinel — a duplicate
19069        // `:caixa` `[("w", ...), ("w", ...)]` entry pair
19070        // ([`crate::SupervisorSpec::validate`] rejects through
19071        // `DuplicateChildNome { nome: "w" }` but the accessor must
19072        // ship the raw slot verbatim so struct-literal fixtures
19073        // continue to expose the duplicate at the accessor boundary).
19074        //
19075        // Pins against a future silent detour that returned an owned
19076        // `Vec<ChildSpec>` (which would type-check but silently clone
19077        // on every accessor call, breaking the zero-cost projection
19078        // every peer sibling slice accessor carries), a `[dup, dup] →
19079        // [dup]` dedup collapse (which would silently absorb the
19080        // `DuplicateChildNome` refusal case at the accessor boundary
19081        // and the [`crate::StandardLayout::verify`] cross-child gate
19082        // would silently accept a struct-literal `Caixa` carrying the
19083        // drift), a reference to an operator-resolved overlay (the
19084        // future per-cluster `:children-overrides` slot — its
19085        // resolution must land at exactly this accessor body, not
19086        // silently divert the raw slot away from a second consumer),
19087        // or an axis-shuffled projection (a future detour that
19088        // reordered children through the accessor would silently
19089        // split the paired [`crate::StandardLayout::verify`] per-
19090        // supervisor gate's traversal input from the peer
19091        // [`Self::supervisor_view`] fold-in path's clone-order input,
19092        // since the OTP `RestForOne` restart strategy dispatches on
19093        // declared child order and axis reordering would silently
19094        // split the operator's per-cluster restart-fan-out order
19095        // from the caixa.lisp source-order).
19096        //
19097        // Second outer top-level [`Caixa`] `&[Composite]`-return slice
19098        // accessor pin on the substrate primitive for M2 / M3 typed-
19099        // slot vec-carry axes — folds on the outer-`Caixa`
19100        // `&[Composite]` composite-slice sub-family the sibling
19101        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19102        // (2a1f907) pin opened, peer at the outer altitude of the
19103        // closed inner-`SupervisorSpec` `SupervisorSpec::children`
19104        // (bc92bce) accessor on the same OTP-supervisor static-child-
19105        // list axis.
19106        use crate::supervisor::{ChildSpec, RestartPolicy};
19107        let fixtures: Vec<Vec<ChildSpec>> = vec![
19108            vec![],
19109            vec![ChildSpec {
19110                caixa: "worker".into(),
19111                versao: "^0.1".into(),
19112                restart: RestartPolicy::Permanent,
19113            }],
19114            vec![
19115                ChildSpec {
19116                    caixa: "worker-a".into(),
19117                    versao: "^0.1".into(),
19118                    restart: RestartPolicy::Permanent,
19119                },
19120                ChildSpec {
19121                    caixa: "worker-b".into(),
19122                    versao: "^0.1".into(),
19123                    restart: RestartPolicy::Transient,
19124                },
19125                ChildSpec {
19126                    caixa: "worker-c".into(),
19127                    versao: "^0.1".into(),
19128                    restart: RestartPolicy::Temporary,
19129                },
19130            ],
19131            vec![
19132                ChildSpec {
19133                    caixa: "w".into(),
19134                    versao: "^0.1".into(),
19135                    restart: RestartPolicy::Permanent,
19136                },
19137                ChildSpec {
19138                    caixa: "w".into(),
19139                    versao: "^0.1".into(),
19140                    restart: RestartPolicy::Permanent,
19141                },
19142            ],
19143        ];
19144        for children in fixtures {
19145            let c = caixa_with_children(children.clone());
19146            assert_eq!(
19147                c.children(),
19148                children.as_slice(),
19149                "Caixa::children must return :children verbatim \
19150                 (got {:?}, expected {children:?})",
19151                c.children(),
19152            );
19153            assert_eq!(
19154                c.children(),
19155                c.children.as_slice(),
19156                "Caixa::children must element-equal the raw \
19157                 `self.children.as_slice()` field access across \
19158                 every value in the Vec<ChildSpec> accept-set",
19159            );
19160            assert_eq!(
19161                c.children().is_empty(),
19162                c.children.is_empty(),
19163                "Caixa::children().is_empty() must byte-equal \
19164                 self.children.is_empty() — a presence-bit drift \
19165                 would silently split the paired \
19166                 Caixa::declared_supervisor_slots supervisor-tree \
19167                 declared-slot enumerator's presence probe from the \
19168                 peer Caixa::supervisor_view typed-view composer's \
19169                 fold-in path",
19170            );
19171        }
19172    }
19173
19174    #[test]
19175    fn declared_supervisor_slots_children_arm_routes_through_accessor() {
19176        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
19177        // `:children` presence-probe arm must key off
19178        // [`Caixa::children`], not the raw
19179        // `!self.children.is_empty()` field-probe. Structurally: a
19180        // `Caixa { children: vec![ChildSpec { caixa: "w", versao:
19181        // "^0.1", restart: Permanent }], .. }` must push
19182        // `SUPERVISOR_AUTHOR_KEY_CHILDREN` onto the declared-slot list
19183        // (the presence bit is non-empty, so the supervisor-tree
19184        // kind-coherence gate must surface the slot as "declared"),
19185        // and a `Caixa { children: vec![], .. }` must NOT push the
19186        // label (the "author omitted the slot entirely" arm — the
19187        // empty-slice partition the serde-default folds onto). The
19188        // pair jointly pins the accessor + declared-slot enumerator
19189        // composition: any future silent detour that had the accessor
19190        // collapse `[Permanent]` to `[]` (a `.filter(|c| c.nome() !=
19191        // "__reserved__")` projection) would silently absorb the
19192        // "declared but degenerate" arm at the accessor boundary and
19193        // the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
19194        // kind-coherence gate would silently accept a struct-literal
19195        // `Caixa` carrying the drift.
19196        //
19197        // Peer of the sibling
19198        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19199        // (2a1f907) on the M2 `:upgrade-from` composite-slice arm —
19200        // same "the enumerator gate must route through the substrate-
19201        // primitive typed dispatch" discipline extended onto the
19202        // supervisor-tree `:children` composite-slice arm.
19203        use crate::supervisor::{ChildSpec, RestartPolicy};
19204        let c = caixa_with_children(vec![ChildSpec {
19205            caixa: "w".into(),
19206            versao: "^0.1".into(),
19207            restart: RestartPolicy::Permanent,
19208        }]);
19209        let slots = c.declared_supervisor_slots();
19210        assert!(
19211            slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
19212            "declared_supervisor_slots must push \
19213             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
19214             non-empty — the accessor and the enumerator gate must \
19215             route through the same substrate-primitive typed \
19216             dispatch on the outer :children presence bit (got \
19217             slots={slots:?})",
19218        );
19219        let c = caixa_with_children(vec![]);
19220        let slots = c.declared_supervisor_slots();
19221        assert!(
19222            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
19223            "declared_supervisor_slots must NOT push \
19224             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
19225             empty — the author-omitted arm must route through the \
19226             accessor's empty-slice return unchanged (got \
19227             slots={slots:?})",
19228        );
19229    }
19230
19231    #[test]
19232    fn supervisor_view_children_arm_routes_through_accessor() {
19233        // Composition pin: [`Caixa::supervisor_view`]'s per-`:children`
19234        // fold-in arm must key off [`Caixa::children`], not the raw
19235        // `self.children.clone()` field-clone. Structurally: a `Caixa {
19236        // kind: Supervisor, estrategia: Some(OneForOne), children:
19237        // vec![ChildSpec { caixa: "w", .. }], .. }` must fold the
19238        // per-child list through the accessor into the typed
19239        // [`SupervisorSpec`] view's `children` field verbatim — every
19240        // entry the accessor surfaces must land in the view's
19241        // `children` slot in the same order. The pair jointly pins the
19242        // accessor + view-composer composition: any future silent
19243        // detour that had the accessor return a fresh-cloned
19244        // `Vec<ChildSpec>` copy would silently break the reference-
19245        // identity pin the peer `supervisor_view` fold-in path reads
19246        // from — the fold would clone once more per accessor call
19247        // instead of borrowing the storage buffer verbatim once.
19248        //
19249        // Peer of the sibling
19250        // `supervisor_view_kind_gate_routes_through_accessor` (35d8b52-
19251        // family) composition pin on the peer kind-gate arm — same
19252        // "the view composer must route through the substrate-
19253        // primitive typed dispatch" discipline extended onto the
19254        // per-`:children` fold-in arm, closing the supervisor-view
19255        // composer's routing invariant on the composite-slice input.
19256        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
19257        let mut c = caixa_with_children(vec![
19258            ChildSpec {
19259                caixa: "worker-a".into(),
19260                versao: "^0.1".into(),
19261                restart: RestartPolicy::Permanent,
19262            },
19263            ChildSpec {
19264                caixa: "worker-b".into(),
19265                versao: "^0.1".into(),
19266                restart: RestartPolicy::Transient,
19267            },
19268        ]);
19269        c.kind = crate::CaixaKind::Supervisor;
19270        c.estrategia = Some(RestartStrategy::OneForOne);
19271        let view = c
19272            .supervisor_view()
19273            .expect("Supervisor kind must produce a supervisor_view");
19274        assert_eq!(
19275            view.children(),
19276            c.children(),
19277            "supervisor_view must fold Caixa::children verbatim into \
19278             SupervisorSpec::children — the accessor and the view \
19279             composer must route through the same substrate-primitive \
19280             typed dispatch on the outer :children slice (got view \
19281             children={:?}, expected {:?})",
19282            view.children(),
19283            c.children(),
19284        );
19285    }
19286
19287    #[test]
19288    fn children_projects_slice_by_borrow() {
19289        // The by-borrow pin: [`Caixa::children`] returns
19290        // `&[ChildSpec]` by borrow — the returned slice borrows the
19291        // underlying `Vec<ChildSpec>` storage of the `:children` slot
19292        // and the accessor must not clone the backing `Vec` on every
19293        // call. Peer of the sibling outer top-level [`Caixa`]
19294        // `&[T]`-return by-borrow pins (`autores_projects_slice_by_borrow`
19295        // b5d813f, `etiquetas_projects_slice_by_borrow` 78c7d3c,
19296        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19297        // `exe_projects_slice_by_borrow` 65d9527,
19298        // `servicos_projects_slice_by_borrow` 611f78b,
19299        // `deps_projects_slice_by_borrow` ad34b4e,
19300        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19301        // `upgrade_from_projects_slice_by_borrow` 2a1f907) on the
19302        // sibling outer top-level [`Caixa`] scalar-element and
19303        // composite-element `&[T]` axes — folds on the outer-`Caixa`
19304        // composite-element `&[Composite]` axis: the accessor's
19305        // returned slice must borrow from `&self` (the returned
19306        // reference's lifetime is tied to `&self`), and calling the
19307        // accessor twice on the same [`Caixa`] must yield slices
19308        // that are pointer-equal (the underlying byte-buffer is the
19309        // storage `Vec`'s allocation, not a fresh copy) as well as
19310        // value-equal (idempotent, no side effects on `&self`).
19311        //
19312        // Pins against a future silent detour that returned an owned
19313        // `Vec<ChildSpec>` (which would type-check but silently clone
19314        // on every call), a `&Vec<ChildSpec>` return (which would leak
19315        // the backing `Vec`'s grow/push/reserve surface no downstream
19316        // consumer reaches for), or a one-arm-only accessor that
19317        // returned a saturating value on some sentinel input.
19318        use crate::supervisor::{ChildSpec, RestartPolicy};
19319        for children in [
19320            vec![],
19321            vec![ChildSpec {
19322                caixa: "w".into(),
19323                versao: "^0.1".into(),
19324                restart: RestartPolicy::Permanent,
19325            }],
19326            vec![
19327                ChildSpec {
19328                    caixa: "worker-a".into(),
19329                    versao: "^0.1".into(),
19330                    restart: RestartPolicy::Permanent,
19331                },
19332                ChildSpec {
19333                    caixa: "worker-b".into(),
19334                    versao: "^0.1".into(),
19335                    restart: RestartPolicy::Transient,
19336                },
19337            ],
19338        ] {
19339            let c = caixa_with_children(children.clone());
19340            let first = c.children();
19341            let second = c.children();
19342            assert_eq!(
19343                first, second,
19344                "Caixa::children must be idempotent — two successive \
19345                 calls on the same &self must return the same \
19346                 &[ChildSpec]",
19347            );
19348            assert_eq!(
19349                first.as_ptr(),
19350                second.as_ptr(),
19351                "Caixa::children must borrow the underlying \
19352                 Vec<ChildSpec> storage — two successive calls must \
19353                 return slices with the same backing pointer (a fresh \
19354                 Vec<ChildSpec> clone would change the pointer on \
19355                 every call)",
19356            );
19357            assert_eq!(
19358                first,
19359                children.as_slice(),
19360                "Caixa::children must return :children verbatim by \
19361                 borrow — got {first:?}, expected {children:?}",
19362            );
19363        }
19364    }
19365
19366    // ── Caixa::membros — outer top-level &[Membro] composite-slice accessor ──
19367
19368    fn caixa_aplicacao_with_membros(membros: Vec<crate::aplicacao::Membro>) -> Caixa {
19369        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19370        c.kind = CaixaKind::Aplicacao;
19371        c.membros = membros;
19372        c
19373    }
19374
19375    #[test]
19376    fn membros_returns_membros_slice_verbatim_across_permutations() {
19377        // The canonical per-`Caixa` `:membros` M3 mesh-slot outer-
19378        // composite `&[Membro]`-return slice-shape pin:
19379        // [`Caixa::membros`] must return the `:membros` typed
19380        // `Vec<Membro>` verbatim as a `&[Membro]` slice-view over the
19381        // same backing buffer the raw `self.membros.as_slice()` field
19382        // access borrows from, element-equal across every
19383        // representative fixture in the accept-set — `[]` (the "no
19384        // members declared" arm every non-`Aplicacao`-kind `defcaixa`
19385        // carries by `#[serde(default)]` and every partially-authored
19386        // Aplicacao carries before the
19387        // [`crate::AplicacaoError::MembrosEmpty`] gate fires), a
19388        // canonical single-member fixture (the shape a minimal
19389        // Aplicacao carries — one Servico wrapping one contained
19390        // computation), a canonical multi-member list carrying three
19391        // distinct entries (the canonical checkout-shape Aplicacao —
19392        // cart / pricing / auth — every canonical example carries), and
19393        // a past-the-guard sentinel — a duplicate `:caixa`
19394        // `[("cart", ...), ("cart", ...)]` entry pair
19395        // ([`crate::AplicacaoSpec::validate`] rejects through
19396        // `DuplicateMembro { nome: "cart" }` but the accessor must ship
19397        // the raw slot verbatim so struct-literal fixtures continue to
19398        // expose the duplicate at the accessor boundary).
19399        //
19400        // Pins against a future silent detour that returned an owned
19401        // `Vec<Membro>` (which would type-check but silently clone on
19402        // every accessor call, breaking the zero-cost projection every
19403        // peer sibling slice accessor carries), a `[dup, dup] → [dup]`
19404        // dedup collapse (which would silently absorb the
19405        // `DuplicateMembro` refusal case at the accessor boundary and
19406        // the [`crate::StandardLayout::verify`] cross-member gate would
19407        // silently accept a struct-literal `Caixa` carrying the drift),
19408        // a reference to an operator-resolved overlay (the future per-
19409        // cluster `:membros-overrides` slot — its resolution must land
19410        // at exactly this accessor body, not silently divert the raw
19411        // slot away from a second consumer), or an axis-shuffled
19412        // projection (a future detour that reordered members through
19413        // the accessor would silently split the paired
19414        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
19415        // traversal input from the peer [`Self::aplicacao_view`] fold-
19416        // in path's clone-order input, since the canonical `:contratos`
19417        // `:de`/`:para` and `:entrada :para` cross-slot refusal probes
19418        // read the member set through the same slice).
19419        //
19420        // Third outer top-level [`Caixa`] `&[Composite]`-return slice
19421        // accessor pin on the substrate primitive for M2 / M3 typed-
19422        // slot vec-carry axes — opens the outer-`Caixa` M3 mesh-slot
19423        // arm of the `&[Composite]` composite-slice sub-family the
19424        // sibling M2 `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19425        // (2a1f907) and
19426        // `children_returns_children_slice_verbatim_across_permutations`
19427        // (c17b51e) pins opened, peer at the outer altitude of the
19428        // closed inner-[`crate::AplicacaoSpec::membros`] (6c77e36)
19429        // accessor on the same MESH-COMPOSITION per-Aplicacao member-
19430        // list axis.
19431        use crate::aplicacao::Membro;
19432        let fixtures: Vec<Vec<Membro>> = vec![
19433            vec![],
19434            vec![Membro {
19435                caixa: "cart".into(),
19436                versao: "^0.1".into(),
19437            }],
19438            vec![
19439                Membro {
19440                    caixa: "cart".into(),
19441                    versao: "^0.1".into(),
19442                },
19443                Membro {
19444                    caixa: "pricing".into(),
19445                    versao: "^0.2".into(),
19446                },
19447                Membro {
19448                    caixa: "auth".into(),
19449                    versao: "^1.0".into(),
19450                },
19451            ],
19452            vec![
19453                Membro {
19454                    caixa: "cart".into(),
19455                    versao: "^0.1".into(),
19456                },
19457                Membro {
19458                    caixa: "cart".into(),
19459                    versao: "^0.1".into(),
19460                },
19461            ],
19462        ];
19463        for membros in fixtures {
19464            let c = caixa_aplicacao_with_membros(membros.clone());
19465            assert_eq!(
19466                c.membros(),
19467                membros.as_slice(),
19468                "Caixa::membros must return :membros verbatim \
19469                 (got {:?}, expected {membros:?})",
19470                c.membros(),
19471            );
19472            assert_eq!(
19473                c.membros(),
19474                c.membros.as_slice(),
19475                "Caixa::membros must element-equal the raw \
19476                 `self.membros.as_slice()` field access across every \
19477                 value in the Vec<Membro> accept-set",
19478            );
19479            assert_eq!(
19480                c.membros().is_empty(),
19481                c.membros.is_empty(),
19482                "Caixa::membros().is_empty() must byte-equal \
19483                 self.membros.is_empty() — a presence-bit drift would \
19484                 silently split the paired Caixa::declared_mesh_slots \
19485                 mesh declared-slot enumerator's presence probe from \
19486                 the peer Caixa::aplicacao_view typed-view composer's \
19487                 fold-in path",
19488            );
19489        }
19490    }
19491
19492    #[test]
19493    fn declared_mesh_slots_membros_arm_routes_through_accessor() {
19494        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:membros`
19495        // presence-probe arm must key off [`Caixa::membros`], not the
19496        // raw `!self.membros.is_empty()` field-probe. Structurally: a
19497        // `Caixa { membros: vec![Membro { caixa: "cart", versao:
19498        // "^0.1" }], .. }` must push `M3_AUTHOR_KEY_MEMBROS` onto the
19499        // declared-slot list (the presence bit is non-empty, so the
19500        // mesh kind-coherence gate must surface the slot as
19501        // "declared"), and a `Caixa { membros: vec![], .. }` must NOT
19502        // push the label (the "author omitted the slot entirely" arm
19503        // — the empty-slice partition the serde-default folds onto).
19504        // The pair jointly pins the accessor + declared-slot
19505        // enumerator composition: any future silent detour that had
19506        // the accessor collapse `[Membro { .. }]` to `[]` (a
19507        // `.filter(|m| m.nome() != "__reserved__")` projection) would
19508        // silently absorb the "declared but degenerate" arm at the
19509        // accessor boundary and the
19510        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
19511        // coherence gate would silently accept a struct-literal
19512        // `Caixa` carrying the drift.
19513        //
19514        // Peer of the sibling
19515        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19516        // (2a1f907) and
19517        // `declared_supervisor_slots_children_arm_routes_through_accessor`
19518        // (c17b51e) composition pins on the M2 `:upgrade-from` /
19519        // `:children` composite-slice arms — same "the enumerator gate
19520        // must route through the substrate-primitive typed dispatch"
19521        // discipline extended onto the M3 `:membros` composite-slice
19522        // arm, opening the M3 arm of the declared-slot enumerator's
19523        // routing invariant.
19524        use crate::aplicacao::Membro;
19525        let c = caixa_aplicacao_with_membros(vec![Membro {
19526            caixa: "cart".into(),
19527            versao: "^0.1".into(),
19528        }]);
19529        let slots = c.declared_mesh_slots();
19530        assert!(
19531            slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
19532            "declared_mesh_slots must push M3_AUTHOR_KEY_MEMBROS when \
19533             `:membros` is non-empty — the accessor and the enumerator \
19534             gate must route through the same substrate-primitive \
19535             typed dispatch on the outer :membros presence bit (got \
19536             slots={slots:?})",
19537        );
19538        let c = caixa_aplicacao_with_membros(vec![]);
19539        let slots = c.declared_mesh_slots();
19540        assert!(
19541            !slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
19542            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_MEMBROS \
19543             when `:membros` is empty — the author-omitted arm must \
19544             route through the accessor's empty-slice return unchanged \
19545             (got slots={slots:?})",
19546        );
19547    }
19548
19549    #[test]
19550    fn aplicacao_view_membros_arm_routes_through_accessor() {
19551        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:membros`
19552        // fold-in arm must key off [`Caixa::membros`], not the raw
19553        // `self.membros.clone()` field-clone. Structurally: a `Caixa {
19554        // kind: Aplicacao, membros: vec![Membro { caixa: "cart", .. },
19555        // Membro { caixa: "pricing", .. }], .. }` must fold the per-
19556        // member list through the accessor into the typed
19557        // [`crate::AplicacaoSpec`] view's `membros` slot verbatim —
19558        // every entry the accessor surfaces must land in the view's
19559        // `membros` slot in the same order. The pair jointly pins the
19560        // accessor + view-composer composition: any future silent
19561        // detour that had the accessor return a fresh-cloned
19562        // `Vec<Membro>` copy would silently break the reference-
19563        // identity pin the peer `aplicacao_view` fold-in path reads
19564        // from — the fold would clone once more per accessor call
19565        // instead of borrowing the storage buffer verbatim once.
19566        //
19567        // Peer of the sibling
19568        // `aplicacao_view_politicas_arm_folds_through_accessor`
19569        // (5d23d29) /
19570        // `aplicacao_view_placement_arm_folds_through_accessor`
19571        // (4fb8074) /
19572        // `aplicacao_view_entrada_arm_folds_through_accessor` (e4128e4)
19573        // composition pins on the M3 `:politicas` / `:placement` /
19574        // `:entrada` outer-`Option<&Composite>` arms — extended here to
19575        // the M3 `:membros` outer-`&[Composite]` composite-slice arm,
19576        // closing the aplicacao-view composer's routing invariant on
19577        // the composite-slice input.
19578        use crate::aplicacao::Membro;
19579        let c = caixa_aplicacao_with_membros(vec![
19580            Membro {
19581                caixa: "cart".into(),
19582                versao: "^0.1".into(),
19583            },
19584            Membro {
19585                caixa: "pricing".into(),
19586                versao: "^0.2".into(),
19587            },
19588        ]);
19589        let view = c
19590            .aplicacao_view()
19591            .expect("Aplicacao kind must produce an aplicacao_view");
19592        assert_eq!(
19593            view.membros(),
19594            c.membros(),
19595            "aplicacao_view must fold Caixa::membros verbatim into \
19596             AplicacaoSpec::membros — the accessor and the view \
19597             composer must route through the same substrate-primitive \
19598             typed dispatch on the outer :membros slice (got view \
19599             membros={:?}, expected {:?})",
19600            view.membros(),
19601            c.membros(),
19602        );
19603    }
19604
19605    #[test]
19606    fn membros_projects_slice_by_borrow() {
19607        // The by-borrow pin: [`Caixa::membros`] returns `&[Membro]` by
19608        // borrow — the returned slice borrows the underlying
19609        // `Vec<Membro>` storage of the `:membros` slot and the
19610        // accessor must not clone the backing `Vec` on every call.
19611        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
19612        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
19613        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
19614        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19615        // `exe_projects_slice_by_borrow` 65d9527,
19616        // `servicos_projects_slice_by_borrow` 611f78b,
19617        // `deps_projects_slice_by_borrow` ad34b4e,
19618        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19619        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
19620        // `children_projects_slice_by_borrow` c17b51e) on the sibling
19621        // outer top-level [`Caixa`] scalar-element and composite-
19622        // element `&[T]` axes — folds on the outer-`Caixa` M3 mesh-
19623        // slot composite-element `&[Composite]` axis: the accessor's
19624        // returned slice must borrow from `&self` (the returned
19625        // reference's lifetime is tied to `&self`), and calling the
19626        // accessor twice on the same [`Caixa`] must yield slices that
19627        // are pointer-equal (the underlying byte-buffer is the storage
19628        // `Vec`'s allocation, not a fresh copy) as well as value-equal
19629        // (idempotent, no side effects on `&self`).
19630        //
19631        // Pins against a future silent detour that returned an owned
19632        // `Vec<Membro>` (which would type-check but silently clone on
19633        // every call), a `&Vec<Membro>` return (which would leak the
19634        // backing `Vec`'s grow/push/reserve surface no downstream
19635        // consumer reaches for), or a one-arm-only accessor that
19636        // returned a saturating value on some sentinel input.
19637        use crate::aplicacao::Membro;
19638        for membros in [
19639            vec![],
19640            vec![Membro {
19641                caixa: "cart".into(),
19642                versao: "^0.1".into(),
19643            }],
19644            vec![
19645                Membro {
19646                    caixa: "cart".into(),
19647                    versao: "^0.1".into(),
19648                },
19649                Membro {
19650                    caixa: "pricing".into(),
19651                    versao: "^0.2".into(),
19652                },
19653            ],
19654        ] {
19655            let c = caixa_aplicacao_with_membros(membros.clone());
19656            let first = c.membros();
19657            let second = c.membros();
19658            assert_eq!(
19659                first, second,
19660                "Caixa::membros must be idempotent — two successive \
19661                 calls on the same &self must return the same &[Membro]",
19662            );
19663            assert_eq!(
19664                first.as_ptr(),
19665                second.as_ptr(),
19666                "Caixa::membros must borrow the underlying Vec<Membro> \
19667                 storage — two successive calls must return slices with \
19668                 the same backing pointer (a fresh Vec<Membro> clone \
19669                 would change the pointer on every call)",
19670            );
19671            assert_eq!(
19672                first,
19673                membros.as_slice(),
19674                "Caixa::membros must return :membros verbatim by borrow \
19675                 — got {first:?}, expected {membros:?}",
19676            );
19677        }
19678    }
19679
19680    // ── Caixa::contratos — outer top-level &[WitContract] composite-slice accessor ──
19681
19682    fn caixa_aplicacao_with_contratos(contratos: Vec<crate::aplicacao::WitContract>) -> Caixa {
19683        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19684        c.kind = CaixaKind::Aplicacao;
19685        c.contratos = contratos;
19686        c
19687    }
19688
19689    fn contrato_http_for_test(
19690        de: &str,
19691        para: &str,
19692        endpoint: &str,
19693    ) -> crate::aplicacao::WitContract {
19694        crate::aplicacao::WitContract {
19695            de: de.into(),
19696            para: para.into(),
19697            wit: "wasi:http/proxy".into(),
19698            endpoint: Some(endpoint.into()),
19699            subject: None,
19700            slot: None,
19701        }
19702    }
19703
19704    #[test]
19705    fn contratos_returns_contratos_slice_verbatim_across_permutations() {
19706        // The canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
19707        // composite `&[WitContract]`-return slice-shape pin:
19708        // [`Caixa::contratos`] must return the `:contratos` typed
19709        // `Vec<WitContract>` verbatim as a `&[WitContract]` slice-view
19710        // over the same backing buffer the raw
19711        // `self.contratos.as_slice()` field access borrows from,
19712        // element-equal across every representative fixture in the
19713        // accept-set — `[]` (the "no contracts declared" arm every
19714        // non-`Aplicacao`-kind `defcaixa` carries by
19715        // `#[serde(default)]` and every leaf-Aplicacao with a single
19716        // member carries), a canonical single-edge fixture (the
19717        // minimal directed-graph shape: one HTTP-shape `(cart → catalog)`
19718        // edge), and a canonical multi-edge fixture with three distinct
19719        // edges (the checkout-shape Aplicacao's HTTP-fan pattern:
19720        // `(cart → catalog)`, `(cart → pricing)`, `(cart → auth)`).
19721        //
19722        // Pins against a future silent detour that returned an owned
19723        // `Vec<WitContract>` (which would type-check but silently clone
19724        // on every accessor call, breaking the zero-cost projection
19725        // every peer sibling slice accessor carries), an axis-shuffled
19726        // projection (a future detour that reordered edges through the
19727        // accessor would silently split the paired
19728        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
19729        // traversal input from the peer [`Self::aplicacao_view`] fold-
19730        // in path's clone-order input, since every canonical
19731        // `caixa-mesh` renderer's per-`(:de, :para)` adjacency-list
19732        // seed dispatch reads the edge set through the same slice),
19733        // or a reference to an operator-resolved overlay (the future
19734        // per-cluster `:contratos-overrides` slot — its resolution
19735        // must land at exactly this accessor body, not silently divert
19736        // the raw slot away from a second consumer).
19737        //
19738        // Fourth outer top-level [`Caixa`] `&[Composite]`-return slice
19739        // accessor pin on the substrate primitive for M2 / M3 typed-
19740        // slot vec-carry axes — closes the outer-`Caixa`
19741        // `&[Composite]` composite-slice sub-family the sibling M2
19742        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19743        // (2a1f907) and
19744        // `children_returns_children_slice_verbatim_across_permutations`
19745        // (c17b51e) pins opened and the M3
19746        // `membros_returns_membros_slice_verbatim_across_permutations`
19747        // (0f26987) pin folded on, closing the outer-`Caixa` M3 mesh-
19748        // slot arm of the composite-slice sub-family. Peer at the outer
19749        // altitude of the closed inner-
19750        // [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
19751        // same MESH-COMPOSITION per-Aplicacao contract-list axis.
19752        let fixtures: Vec<Vec<crate::aplicacao::WitContract>> = vec![
19753            vec![],
19754            vec![contrato_http_for_test("cart", "catalog", "/items")],
19755            vec![
19756                contrato_http_for_test("cart", "catalog", "/items"),
19757                contrato_http_for_test("cart", "pricing", "/price"),
19758                contrato_http_for_test("cart", "auth", "/whoami"),
19759            ],
19760        ];
19761        for contratos in fixtures {
19762            let c = caixa_aplicacao_with_contratos(contratos.clone());
19763            assert_eq!(
19764                c.contratos(),
19765                contratos.as_slice(),
19766                "Caixa::contratos must return :contratos verbatim \
19767                 (got {:?}, expected {contratos:?})",
19768                c.contratos(),
19769            );
19770            assert_eq!(
19771                c.contratos(),
19772                c.contratos.as_slice(),
19773                "Caixa::contratos must element-equal the raw \
19774                 `self.contratos.as_slice()` field access across every \
19775                 value in the Vec<WitContract> accept-set",
19776            );
19777            assert_eq!(
19778                c.contratos().is_empty(),
19779                c.contratos.is_empty(),
19780                "Caixa::contratos().is_empty() must byte-equal \
19781                 self.contratos.is_empty() — a presence-bit drift would \
19782                 silently split the paired Caixa::declared_mesh_slots \
19783                 mesh declared-slot enumerator's presence probe from \
19784                 the peer Caixa::aplicacao_view typed-view composer's \
19785                 fold-in path",
19786            );
19787        }
19788    }
19789
19790    #[test]
19791    fn declared_mesh_slots_contratos_arm_routes_through_accessor() {
19792        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:contratos`
19793        // presence-probe arm must key off [`Caixa::contratos`], not the
19794        // raw `!self.contratos.is_empty()` field-probe. Structurally: a
19795        // `Caixa { contratos: vec![WitContract { .. }], .. }` must push
19796        // `M3_AUTHOR_KEY_CONTRATOS` onto the declared-slot list (the
19797        // presence bit is non-empty, so the mesh kind-coherence gate
19798        // must surface the slot as "declared"), and a `Caixa {
19799        // contratos: vec![], .. }` must NOT push the label (the "author
19800        // omitted the slot entirely" arm — the empty-slice partition
19801        // the serde-default folds onto). The pair jointly pins the
19802        // accessor + declared-slot enumerator composition: any future
19803        // silent detour that had the accessor collapse
19804        // `[WitContract { .. }]` to `[]` (a `.filter(|c| c.de() !=
19805        // "__reserved__")` projection) would silently absorb the
19806        // "declared but degenerate" arm at the accessor boundary and
19807        // the [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
19808        // coherence gate would silently accept a struct-literal
19809        // `Caixa` carrying the drift.
19810        //
19811        // Peer of the sibling
19812        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19813        // (2a1f907),
19814        // `declared_supervisor_slots_children_arm_routes_through_accessor`
19815        // (c17b51e), and
19816        // `declared_mesh_slots_membros_arm_routes_through_accessor`
19817        // (0f26987) composition pins on the M2 `:upgrade-from` /
19818        // `:children` / M3 `:membros` composite-slice arms — same "the
19819        // enumerator gate must route through the substrate-primitive
19820        // typed dispatch" discipline extended onto the M3 `:contratos`
19821        // composite-slice arm, closing the M3 mesh-slot arm of the
19822        // declared-slot enumerator's routing invariant on the
19823        // composite-slice inputs.
19824        let c = caixa_aplicacao_with_contratos(vec![contrato_http_for_test(
19825            "cart", "catalog", "/items",
19826        )]);
19827        let slots = c.declared_mesh_slots();
19828        assert!(
19829            slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
19830            "declared_mesh_slots must push M3_AUTHOR_KEY_CONTRATOS when \
19831             `:contratos` is non-empty — the accessor and the enumerator \
19832             gate must route through the same substrate-primitive \
19833             typed dispatch on the outer :contratos presence bit (got \
19834             slots={slots:?})",
19835        );
19836        let c = caixa_aplicacao_with_contratos(vec![]);
19837        let slots = c.declared_mesh_slots();
19838        assert!(
19839            !slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
19840            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_CONTRATOS \
19841             when `:contratos` is empty — the author-omitted arm must \
19842             route through the accessor's empty-slice return unchanged \
19843             (got slots={slots:?})",
19844        );
19845    }
19846
19847    #[test]
19848    fn aplicacao_view_contratos_arm_routes_through_accessor() {
19849        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:contratos`
19850        // fold-in arm must key off [`Caixa::contratos`], not the raw
19851        // `self.contratos.clone()` field-clone. Structurally: a `Caixa
19852        // { kind: Aplicacao, contratos: vec![WitContract { de: "cart",
19853        // .. }, WitContract { de: "pricing", .. }], .. }` must fold the
19854        // per-edge list through the accessor into the typed
19855        // [`crate::AplicacaoSpec`] view's `contratos` slot verbatim —
19856        // every entry the accessor surfaces must land in the view's
19857        // `contratos` slot in the same order. The pair jointly pins
19858        // the accessor + view-composer composition: a future silent
19859        // detour that had the accessor shuffle or drop an edge would
19860        // silently split the paired declared-slot enumerator's
19861        // presence bit from the typed-view composer's edge-list, a
19862        // two-consumer split at the enumerator and the view composer
19863        // far from the source `caixa.lisp`.
19864        //
19865        // Peer of the sibling
19866        // `aplicacao_view_membros_arm_routes_through_accessor`
19867        // (0f26987) composition pin on the M3 `:membros` outer-
19868        // `&[Composite]` composite-slice arm, closing the aplicacao-
19869        // view composer's routing invariant on the composite-slice
19870        // inputs at the outer altitude.
19871        let c = caixa_aplicacao_with_contratos(vec![
19872            contrato_http_for_test("cart", "catalog", "/items"),
19873            contrato_http_for_test("cart", "pricing", "/price"),
19874        ]);
19875        let view = c
19876            .aplicacao_view()
19877            .expect("Aplicacao kind must produce an aplicacao_view");
19878        assert_eq!(
19879            view.contratos(),
19880            c.contratos(),
19881            "aplicacao_view must fold Caixa::contratos verbatim into \
19882             AplicacaoSpec::contratos — the accessor and the view \
19883             composer must route through the same substrate-primitive \
19884             typed dispatch on the outer :contratos slice (got view \
19885             contratos={:?}, expected {:?})",
19886            view.contratos(),
19887            c.contratos(),
19888        );
19889    }
19890
19891    #[test]
19892    fn contratos_projects_slice_by_borrow() {
19893        // The by-borrow pin: [`Caixa::contratos`] returns `&[WitContract]`
19894        // by borrow — the returned slice borrows the underlying
19895        // `Vec<WitContract>` storage of the `:contratos` slot and the
19896        // accessor must not clone the backing `Vec` on every call.
19897        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
19898        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
19899        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
19900        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19901        // `exe_projects_slice_by_borrow` 65d9527,
19902        // `servicos_projects_slice_by_borrow` 611f78b,
19903        // `deps_projects_slice_by_borrow` ad34b4e,
19904        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19905        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
19906        // `children_projects_slice_by_borrow` c17b51e,
19907        // `membros_projects_slice_by_borrow` 0f26987) on the sibling
19908        // outer top-level [`Caixa`] scalar-element and composite-
19909        // element `&[T]` axes — closes the outer-`Caixa` M3 mesh-slot
19910        // composite-element `&[Composite]` axis on the by-borrow pin:
19911        // the accessor's returned slice must borrow from `&self` (the
19912        // returned reference's lifetime is tied to `&self`), and
19913        // calling the accessor twice on the same [`Caixa`] must yield
19914        // slices that are pointer-equal (the underlying byte-buffer is
19915        // the storage `Vec`'s allocation, not a fresh copy) as well as
19916        // value-equal (idempotent, no side effects on `&self`).
19917        //
19918        // Pins against a future silent detour that returned an owned
19919        // `Vec<WitContract>` (which would type-check but silently clone
19920        // on every call), a `&Vec<WitContract>` return (which would
19921        // leak the backing `Vec`'s grow/push/reserve surface no
19922        // downstream consumer reaches for), or a one-arm-only accessor
19923        // that returned a saturating value on some sentinel input.
19924        for contratos in [
19925            vec![],
19926            vec![contrato_http_for_test("cart", "catalog", "/items")],
19927            vec![
19928                contrato_http_for_test("cart", "catalog", "/items"),
19929                contrato_http_for_test("cart", "pricing", "/price"),
19930            ],
19931        ] {
19932            let c = caixa_aplicacao_with_contratos(contratos.clone());
19933            let first = c.contratos();
19934            let second = c.contratos();
19935            assert_eq!(
19936                first, second,
19937                "Caixa::contratos must be idempotent — two successive \
19938                 calls on the same &self must return the same \
19939                 &[WitContract]",
19940            );
19941            assert_eq!(
19942                first.as_ptr(),
19943                second.as_ptr(),
19944                "Caixa::contratos must borrow the underlying \
19945                 Vec<WitContract> storage — two successive calls must \
19946                 return slices with the same backing pointer (a fresh \
19947                 Vec<WitContract> clone would change the pointer on \
19948                 every call)",
19949            );
19950            assert_eq!(
19951                first,
19952                contratos.as_slice(),
19953                "Caixa::contratos must return :contratos verbatim by \
19954                 borrow — got {first:?}, expected {contratos:?}",
19955            );
19956        }
19957    }
19958
19959    // ── drift-detection: Caixa top-level multi-word serde-derive-to-const identity ──
19960
19961    #[test]
19962    fn caixa_multi_word_serde_keys_match_lifted_top_level_key_consts() {
19963        // Load-bearing invariant: every multi-word top-level [`Caixa`]
19964        // serde-derived JSON key routes through a lifted `&'static str`
19965        // const. The Rust field names are `snake_case`
19966        // (`deps_dev` / `upgrade_from` / `max_restarts` /
19967        // `restart_window`); [`Caixa`]'s `#[serde(rename_all =
19968        // "camelCase")]` derive attribute maps each to the camelCase
19969        // byte-string the [`Caixa::to_lisp`] round-trip's
19970        // `serde_json::to_value(self)` step lands under before
19971        // `tatara_lisp::domain::json_to_sexp` re-projects the JSON keys
19972        // to the kebab-case `:deps-dev` / `:upgrade-from` /
19973        // `:max-restarts` / `:restart-window` author surface. Serialize
19974        // a fully-populated [`Caixa`] and pin that each canonical
19975        // byte-sequence appears verbatim in the JSON — a future
19976        // accidental `rename_all = "snake_case"` / `"kebab-case"` /
19977        // verbatim-field-name flip at the derive attribute (any of
19978        // which would silently break every [`Caixa::to_lisp`]
19979        // round-trip and the future M4 operator-side manifest ingest's
19980        // `Value::get(<key>)` navigation) surfaces here as a build-time
19981        // test failure at `manifest.rs`, not as an apply-time
19982        // `.get(<stale-canonical-const>)` returning `None` far from the
19983        // derive-attr drift's commit. Same discipline the sibling
19984        // `supervisor_spec_serde_keys_match_lifted_supervisor_key_consts`
19985        // (40cc4e5), `membro_serde_keys_match_lifted_membro_key_consts`
19986        // (ce80ca0), and `upgrade_from_entry_serde_keys_match_lifted_
19987        // m2_upgrade_from_key_consts` (36ffe65) pins established on the
19988        // sibling M2 supervision-tree, M3 [`Membro`] per-entry, and M2
19989        // [`UpgradeFromEntry`] per-entry axes — extended here to the
19990        // enclosing M0 [`Caixa`] top-level axis so the last of the four
19991        // multi-word top-level [`Caixa`] serde-derived JSON keys
19992        // (`depsDev`) joins the substrate's "one canonical byte-string
19993        // per typed serialized-key axis" discipline.
19994        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
19995        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
19996        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19997        c.deps_dev = vec![Dep::simple("tatara-check", "^0.1")];
19998        c.upgrade_from = vec![UpgradeFromEntry {
19999            from: "0.0.1".into(),
20000            instructions: vec![UpgradeInstruction::Restart],
20001        }];
20002        c.estrategia = Some(RestartStrategy::OneForOne);
20003        c.max_restarts = Some(3);
20004        c.restart_window = Some("60s".into());
20005        c.children = vec![ChildSpec {
20006            caixa: "child".into(),
20007            versao: "^0.1".into(),
20008            restart: RestartPolicy::Permanent,
20009        }];
20010        let json = serde_json::to_string(&c).unwrap();
20011        for key in [
20012            crate::render::CAIXA_KEY_DEPS_DEV,
20013            crate::render::M2_KEY_UPGRADE_FROM,
20014            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20015            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20016        ] {
20017            let quoted = format!("\"{key}\"");
20018            assert!(
20019                json.contains(&quoted),
20020                "serialized Caixa must carry the lifted top-level \
20021                 multi-word byte-sequence {quoted} verbatim in the JSON \
20022                 emission (got: {json})",
20023            );
20024        }
20025    }
20026
20027    #[test]
20028    fn caixa_top_level_multi_word_key_consts_are_pairwise_distinct() {
20029        // Cross-axis drift-detection pin: a future collapse of the four
20030        // canonical [`Caixa`] top-level multi-word byte-strings onto the
20031        // same value (e.g. an accidental copy-paste flip of
20032        // [`crate::render::CAIXA_KEY_DEPS_DEV`] to also read
20033        // `"upgradeFrom"`) would silently reroute every downstream
20034        // `Value::get(<key>)` probe on one axis onto the sibling axis's
20035        // top-level entry and pass every propagation-probe test that
20036        // expected only the stale axis's value. Peer of the sibling
20037        // four-way distinct pin on the `SUPERVISOR_KEY_*` tetrad
20038        // (40cc4e5) and the two-way pin on `MEMBRO_KEY_*` (ce80ca0).
20039        let all = [
20040            crate::render::CAIXA_KEY_DEPS_DEV,
20041            crate::render::M2_KEY_UPGRADE_FROM,
20042            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20043            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20044        ];
20045        for (i, a) in all.iter().enumerate() {
20046            for b in all.iter().skip(i + 1) {
20047                assert_ne!(
20048                    a, b,
20049                    "Caixa top-level multi-word key consts must be \
20050                     pairwise-distinct canonical byte-sequences — got \
20051                     `{a}` == `{b}`",
20052                );
20053            }
20054        }
20055    }
20056
20057    #[test]
20058    fn caixa_top_level_multi_word_key_consts_are_lower_camel_case_shape() {
20059        // Shape-pin: every [`Caixa`] top-level multi-word key const must
20060        // be a lowerCamelCase byte-sequence (no `snake_case`
20061        // underscores, no `kebab-case` hyphens, no leading colon, no
20062        // `PascalCase` leading capital, no whitespace / dots) — the
20063        // canonical shape the `#[serde(rename_all = "camelCase")]`
20064        // derive produces on [`Caixa`]. A future flip to a
20065        // non-camelCase attribute at the derive surfaces both here
20066        // (this test fails on the stale-constant shape) and at
20067        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20068        // (that test fails on the mismatch between const and derive).
20069        // Peer with `membro_key_consts_are_lower_camel_case_shape`
20070        // (ce80ca0) and `supervisor_key_consts_are_lower_camel_case_shape`
20071        // (40cc4e5) on the sibling per-entry / supervisor-tree axes.
20072        for key in [
20073            crate::render::CAIXA_KEY_DEPS_DEV,
20074            crate::render::M2_KEY_UPGRADE_FROM,
20075            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20076            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20077        ] {
20078            assert!(
20079                !key.is_empty(),
20080                "Caixa top-level multi-word key const must be non-empty \
20081                 (got {key:?})"
20082            );
20083            let first = key.chars().next().unwrap();
20084            assert!(
20085                first.is_ascii_lowercase(),
20086                "Caixa top-level multi-word key const must lead with an \
20087                 ASCII-lowercase byte (got {key:?}, leads with {first:?})",
20088            );
20089            assert!(
20090                key.chars().all(|c| c.is_ascii_alphanumeric()),
20091                "Caixa top-level multi-word key const must be \
20092                 ASCII-alphanumeric only — no `_` / `-` / `:` / `.` / \
20093                 whitespace (got {key:?})",
20094            );
20095        }
20096    }
20097
20098    #[test]
20099    fn caixa_key_deps_dev_pins_canonical_camel_case_byte_string() {
20100        // Scalar-value pin: the byte-string the
20101        // [`crate::render::CAIXA_KEY_DEPS_DEV`] const resolves to,
20102        // asserted verbatim. A future rebrand (`depsDev` → `devDeps`
20103        // matching Cargo's verbatim `dev-dependencies` axis, `depsDev`
20104        // → `depsTest` matching a hypothetical per-test-target
20105        // vocabulary flip) lands as an edit to exactly one const AND
20106        // one derive attribute — the sibling
20107        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20108        // pin already ties the const to the derive attribute, so a
20109        // rebrand that touches only one side of the pair fails at
20110        // caixa-core build time. Same "scalar-value pin per const"
20111        // discipline the sibling
20112        // `m2_top_level_author_key_consts_pin_canonical_kebab_case_labels`
20113        // (f49c8b0) and `contrato_key_consts_pin_canonical_camel_case_labels`
20114        // (ca463a4) pins carry on the peer M2 / M3 top-level slot axes.
20115        assert_eq!(crate::render::CAIXA_KEY_DEPS_DEV, "depsDev");
20116    }
20117
20118    #[test]
20119    fn caixa_key_deps_pins_canonical_byte_string() {
20120        // Scalar-value pin: the byte-string the
20121        // [`crate::render::CAIXA_KEY_DEPS`] const resolves to, asserted
20122        // verbatim. Peer of `caixa_key_deps_dev_pins_canonical_camel_case_byte_string`
20123        // on the two-list dep-graph serialized-key axis — the sibling
20124        // pin covers the multi-word `deps_dev → depsDev` camelCase
20125        // arm, this pin covers the single-word `deps → deps` no-op arm
20126        // (the [`crate::Caixa::deps`] field name carries no `_`, so the
20127        // `#[serde(rename_all = "camelCase")]` derive is a no-op on this
20128        // axis and the emitted JSON key equals the source-side field
20129        // name byte-for-byte). A future [`crate::Caixa::deps`] field
20130        // rename (`deps` → `dependencies` matching Cargo's verbatim
20131        // `[dependencies]` axis, `deps` → `runtime_deps` matching a
20132        // hypothetical per-runtime-target vocabulary flip) OR an added
20133        // `#[serde(rename = "…")]` explicit override lands as an edit
20134        // to exactly one const AND one derive-attr / field name — the
20135        // sibling `caixa_deps_serde_key_matches_lifted_caixa_key_deps`
20136        // pin ties the const to the emitted JSON key, so a rebrand
20137        // that touches only one side of the pair fails at caixa-core
20138        // build time.
20139        assert_eq!(crate::render::CAIXA_KEY_DEPS, "deps");
20140    }
20141
20142    #[test]
20143    fn caixa_deps_serde_key_matches_lifted_caixa_key_deps() {
20144        // Load-bearing invariant on the single-word `deps` top-level
20145        // axis: the byte-string [`crate::render::CAIXA_KEY_DEPS`] pins
20146        // must appear verbatim in the JSON [`Caixa::to_lisp`]'s
20147        // `serde_json::to_value(self)` step emits. Serialize a
20148        // populated [`Caixa`] whose `:deps` slot carries at least one
20149        // entry (the `#[serde(default)]` attribute on the field emits
20150        // an empty `[]` even without members, but a non-empty vec
20151        // additionally covers the codec's per-`Dep`-entry emission
20152        // path) and pin that `"deps"` appears verbatim in the JSON
20153        // emission — a future accidental `rename_all = "snake_case"` /
20154        // `"kebab-case"` flip at the derive attribute (or an added
20155        // `#[serde(rename = "…")]` explicit override on the field, or
20156        // a Rust field rename) would break every [`Caixa::to_lisp`]
20157        // round-trip and the future M4 operator-side manifest ingest's
20158        // `Value::get(CAIXA_KEY_DEPS)` navigation — surfaces here as a
20159        // build-time test failure at `manifest.rs`, not as an
20160        // apply-time `.get(<stale-canonical-const>)` returning `None`
20161        // far from the drift's commit. Peer of the sibling
20162        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20163        // multi-word pin on the same M0 [`Caixa`] top-level
20164        // serialized-key axis, extended here to the single-word arm
20165        // the multi-word test's `rename_all = "camelCase"` sweep can't
20166        // reach (single-word `deps → deps` is a no-op the multi-word
20167        // pin's `\"depsDev\"` / `\"upgradeFrom\"` / `\"maxRestarts\"` /
20168        // `\"restartWindow\"` byte-scan can never observe).
20169        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20170        c.deps = vec![Dep::simple("caixa-core", "^0.1")];
20171        let json = serde_json::to_string(&c).unwrap();
20172        let quoted = format!("\"{}\"", crate::render::CAIXA_KEY_DEPS);
20173        assert!(
20174            json.contains(&quoted),
20175            "serialized Caixa must carry the lifted top-level `deps` \
20176             byte-sequence {quoted} verbatim in the JSON emission (got: \
20177             {json})",
20178        );
20179    }
20180
20181    #[test]
20182    fn caixa_dep_graph_two_list_key_consts_are_pairwise_distinct() {
20183        // Cross-axis drift-detection pin on the two-list dep-graph
20184        // renderer-side wire-key axis: a future collapse of the
20185        // canonical [`crate::render::CAIXA_KEY_DEPS`] /
20186        // [`crate::render::CAIXA_KEY_DEPS_DEV`] byte-strings onto the
20187        // same value (e.g. an accidental copy-paste flip of
20188        // `CAIXA_KEY_DEPS_DEV` to also read `"deps"`) would silently
20189        // reroute every downstream `Value::get(<key>)` probe on one
20190        // axis onto the sibling axis's dep-list and pass every
20191        // propagation-probe test that expected only the stale axis's
20192        // value — a dev-only dep would land in the runtime closure at
20193        // publish time, or a runtime dep would be excluded from the
20194        // published lacre. Peer of the sibling four-way distinct pin
20195        // on the top-level multi-word tetrad
20196        // (`caixa_top_level_multi_word_key_consts_are_pairwise_distinct`)
20197        // and the two-way pin on the sibling
20198        // [`DEP_AUTHOR_KEY_DEPS`] / [`DEP_AUTHOR_KEY_DEPS_DEV`]
20199        // author-facing arm (4da6fba's test), extended here to the
20200        // renderer-side wire-key arm of the same two-list dep-graph
20201        // axis so both halves of the "one canonical byte-string per
20202        // typed axis per (author, wire)" grid carry the same
20203        // distinct-ness discipline.
20204        assert_ne!(
20205            crate::render::CAIXA_KEY_DEPS,
20206            crate::render::CAIXA_KEY_DEPS_DEV,
20207            "CAIXA_KEY_DEPS and CAIXA_KEY_DEPS_DEV must be distinct \
20208             canonical byte-sequences on the two-list dep-graph \
20209             renderer-side wire-key axis"
20210        );
20211    }
20212
20213    // ── DepList / Caixa::push_dep pin ────────────────────────────────
20214    //
20215    // The compounding pin: the two-arm closed-set typed enum
20216    // [`crate::dep::DepList`] carries the runtime-closure `:deps`
20217    // (`Prod`) vs dev-only-closure `:deps-dev` (`Dev`) dispatch every
20218    // consumer of the top-level manifest's dep-mutation surface reads
20219    // through, and the typed dispatch [`Caixa::push_dep`] on the
20220    // substrate primitive folds the "select list → check within-list
20221    // dup → push" cascade onto one method call. Prior to this landing
20222    // the two axes lived across two `&'static str` constants
20223    // (`DEP_AUTHOR_KEY_DEPS`, `DEP_AUTHOR_KEY_DEPS_DEV`) with no closed-
20224    // set type carrying the pair; the `feira add` mutation site's
20225    // inline `if self.dev { &mut caixa.deps_dev } else { &mut
20226    // caixa.deps }` dispatch expressed no compile-time link back to
20227    // the substrate primitive, and a future third dep-list axis would
20228    // have silently split at every open-coded mutation site.
20229
20230    #[test]
20231    fn dep_list_as_str_routes_through_lifted_author_key_constants() {
20232        // Every arm returns the same `&'static str` the substrate's
20233        // canonical `DEP_AUTHOR_KEY_DEPS` / `DEP_AUTHOR_KEY_DEPS_DEV`
20234        // constants carry. A future rebrand on either constant reaches
20235        // the enum through one edit; a regression to inline literals
20236        // (e.g. `Prod => ":deps"`) would silently split the diagnostic
20237        // quotes from the wire-format constants every consumer routes
20238        // through and this pin flags it at build time.
20239        assert_eq!(
20240            crate::dep::DepList::Prod.as_str(),
20241            crate::render::DEP_AUTHOR_KEY_DEPS
20242        );
20243        assert_eq!(
20244            crate::dep::DepList::Dev.as_str(),
20245            crate::render::DEP_AUTHOR_KEY_DEPS_DEV
20246        );
20247    }
20248
20249    #[test]
20250    fn dep_list_display_routes_through_as_str() {
20251        // Same as-str-through-Display convergence discipline the
20252        // sibling closed-set typed enums carry — a `format!("{list}")`
20253        // call must land byte-for-byte on the accessor's return so a
20254        // future consumer that formats the enum for a diagnostic line
20255        // reaches the same wire-format constant the wire-format
20256        // producers do.
20257        assert_eq!(
20258            format!("{}", crate::dep::DepList::Prod),
20259            crate::dep::DepList::Prod.as_str()
20260        );
20261        assert_eq!(
20262            format!("{}", crate::dep::DepList::Dev),
20263            crate::dep::DepList::Dev.as_str()
20264        );
20265    }
20266
20267    #[test]
20268    fn dep_list_all_enumerates_every_variant_once() {
20269        // Exhaustive-iteration pin — every arm appears exactly once in
20270        // `ALL`, matching the closed set the compiler enforces on the
20271        // sibling `match self` arms. A future variant addition that
20272        // extends only one method's match without extending `ALL`
20273        // would silently drop the new arm from every consumer that
20274        // iterates the slice.
20275        let variants: &[crate::dep::DepList] = crate::dep::DepList::ALL;
20276        assert!(variants.contains(&crate::dep::DepList::Prod));
20277        assert!(variants.contains(&crate::dep::DepList::Dev));
20278        assert_eq!(variants.len(), 2);
20279    }
20280
20281    #[test]
20282    fn dep_list_from_wire_returns_prod_on_deps_wire_scalar() {
20283        // Reverse projection on the two-list dep-graph axis: the
20284        // author-surface wire tag the sibling `as_str` emitter walks
20285        // for `Prod` (`:deps` via `DEP_AUTHOR_KEY_DEPS`) parses back to
20286        // `Some(DepList::Prod)`. A regression that hand-rolled the
20287        // per-arm match without routing through the lifted
20288        // `DEP_AUTHOR_KEY_DEPS` const would silently disagree on any
20289        // future wire-tag rebrand and this pin flags it at build time.
20290        assert_eq!(
20291            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS),
20292            Some(crate::dep::DepList::Prod)
20293        );
20294    }
20295
20296    #[test]
20297    fn dep_list_from_wire_returns_dev_on_deps_dev_wire_scalar() {
20298        // Peer of the `Prod`-arm pin on the dev-only axis: the
20299        // author-surface wire tag the sibling `as_str` emitter walks
20300        // for `Dev` (`:deps-dev` via `DEP_AUTHOR_KEY_DEPS_DEV`) parses
20301        // back to `Some(DepList::Dev)`. Same drift-detection posture
20302        // as the peer arm — the sibling method `match` arms are
20303        // compiler-checked exhaustive so a future variant addition
20304        // trips at build time.
20305        assert_eq!(
20306            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS_DEV),
20307            Some(crate::dep::DepList::Dev)
20308        );
20309    }
20310
20311    #[test]
20312    fn dep_list_from_wire_returns_none_on_unknown_wire_scalar() {
20313        // Every input outside the closed-set arm-string set the
20314        // sibling `as_str` emitter walks lands on the terminal `None`
20315        // fallback — no silent-accept surface. Sweeps a set of
20316        // plausibly-adjacent scalars (unprefixed wire form, PascalCase
20317        // rebrand candidates, foreign wire tags, empty string) so a
20318        // future variant addition that widened one wire form without
20319        // extending the emitter's arm-set would trip the sibling
20320        // round-trip pin below rather than silently accepting the new
20321        // form here.
20322        for candidate in [
20323            "",
20324            "deps",
20325            "deps-dev",
20326            ":deps ",
20327            ":Deps",
20328            ":DEPS",
20329            ":build-dep",
20330            ":tool-dep",
20331            "prod",
20332            "dev",
20333        ] {
20334            assert_eq!(
20335                crate::dep::DepList::from_wire(candidate),
20336                None,
20337                "from_wire({candidate:?}) must return None; every input outside \
20338                 the {{DEP_AUTHOR_KEY_DEPS, DEP_AUTHOR_KEY_DEPS_DEV}} accept-set \
20339                 the sibling as_str emitter walks lands on the terminal fallback",
20340            );
20341        }
20342    }
20343
20344    #[test]
20345    fn dep_list_round_trips_through_as_str_and_from_wire() {
20346        // Load-bearing round-trip pin: every arm the `ALL` iteration
20347        // exposes survives the `as_str` → `from_wire` composition
20348        // byte-for-byte. Same discipline the sibling closed-set enums
20349        // carry — `CaixaKind` /
20350        // `RestartStrategy` / `RestartPolicy` /
20351        // `PlacementStrategy` — extended onto the two-list dep-graph
20352        // axis. A future variant addition that extends `ALL` +
20353        // `as_str` without extending `from_wire` (or vice versa)
20354        // trips at build time on this iteration because the compiler
20355        // enforces exhaustiveness on the sibling `match self` arms.
20356        for &list in crate::dep::DepList::ALL {
20357            assert_eq!(
20358                crate::dep::DepList::from_wire(list.as_str()),
20359                Some(list),
20360                "DepList::from_wire(as_str({list:?})) must round-trip to Some({list:?}) — \
20361                 a silent split between the forward emitter and the reverse parser \
20362                 would drift the two halves of the two-list dep-graph axis's typed dispatch",
20363            );
20364        }
20365    }
20366
20367    #[test]
20368    fn push_dep_routes_to_deps_slot_on_prod_arm() {
20369        // The `Prod` arm dispatches to the runtime-closure `:deps`
20370        // slot every downstream lacre-pipeline consumer resolves at
20371        // build time. A future arm that regressed to inline `&mut
20372        // self.deps_dev` on the `Prod` path would silently reroute
20373        // every runtime dep into the dev-only closure at publish time
20374        // — this pin refuses that regression.
20375        let src = Caixa::template("host");
20376        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20377        let before_deps = caixa.deps().len();
20378        let before_deps_dev = caixa.deps_dev().len();
20379        let dep = Dep {
20380            nome: "caixa-teia".to_string(),
20381            versao: "^0.1".to_string(),
20382            fonte: None,
20383            opcional: false,
20384            caracteristicas: Vec::new(),
20385        };
20386        caixa
20387            .push_dep(crate::dep::DepList::Prod, dep)
20388            .expect("first push into :deps succeeds");
20389        assert_eq!(caixa.deps().len(), before_deps + 1);
20390        assert_eq!(caixa.deps_dev().len(), before_deps_dev);
20391        assert_eq!(caixa.deps().last().unwrap().nome(), "caixa-teia");
20392    }
20393
20394    #[test]
20395    fn push_dep_routes_to_deps_dev_slot_on_dev_arm() {
20396        // Peer of the sibling `Prod`-arm dispatch pin — the `Dev` arm
20397        // must dispatch to the dev-only-closure `:deps-dev` slot every
20398        // downstream test-facing artifact resolver reads. A future
20399        // regression that inverted the two arms would silently route
20400        // every dev-only dep into the runtime closure at publish time
20401        // and this pin catches it before the drift ships.
20402        let src = Caixa::template("host");
20403        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20404        let dep = Dep {
20405            nome: "tatara-check".to_string(),
20406            versao: "*".to_string(),
20407            fonte: None,
20408            opcional: false,
20409            caracteristicas: Vec::new(),
20410        };
20411        caixa
20412            .push_dep(crate::dep::DepList::Dev, dep)
20413            .expect("first push into :deps-dev succeeds");
20414        assert!(caixa.deps().is_empty());
20415        assert_eq!(caixa.deps_dev().len(), 1);
20416        assert_eq!(caixa.deps_dev().last().unwrap().nome(), "tatara-check");
20417    }
20418
20419    #[test]
20420    fn push_dep_refuses_within_list_duplicate_nome_with_typed_error() {
20421        // Within-list dup check routes through the canonical
20422        // [`DepError::DuplicateNome`] carrier — the substrate's typed
20423        // diagnostic for the same axis [`Caixa::validate_deps`]'s
20424        // parse-time [`crate::render::insert_first_seen`] walk raises
20425        // on. Prior to the lift the mutation site's inline
20426        // `bail!("dep '{}' already declared", …)` string-diagnostic
20427        // path expressed no through-line back to the typed error;
20428        // routing every dep-list refusal through one carrier means an
20429        // author reading a `feira add` refusal and a `feira build`
20430        // refusal reaches for the same corrective surface without
20431        // switching diagnostic idioms.
20432        let src = Caixa::template("host");
20433        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20434        let dep = Dep {
20435            nome: "caixa-teia".to_string(),
20436            versao: "^0.1".to_string(),
20437            fonte: None,
20438            opcional: false,
20439            caracteristicas: Vec::new(),
20440        };
20441        caixa
20442            .push_dep(crate::dep::DepList::Prod, dep.clone())
20443            .expect("first push succeeds");
20444        let dup = Dep {
20445            nome: "caixa-teia".to_string(),
20446            versao: "^0.2".to_string(),
20447            fonte: None,
20448            opcional: false,
20449            caracteristicas: Vec::new(),
20450        };
20451        let err = caixa
20452            .push_dep(crate::dep::DepList::Prod, dup)
20453            .expect_err("second push with same :nome refuses");
20454        assert_eq!(
20455            err,
20456            DepError::DuplicateNome {
20457                nome: "caixa-teia".to_string(),
20458                list: crate::render::DEP_AUTHOR_KEY_DEPS,
20459            }
20460        );
20461        // The refused mutation must not corrupt the target list —
20462        // exactly one entry lives past the refusal, matching the
20463        // canonical single-source-of-truth invariant `Caixa::deps()`
20464        // carries.
20465        assert_eq!(caixa.deps().len(), 1);
20466    }
20467
20468    #[test]
20469    fn push_dep_refuses_dup_on_dev_list_arm_names_deps_dev_key() {
20470        // Peer of the sibling `Prod`-arm dup-refusal pin — the `Dev`
20471        // arm's refusal must carry `DEP_AUTHOR_KEY_DEPS_DEV` in the
20472        // `list` payload so a future author reading the refusal grep's
20473        // for the correct `:deps-dev` block in their `caixa.lisp`,
20474        // not the sibling `:deps` block the runtime closure resolves.
20475        let src = Caixa::template("host");
20476        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20477        let dep = Dep {
20478            nome: "tatara-check".to_string(),
20479            versao: "*".to_string(),
20480            fonte: None,
20481            opcional: false,
20482            caracteristicas: Vec::new(),
20483        };
20484        caixa
20485            .push_dep(crate::dep::DepList::Dev, dep.clone())
20486            .expect("first push succeeds");
20487        let err = caixa
20488            .push_dep(crate::dep::DepList::Dev, dep)
20489            .expect_err("second push with same :nome refuses");
20490        assert!(matches!(
20491            err,
20492            DepError::DuplicateNome {
20493                ref nome,
20494                list,
20495            } if nome == "tatara-check"
20496                && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
20497        ));
20498    }
20499
20500    #[test]
20501    fn push_dep_allows_same_nome_across_prod_and_dev_lists() {
20502        // The within-list dup check is scoped to the target arm — a
20503        // caixa may legitimately carry the same `:nome` under both
20504        // `:deps` and `:deps-dev` (though the substrate's peer
20505        // [`crate::Caixa::validate_deps`] walk still refuses the
20506        // shape at parse time; the mutation-site refusal is scoped to
20507        // the mutation-site's list to match the peer parse-time
20508        // per-list [`crate::render::insert_first_seen`] discipline).
20509        // The two arms hold independent seen-sets.
20510        let src = Caixa::template("host");
20511        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20512        let dep_prod = Dep {
20513            nome: "shared".to_string(),
20514            versao: "^0.1".to_string(),
20515            fonte: None,
20516            opcional: false,
20517            caracteristicas: Vec::new(),
20518        };
20519        let dep_dev = Dep {
20520            nome: "shared".to_string(),
20521            versao: "*".to_string(),
20522            fonte: None,
20523            opcional: false,
20524            caracteristicas: Vec::new(),
20525        };
20526        caixa
20527            .push_dep(crate::dep::DepList::Prod, dep_prod)
20528            .expect("push into :deps succeeds");
20529        caixa
20530            .push_dep(crate::dep::DepList::Dev, dep_dev)
20531            .expect("push same :nome into :deps-dev succeeds");
20532        assert_eq!(caixa.deps().len(), 1);
20533        assert_eq!(caixa.deps_dev().len(), 1);
20534    }
20535
20536    #[test]
20537    fn deps_of_prod_returns_the_deps_slot_verbatim() {
20538        // The `Prod` arm of the typed-dispatch [`Caixa::deps_of`] read
20539        // accessor must project onto the runtime-closure `:deps` slot —
20540        // element-equal and length-equal to the sibling per-slot
20541        // [`Caixa::deps`] accessor's return over every per-caixa fixture.
20542        // A future arm that regressed to `self.deps_dev()` on the `Prod`
20543        // path would silently reroute every downstream typed-dispatch
20544        // walker (the [`Caixa::validate_deps`] per-list
20545        // [`crate::render::insert_first_seen`] dedup walk, any future
20546        // per-axis-parametrised consumer) into the sibling dev-only
20547        // closure and this pin refuses that regression.
20548        let src = Caixa::template("host");
20549        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20550        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
20551        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 0);
20552        let dep = Dep {
20553            nome: "caixa-teia".to_string(),
20554            versao: "^0.1".to_string(),
20555            fonte: None,
20556            opcional: false,
20557            caracteristicas: Vec::new(),
20558        };
20559        caixa
20560            .push_dep(crate::dep::DepList::Prod, dep.clone())
20561            .expect("push into :deps succeeds");
20562        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
20563        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 1);
20564        assert_eq!(
20565            caixa.deps_of(crate::dep::DepList::Prod)[0].nome(),
20566            "caixa-teia"
20567        );
20568    }
20569
20570    #[test]
20571    fn deps_of_dev_returns_the_deps_dev_slot_verbatim() {
20572        // Peer of the sibling `Prod`-arm pin — the `Dev` arm of
20573        // [`Caixa::deps_of`] must project onto the dev-only-closure
20574        // `:deps-dev` slot, element-equal and length-equal to the
20575        // sibling per-slot [`Caixa::deps_dev`] accessor's return. A
20576        // future regression that inverted the two arms would silently
20577        // route every dev-list walker onto the runtime closure and this
20578        // pin catches it before the drift ships.
20579        let src = Caixa::template("host");
20580        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20581        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
20582        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 0);
20583        let dep = Dep {
20584            nome: "tatara-check".to_string(),
20585            versao: "*".to_string(),
20586            fonte: None,
20587            opcional: false,
20588            caracteristicas: Vec::new(),
20589        };
20590        caixa
20591            .push_dep(crate::dep::DepList::Dev, dep)
20592            .expect("push into :deps-dev succeeds");
20593        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
20594        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 1);
20595        assert_eq!(
20596            caixa.deps_of(crate::dep::DepList::Dev)[0].nome(),
20597            "tatara-check"
20598        );
20599    }
20600
20601    #[test]
20602    fn deps_of_exhaustive_over_dep_list_all_covers_the_two_slots() {
20603        // Composition pin: iterating [`crate::dep::DepList::ALL`] through
20604        // [`Caixa::deps_of`] must land on the same two-slot partition the
20605        // per-slot [`Caixa::deps`] / [`Caixa::deps_dev`] accessors
20606        // expose — the canonical dispatch a future per-axis-parametrised
20607        // walker (a future `feira app graph` per-list dep summary, a
20608        // future M4 per-cluster dev-closure-audit overlay the CR
20609        // materializer resolves per-CR) reads through. Prior to the
20610        // lift the two-block iteration lived open-coded at every walker,
20611        // so a future third dep-list axis (`:deps-build`, per CAIXA-SDLC
20612        // §I) would have had to grow a third block at every consumer.
20613        // A regression that dropped the `Dev` arm from `ALL` would flip
20614        // the collected pairs to `[(":deps", &[])]` alone and this pin
20615        // refuses that shape.
20616        let src = Caixa::template("host");
20617        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20618        let prod_dep = Dep {
20619            nome: "caixa-teia".to_string(),
20620            versao: "^0.1".to_string(),
20621            fonte: None,
20622            opcional: false,
20623            caracteristicas: Vec::new(),
20624        };
20625        let dev_dep = Dep {
20626            nome: "tatara-check".to_string(),
20627            versao: "*".to_string(),
20628            fonte: None,
20629            opcional: false,
20630            caracteristicas: Vec::new(),
20631        };
20632        caixa
20633            .push_dep(crate::dep::DepList::Prod, prod_dep)
20634            .expect("push into :deps succeeds");
20635        caixa
20636            .push_dep(crate::dep::DepList::Dev, dev_dep)
20637            .expect("push into :deps-dev succeeds");
20638        let collected: Vec<(&'static str, usize, &str)> = crate::dep::DepList::ALL
20639            .iter()
20640            .map(|&list| {
20641                let slice = caixa.deps_of(list);
20642                (list.as_str(), slice.len(), slice[0].nome())
20643            })
20644            .collect();
20645        assert_eq!(
20646            collected,
20647            vec![
20648                (crate::render::DEP_AUTHOR_KEY_DEPS, 1, "caixa-teia"),
20649                (crate::render::DEP_AUTHOR_KEY_DEPS_DEV, 1, "tatara-check"),
20650            ]
20651        );
20652    }
20653
20654    #[test]
20655    fn caixa_deps_of_is_const_fn() {
20656        // Fail-before-pass-after pin on [`Caixa::deps_of`]'s
20657        // `const`-eval-surface posture. The typed-dispatch read
20658        // accessor forwards through the sibling `pub const fn`
20659        // [`Caixa::deps`] / [`Caixa::deps_dev`] per-slot slice
20660        // accessors on the two [`crate::dep::DepList`] enum arms —
20661        // every operator in the body is already `const`-callable
20662        // (`DepList` is a plain `#[derive(Copy)]` closed-set
20663        // discriminator so the `match` arms are const-evaluable, and
20664        // each arm dispatches through the sibling `pub const fn`
20665        // slice accessor). Any future accidental downgrade to
20666        // non-`const` fails the `deps_of_via_const_fn` wrapper below
20667        // at caixa-core build time with E0015 (`cannot call non-const
20668        // method`), strictly stronger than a runtime `assert!` and
20669        // side-stepping the destructor-in-const restriction the
20670        // `Caixa` fixture's owning `String` / `Vec<Dep>` carriers
20671        // rule out on the direct-`const _: () = assert!(...)`
20672        // residence.
20673        //
20674        // Peer of the sibling outer-`Caixa` accessor family pins
20675        // ([`caixa_outer_string_slice_return_accessor_family_is_const_fn`]
20676        // on the `&[String]` universal-axis surface,
20677        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
20678        // on the outer `&[T]` composite-slice surface,
20679        // [`caixa_outer_option_composite_reference_return_accessor_family_is_const_fn`]
20680        // on the outer `Option<&Composite>` surface) — this pin
20681        // extends the `const`-eval-surface discipline onto the outer-
20682        // `Caixa` typed-dispatch read surface on the [`DepList`]-keyed
20683        // dep-list axis, closing the outer-`Caixa` accessor family's
20684        // last unlifted `pub fn` on the read side.
20685        const fn deps_of_via_const_fn(c: &Caixa, list: crate::dep::DepList) -> &[Dep] {
20686            c.deps_of(list)
20687        }
20688        let src = Caixa::template("host");
20689        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20690        // Empty-list arm: both `Prod` and `Dev` degenerate to the
20691        // empty slice with no silent `None` collapse — the
20692        // `#[serde(default)]` `Vec::new()` fold every `defcaixa` form
20693        // that omits the slot lands on.
20694        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod).is_empty());
20695        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev).is_empty());
20696        assert_eq!(
20697            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
20698            caixa.deps()
20699        );
20700        assert_eq!(
20701            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
20702            caixa.deps_dev()
20703        );
20704        // Populated arms: each list carries its own entry, and the
20705        // wrapper / direct dispatches agree byte-for-byte on the
20706        // slice-view under both non-empty arms.
20707        let prod_dep = Dep {
20708            nome: "caixa-teia".to_string(),
20709            versao: "^0.1".to_string(),
20710            fonte: None,
20711            opcional: false,
20712            caracteristicas: Vec::new(),
20713        };
20714        let dev_dep = Dep {
20715            nome: "tatara-check".to_string(),
20716            versao: "*".to_string(),
20717            fonte: None,
20718            opcional: false,
20719            caracteristicas: Vec::new(),
20720        };
20721        caixa
20722            .push_dep(crate::dep::DepList::Prod, prod_dep)
20723            .expect("push into :deps succeeds");
20724        caixa
20725            .push_dep(crate::dep::DepList::Dev, dev_dep)
20726            .expect("push into :deps-dev succeeds");
20727        assert_eq!(
20728            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
20729            caixa.deps()
20730        );
20731        assert_eq!(
20732            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
20733            caixa.deps_dev()
20734        );
20735        assert_eq!(
20736            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod)[0].nome(),
20737            "caixa-teia"
20738        );
20739        assert_eq!(
20740            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev)[0].nome(),
20741            "tatara-check"
20742        );
20743    }
20744
20745    #[test]
20746    fn validate_deps_iterates_through_dep_list_all_via_deps_of() {
20747        // Composition pin: the [`Caixa::validate_deps`] parse-time gate
20748        // must route its per-list [`crate::render::insert_first_seen`]
20749        // dedup walk through [`Caixa::deps_of`] + [`crate::dep::DepList::ALL`]
20750        // rather than the pre-lift open-coded two-block iteration over
20751        // `self.deps()` + `self.deps_dev()`. A regression that dropped
20752        // one arm (e.g. hand-inlining `self.deps()` alone) would silently
20753        // stop refusing within-list dups on the sibling arm; a
20754        // regression that flipped the arm-to-list-key mapping
20755        // (`Dev => DEP_AUTHOR_KEY_DEPS`) would silently mislabel the
20756        // diagnostic surface. Both drifts surface here through a paired
20757        // duplicate-name refusal per arm plus an offending-list-key
20758        // check on the emitted [`DepError::DuplicateNome`] carrier.
20759        for &list in crate::dep::DepList::ALL {
20760            let src = Caixa::template("host");
20761            let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20762            let dup = Dep {
20763                nome: "twin".to_string(),
20764                versao: "^0.1".to_string(),
20765                fonte: None,
20766                opcional: false,
20767                caracteristicas: Vec::new(),
20768            };
20769            match list {
20770                crate::dep::DepList::Prod => {
20771                    caixa.deps.push(dup.clone());
20772                    caixa.deps.push(dup);
20773                }
20774                crate::dep::DepList::Dev => {
20775                    caixa.deps_dev.push(dup.clone());
20776                    caixa.deps_dev.push(dup);
20777                }
20778            }
20779            let err = caixa
20780                .validate_deps()
20781                .expect_err("within-list duplicate :nome must refuse");
20782            assert_eq!(
20783                err,
20784                DepError::DuplicateNome {
20785                    nome: "twin".to_string(),
20786                    list: list.as_str(),
20787                },
20788                "validate_deps on {list} arm must emit \
20789                 DepError::DuplicateNome carrying the arm's own \
20790                 as_str() diagnostic — the arm-to-list-key mapping \
20791                 flowed through DepList::ALL + Caixa::deps_of"
20792            );
20793        }
20794    }
20795
20796    #[test]
20797    fn caixa_licenca_default_pins_canonical_mit_byte() {
20798        // Bridge-arm pin: [`CAIXA_LICENCA_DEFAULT`] resolves to the
20799        // canonical SPDX-`"MIT"` byte today, the same license expression
20800        // every peer substrate-side consumer of the author-omitted
20801        // `:licenca` slot ([`caixa-helm`]'s `build_readme` fallback arm at
20802        // `caixa-helm/src/lib.rs`, the future M4
20803        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-CR
20804        // `Chart.yaml annotations["artifacthub.io/license"]` emitter this
20805        // crate's [`Caixa::validate_licenca`] docstring roadmap already
20806        // names as the second consumer) fills into its per-consumer
20807        // README/annotation emit site. Pin the literal here (peer with the
20808        // [`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`] /
20809        // [`crate::version::DEFAULT_GIT_REMOTE`] /
20810        // [`crate::version::DEFAULT_PLEME_GIT_ORG`] canonical-literal pins
20811        // on the sibling lifted-constant surfaces) so a future
20812        // substrate-side license-fallback rebrand surfaces here as a
20813        // coordinated edit-point: the sibling caixa-helm
20814        // `build_readme_license_line_routes_through_lifted_caixa_licenca_default`
20815        // pinning test already pins the equality at the renderer-emit
20816        // axis; this pin closes the second coordinate of the pair by
20817        // anchoring the lifted constant's current byte to the canonical
20818        // CAIXA-SDLC §I license scaffold's documented shape.
20819        assert_eq!(CAIXA_LICENCA_DEFAULT, "MIT");
20820    }
20821
20822    // ── Caixa::validate_upgrade_from — compound per-Caixa entry gate on ──
20823    // ── the M2 `:upgrade-from` slot: folds the three top-level        ──
20824    // ── `crate::upgrade` validators (per-entry + cross-entry           ──
20825    // ── duplicate-`:from`, cross-slot `:from < :versao` precedence,   ──
20826    // ── cross-slot `:state-change` ↔ `:on-state-change` composition)  ──
20827    // ── onto one substrate primitive. Byte-for-byte equivalent to the ──
20828    // ── pre-fold three-block cascade at                               ──
20829    // ── `crate::layout::StandardLayout::verify` under the same        ──
20830    // ── canonical dispatch order.                                     ──
20831
20832    #[test]
20833    fn validate_upgrade_from_folds_per_entry_arm_matches_gate() {
20834        // Fail-before-pass-after per-arm equivalence pin on the
20835        // per-entry + cross-entry axis: a fixture whose `:upgrade-from`
20836        // carries a per-entry-invalid `:from` (git-tag shape `"v0.1.0"`,
20837        // which `semver::Version::parse` rejects) surfaces the same
20838        // [`crate::UpgradeError`] through the compound gate
20839        // [`Caixa::validate_upgrade_from`] and the standalone per-entry
20840        // gate [`crate::upgrade::validate_upgrade_from`] on the same
20841        // [`Caixa::upgrade_from`] slice. Pins the fold — a silent
20842        // regression that de-folded the per-entry arm would surface here
20843        // as a mismatch between the two dispatches. Sibling in shape to
20844        // the peer per-slot-≡-standalone equivalence pins the
20845        // [`crate::AplicacaoSpec::validate_contratos`] /
20846        // [`crate::MeshPolicy::validate`] /
20847        // [`crate::SupervisorSpec::validate_children`] compound gates
20848        // each carry on their axes.
20849        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20850        c.upgrade_from = vec![crate::UpgradeFromEntry {
20851            from: "v0.1.0".into(),
20852            instructions: vec![crate::UpgradeInstruction::Restart],
20853        }];
20854        let via_method = c.validate_upgrade_from().unwrap_err();
20855        let via_standalone = crate::upgrade::validate_upgrade_from(c.upgrade_from()).unwrap_err();
20856        assert_eq!(
20857            via_method, via_standalone,
20858            "Caixa::validate_upgrade_from must surface the per-entry \
20859             axis's diagnostic byte-equal to the standalone \
20860             `crate::upgrade::validate_upgrade_from` on the same \
20861             upgrade_from() slice"
20862        );
20863        assert!(
20864            matches!(
20865                via_method,
20866                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.1.0"
20867            ),
20868            "expected FromInvalid on the git-tag-shape `:from`, got {via_method:?}"
20869        );
20870    }
20871
20872    #[test]
20873    fn validate_upgrade_from_folds_versao_arm_matches_gate() {
20874        // Per-arm equivalence pin on the cross-slot `:from ↔ :versao`
20875        // precedence axis: a fixture with a well-formed `:from` (so the
20876        // per-entry arm passes) whose parsed semver is >= the caixa's
20877        // `:versao` under SemVer-2 precedence surfaces the same
20878        // [`crate::UpgradeError::FromNotBeforeVersao`] through both the
20879        // compound gate and the standalone
20880        // [`crate::upgrade::validate_upgrade_from_against_versao`] gate
20881        // keyed off the same `(upgrade_from, versao)` pair. Pins the
20882        // fold's second arm — reaching this arm through the compound
20883        // gate requires the per-entry arm to pass first, which itself
20884        // pins the per-arm cross-arm ordering.
20885        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20886        c.versao = "0.1.0".into();
20887        c.upgrade_from = vec![crate::UpgradeFromEntry {
20888            from: "0.2.0".into(),
20889            instructions: vec![crate::UpgradeInstruction::Restart],
20890        }];
20891        let via_method = c.validate_upgrade_from().unwrap_err();
20892        let via_standalone =
20893            crate::upgrade::validate_upgrade_from_against_versao(c.upgrade_from(), c.versao())
20894                .unwrap_err();
20895        assert_eq!(
20896            via_method, via_standalone,
20897            "Caixa::validate_upgrade_from must surface the \
20898             `:from >= :versao` diagnostic byte-equal to the standalone \
20899             `crate::upgrade::validate_upgrade_from_against_versao` on \
20900             the same (upgrade_from, versao) pair"
20901        );
20902        assert!(
20903            matches!(
20904                via_method,
20905                crate::UpgradeError::FromNotBeforeVersao { ref from, ref versao }
20906                    if from == "0.2.0" && versao == "0.1.0"
20907            ),
20908            "expected FromNotBeforeVersao carrying the offending pair, got {via_method:?}"
20909        );
20910    }
20911
20912    #[test]
20913    fn validate_upgrade_from_folds_behavior_arm_matches_gate() {
20914        // Per-arm equivalence pin on the cross-slot `:state-change ↔
20915        // :on-state-change` composition axis: a fixture with a
20916        // well-formed `:from` strictly less than `:versao` (so the
20917        // per-entry and versao arms both pass) whose `:instructions`
20918        // list carries a `(:state-change …)` instruction with no
20919        // `:behavior :on-state-change` callback declared surfaces the
20920        // same [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
20921        // through both the compound gate and the standalone
20922        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
20923        // gate keyed off the same `(upgrade_from, behavior)` pair.
20924        // Reaching this arm through the compound gate requires both
20925        // prior arms to pass first — the ordering pin below pins the
20926        // per-arm dispatch order explicitly.
20927        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20928        c.versao = "0.2.0".into();
20929        c.behavior = None;
20930        c.upgrade_from = vec![crate::UpgradeFromEntry {
20931            from: "0.1.0".into(),
20932            instructions: vec![
20933                crate::UpgradeInstruction::LoadModule {
20934                    module: "demo".into(),
20935                },
20936                crate::UpgradeInstruction::StateChange {
20937                    script: std::path::PathBuf::from("lib/m.lisp"),
20938                },
20939                crate::UpgradeInstruction::SoftPurge {
20940                    module: "demo-old".into(),
20941                },
20942            ],
20943        }];
20944        let via_method = c.validate_upgrade_from().unwrap_err();
20945        let via_standalone =
20946            crate::upgrade::validate_upgrade_from_against_behavior(c.upgrade_from(), c.behavior())
20947                .unwrap_err();
20948        assert_eq!(
20949            via_method, via_standalone,
20950            "Caixa::validate_upgrade_from must surface the \
20951             `:state-change` ↔ `:on-state-change` composition \
20952             diagnostic byte-equal to the standalone \
20953             `crate::upgrade::validate_upgrade_from_against_behavior` \
20954             on the same (upgrade_from, behavior) pair"
20955        );
20956        assert!(
20957            matches!(
20958                via_method,
20959                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback {
20960                    ref from,
20961                    ref script,
20962                } if from == "0.1.0" && script == &std::path::PathBuf::from("lib/m.lisp")
20963            ),
20964            "expected StateChangeWithoutOnStateChangeCallback carrying \
20965             the offending (from, script) pair, got {via_method:?}"
20966        );
20967    }
20968
20969    #[test]
20970    fn validate_upgrade_from_per_entry_arm_fires_before_versao_arm() {
20971        // Cross-arm ordering pin between the first two arms of the
20972        // fold: a fixture carrying BOTH a per-entry-invalid `:from`
20973        // (`"v0.0.5"` — git-tag shape rejected by
20974        // [`crate::upgrade::validate_upgrade_from`]) AND a would-be
20975        // versao-precedence violation on a second entry (`"0.2.0" >=
20976        // :versao "0.1.0"`) surfaces the per-entry diagnostic first
20977        // through the compound gate. Sanity assertion: the second
20978        // entry alone under the same `:versao` trips the versao arm
20979        // on its own via the standalone
20980        // [`crate::upgrade::validate_upgrade_from_against_versao`], so
20981        // the per-entry-first surfacing is a real ordering property,
20982        // not a case where the versao arm silently accepts the
20983        // fixture. Pins the pre-fold layout wire-up's canonical
20984        // dispatch order (per-entry → versao → behavior) as a
20985        // property of the substrate primitive rather than a
20986        // convention of the layout call site.
20987        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20988        c.versao = "0.1.0".into();
20989        c.upgrade_from = vec![
20990            crate::UpgradeFromEntry {
20991                from: "v0.0.5".into(),
20992                instructions: vec![crate::UpgradeInstruction::Restart],
20993            },
20994            crate::UpgradeFromEntry {
20995                from: "0.2.0".into(),
20996                instructions: vec![crate::UpgradeInstruction::Restart],
20997            },
20998        ];
20999        let err = c.validate_upgrade_from().unwrap_err();
21000        assert!(
21001            matches!(
21002                err,
21003                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.0.5"
21004            ),
21005            "per-entry arm must fire before versao arm — expected \
21006             FromInvalid on `v0.0.5`, got {err:?}"
21007        );
21008        // Sanity: the versao-violating second entry alone under the
21009        // same `:versao` trips the versao arm on its own — proves the
21010        // per-entry-first surfacing above is a real ordering property.
21011        let sanity = crate::upgrade::validate_upgrade_from_against_versao(
21012            &[crate::UpgradeFromEntry {
21013                from: "0.2.0".into(),
21014                instructions: vec![crate::UpgradeInstruction::Restart],
21015            }],
21016            "0.1.0",
21017        )
21018        .unwrap_err();
21019        assert!(
21020            matches!(sanity, crate::UpgradeError::FromNotBeforeVersao { .. }),
21021            "sanity: the versao-violating fixture alone must trip the \
21022             versao arm — got {sanity:?}"
21023        );
21024    }
21025
21026    #[test]
21027    fn validate_upgrade_from_versao_arm_fires_before_behavior_arm() {
21028        // Cross-arm ordering pin between the second and third arms of
21029        // the fold: a fixture carrying BOTH a versao-precedence
21030        // violation (`:from "0.2.0" >= :versao "0.1.0"`) AND a
21031        // would-be missing-callback violation (a `(:state-change …)`
21032        // instruction with no `:behavior :on-state-change`) surfaces
21033        // the versao diagnostic first through the compound gate.
21034        // Sanity assertion: the missing-callback fixture alone (with
21035        // the versao-precedence violation removed by bumping
21036        // `:versao` past `:from`) trips the behavior arm on its own
21037        // via the standalone
21038        // [`crate::upgrade::validate_upgrade_from_against_behavior`],
21039        // so the versao-first surfacing is a real ordering property,
21040        // not a case where the behavior arm silently accepts the
21041        // fixture.
21042        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21043        c.versao = "0.1.0".into();
21044        c.behavior = None;
21045        c.upgrade_from = vec![crate::UpgradeFromEntry {
21046            from: "0.2.0".into(),
21047            instructions: vec![
21048                crate::UpgradeInstruction::LoadModule {
21049                    module: "demo".into(),
21050                },
21051                crate::UpgradeInstruction::StateChange {
21052                    script: std::path::PathBuf::from("lib/m.lisp"),
21053                },
21054            ],
21055        }];
21056        let err = c.validate_upgrade_from().unwrap_err();
21057        assert!(
21058            matches!(
21059                err,
21060                crate::UpgradeError::FromNotBeforeVersao { ref from, .. } if from == "0.2.0"
21061            ),
21062            "versao arm must fire before behavior arm — expected \
21063             FromNotBeforeVersao on `0.2.0`, got {err:?}"
21064        );
21065        // Sanity: the same instructions under a `:versao` that
21066        // accepts the `:from` (so the versao arm passes) trips the
21067        // behavior arm — proves the versao-first surfacing above is a
21068        // real ordering property.
21069        let sanity = crate::upgrade::validate_upgrade_from_against_behavior(
21070            &[crate::UpgradeFromEntry {
21071                from: "0.2.0".into(),
21072                instructions: vec![
21073                    crate::UpgradeInstruction::LoadModule {
21074                        module: "demo".into(),
21075                    },
21076                    crate::UpgradeInstruction::StateChange {
21077                        script: std::path::PathBuf::from("lib/m.lisp"),
21078                    },
21079                ],
21080            }],
21081            None,
21082        )
21083        .unwrap_err();
21084        assert!(
21085            matches!(
21086                sanity,
21087                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback { .. }
21088            ),
21089            "sanity: the missing-callback fixture alone must trip the \
21090             behavior arm — got {sanity:?}"
21091        );
21092    }
21093
21094    #[test]
21095    fn validate_upgrade_from_accepts_clean_fixture() {
21096        // Positive control: a well-formed `:upgrade-from` (single entry
21097        // with `:from` strictly less than `:versao`, no
21098        // `:state-change` instruction so the behavior arm is vacuous)
21099        // passes the compound gate cleanly. A future tightening of any
21100        // one arm's accepted set surfaces here as a test failure
21101        // first. Mirrors the peer `validate_versao_accepts_canonical_forms`
21102        // positive-control posture on the sibling per-Caixa gate.
21103        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21104        c.versao = "0.2.0".into();
21105        c.upgrade_from = vec![crate::UpgradeFromEntry {
21106            from: "0.1.0".into(),
21107            instructions: vec![crate::UpgradeInstruction::Restart],
21108        }];
21109        c.validate_upgrade_from()
21110            .expect("clean fixture must pass the compound `:upgrade-from` gate");
21111    }
21112
21113    #[test]
21114    fn validate_upgrade_from_accepts_empty_upgrade_from() {
21115        // Positive control on the empty-list arm: a caixa without any
21116        // `:upgrade-from` block (the default `Vec::new()`
21117        // `#[serde(default)]` folds an omitted slot onto) passes the
21118        // compound gate cleanly regardless of `:versao` or `:behavior`
21119        // — each of the three standalone validators is vacuous on the
21120        // empty entry list. Pins the identity element of the fold on
21121        // the empty-slot side.
21122        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21123        assert!(
21124            c.upgrade_from().is_empty(),
21125            "template caixa must carry an empty :upgrade-from — got {:?}",
21126            c.upgrade_from()
21127        );
21128        c.validate_upgrade_from()
21129            .expect("empty :upgrade-from must pass the compound gate cleanly");
21130    }
21131
21132    // ── Caixa::validate_limits — compound per-Caixa entry gate on   ──
21133    // ── the M2 `:limits` slot: folds the                            ──
21134    // ── [`crate::LimitsSpec::validate`] four-axis cascade on the    ──
21135    // ── present-slot arm and the `Option::None` identity element on ──
21136    // ── the absent-slot arm onto one substrate primitive.           ──
21137    // ── Byte-for-byte equivalent to the pre-fold                    ──
21138    // ── `if let Some(l) = caixa.limits() { l.validate() }`          ──
21139    // ── unwrap-and-dispatch pattern at                              ──
21140    // ── `crate::layout::StandardLayout::verify` (`layout.rs`).      ──
21141
21142    #[test]
21143    fn validate_limits_folds_arm_matches_gate() {
21144        // Fail-before-pass-after per-arm equivalence pin on the
21145        // present-slot arm: a fixture whose `:limits` carries a
21146        // zero-floor-violating `:fuel` (`Some(0)`, which
21147        // [`crate::LimitsSpec::validate`] rejects through
21148        // [`crate::LimitsError::FuelZero`]) surfaces the same
21149        // [`crate::LimitsError`] byte-equal through both the compound
21150        // gate [`Caixa::validate_limits`] and the standalone
21151        // [`crate::LimitsSpec::validate`] gate on the same `LimitsSpec`
21152        // value. Pins the fold — a silent regression that de-folded
21153        // the present-slot arm would surface here as a mismatch
21154        // between the two dispatches. Sibling in shape to the peer
21155        // per-arm equivalence pins the
21156        // [`crate::AplicacaoSpec::validate_contratos`] /
21157        // [`crate::MeshPolicy::validate`] /
21158        // [`crate::SupervisorSpec::validate_children`] /
21159        // [`Caixa::validate_upgrade_from`] compound gates each carry
21160        // on their axes.
21161        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21162        let l = crate::LimitsSpec {
21163            memory: None,
21164            fuel: Some(0),
21165            wall_clock: None,
21166            cpu: None,
21167        };
21168        c.limits = Some(l);
21169        let via_method = c.validate_limits().unwrap_err();
21170        let via_standalone = l.validate().unwrap_err();
21171        assert_eq!(
21172            via_method, via_standalone,
21173            "Caixa::validate_limits must surface the present-slot \
21174             arm's diagnostic byte-equal to the standalone \
21175             `LimitsSpec::validate` on the same `LimitsSpec` value"
21176        );
21177        assert!(
21178            matches!(via_method, crate::LimitsError::FuelZero),
21179            "expected FuelZero on the zero-floor-violating `:fuel`, \
21180             got {via_method:?}"
21181        );
21182    }
21183
21184    #[test]
21185    fn validate_limits_accepts_none() {
21186        // Positive control on the absent-slot arm (the fold's identity
21187        // element): a caixa without any `:limits` block (the
21188        // canonical "no bound declared — engine-default applies"
21189        // author shape [`crate::LimitsSpec::is_empty`]'s per-axis
21190        // `None` cascade reads, and the shape the [`Caixa::template`]
21191        // scaffold emits by construction) passes the compound gate
21192        // cleanly, regardless of any per-axis defect a subsequent
21193        // `Some(_)` binding would surface. Pins the identity element
21194        // of the fold on the absent-slot side, matching the peer
21195        // `validate_upgrade_from_accepts_empty_upgrade_from` positive-
21196        // control posture on the sibling M2 slot.
21197        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21198        assert!(
21199            c.limits().is_none(),
21200            "template caixa must carry an absent :limits — got {:?}",
21201            c.limits()
21202        );
21203        c.validate_limits()
21204            .expect("absent :limits must pass the compound gate cleanly");
21205    }
21206
21207    #[test]
21208    fn validate_limits_accepts_clean_fixture() {
21209        // Positive control on the present-slot arm: a caixa whose
21210        // `:limits` is `Some(LimitsSpec::default())` (all four axes
21211        // `None` — every axis absent under the outer `Some(_)`
21212        // binding, so every present-slot arm on
21213        // [`crate::LimitsSpec::validate`] is vacuous) passes the
21214        // compound gate cleanly. A future tightening of any one axis
21215        // that surfaces a diagnostic on the all-`None` `LimitsSpec`
21216        // would land here as a test failure first. Pins the
21217        // present-slot arm's accept-shape on the canonical
21218        // "declared-but-empty" author fixture the
21219        // `limits_round_trip_via_json` peer already round-trips
21220        // (`caixa-core/src/manifest.rs:6971`).
21221        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21222        c.limits = Some(crate::LimitsSpec::default());
21223        c.validate_limits()
21224            .expect("Some(LimitsSpec::default()) must pass the compound gate cleanly");
21225    }
21226
21227    // ── Caixa::validate_behavior — compound per-Caixa entry gate on ──
21228    // ── the M2 `:behavior` slot's pure value-shape surface: folds   ──
21229    // ── the [`crate::BehaviorSpec::validate`] six-slot cascade on   ──
21230    // ── the present-slot arm and the `Option::None` identity        ──
21231    // ── element on the absent-slot arm onto one substrate primitive.──
21232    // ── Byte-for-byte equivalent to the pre-fold                    ──
21233    // ── `if let Some(b) = caixa.behavior() { b.validate() }`        ──
21234    // ── unwrap-and-dispatch pattern at                              ──
21235    // ── `crate::layout::StandardLayout::verify` (`layout.rs`). The  ──
21236    // ── on-disk callback-path existence walk stays open-coded at    ──
21237    // ── the layout altitude because it needs the                    ──
21238    // ── [`crate::layout::LayoutInvariants::exists`] filesystem       ──
21239    // ── oracle the pure typed-shape surface has no reference to —   ──
21240    // ── mirror of the peer M2 `:upgrade-from` per-instruction       ──
21241    // ── script-path existence probe that stayed at the layout       ──
21242    // ── altitude after the [`Caixa::validate_upgrade_from`] lift    ──
21243    // ── (d6801df) for the same reason.                              ──
21244
21245    #[test]
21246    fn validate_behavior_folds_arm_matches_gate() {
21247        // Fail-before-pass-after per-arm equivalence pin on the
21248        // present-slot arm: a fixture whose `:behavior` carries an
21249        // absolute-path `:on-init` (`"/etc/passwd"`, which
21250        // [`crate::BehaviorSpec::validate`] rejects through
21251        // [`crate::BehaviorError::AbsolutePath`]) surfaces the same
21252        // [`crate::BehaviorError`] byte-equal through both the
21253        // compound gate [`Caixa::validate_behavior`] and the standalone
21254        // [`crate::BehaviorSpec::validate`] gate on the same
21255        // `BehaviorSpec` value. Pins the fold — a silent regression
21256        // that de-folded the present-slot arm would surface here as a
21257        // mismatch between the two dispatches. Sibling in shape to the
21258        // peer per-arm equivalence pins the
21259        // [`Caixa::validate_limits`] (baa4688),
21260        // [`Caixa::validate_upgrade_from`] (d6801df),
21261        // [`crate::MeshPolicy::validate`],
21262        // [`crate::AplicacaoSpec::validate_contratos`], and
21263        // [`crate::SupervisorSpec::validate_children`] compound gates
21264        // each carry on their axes.
21265        use crate::BehaviorSpec;
21266        use std::path::PathBuf;
21267        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21268        let b = BehaviorSpec {
21269            on_init: Some(PathBuf::from("/etc/passwd")),
21270            ..Default::default()
21271        };
21272        c.behavior = Some(b.clone());
21273        let via_method = c.validate_behavior().unwrap_err();
21274        let via_standalone = b.validate().unwrap_err();
21275        assert_eq!(
21276            via_method, via_standalone,
21277            "Caixa::validate_behavior must surface the present-slot \
21278             arm's diagnostic byte-equal to the standalone \
21279             `BehaviorSpec::validate` on the same `BehaviorSpec` value"
21280        );
21281        assert!(
21282            matches!(via_method, crate::BehaviorError::AbsolutePath { .. }),
21283            "expected AbsolutePath on the absolute `:on-init` path, \
21284             got {via_method:?}"
21285        );
21286    }
21287
21288    #[test]
21289    fn validate_behavior_accepts_none() {
21290        // Positive control on the absent-slot arm (the fold's identity
21291        // element): a caixa without any `:behavior` block (the
21292        // canonical "no callback declared — the runtime falls back to
21293        // the wasm-engine's default per arm" author shape
21294        // [`crate::BehaviorSpec::is_empty`]'s per-slot `None` cascade
21295        // reads, and the shape the [`Caixa::template`] scaffold emits
21296        // by construction) passes the compound gate cleanly,
21297        // regardless of any per-slot defect a subsequent `Some(_)`
21298        // binding would surface. Pins the identity element of the fold
21299        // on the absent-slot side, matching the peer
21300        // `validate_limits_accepts_none` (baa4688) and
21301        // `validate_upgrade_from_accepts_empty_upgrade_from` (d6801df)
21302        // positive-control postures on the sibling M2 slots.
21303        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21304        assert!(
21305            c.behavior().is_none(),
21306            "template caixa must carry an absent :behavior — got {:?}",
21307            c.behavior()
21308        );
21309        c.validate_behavior()
21310            .expect("absent :behavior must pass the compound gate cleanly");
21311    }
21312
21313    #[test]
21314    fn validate_behavior_accepts_clean_fixture() {
21315        // Positive control on the present-slot arm: a caixa whose
21316        // `:behavior` is `Some(BehaviorSpec::default())` (all six
21317        // slots `None` — every slot absent under the outer `Some(_)`
21318        // binding, so every present-slot arm on
21319        // [`crate::BehaviorSpec::validate`] is vacuous) passes the
21320        // compound gate cleanly. A future tightening of any one arm
21321        // that surfaces a diagnostic on the all-`None` `BehaviorSpec`
21322        // would land here as a test failure first. Pins the
21323        // present-slot arm's accept-shape on the canonical
21324        // "declared-but-empty" author fixture the sibling
21325        // `empty_behavior_round_trip` peer already round-trips
21326        // (`caixa-core/src/behavior.rs` tests). Mirror of the peer
21327        // `validate_limits_accepts_clean_fixture` (baa4688)
21328        // positive-control posture on the sibling M2 `:limits` slot.
21329        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21330        c.behavior = Some(crate::BehaviorSpec::default());
21331        c.validate_behavior()
21332            .expect("Some(BehaviorSpec::default()) must pass the compound gate cleanly");
21333    }
21334
21335    // ── Caixa::validate_deps — compound per-Caixa entry gate on the ──
21336    // ── dep-graph axis: folds the two standalone validators         ──
21337    // ── (per-entry + within-list duplicate walk that this method    ──
21338    // ── opened on, cross-slot self-edge via                         ──
21339    // ── `crate::dep::validate_no_self_dep`) onto one substrate      ──
21340    // ── primitive. Byte-for-byte equivalent to the pre-fold         ──
21341    // ── two-block cascade at                                        ──
21342    // ── `crate::layout::StandardLayout::verify` under the same      ──
21343    // ── canonical dispatch order (per-entry → self-edge).           ──
21344
21345    #[test]
21346    fn validate_deps_folds_per_entry_arm_matches_gate() {
21347        // Fail-before-pass-after per-arm equivalence pin on the
21348        // per-entry + within-list duplicate axis: a fixture whose
21349        // `:deps` carries a per-entry-invalid `:versao` (`"^bad"`,
21350        // which [`crate::parse_requirement`] rejects) surfaces the
21351        // same [`crate::DepError`] through the compound gate
21352        // [`Caixa::validate_deps`] and the standalone per-entry walk
21353        // ([`Dep::validate`]) on the offending entry. Pins the
21354        // fold — a silent regression that de-folded the per-entry arm
21355        // would surface here as a mismatch between the two
21356        // dispatches. Sibling in shape to the peer
21357        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
21358        // per-arm equivalence pin (d6801df) on the M2
21359        // `:upgrade-from` compound gate's per-entry arm, extended
21360        // here onto the universal-axis `:deps` compound gate's
21361        // per-entry arm.
21362        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21363        c.deps = vec![Dep::simple("d", "^bad")];
21364        let via_method = c.validate_deps().unwrap_err();
21365        let via_standalone = c.deps()[0].validate().unwrap_err();
21366        assert_eq!(
21367            via_method, via_standalone,
21368            "Caixa::validate_deps must surface the per-entry arm's \
21369             diagnostic byte-equal to the standalone \
21370             `Dep::validate` on the same offending entry",
21371        );
21372        assert!(
21373            matches!(
21374                via_method,
21375                DepError::VersaoInvalid { ref nome, .. } if nome == "d"
21376            ),
21377            "expected VersaoInvalid on the malformed :versao, got {via_method:?}",
21378        );
21379    }
21380
21381    #[test]
21382    fn validate_deps_folds_self_edge_arm_matches_gate() {
21383        // Per-arm equivalence pin on the cross-slot self-edge axis:
21384        // a fixture whose `:deps` lists the caixa's own `:nome`
21385        // (a self-dep, which
21386        // [`crate::dep::validate_no_self_dep`] rejects as a
21387        // structurally-invalid one-node cycle in the lacre closure's
21388        // dep-graph) surfaces the same [`crate::DepError::DepIsSelf`]
21389        // through both the compound gate and the standalone
21390        // [`crate::dep::validate_no_self_dep`] gate keyed off the
21391        // same `(deps, deps_dev, nome)` triple. Pins the fold's
21392        // second arm — reaching this arm through the compound gate
21393        // requires the per-entry + within-list duplicate walk to
21394        // pass first, which itself pins one cross-arm ordering step.
21395        // Sibling in shape to the peer
21396        // `validate_upgrade_from_folds_versao_arm_matches_gate` /
21397        // `_folds_behavior_arm_matches_gate` cross-slot equivalence
21398        // pins (d6801df) on the M2 `:upgrade-from` compound gate's
21399        // cross-slot arms.
21400        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21401        c.deps = vec![Dep::simple("demo", "^0.1")];
21402        let via_method = c.validate_deps().unwrap_err();
21403        let via_standalone =
21404            crate::dep::validate_no_self_dep(c.deps(), c.deps_dev(), c.nome()).unwrap_err();
21405        assert_eq!(
21406            via_method, via_standalone,
21407            "Caixa::validate_deps must surface the cross-slot \
21408             self-edge diagnostic byte-equal to the standalone \
21409             `crate::dep::validate_no_self_dep` on the same \
21410             (deps, deps_dev, nome) triple",
21411        );
21412        assert!(
21413            matches!(
21414                via_method,
21415                DepError::DepIsSelf { ref nome, list }
21416                    if nome == "demo" && list == crate::render::DEP_AUTHOR_KEY_DEPS
21417            ),
21418            "expected DepIsSelf carrying (nome=\"demo\", list=\":deps\"), got {via_method:?}",
21419        );
21420    }
21421
21422    #[test]
21423    fn validate_deps_per_entry_arm_fires_before_self_edge_arm() {
21424        // Cross-arm ordering pin between the two arms of the fold:
21425        // a fixture carrying BOTH a per-entry-invalid `:versao`
21426        // (`"^bad"` — [`crate::parse_requirement`] rejects the
21427        // requirement grammar) on a non-self-dep entry AND a
21428        // would-be self-edge violation on a second entry (the
21429        // caixa's own `:nome` "demo") surfaces the per-entry
21430        // diagnostic first through the compound gate. Sanity
21431        // assertion: the second entry alone under the same parent
21432        // `:nome` trips the self-edge arm on its own via the
21433        // standalone [`crate::dep::validate_no_self_dep`], so the
21434        // per-entry-first surfacing is a real ordering property,
21435        // not a case where the self-edge arm silently accepts the
21436        // fixture. Pins the pre-fold layout wire-up's canonical
21437        // dispatch order (per-entry + within-list duplicate →
21438        // self-edge) as a property of the substrate primitive
21439        // rather than a convention of the layout call site. Sibling
21440        // in shape to
21441        // `validate_upgrade_from_per_entry_arm_fires_before_versao_arm`
21442        // (d6801df) on the M2 `:upgrade-from` compound gate's
21443        // per-arm ordering property.
21444        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21445        c.deps = vec![
21446            Dep::simple("orquestra", "^bad"),
21447            Dep::simple("demo", "^0.1"),
21448        ];
21449        let err = c.validate_deps().unwrap_err();
21450        assert!(
21451            matches!(
21452                err,
21453                DepError::VersaoInvalid { ref nome, .. } if nome == "orquestra"
21454            ),
21455            "per-entry arm must fire before self-edge arm — expected \
21456             VersaoInvalid on \"orquestra\", got {err:?}",
21457        );
21458        // Sanity: the self-referential entry alone under the same
21459        // parent `:nome` trips the self-edge arm on its own — proves
21460        // the per-entry-first surfacing above is a real ordering
21461        // property, not a case where the self-edge arm silently
21462        // accepts the fixture.
21463        let sanity = crate::dep::validate_no_self_dep(&[Dep::simple("demo", "^0.1")], &[], "demo")
21464            .unwrap_err();
21465        assert!(
21466            matches!(sanity, DepError::DepIsSelf { ref nome, .. } if nome == "demo"),
21467            "sanity: the self-referential entry alone must trip the \
21468             self-edge arm — got {sanity:?}",
21469        );
21470    }
21471
21472    #[test]
21473    fn validate_deps_accepts_clean_fixture() {
21474        // Positive control: a well-formed dep-graph (one `:deps`
21475        // entry naming a non-self DNS-1123 nome + Cargo-shaped
21476        // requirement, one `:deps-dev` entry on a distinct non-self
21477        // nome) passes the compound gate cleanly. A future
21478        // tightening of either arm's accepted set surfaces here as
21479        // a test failure first. Mirrors the peer
21480        // `validate_upgrade_from_accepts_clean_fixture` positive-
21481        // control posture on the sibling per-Caixa compound gate.
21482        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21483        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
21484        c.deps_dev = vec![Dep::simple("caixa-lint", "^0.2")];
21485        c.validate_deps()
21486            .expect("clean fixture must pass the compound `:deps` gate");
21487    }
21488
21489    #[test]
21490    fn validate_deps_accepts_empty_deps_lists() {
21491        // Positive control on the empty-list arm: a caixa without
21492        // any `:deps` or `:deps-dev` entries (the default
21493        // `Vec::new()` `#[serde(default)]` folds an omitted slot
21494        // onto) passes the compound gate cleanly regardless of
21495        // `:nome` — both the per-entry walk and the self-edge walk
21496        // are vacuous on the empty entry list. Pins the identity
21497        // element of the fold on the empty-slot side, peer with the
21498        // `validate_upgrade_from_accepts_empty_upgrade_from` empty-
21499        // arm positive control (d6801df) on the sibling
21500        // `:upgrade-from` compound gate.
21501        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21502        assert!(
21503            c.deps().is_empty(),
21504            "template caixa must carry an empty :deps — got {:?}",
21505            c.deps(),
21506        );
21507        assert!(
21508            c.deps_dev().is_empty(),
21509            "template caixa must carry an empty :deps-dev — got {:?}",
21510            c.deps_dev(),
21511        );
21512        c.validate_deps()
21513            .expect("empty :deps / :deps-dev must pass the compound gate cleanly");
21514    }
21515
21516    // ── Caixa::validate_aplicacao_shape — compound per-Caixa gate ────────
21517
21518    /// Build a minimal well-formed Aplicacao fixture on top of the
21519    /// canonical template. Every arm of the compound gate then patches
21520    /// exactly one axis away from clean so its per-arm diagnostic
21521    /// surfaces without collateral noise from a peer slot.
21522    fn aplicacao_fixture(nome: &str) -> Caixa {
21523        use crate::aplicacao::{Membro, Placement, PlacementStrategy};
21524        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
21525        c.kind = CaixaKind::Aplicacao;
21526        c.bibliotecas = vec![];
21527        c.membros = vec![
21528            Membro {
21529                caixa: "checkout".into(),
21530                versao: "^0.1".into(),
21531            },
21532            Membro {
21533                caixa: "cart".into(),
21534                versao: "^0.1".into(),
21535            },
21536        ];
21537        // `:placement` defaults to `Replicated` with an empty
21538        // `:clusters` list which
21539        // [`crate::AplicacaoSpec::validate_placement`] refuses; every
21540        // per-strategy variant needs at least one named cluster (per
21541        // MESH-COMPOSITION §II.1). Pin a single-cluster `SingleNode`
21542        // placement so the typed-shape cascade passes cleanly and the
21543        // per-arm fixtures below can each patch exactly one axis.
21544        c.placement = Some(Placement {
21545            estrategia: PlacementStrategy::SingleNode,
21546            clusters: vec!["rio".into()],
21547            shard_key: None,
21548            affinity: None,
21549        });
21550        c
21551    }
21552
21553    #[test]
21554    fn validate_aplicacao_shape_folds_view_arm_matches_gate() {
21555        // Fail-before-pass-after per-arm equivalence pin on the
21556        // typed-shape cascade arm: a fixture whose typed
21557        // [`crate::AplicacaoSpec`] view fails
21558        // [`crate::AplicacaoSpec::validate`] (here — empty `:membros`,
21559        // which [`crate::AplicacaoSpec::validate_membros`] rejects as
21560        // [`crate::AplicacaoError::NoMembros`] at the first per-slot
21561        // gate) surfaces the same [`crate::AplicacaoError`] diagnostic
21562        // through both the compound gate
21563        // [`Caixa::validate_aplicacao_shape`] and the standalone
21564        // [`crate::AplicacaoSpec::validate`] on the same folded view.
21565        // Pins the fold — a silent regression that de-folded the
21566        // typed-shape arm would surface here as a mismatch between the
21567        // two dispatches. Sibling in shape to the peer
21568        // `validate_deps_folds_per_entry_arm_matches_gate` (b5dd55e) /
21569        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
21570        // (d6801df) per-arm equivalence pins on the sibling per-slot
21571        // compound gates.
21572        let mut c = aplicacao_fixture("demo");
21573        c.membros = vec![];
21574        let via_method = c.validate_aplicacao_shape().unwrap_err();
21575        let via_standalone = c.aplicacao_view().unwrap().validate().unwrap_err();
21576        assert_eq!(
21577            via_method, via_standalone,
21578            "Caixa::validate_aplicacao_shape must surface the typed-\
21579             shape arm's diagnostic byte-equal to the standalone \
21580             `AplicacaoSpec::validate` on the same folded view",
21581        );
21582        assert!(
21583            matches!(via_method, crate::AplicacaoError::NoMembros),
21584            "expected NoMembros on the empty :membros, got {via_method:?}",
21585        );
21586    }
21587
21588    #[test]
21589    fn validate_aplicacao_shape_folds_self_membership_arm_matches_gate() {
21590        // Per-arm equivalence pin on the cross-slot self-edge axis: a
21591        // fixture whose `:membros` names the Aplicacao's own `:nome`
21592        // (which [`crate::aplicacao::validate_no_self_membership`]
21593        // rejects as [`crate::AplicacaoError::MembroIsSelfAplicacao`],
21594        // a one-node lacre-closure recursion in the Aplicacao's
21595        // mesh-graph) surfaces the same
21596        // [`crate::AplicacaoError::MembroIsSelfAplicacao`] through both
21597        // the compound gate and the standalone
21598        // [`crate::aplicacao::validate_no_self_membership`] keyed off
21599        // the same `(membros, nome)` pair. Pins the fold's second arm
21600        // — reaching this arm through the compound gate requires the
21601        // typed-shape cascade to pass first, which itself pins one
21602        // cross-arm ordering step. Sibling in shape to the peer
21603        // `validate_deps_folds_self_edge_arm_matches_gate` (b5dd55e)
21604        // cross-slot equivalence pin on the sibling per-slot compound
21605        // gate.
21606        use crate::aplicacao::Membro;
21607        let mut c = aplicacao_fixture("demo");
21608        c.membros = vec![Membro {
21609            caixa: "demo".into(),
21610            versao: "^0.1".into(),
21611        }];
21612        let via_method = c.validate_aplicacao_shape().unwrap_err();
21613        let via_standalone =
21614            crate::aplicacao::validate_no_self_membership(c.membros(), c.nome()).unwrap_err();
21615        assert_eq!(
21616            via_method, via_standalone,
21617            "Caixa::validate_aplicacao_shape must surface the cross-\
21618             slot self-edge diagnostic byte-equal to the standalone \
21619             `aplicacao::validate_no_self_membership` on the same \
21620             (membros, nome) pair",
21621        );
21622        assert!(
21623            matches!(
21624                via_method,
21625                crate::AplicacaoError::MembroIsSelfAplicacao { ref caixa } if caixa == "demo"
21626            ),
21627            "expected MembroIsSelfAplicacao carrying (caixa=\"demo\"), \
21628             got {via_method:?}",
21629        );
21630    }
21631
21632    #[test]
21633    fn validate_aplicacao_shape_view_arm_fires_before_self_membership_arm() {
21634        // Cross-arm ordering pin between the two arms of the fold: a
21635        // fixture carrying BOTH a typed-shape violation (a `:contratos`
21636        // edge whose `:para` is not a declared member — rejected by
21637        // [`crate::AplicacaoSpec::validate_contratos`] as
21638        // [`crate::AplicacaoError::ContratoMemberMissing`]) AND a
21639        // would-be self-edge violation (a `:membros` entry naming the
21640        // caixa's own `:nome`) surfaces the typed-shape diagnostic
21641        // first through the compound gate. Sanity assertion: the
21642        // self-referential `:membros` entry alone under the same
21643        // parent `:nome` trips the self-edge arm on its own via the
21644        // standalone [`crate::aplicacao::validate_no_self_membership`],
21645        // so the typed-shape-first surfacing is a real ordering
21646        // property, not a case where the self-edge arm silently
21647        // accepts the fixture. Pins the pre-fold layout wire-up's
21648        // canonical dispatch order (typed-shape cascade → cross-slot
21649        // self-edge) as a property of the substrate primitive rather
21650        // than a convention of the layout call site. Sibling in shape
21651        // to `validate_deps_per_entry_arm_fires_before_self_edge_arm`
21652        // (b5dd55e) on the sibling per-slot compound gate's per-arm
21653        // ordering property.
21654        use crate::aplicacao::{Membro, WitContract};
21655        let mut c = aplicacao_fixture("demo");
21656        c.membros = vec![Membro {
21657            caixa: "demo".into(),
21658            versao: "^0.1".into(),
21659        }];
21660        c.contratos = vec![WitContract {
21661            de: "demo".into(),
21662            para: "orphan".into(),
21663            wit: "wasi:http/proxy".into(),
21664            endpoint: Some("/x".into()),
21665            subject: None,
21666            slot: None,
21667        }];
21668        let err = c.validate_aplicacao_shape().unwrap_err();
21669        assert!(
21670            matches!(
21671                err,
21672                crate::AplicacaoError::ContratoMemberMissing { ref caixa }
21673                    if caixa == "orphan"
21674            ),
21675            "typed-shape arm must fire before self-edge arm — expected \
21676             ContratoMemberMissing on \"orphan\", got {err:?}",
21677        );
21678        // Sanity: the self-referential `:membros` entry alone under
21679        // the same parent `:nome` trips the self-edge arm on its own
21680        // — proves the typed-shape-first surfacing above is a real
21681        // ordering property, not a case where the self-edge arm
21682        // silently accepts the fixture.
21683        let sanity = crate::aplicacao::validate_no_self_membership(
21684            &[Membro {
21685                caixa: "demo".into(),
21686                versao: "^0.1".into(),
21687            }],
21688            "demo",
21689        )
21690        .unwrap_err();
21691        assert!(
21692            matches!(
21693                sanity,
21694                crate::AplicacaoError::MembroIsSelfAplicacao { ref caixa }
21695                    if caixa == "demo"
21696            ),
21697            "sanity: the self-referential :membros entry alone must \
21698             trip the self-edge arm — got {sanity:?}",
21699        );
21700    }
21701
21702    #[test]
21703    fn validate_aplicacao_shape_accepts_non_aplicacao_kind() {
21704        // Positive control on the identity-element arm: every non-
21705        // Aplicacao kind passes the compound gate trivially — the
21706        // paired [`Caixa::aplicacao_view`] accessor returns `None`
21707        // off the Aplicacao arm (by construction, keyed on
21708        // `caixa.kind().is_aplicacao()`), so the fold short-circuits
21709        // to `Ok(())` without touching the mesh slots. Pins the
21710        // identity element on every non-Aplicacao kind — a future
21711        // refactor that made the mesh-slot cascade fire on the wrong
21712        // kind (say, on a `Servico` whose mesh slots happen to be
21713        // populated in a mis-authored manifest, which the peer
21714        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
21715        // coherence gate would refuse upstream anyway) surfaces here
21716        // as a test failure first. Peer with the
21717        // `validate_limits_accepts_none` / `validate_behavior_accepts_none`
21718        // identity-element pins on the sibling M2 `Option`-shaped
21719        // per-Caixa compound gates.
21720        for kind in [
21721            CaixaKind::Biblioteca,
21722            CaixaKind::Binario,
21723            CaixaKind::Servico,
21724            CaixaKind::Supervisor,
21725            CaixaKind::Acao,
21726        ] {
21727            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21728            c.kind = kind;
21729            assert!(
21730                c.aplicacao_view().is_none(),
21731                "aplicacao_view must return None off the Aplicacao arm \
21732                 for kind {kind:?}",
21733            );
21734            c.validate_aplicacao_shape().expect(
21735                "non-Aplicacao kinds must pass the compound gate as the fold's identity element",
21736            );
21737        }
21738    }
21739
21740    #[test]
21741    fn validate_aplicacao_shape_accepts_clean_fixture() {
21742        // Positive control: a well-formed Aplicacao (two DNS-1123
21743        // members with valid semver constraints, no `:contratos` /
21744        // `:entrada` / `:placement` / `:politicas` set — every
21745        // per-slot gate accepts the vacuous / omitted arm) passes the
21746        // compound gate cleanly. A future tightening of either arm's
21747        // accepted set surfaces here as a test failure first. Mirrors
21748        // the peer `validate_deps_accepts_clean_fixture` (b5dd55e) /
21749        // `validate_upgrade_from_accepts_clean_fixture` (d6801df)
21750        // positive-control postures on the sibling per-Caixa
21751        // compound gates.
21752        let c = aplicacao_fixture("demo");
21753        c.validate_aplicacao_shape()
21754            .expect("clean Aplicacao fixture must pass the compound gate");
21755    }
21756
21757    // ── Caixa::validate_supervisor_shape — compound per-Caixa gate ───────
21758
21759    /// Build a minimal well-formed Supervisor fixture on top of the
21760    /// canonical template. Every arm of the compound gate then patches
21761    /// exactly one axis away from clean so its per-arm diagnostic
21762    /// surfaces without collateral noise from a peer slot. Peer of
21763    /// [`aplicacao_fixture`] on the sibling per-Aplicacao compound
21764    /// gate's pin family.
21765    fn supervisor_fixture(nome: &str) -> Caixa {
21766        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
21767        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
21768        c.kind = CaixaKind::Supervisor;
21769        // Supervisors don't run code — clear the biblioteca slot the
21770        // template seeds so the fold's per-arm diagnostics surface
21771        // without the peer `SupervisorOwnsCode` kind-coherence gate
21772        // firing upstream at the layout altitude.
21773        c.bibliotecas = vec![];
21774        // `:estrategia` defaults to `OneForOne` at the typed view level,
21775        // and `OneForOne` requires at least one `:children` entry — pin
21776        // a single-child `Permanent` worker so the typed-shape cascade
21777        // passes cleanly and the per-arm fixtures below can each patch
21778        // exactly one axis.
21779        c.estrategia = Some(RestartStrategy::OneForOne);
21780        c.children = vec![ChildSpec {
21781            caixa: "worker".into(),
21782            versao: "^0.1".into(),
21783            restart: RestartPolicy::Permanent,
21784        }];
21785        c
21786    }
21787
21788    #[test]
21789    fn validate_supervisor_shape_folds_view_arm_matches_gate() {
21790        // Fail-before-pass-after per-arm equivalence pin on the
21791        // typed-shape cascade arm: a fixture whose typed
21792        // [`crate::SupervisorSpec`] view fails
21793        // [`crate::SupervisorSpec::validate`] (here — a duplicate
21794        // `:children` `:caixa` entry, which
21795        // [`crate::SupervisorSpec::validate`]'s set-not-multiset gate
21796        // rejects as [`crate::SupervisorError::DuplicateChildCaixa`])
21797        // surfaces the same [`crate::SupervisorError`] diagnostic
21798        // through both the compound gate
21799        // [`Caixa::validate_supervisor_shape`] and the standalone
21800        // [`crate::SupervisorSpec::validate`] on the same folded view.
21801        // Pins the fold — a silent regression that de-folded the
21802        // typed-shape arm would surface here as a mismatch between the
21803        // two dispatches. Sibling in shape to the peer
21804        // `validate_aplicacao_shape_folds_view_arm_matches_gate`
21805        // (949a7a0) on the sibling per-Aplicacao compound gate.
21806        use crate::supervisor::{ChildSpec, RestartPolicy};
21807        let mut c = supervisor_fixture("demo");
21808        c.children = vec![
21809            ChildSpec {
21810                caixa: "worker".into(),
21811                versao: "^0.1".into(),
21812                restart: RestartPolicy::Permanent,
21813            },
21814            ChildSpec {
21815                caixa: "worker".into(),
21816                versao: "^0.1".into(),
21817                restart: RestartPolicy::Permanent,
21818            },
21819        ];
21820        let via_method = c.validate_supervisor_shape().unwrap_err();
21821        let via_standalone = c.supervisor_view().unwrap().validate().unwrap_err();
21822        assert_eq!(
21823            via_method, via_standalone,
21824            "Caixa::validate_supervisor_shape must surface the typed-\
21825             shape arm's diagnostic byte-equal to the standalone \
21826             `SupervisorSpec::validate` on the same folded view",
21827        );
21828        assert!(
21829            matches!(
21830                via_method,
21831                crate::SupervisorError::DuplicateChildCaixa { ref caixa }
21832                    if caixa == "worker"
21833            ),
21834            "expected DuplicateChildCaixa on the duplicate 'worker' \
21835             child, got {via_method:?}",
21836        );
21837    }
21838
21839    #[test]
21840    fn validate_supervisor_shape_folds_self_supervision_arm_matches_gate() {
21841        // Per-arm equivalence pin on the cross-slot self-edge axis: a
21842        // fixture whose `:children :caixa` names the Supervisor's own
21843        // `:nome` (which
21844        // [`crate::supervisor::validate_no_self_supervision`] rejects
21845        // as [`crate::SupervisorError::ChildSupervisesSelf`], a
21846        // one-node reconciliation cycle in the supervisor's
21847        // supervision-tree) surfaces the same
21848        // [`crate::SupervisorError::ChildSupervisesSelf`] through both
21849        // the compound gate and the standalone
21850        // [`crate::supervisor::validate_no_self_supervision`] keyed
21851        // off the same `(children, nome)` pair. Pins the fold's
21852        // second arm — reaching this arm through the compound gate
21853        // requires the typed-shape cascade to pass first, which itself
21854        // pins one cross-arm ordering step. Sibling in shape to the
21855        // peer
21856        // `validate_aplicacao_shape_folds_self_membership_arm_matches_gate`
21857        // (949a7a0) cross-slot equivalence pin on the sibling
21858        // per-Aplicacao compound gate.
21859        use crate::supervisor::{ChildSpec, RestartPolicy};
21860        let mut c = supervisor_fixture("demo");
21861        c.children = vec![ChildSpec {
21862            caixa: "demo".into(),
21863            versao: "^0.1".into(),
21864            restart: RestartPolicy::Permanent,
21865        }];
21866        let via_method = c.validate_supervisor_shape().unwrap_err();
21867        let via_standalone =
21868            crate::supervisor::validate_no_self_supervision(c.children(), c.nome()).unwrap_err();
21869        assert_eq!(
21870            via_method, via_standalone,
21871            "Caixa::validate_supervisor_shape must surface the cross-\
21872             slot self-edge diagnostic byte-equal to the standalone \
21873             `supervisor::validate_no_self_supervision` on the same \
21874             (children, nome) pair",
21875        );
21876        assert!(
21877            matches!(
21878                via_method,
21879                crate::SupervisorError::ChildSupervisesSelf { ref caixa } if caixa == "demo"
21880            ),
21881            "expected ChildSupervisesSelf carrying (caixa=\"demo\"), \
21882             got {via_method:?}",
21883        );
21884    }
21885
21886    #[test]
21887    fn validate_supervisor_shape_view_arm_fires_before_self_supervision_arm() {
21888        // Cross-arm ordering pin between the two arms of the fold: a
21889        // fixture carrying BOTH a typed-shape violation (a per-child
21890        // empty `:caixa` name — rejected by
21891        // [`crate::SupervisorSpec::validate`] as
21892        // [`crate::SupervisorError::EmptyChildName`]) AND a would-be
21893        // self-edge violation (a `:children` entry naming the
21894        // supervisor's own `:nome`) surfaces the typed-shape
21895        // diagnostic first through the compound gate. Sanity
21896        // assertion: the self-referential `:children` entry alone
21897        // under the same parent `:nome` trips the self-edge arm on
21898        // its own via the standalone
21899        // [`crate::supervisor::validate_no_self_supervision`], so the
21900        // typed-shape-first surfacing is a real ordering property, not
21901        // a case where the self-edge arm silently accepts the fixture.
21902        // Pins the pre-fold layout wire-up's canonical dispatch order
21903        // (typed-shape cascade → cross-slot self-edge) as a property
21904        // of the substrate primitive rather than a convention of the
21905        // layout call site. Sibling in shape to
21906        // `validate_aplicacao_shape_view_arm_fires_before_self_membership_arm`
21907        // (949a7a0) on the sibling per-Aplicacao compound gate.
21908        use crate::supervisor::{ChildSpec, RestartPolicy};
21909        let mut c = supervisor_fixture("demo");
21910        c.children = vec![
21911            ChildSpec {
21912                caixa: String::new(),
21913                versao: "^0.1".into(),
21914                restart: RestartPolicy::Permanent,
21915            },
21916            ChildSpec {
21917                caixa: "demo".into(),
21918                versao: "^0.1".into(),
21919                restart: RestartPolicy::Permanent,
21920            },
21921        ];
21922        let err = c.validate_supervisor_shape().unwrap_err();
21923        assert!(
21924            matches!(err, crate::SupervisorError::EmptyChildName),
21925            "typed-shape arm must fire before self-edge arm — expected \
21926             EmptyChildName on the empty :caixa child, got {err:?}",
21927        );
21928        // Sanity: the self-referential `:children` entry alone under
21929        // the same parent `:nome` trips the self-edge arm on its own
21930        // — proves the typed-shape-first surfacing above is a real
21931        // ordering property, not a case where the self-edge arm
21932        // silently accepts the fixture.
21933        let sanity = crate::supervisor::validate_no_self_supervision(
21934            &[ChildSpec {
21935                caixa: "demo".into(),
21936                versao: "^0.1".into(),
21937                restart: RestartPolicy::Permanent,
21938            }],
21939            "demo",
21940        )
21941        .unwrap_err();
21942        assert!(
21943            matches!(
21944                sanity,
21945                crate::SupervisorError::ChildSupervisesSelf { ref caixa } if caixa == "demo"
21946            ),
21947            "sanity: the self-referential :children entry alone must \
21948             trip the self-edge arm — got {sanity:?}",
21949        );
21950    }
21951
21952    #[test]
21953    fn validate_supervisor_shape_accepts_non_supervisor_kind() {
21954        // Positive control on the identity-element arm: every non-
21955        // Supervisor kind passes the compound gate trivially — the
21956        // paired [`Caixa::supervisor_view`] accessor returns `None`
21957        // off the Supervisor arm (by construction, keyed on
21958        // `caixa.kind().is_supervisor()`), so the fold short-circuits
21959        // to `Ok(())` without touching the supervision-tree slots.
21960        // Pins the identity element on every non-Supervisor kind — a
21961        // future refactor that made the supervision-tree cascade fire
21962        // on the wrong kind (say, on a `Servico` whose supervision
21963        // slots happen to be populated in a mis-authored manifest,
21964        // which the peer
21965        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
21966        // kind-coherence gate would refuse upstream anyway) surfaces
21967        // here as a test failure first. Peer with the
21968        // `validate_aplicacao_shape_accepts_non_aplicacao_kind`
21969        // (949a7a0) / `validate_limits_accepts_none` /
21970        // `validate_behavior_accepts_none` identity-element pins on
21971        // the sibling per-Caixa compound gates.
21972        for kind in [
21973            CaixaKind::Biblioteca,
21974            CaixaKind::Binario,
21975            CaixaKind::Servico,
21976            CaixaKind::Aplicacao,
21977            CaixaKind::Acao,
21978        ] {
21979            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21980            c.kind = kind;
21981            assert!(
21982                c.supervisor_view().is_none(),
21983                "supervisor_view must return None off the Supervisor \
21984                 arm for kind {kind:?}",
21985            );
21986            c.validate_supervisor_shape().expect(
21987                "non-Supervisor kinds must pass the compound gate as the fold's identity element",
21988            );
21989        }
21990    }
21991
21992    #[test]
21993    fn validate_supervisor_shape_accepts_clean_fixture() {
21994        // Positive control: a well-formed Supervisor (single
21995        // DNS-1123-valid `Permanent` worker child under the
21996        // `OneForOne` strategy — the OTP MaxIntensity/Period defaults
21997        // accept the vacuous `:max-restarts` / `:restart-window`
21998        // arms) passes the compound gate cleanly. A future tightening
21999        // of either arm's accepted set surfaces here as a test
22000        // failure first. Mirrors the peer
22001        // `validate_aplicacao_shape_accepts_clean_fixture` (949a7a0)
22002        // positive-control posture on the sibling per-Caixa compound
22003        // gate.
22004        let c = supervisor_fixture("demo");
22005        c.validate_supervisor_shape()
22006            .expect("clean Supervisor fixture must pass the compound gate");
22007    }
22008
22009    // ── Caixa::validate_acao_shape — compound per-Caixa gate ─────────────
22010
22011    /// Build a minimal well-formed `:kind Acao` fixture with a valid
22012    /// two-node acyclic `:ci` slot. Every arm of the compound gate
22013    /// then patches exactly one axis away from clean so its per-arm
22014    /// diagnostic surfaces without collateral noise from a peer slot.
22015    /// Peer of [`supervisor_fixture`] / [`aplicacao_fixture`] on the
22016    /// sibling per-kind compound gates' pin families.
22017    fn acao_fixture(nome: &str) -> Caixa {
22018        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
22019        c.kind = CaixaKind::Acao;
22020        // Acaos don't run code — clear the biblioteca slot the template
22021        // seeds so the compound gate's per-arm diagnostics surface
22022        // without the peer `AcaoOwnsCode` kind-coherence gate firing
22023        // upstream at the layout altitude.
22024        c.bibliotecas = vec![];
22025        c.ci = Some(canteiro_types::CiRun {
22026            workspace: "pleme-io".into(),
22027            repo: "caixa".into(),
22028            nodes: vec![
22029                canteiro_types::CiNode::new(
22030                    "build",
22031                    canteiro_types::EnvClass::None,
22032                    canteiro_types::ActionRef {
22033                        name: "build".into(),
22034                        command: "true".into(),
22035                        args: vec![],
22036                    },
22037                    vec![],
22038                ),
22039                canteiro_types::CiNode::new(
22040                    "test",
22041                    canteiro_types::EnvClass::None,
22042                    canteiro_types::ActionRef {
22043                        name: "test".into(),
22044                        command: "true".into(),
22045                        args: vec![],
22046                    },
22047                    vec!["build".into()],
22048                ),
22049            ],
22050        });
22051        c
22052    }
22053
22054    #[test]
22055    fn validate_acao_shape_folds_decompose_arm_matches_gate() {
22056        // Fail-before-pass-after per-arm equivalence pin on the
22057        // decompose axis: a fixture whose `:ci` slot fails
22058        // [`canteiro_types::decompose`] (here — a minimal two-node
22059        // cycle `a → b → a`, which the sibling
22060        // [`crate::render::decompose_ci`] wraps as
22061        // [`crate::CiDecomposeFailure`] carrying
22062        // [`canteiro_types::DecomposeError::Cycle`]) surfaces the same
22063        // [`crate::CiDecomposeFailure`] diagnostic through both the
22064        // compound gate [`Caixa::validate_acao_shape`] and the
22065        // standalone [`crate::render::decompose_ci`] on the same
22066        // `(caixa, ci)` fixture. Pins the fold — a silent regression
22067        // that de-folded the decompose arm would surface here as a
22068        // mismatch between the two dispatches. Sibling in shape to the
22069        // peer `validate_supervisor_shape_folds_view_arm_matches_gate`
22070        // / `validate_aplicacao_shape_folds_view_arm_matches_gate` on
22071        // the sibling per-kind compound gates.
22072        //
22073        // [`crate::CiDecomposeFailure`] does not derive `PartialEq`
22074        // (its `#[source]` carrier [`canteiro_types::DecomposeError`]
22075        // does, but the wrapper deliberately does not), so the two
22076        // dispatches are compared through their field pair
22077        // (`nome` + `source`) rather than through `assert_eq!` on the
22078        // wrapper itself — every field on the wrapper is thereby
22079        // pinned byte-equal without depending on an implementation
22080        // detail of `CiDecomposeFailure`'s derive set.
22081        let mut c = acao_fixture("demo");
22082        c.ci = Some(canteiro_types::CiRun {
22083            workspace: "pleme-io".into(),
22084            repo: "caixa".into(),
22085            nodes: vec![
22086                canteiro_types::CiNode::new(
22087                    "a",
22088                    canteiro_types::EnvClass::None,
22089                    canteiro_types::ActionRef {
22090                        name: "a".into(),
22091                        command: "true".into(),
22092                        args: vec![],
22093                    },
22094                    vec!["b".into()],
22095                ),
22096                canteiro_types::CiNode::new(
22097                    "b",
22098                    canteiro_types::EnvClass::None,
22099                    canteiro_types::ActionRef {
22100                        name: "b".into(),
22101                        command: "true".into(),
22102                        args: vec![],
22103                    },
22104                    vec!["a".into()],
22105                ),
22106            ],
22107        });
22108        let via_method = c.validate_acao_shape().unwrap_err();
22109        let via_standalone =
22110            crate::render::decompose_ci(&c, c.ci().expect("fixture has a :ci")).unwrap_err();
22111        assert_eq!(
22112            via_method.nome, via_standalone.nome,
22113            "Caixa::validate_acao_shape must surface the decompose \
22114             failure's `nome` byte-equal to the standalone \
22115             `decompose_ci` on the same (caixa, ci) fixture",
22116        );
22117        assert_eq!(
22118            via_method.source, via_standalone.source,
22119            "Caixa::validate_acao_shape must surface the decompose \
22120             failure's `source` byte-equal to the standalone \
22121             `decompose_ci` on the same (caixa, ci) fixture",
22122        );
22123        assert_eq!(
22124            via_method.source,
22125            canteiro_types::DecomposeError::Cycle,
22126            "expected the two-node cycle `a → b → a` to surface as \
22127             DecomposeError::Cycle, got {source:?}",
22128            source = via_method.source,
22129        );
22130    }
22131
22132    #[test]
22133    fn validate_acao_shape_folds_duplicate_node_arm_matches_gate() {
22134        // Per-arm equivalence pin on the `DuplicateNode` decompose
22135        // arm — the sibling of `Cycle` on the substrate's
22136        // `canteiro_types::DecomposeError` enumeration. A fixture
22137        // whose `:ci` slot carries two nodes sharing one name
22138        // surfaces the same [`crate::CiDecomposeFailure`] through
22139        // both dispatches, pinned by field pair. The three
22140        // decompose arms (`DuplicateNode` / `UnknownDep` / `Cycle`)
22141        // together enumerate every failure mode
22142        // [`canteiro_types::decompose`] refuses, so the per-arm
22143        // pins collectively cover the whole decompose axis.
22144        let mut c = acao_fixture("demo");
22145        c.ci = Some(canteiro_types::CiRun {
22146            workspace: "pleme-io".into(),
22147            repo: "caixa".into(),
22148            nodes: vec![
22149                canteiro_types::CiNode::new(
22150                    "twin",
22151                    canteiro_types::EnvClass::None,
22152                    canteiro_types::ActionRef {
22153                        name: "twin".into(),
22154                        command: "true".into(),
22155                        args: vec![],
22156                    },
22157                    vec![],
22158                ),
22159                canteiro_types::CiNode::new(
22160                    "twin",
22161                    canteiro_types::EnvClass::None,
22162                    canteiro_types::ActionRef {
22163                        name: "twin".into(),
22164                        command: "true".into(),
22165                        args: vec![],
22166                    },
22167                    vec![],
22168                ),
22169            ],
22170        });
22171        let via_method = c.validate_acao_shape().unwrap_err();
22172        assert_eq!(
22173            via_method.source,
22174            canteiro_types::DecomposeError::DuplicateNode("twin".into()),
22175            "expected DuplicateNode on the two-\"twin\"-name fixture, \
22176             got {source:?}",
22177            source = via_method.source,
22178        );
22179    }
22180
22181    #[test]
22182    fn validate_acao_shape_folds_unknown_dep_arm_matches_gate() {
22183        // Per-arm equivalence pin on the `UnknownDep` decompose arm —
22184        // the third and last arm on `canteiro_types::DecomposeError`
22185        // after `Cycle` and `DuplicateNode`. A fixture whose `:ci`
22186        // slot names a `deps` entry no declared node satisfies
22187        // surfaces the same [`crate::CiDecomposeFailure`] through
22188        // both dispatches. Pins the third decompose arm at the
22189        // compound gate.
22190        let mut c = acao_fixture("demo");
22191        c.ci = Some(canteiro_types::CiRun {
22192            workspace: "pleme-io".into(),
22193            repo: "caixa".into(),
22194            nodes: vec![canteiro_types::CiNode::new(
22195                "orphan",
22196                canteiro_types::EnvClass::None,
22197                canteiro_types::ActionRef {
22198                    name: "orphan".into(),
22199                    command: "true".into(),
22200                    args: vec![],
22201                },
22202                vec!["ghost".into()],
22203            )],
22204        });
22205        let via_method = c.validate_acao_shape().unwrap_err();
22206        assert_eq!(
22207            via_method.source,
22208            canteiro_types::DecomposeError::UnknownDep {
22209                node: "orphan".into(),
22210                dep: "ghost".into(),
22211            },
22212            "expected UnknownDep on the orphan-node-depends-on-ghost \
22213             fixture, got {source:?}",
22214            source = via_method.source,
22215        );
22216    }
22217
22218    #[test]
22219    fn validate_acao_shape_accepts_non_acao_kind() {
22220        // Positive control on the identity-element arm: every non-
22221        // Acao kind passes the compound gate trivially — the paired
22222        // `caixa.kind().is_acao()` guard short-circuits before the
22223        // decompose gate ever fires, so the fold returns `Ok(())`
22224        // without touching the `:ci` slot even when a non-Acao
22225        // fixture happens to declare one (the sibling
22226        // [`crate::LayoutError::CiOnNonAcao`] kind-coherence gate
22227        // catches that at the layout altitude anyway). Pins the
22228        // identity element on every non-Acao kind. Peer with the
22229        // `validate_supervisor_shape_accepts_non_supervisor_kind` /
22230        // `validate_aplicacao_shape_accepts_non_aplicacao_kind`
22231        // identity-element pins on the sibling per-Caixa compound
22232        // gates.
22233        for kind in [
22234            CaixaKind::Biblioteca,
22235            CaixaKind::Binario,
22236            CaixaKind::Servico,
22237            CaixaKind::Supervisor,
22238            CaixaKind::Aplicacao,
22239        ] {
22240            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22241            c.kind = kind;
22242            c.validate_acao_shape().expect(
22243                "non-Acao kinds must pass the compound gate as the fold's identity element",
22244            );
22245        }
22246    }
22247
22248    #[test]
22249    fn validate_acao_shape_accepts_absent_ci_slot() {
22250        // Positive control on the second identity-element arm: a
22251        // `:kind Acao` caixa with `ci = None` passes the compound
22252        // gate trivially — the presence gate is the sibling axis
22253        // owned by [`crate::LayoutError::MissingCi`] /
22254        // [`crate::require_ci`] / [`crate::MissingCiSlot`], not by
22255        // the decompose gate. A caixa that carries no `:ci` slot
22256        // has no run to decompose, so the fold's `let Some(ci) = …
22257        // else { return Ok(()) }` arm short-circuits before the
22258        // decompose gate fires. Pins that the two axes stay
22259        // separately diagnosable at the layout altitude — a future
22260        // regression that collapsed the presence gate onto the
22261        // shape gate here would land a
22262        // [`crate::CiDecomposeFailure`] on the wrong axis and
22263        // surface an off-target diagnostic at `feira build` time.
22264        let mut c = acao_fixture("demo");
22265        c.ci = None;
22266        c.validate_acao_shape().expect(
22267            "an :kind Acao caixa with absent :ci must pass the compound gate — \
22268             the presence gate is layout's MissingCi axis, not the decompose gate",
22269        );
22270    }
22271
22272    #[test]
22273    fn validate_acao_shape_accepts_clean_fixture() {
22274        // Positive control: a well-formed Acao (a two-node acyclic
22275        // `:ci` run with `test` depending on `build`) passes the
22276        // compound gate cleanly. A future tightening of the
22277        // decompose gate's accepted set surfaces here as a test
22278        // failure first. Mirrors the peer
22279        // `validate_supervisor_shape_accepts_clean_fixture` /
22280        // `validate_aplicacao_shape_accepts_clean_fixture`
22281        // positive-control posture on the sibling per-Caixa
22282        // compound gates.
22283        let c = acao_fixture("demo");
22284        c.validate_acao_shape()
22285            .expect("clean Acao fixture must pass the compound gate");
22286    }
22287
22288    fn bare_servico_fixture(nome: &str) -> Caixa {
22289        // A minimal Servico caixa with no code and no typed slots —
22290        // the cross-family fold's identity element on every arm.
22291        // Clears the biblioteca slot the template seeds so the
22292        // per-arm patches below can each add exactly one typed slot
22293        // without a peer `ServicoOwnsCode` / layout-side kind-gate
22294        // firing upstream.
22295        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
22296        c.kind = CaixaKind::Servico;
22297        c.bibliotecas = vec![];
22298        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
22299        c
22300    }
22301
22302    #[test]
22303    fn validate_kind_slot_coherence_folds_mesh_arm_matches_gate() {
22304        // Fail-before-pass-after per-arm equivalence pin on the M3
22305        // mesh-slot arm of the cross-family kind-coherence fold: a
22306        // non-Aplicacao caixa carrying a declared M3 mesh slot (here
22307        // a `:kind Servico` fixture with a single `:membros` entry —
22308        // the smallest possible M3 slot declaration on a foreign
22309        // kind) surfaces the same
22310        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] variant
22311        // through both the compound gate
22312        // [`Caixa::validate_kind_slot_coherence`] and the standalone
22313        // constructor [`crate::LayoutError::mesh_slots_on_non_aplicacao`]
22314        // dispatched on the same `declared_mesh_slots` list. Pins
22315        // the fold — a silent regression that de-folded the mesh
22316        // arm would surface here as a mismatch between the two
22317        // dispatches. Sibling in shape to the peer
22318        // `validate_aplicacao_shape_folds_view_arm_matches_gate` /
22319        // `validate_supervisor_shape_folds_view_arm_matches_gate` /
22320        // `validate_acao_shape_folds_decompose_arm_matches_gate`
22321        // per-arm equivalence pins on the sibling per-kind compound
22322        // gates.
22323        use crate::aplicacao::Membro;
22324        let mut c = bare_servico_fixture("demo");
22325        c.membros = vec![Membro {
22326            caixa: "cart".into(),
22327            versao: "^0.1".into(),
22328        }];
22329        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22330        let via_standalone =
22331            crate::LayoutError::mesh_slots_on_non_aplicacao(&c, c.declared_mesh_slots());
22332        assert_eq!(
22333            via_method, via_standalone,
22334            "Caixa::validate_kind_slot_coherence must surface the M3 \
22335             mesh-slot arm's diagnostic byte-equal to the standalone \
22336             LayoutError::mesh_slots_on_non_aplicacao ctor on the same \
22337             declared_mesh_slots list",
22338        );
22339    }
22340
22341    #[test]
22342    fn validate_kind_slot_coherence_folds_supervisor_arm_matches_gate() {
22343        // Per-arm equivalence pin on the supervisor-tree arm — the
22344        // sibling of the mesh arm on the cross-family fold. A
22345        // non-Supervisor caixa carrying a declared supervisor slot
22346        // (a `:kind Servico` fixture with `:estrategia` set — the
22347        // smallest possible supervisor slot declaration on a
22348        // foreign kind) surfaces the same
22349        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
22350        // variant through both dispatches, pinned by field pair
22351        // through `PartialEq`.
22352        use crate::supervisor::RestartStrategy;
22353        let mut c = bare_servico_fixture("demo");
22354        c.estrategia = Some(RestartStrategy::OneForOne);
22355        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22356        let via_standalone = crate::LayoutError::supervisor_slots_on_non_supervisor(
22357            &c,
22358            c.declared_supervisor_slots(),
22359        );
22360        assert_eq!(
22361            via_method, via_standalone,
22362            "Caixa::validate_kind_slot_coherence must surface the \
22363             supervisor-tree arm's diagnostic byte-equal to the \
22364             standalone LayoutError::supervisor_slots_on_non_supervisor \
22365             ctor on the same declared_supervisor_slots list",
22366        );
22367    }
22368
22369    #[test]
22370    fn validate_kind_slot_coherence_folds_servico_arm_matches_gate() {
22371        // Per-arm equivalence pin on the M2 Servico-runtime arm —
22372        // the third and last arm on the cross-family fold. A
22373        // non-Servico caixa carrying a declared M2 slot (a `:kind
22374        // Biblioteca` fixture with `:limits` set — the smallest
22375        // possible M2 slot declaration on a foreign kind) surfaces
22376        // the same [`crate::LayoutError::ServicoSlotsOnNonServico`]
22377        // variant through both dispatches. The three arms together
22378        // enumerate every typed-slot family the substrate carries
22379        // whose "declared but ignored" footgun is gated at the
22380        // layout altitude by a `{ caixa, kind, slots }` wrap variant,
22381        // so the per-arm pins collectively cover the whole
22382        // cross-family kind-coherence axis.
22383        use crate::limits::LimitsSpec;
22384        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22385        c.kind = CaixaKind::Biblioteca;
22386        c.limits = Some(LimitsSpec {
22387            memory: Some(64 * 1024 * 1024),
22388            fuel: None,
22389            wall_clock: None,
22390            cpu: None,
22391        });
22392        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22393        let via_standalone =
22394            crate::LayoutError::servico_slots_on_non_servico(&c, c.declared_servico_slots());
22395        assert_eq!(
22396            via_method, via_standalone,
22397            "Caixa::validate_kind_slot_coherence must surface the M2 \
22398             Servico-runtime arm's diagnostic byte-equal to the \
22399             standalone LayoutError::servico_slots_on_non_servico ctor \
22400             on the same declared_servico_slots list",
22401        );
22402    }
22403
22404    #[test]
22405    fn validate_kind_slot_coherence_mesh_arm_fires_before_supervisor_arm() {
22406        // Cross-arm ordering pin between the first two arms of the
22407        // fold: a fixture carrying BOTH a declared M3 mesh slot
22408        // (`:membros`) AND a declared supervisor-tree slot
22409        // (`:estrategia`) on a foreign kind (a `:kind Servico` here —
22410        // foreign to both the Aplicacao arm and the Supervisor arm)
22411        // surfaces the M3 mesh diagnostic first through the compound
22412        // gate. Pins the pre-fold layout wire-up's canonical
22413        // diagnostic sequence (mesh → supervisor → servico) as a
22414        // property of the substrate primitive rather than a
22415        // convention of the layout call site. A silent reordering
22416        // regression at the primitive would surface here as a
22417        // wrong-variant match before landing at a downstream
22418        // consumer's diagnostic-ordering expectation.
22419        use crate::aplicacao::Membro;
22420        use crate::supervisor::RestartStrategy;
22421        let mut c = bare_servico_fixture("demo");
22422        c.membros = vec![Membro {
22423            caixa: "cart".into(),
22424            versao: "^0.1".into(),
22425        }];
22426        c.estrategia = Some(RestartStrategy::OneForOne);
22427        let err = c.validate_kind_slot_coherence().unwrap_err();
22428        assert!(
22429            matches!(err, crate::LayoutError::MeshSlotsOnNonAplicacao { .. }),
22430            "expected MeshSlotsOnNonAplicacao to fire before \
22431             SupervisorSlotsOnNonSupervisor under the canonical \
22432             mesh → supervisor → servico order, got {err:?}",
22433        );
22434    }
22435
22436    #[test]
22437    fn validate_kind_slot_coherence_supervisor_arm_fires_before_servico_arm() {
22438        // Cross-arm ordering pin between the second and third arms
22439        // of the fold: a fixture carrying BOTH a declared
22440        // supervisor-tree slot (`:estrategia`) AND a declared M2 slot
22441        // (`:limits`) on a kind foreign to both (a `:kind Biblioteca`
22442        // here — foreign to both the Supervisor and the Servico
22443        // arms) surfaces the supervisor-tree diagnostic first
22444        // through the compound gate. Together with the peer
22445        // `_mesh_arm_fires_before_supervisor_arm` pin above this
22446        // pins the whole three-arm canonical order (mesh →
22447        // supervisor → servico) at the substrate primitive.
22448        use crate::limits::LimitsSpec;
22449        use crate::supervisor::RestartStrategy;
22450        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22451        c.kind = CaixaKind::Biblioteca;
22452        c.estrategia = Some(RestartStrategy::OneForOne);
22453        c.limits = Some(LimitsSpec {
22454            memory: Some(64 * 1024 * 1024),
22455            fuel: None,
22456            wall_clock: None,
22457            cpu: None,
22458        });
22459        let err = c.validate_kind_slot_coherence().unwrap_err();
22460        assert!(
22461            matches!(
22462                err,
22463                crate::LayoutError::SupervisorSlotsOnNonSupervisor { .. }
22464            ),
22465            "expected SupervisorSlotsOnNonSupervisor to fire before \
22466             ServicoSlotsOnNonServico under the canonical mesh → \
22467             supervisor → servico order, got {err:?}",
22468        );
22469    }
22470
22471    #[test]
22472    fn validate_kind_slot_coherence_accepts_owner_kind_on_every_arm() {
22473        // Positive control on the identity-element arm: the owner
22474        // kind of each typed-slot family passes the compound gate
22475        // even when it declares the full slot set that family owns.
22476        // Aplicacao with `:membros` populated passes the mesh arm;
22477        // Supervisor with `:estrategia` populated passes the
22478        // supervisor arm; Servico with `:limits` populated passes
22479        // the servico arm. Pins the fold's identity element on
22480        // every owner kind — a silent regression that dropped the
22481        // paired `!kind().is_<owner>()` short-circuit guard would
22482        // surface here as a false-positive rejection of every
22483        // native-slot declaration. Peer with the
22484        // `validate_<kind>_shape_accepts_non_<kind>_kind` identity-
22485        // element pins on the sibling per-Caixa compound gates.
22486        use crate::aplicacao::{Membro, Placement, PlacementStrategy};
22487        use crate::limits::LimitsSpec;
22488        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
22489
22490        let mut apli = Caixa::from_lisp(&Caixa::template("app")).unwrap();
22491        apli.kind = CaixaKind::Aplicacao;
22492        apli.bibliotecas = vec![];
22493        apli.membros = vec![Membro {
22494            caixa: "cart".into(),
22495            versao: "^0.1".into(),
22496        }];
22497        apli.placement = Some(Placement {
22498            estrategia: PlacementStrategy::SingleNode,
22499            clusters: vec!["rio".into()],
22500            shard_key: None,
22501            affinity: None,
22502        });
22503        apli.validate_kind_slot_coherence().expect(
22504            "an :kind Aplicacao caixa with declared M3 mesh slots must \
22505             pass the compound gate — Aplicacao is the mesh-slot family's \
22506             owner kind and the fold's identity element on that arm",
22507        );
22508
22509        let mut sup = Caixa::from_lisp(&Caixa::template("sup")).unwrap();
22510        sup.kind = CaixaKind::Supervisor;
22511        sup.bibliotecas = vec![];
22512        sup.estrategia = Some(RestartStrategy::OneForOne);
22513        sup.children = vec![ChildSpec {
22514            caixa: "worker".into(),
22515            versao: "^0.1".into(),
22516            restart: RestartPolicy::Permanent,
22517        }];
22518        sup.validate_kind_slot_coherence().expect(
22519            "an :kind Supervisor caixa with declared supervisor-tree slots \
22520             must pass the compound gate — Supervisor is the \
22521             supervisor-slot family's owner kind and the fold's identity \
22522             element on that arm",
22523        );
22524
22525        let mut svc = bare_servico_fixture("svc");
22526        svc.limits = Some(LimitsSpec {
22527            memory: Some(64 * 1024 * 1024),
22528            fuel: None,
22529            wall_clock: None,
22530            cpu: None,
22531        });
22532        svc.validate_kind_slot_coherence().expect(
22533            "an :kind Servico caixa with declared M2 slots must pass the \
22534             compound gate — Servico is the M2-slot family's owner kind \
22535             and the fold's identity element on that arm",
22536        );
22537    }
22538
22539    #[test]
22540    fn validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind() {
22541        // Positive control on the second identity-element arm: a
22542        // bare caixa (no declared typed slots) passes the compound
22543        // gate on every kind. Pins the fold's identity element on
22544        // the empty-slot axis — the paired `Vec::is_empty` short-
22545        // circuit guard fires before the wrap dispatch on all three
22546        // arms, so a bare caixa of any kind surfaces no diagnostic.
22547        // A silent regression that dropped the emptiness guard
22548        // would surface here as a false-positive rejection of every
22549        // no-slot caixa across the whole kind axis.
22550        for kind in CaixaKind::ALL {
22551            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22552            c.kind = *kind;
22553            c.bibliotecas = vec![];
22554            c.validate_kind_slot_coherence().unwrap_or_else(|err| {
22555                panic!(
22556                    "a bare :kind {kind:?} caixa (no declared typed slots) \
22557                     must pass the compound gate — the fold's identity \
22558                     element on the empty-slot axis is the paired \
22559                     Vec::is_empty short-circuit guard, got {err:?}",
22560                )
22561            });
22562        }
22563    }
22564
22565    #[test]
22566    fn run_kind_owned_slot_family_gate_owner_kind_short_circuits_before_accumulator() {
22567        // Fail-before-pass-after identity-element pin on the owner-kind
22568        // arm of the substrate primitive: on a caixa whose kind IS the
22569        // owner of the family named by `is_owner`, the primitive
22570        // short-circuits before dispatching `accumulator` — pinned here
22571        // by a poison-pill accumulator that panics on call. If a
22572        // regression drops the `is_owner` short-circuit and always
22573        // invokes the accumulator, the poison panic surfaces here
22574        // rather than a spurious pass. Byte-equal to the pre-lift
22575        // `if !self.kind().is_<owner>() { … }` outer guard's
22576        // short-circuit at the pre-fold layout call site.
22577        let c = bare_servico_fixture("demo");
22578        c.run_kind_owned_slot_family_gate(
22579            CaixaKind::is_servico,
22580            |_| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking accumulator on the owner kind"),
22581            |_, _| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking wrap on the owner kind"),
22582        )
22583        .expect(
22584            "the owner kind of a slot family must pass the substrate \
22585             primitive as the fold's identity element on the outer \
22586             is_owner guard, without invoking accumulator or wrap",
22587        );
22588    }
22589
22590    #[test]
22591    fn run_kind_owned_slot_family_gate_empty_accumulator_short_circuits_before_wrap() {
22592        // Fail-before-pass-after identity-element pin on the empty-
22593        // accumulator arm: on a non-owner kind whose per-family
22594        // accumulator yields no declared slot, the primitive short-
22595        // circuits before dispatching `wrap` — pinned here by a
22596        // poison-pill wrap that panics on call. Byte-equal to the
22597        // pre-lift `if !<slots>.is_empty() { … }` inner emptiness
22598        // guard's short-circuit at the pre-fold layout call site.
22599        let c = bare_servico_fixture("demo");
22600        c.run_kind_owned_slot_family_gate(
22601            CaixaKind::is_aplicacao,
22602            Caixa::declared_mesh_slots,
22603            |_, _| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking wrap on an empty accumulator"),
22604        )
22605        .expect(
22606            "a non-owner kind carrying no declared slot in the family \
22607             must pass the substrate primitive as the fold's identity \
22608             element on the inner emptiness guard, without invoking \
22609             wrap",
22610        );
22611    }
22612
22613    #[test]
22614    fn run_kind_owned_slot_family_gate_non_owner_non_empty_wraps_verbatim() {
22615        // Equivalence pin on the refusal arm: on a non-owner kind
22616        // whose accumulator yields a non-empty slot list, the primitive
22617        // returns the caller-supplied wrap byte-equal to the direct
22618        // ctor dispatch on the same `(caixa, slots)` pair. Pins the
22619        // three-argument route through — `is_owner` fires false, the
22620        // accumulator produces the slot list, and the wrap ctor
22621        // receives verbatim what a direct dispatch would receive.
22622        // Sibling of the peer per-arm equivalence pins on
22623        // [`Caixa::validate_kind_slot_coherence`].
22624        use crate::aplicacao::Membro;
22625        let mut c = bare_servico_fixture("demo");
22626        c.membros = vec![Membro {
22627            caixa: "cart".into(),
22628            versao: "^0.1".into(),
22629        }];
22630        let via_primitive = c
22631            .run_kind_owned_slot_family_gate(
22632                CaixaKind::is_aplicacao,
22633                Caixa::declared_mesh_slots,
22634                crate::LayoutError::mesh_slots_on_non_aplicacao,
22635            )
22636            .unwrap_err();
22637        let via_direct =
22638            crate::LayoutError::mesh_slots_on_non_aplicacao(&c, c.declared_mesh_slots());
22639        assert_eq!(
22640            via_primitive, via_direct,
22641            "Caixa::run_kind_owned_slot_family_gate must route the \
22642             non-owner-kind + non-empty-accumulator arm through the \
22643             caller-supplied wrap byte-equal to the direct ctor \
22644             dispatch on the same (caixa, slots) pair",
22645        );
22646    }
22647
22648    #[test]
22649    fn validate_kind_slot_coherence_routes_each_arm_through_run_kind_owned_slot_family_gate() {
22650        // Cross-primitive routing pin: every arm of the compound gate
22651        // [`Caixa::validate_kind_slot_coherence`] routes through the
22652        // substrate primitive [`Caixa::run_kind_owned_slot_family_gate`]
22653        // on its `(is_owner, accumulator, wrap)` triple. A silent
22654        // regression that de-folded one arm and re-inlined the four-
22655        // line block would surface here as a mismatch between the
22656        // compound-gate error and the direct-primitive-dispatch error
22657        // on the same fixture. Sibling of the peer
22658        // `probe_declared_entries_routes_miss_arm_through_probe_declared_entry`
22659        // cross-primitive routing pin on the layout-pipeline
22660        // existence-probe axis.
22661        use crate::aplicacao::Membro;
22662        use crate::limits::LimitsSpec;
22663        use crate::supervisor::RestartStrategy;
22664
22665        // Mesh arm — non-Aplicacao carrying a declared M3 slot.
22666        let mut mesh = bare_servico_fixture("demo");
22667        mesh.membros = vec![Membro {
22668            caixa: "cart".into(),
22669            versao: "^0.1".into(),
22670        }];
22671        let via_compound = mesh.validate_kind_slot_coherence().unwrap_err();
22672        let via_primitive = mesh
22673            .run_kind_owned_slot_family_gate(
22674                CaixaKind::is_aplicacao,
22675                Caixa::declared_mesh_slots,
22676                crate::LayoutError::mesh_slots_on_non_aplicacao,
22677            )
22678            .unwrap_err();
22679        assert_eq!(
22680            via_compound, via_primitive,
22681            "validate_kind_slot_coherence's mesh arm must route \
22682             byte-equal through the run_kind_owned_slot_family_gate \
22683             substrate primitive",
22684        );
22685
22686        // Supervisor arm — non-Supervisor carrying a declared
22687        // supervisor-tree slot on a kind foreign to both the Aplicacao
22688        // arm and this one.
22689        let mut sup = bare_servico_fixture("demo");
22690        sup.estrategia = Some(RestartStrategy::OneForOne);
22691        let via_compound = sup.validate_kind_slot_coherence().unwrap_err();
22692        let via_primitive = sup
22693            .run_kind_owned_slot_family_gate(
22694                CaixaKind::is_supervisor,
22695                Caixa::declared_supervisor_slots,
22696                crate::LayoutError::supervisor_slots_on_non_supervisor,
22697            )
22698            .unwrap_err();
22699        assert_eq!(
22700            via_compound, via_primitive,
22701            "validate_kind_slot_coherence's supervisor arm must route \
22702             byte-equal through the run_kind_owned_slot_family_gate \
22703             substrate primitive",
22704        );
22705
22706        // Servico arm — non-Servico carrying a declared M2 slot on a
22707        // kind foreign to every prior arm (Biblioteca — foreign to
22708        // both the Aplicacao mesh arm and the Supervisor supervisor
22709        // arm and the Servico M2 arm).
22710        let mut svc = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22711        svc.kind = CaixaKind::Biblioteca;
22712        svc.limits = Some(LimitsSpec {
22713            memory: Some(64 * 1024 * 1024),
22714            fuel: None,
22715            wall_clock: None,
22716            cpu: None,
22717        });
22718        let via_compound = svc.validate_kind_slot_coherence().unwrap_err();
22719        let via_primitive = svc
22720            .run_kind_owned_slot_family_gate(
22721                CaixaKind::is_servico,
22722                Caixa::declared_servico_slots,
22723                crate::LayoutError::servico_slots_on_non_servico,
22724            )
22725            .unwrap_err();
22726        assert_eq!(
22727            via_compound, via_primitive,
22728            "validate_kind_slot_coherence's servico arm must route \
22729             byte-equal through the run_kind_owned_slot_family_gate \
22730             substrate primitive",
22731        );
22732    }
22733
22734    #[test]
22735    fn validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate() {
22736        // Fail-before-pass-after per-arm equivalence pin on the
22737        // Supervisor no-code arm of the reciprocal code-surface
22738        // fold: a `:kind Supervisor` caixa carrying a declared
22739        // `:bibliotecas` entry (the smallest possible code-surface
22740        // declaration on a no-code kind) surfaces the same
22741        // [`crate::LayoutError::SupervisorOwnsCode`] variant
22742        // through both the compound gate
22743        // [`Caixa::validate_no_code_kind_coherence`] and the
22744        // standalone constructor
22745        // [`crate::LayoutError::supervisor_owns_code`]. Pins the
22746        // fold — a silent regression that de-folded the Supervisor
22747        // arm would surface here as a mismatch between the two
22748        // dispatches. Sibling in shape to the peer
22749        // `validate_kind_slot_coherence_folds_supervisor_arm_matches_gate`
22750        // per-arm equivalence pin on the cross-family
22751        // typed-slot-coherence fold.
22752        let mut c = Caixa::from_lisp(&Caixa::template("sup")).unwrap();
22753        c.kind = CaixaKind::Supervisor;
22754        c.bibliotecas = vec!["lib/sup.lisp".into()];
22755        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22756        let via_standalone = crate::LayoutError::supervisor_owns_code(&c);
22757        assert_eq!(
22758            via_method, via_standalone,
22759            "Caixa::validate_no_code_kind_coherence must surface the \
22760             Supervisor arm's diagnostic byte-equal to the standalone \
22761             LayoutError::supervisor_owns_code ctor",
22762        );
22763    }
22764
22765    #[test]
22766    fn validate_no_code_kind_coherence_folds_aplicacao_arm_matches_gate() {
22767        // Per-arm equivalence pin on the Aplicacao no-code arm —
22768        // the sibling of the Supervisor arm on the code-surface
22769        // fold. A `:kind Aplicacao` caixa carrying a declared
22770        // `:exe` entry surfaces the same
22771        // [`crate::LayoutError::AplicacaoOwnsCode`] variant through
22772        // both dispatches. Uses the `:exe` code-surface axis (a
22773        // second axis distinct from the Supervisor arm's
22774        // `:bibliotecas` fixture) so the three per-arm pins
22775        // collectively exercise every arm of the `has_code`
22776        // disjunction (`:bibliotecas || :exe || :servicos`).
22777        let mut c = Caixa::from_lisp(&Caixa::template("app")).unwrap();
22778        c.kind = CaixaKind::Aplicacao;
22779        c.bibliotecas = vec![];
22780        c.exe = vec!["exe/app".into()];
22781        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22782        let via_standalone = crate::LayoutError::aplicacao_owns_code(&c);
22783        assert_eq!(
22784            via_method, via_standalone,
22785            "Caixa::validate_no_code_kind_coherence must surface the \
22786             Aplicacao arm's diagnostic byte-equal to the standalone \
22787             LayoutError::aplicacao_owns_code ctor",
22788        );
22789    }
22790
22791    #[test]
22792    fn validate_no_code_kind_coherence_folds_acao_arm_matches_gate() {
22793        // Per-arm equivalence pin on the Acao no-code arm — the
22794        // third and last arm on the code-surface fold. A `:kind
22795        // Acao` caixa carrying a declared `:servicos` entry
22796        // surfaces the same [`crate::LayoutError::AcaoOwnsCode`]
22797        // variant through both dispatches. Uses the `:servicos`
22798        // code-surface axis (the third distinct axis of the
22799        // `has_code` disjunction) so the three per-arm pins
22800        // collectively cover every arm of the code-surface
22801        // disjunction plus every no-code kind of the arm
22802        // dispatch.
22803        let mut c = Caixa::from_lisp(&Caixa::template("acao")).unwrap();
22804        c.kind = CaixaKind::Acao;
22805        c.bibliotecas = vec![];
22806        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
22807        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22808        let via_standalone = crate::LayoutError::acao_owns_code(&c);
22809        assert_eq!(
22810            via_method, via_standalone,
22811            "Caixa::validate_no_code_kind_coherence must surface the \
22812             Acao arm's diagnostic byte-equal to the standalone \
22813             LayoutError::acao_owns_code ctor",
22814        );
22815    }
22816
22817    #[test]
22818    fn validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis() {
22819        // Positive control on the code-owning-kind identity
22820        // element: each of the three code-owning kinds
22821        // (`Biblioteca` owning `:bibliotecas`, `Binario` owning
22822        // `:exe`, `Servico` owning `:servicos`) passes the
22823        // compound gate cleanly when it declares its native code
22824        // surface. Pins the fold's second identity element — the
22825        // paired per-arm `is_<no-code-kind>()` short-circuit
22826        // fires on every code-owning kind, so a caixa with any
22827        // native code declaration on its owner kind surfaces no
22828        // diagnostic. A silent regression that dropped the paired
22829        // `is_<no-code-kind>()` short-circuit guard on any arm
22830        // would surface here as a false-positive rejection of the
22831        // corresponding owner kind. Peer with the
22832        // `validate_kind_slot_coherence_accepts_owner_kind_on_every_arm`
22833        // identity-element pin on the sibling cross-family fold.
22834        let mut bib = Caixa::from_lisp(&Caixa::template("bib")).unwrap();
22835        bib.kind = CaixaKind::Biblioteca;
22836        bib.bibliotecas = vec!["lib/bib.lisp".into()];
22837        bib.validate_no_code_kind_coherence().expect(
22838            "a :kind Biblioteca caixa with declared :bibliotecas must pass \
22839             the compound gate — Biblioteca owns the :bibliotecas code surface",
22840        );
22841
22842        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
22843        bin.kind = CaixaKind::Binario;
22844        bin.bibliotecas = vec![];
22845        bin.exe = vec!["exe/bin".into()];
22846        bin.validate_no_code_kind_coherence().expect(
22847            "a :kind Binario caixa with declared :exe must pass the compound \
22848             gate — Binario owns the :exe code surface",
22849        );
22850
22851        let svc = bare_servico_fixture("svc");
22852        svc.validate_no_code_kind_coherence().expect(
22853            "a :kind Servico caixa with declared :servicos must pass the \
22854             compound gate — Servico owns the :servicos code surface",
22855        );
22856    }
22857
22858    #[test]
22859    fn validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind() {
22860        // Positive control on the has-no-code identity element:
22861        // a bare caixa (no declared code) passes the compound
22862        // gate on every kind — including the three no-code kinds
22863        // that would otherwise fire an OwnsCode diagnostic. Pins
22864        // the fold's first identity element — the paired
22865        // `!has_code` short-circuit fires before every per-arm
22866        // wrap dispatch, so a bare caixa of any kind surfaces no
22867        // diagnostic. A silent regression that dropped the
22868        // has_code guard would surface here as a false-positive
22869        // rejection of every no-code kind that declares no code.
22870        // Peer with the
22871        // `validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind`
22872        // identity-element pin on the sibling cross-family fold.
22873        for kind in CaixaKind::ALL {
22874            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22875            c.kind = *kind;
22876            c.bibliotecas = vec![];
22877            c.exe = vec![];
22878            c.servicos = vec![];
22879            c.validate_no_code_kind_coherence().unwrap_or_else(|err| {
22880                panic!(
22881                    "a bare :kind {kind:?} caixa (no declared code) must pass \
22882                     the compound gate — the fold's first identity element is \
22883                     the paired !has_code short-circuit, got {err:?}",
22884                )
22885            });
22886        }
22887    }
22888
22889    #[test]
22890    fn validate_ci_kind_coherence_folds_arm_matches_gate() {
22891        // Fail-before-pass-after per-arm equivalence pin on the
22892        // `:ci`-on-non-`Acao` arm: a `:kind Biblioteca` caixa
22893        // (the smallest non-`Acao` kind) carrying a declared
22894        // `:ci` slot surfaces the same
22895        // [`crate::LayoutError::CiOnNonAcao`] variant through the
22896        // compound gate [`Caixa::validate_ci_kind_coherence`] and
22897        // an inlined struct-literal wrap carrying `caixa.nome()`
22898        // + `caixa.kind()` verbatim. Pins the fold — a silent
22899        // regression that de-folded the arm would surface here as
22900        // a mismatch between the two dispatches. Sibling in shape
22901        // to the peer
22902        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
22903        // per-arm equivalence pin on the reciprocal
22904        // code-surface fold.
22905        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22906        c.kind = CaixaKind::Biblioteca;
22907        c.ci = Some(canteiro_types::CiRun {
22908            workspace: "pleme-io".into(),
22909            repo: "caixa".into(),
22910            nodes: vec![],
22911        });
22912        let via_method = c.validate_ci_kind_coherence().unwrap_err();
22913        let via_standalone = crate::LayoutError::CiOnNonAcao {
22914            caixa: c.nome().to_string(),
22915            kind: c.kind(),
22916        };
22917        assert_eq!(
22918            via_method, via_standalone,
22919            "Caixa::validate_ci_kind_coherence must surface the \
22920             :ci-on-non-Acao arm's diagnostic byte-equal to a \
22921             LayoutError::CiOnNonAcao struct literal carrying the \
22922             caixa's nome + kind",
22923        );
22924    }
22925
22926    #[test]
22927    fn validate_ci_kind_coherence_fold_names_offending_kind_on_every_non_acao_kind() {
22928        // Exhaustive per-kind sweep on the non-`Acao` arm: for each
22929        // of the five non-`Acao` kinds
22930        // (`Biblioteca` / `Binario` / `Servico` / `Supervisor` /
22931        // `Aplicacao`), a caixa carrying a declared `:ci` slot
22932        // surfaces the [`crate::LayoutError::CiOnNonAcao`]
22933        // variant naming the offending kind verbatim. A silent
22934        // regression that mistyped one arm's kind-projection
22935        // (e.g. always threading `CaixaKind::Biblioteca` regardless
22936        // of the caixa's actual kind) would surface here as a
22937        // mismatch on every kind past the first. Peer of the
22938        // `validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind`
22939        // exhaustive-sweep pin on the sibling code-surface fold.
22940        for kind in CaixaKind::ALL {
22941            if kind.is_acao() {
22942                continue;
22943            }
22944            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22945            c.kind = *kind;
22946            c.ci = Some(canteiro_types::CiRun {
22947                workspace: "pleme-io".into(),
22948                repo: "caixa".into(),
22949                nodes: vec![],
22950            });
22951            let err = c.validate_ci_kind_coherence().unwrap_err();
22952            match err {
22953                crate::LayoutError::CiOnNonAcao {
22954                    caixa: got_caixa,
22955                    kind: got_kind,
22956                } => {
22957                    assert_eq!(
22958                        got_caixa,
22959                        c.nome(),
22960                        "CiOnNonAcao must name the offending caixa's nome verbatim on kind {kind:?}",
22961                    );
22962                    assert_eq!(
22963                        got_kind, *kind,
22964                        "CiOnNonAcao must name the offending kind verbatim on kind {kind:?}",
22965                    );
22966                }
22967                other => panic!(
22968                    "expected CiOnNonAcao on :kind {kind:?} with declared :ci, got {other:?}",
22969                ),
22970            }
22971        }
22972    }
22973
22974    #[test]
22975    fn validate_ci_kind_coherence_accepts_acao_on_every_ci_shape() {
22976        // Positive control on the owner-kind identity element: an
22977        // `:kind Acao` caixa passes the coherence gate cleanly on
22978        // every `:ci` shape — the arm's paired
22979        // `!kind().is_acao()` short-circuit fires before the
22980        // dispatch, so the fold surfaces no diagnostic even on
22981        // fixtures whose `:ci` would fail the peer
22982        // [`Self::validate_acao_shape`] decompose gate (a
22983        // duplicate-node fixture, an unknown-dep fixture, a
22984        // cyclic fixture). Pins the fold's first identity element
22985        // — a silent regression that dropped the paired
22986        // `!kind().is_acao()` short-circuit guard would surface
22987        // here as a false-positive rejection of every `Acao`
22988        // caixa. Peer with the
22989        // `validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis`
22990        // identity-element pin on the sibling code-surface fold.
22991        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22992        c.kind = CaixaKind::Acao;
22993        c.bibliotecas = vec![];
22994        c.ci = Some(canteiro_types::CiRun {
22995            workspace: "pleme-io".into(),
22996            repo: "caixa".into(),
22997            nodes: vec![],
22998        });
22999        c.validate_ci_kind_coherence().expect(
23000            "a :kind Acao caixa with declared :ci must pass the compound \
23001             coherence gate — Acao is the :ci-owning kind (a malformed \
23002             :ci on Acao surfaces via validate_acao_shape's decompose gate, \
23003             not via this kind-coherence gate)",
23004        );
23005    }
23006
23007    #[test]
23008    fn validate_ci_kind_coherence_accepts_absent_ci_on_every_kind() {
23009        // Positive control on the absent-`:ci` identity element:
23010        // a caixa with `ci = None` passes the coherence gate on
23011        // every kind — including `Acao`, whose absent `:ci`
23012        // fails a separate presence gate ([`crate::LayoutError::MissingCi`])
23013        // downstream at the layout altitude, not this coherence
23014        // gate. Pins the fold's second identity element — the
23015        // paired `ci().is_some()` short-circuit fires before every
23016        // per-arm dispatch, so a caixa with no declared `:ci`
23017        // surfaces no coherence diagnostic. A silent regression
23018        // that dropped the paired `ci().is_some()` short-circuit
23019        // would surface here as a false-positive rejection on
23020        // every non-`Acao` kind. Peer with the
23021        // `validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind`
23022        // identity-element pin on the sibling code-surface fold.
23023        for kind in CaixaKind::ALL {
23024            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23025            c.kind = *kind;
23026            c.ci = None;
23027            c.validate_ci_kind_coherence().unwrap_or_else(|err| {
23028                panic!(
23029                    "a :kind {kind:?} caixa with no declared :ci must pass \
23030                     the compound coherence gate — the fold's second identity \
23031                     element is the paired ci().is_some() short-circuit, got \
23032                     {err:?}",
23033                )
23034            });
23035        }
23036    }
23037
23038    #[test]
23039    fn validate_foreign_code_kind_coherence_folds_arm_matches_gate() {
23040        // Fail-before-pass-after equivalence pin on the compound
23041        // foreign-code-slot coherence fold: a `:kind Servico` caixa
23042        // carrying a declared `:exe` entry (the smallest possible
23043        // foreign-code-slot declaration on a code-running kind that
23044        // is not its owner — Servico owns `:servicos`, not `:exe`)
23045        // surfaces the same [`crate::LayoutError::ForeignCodeSlot`]
23046        // variant through both the compound gate
23047        // [`Caixa::validate_foreign_code_kind_coherence`] and the
23048        // standalone constructor
23049        // [`crate::LayoutError::foreign_code_slot`] dispatched on the
23050        // same `declared_foreign_code_slots` list. Pins the fold — a
23051        // silent regression that de-folded the arm would surface here
23052        // as a mismatch between the two dispatches. Sibling in shape
23053        // to the peer
23054        // `validate_kind_slot_coherence_folds_mesh_arm_matches_gate`
23055        // / `validate_ci_kind_coherence_folds_arm_matches_gate` /
23056        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
23057        // per-arm equivalence pins on the sibling kind-coherence folds.
23058        let mut c = bare_servico_fixture("demo");
23059        c.exe = vec!["exe/foreign".into()];
23060        let via_method = c.validate_foreign_code_kind_coherence().unwrap_err();
23061        let via_standalone =
23062            crate::LayoutError::foreign_code_slot(&c, c.declared_foreign_code_slots());
23063        assert_eq!(
23064            via_method, via_standalone,
23065            "Caixa::validate_foreign_code_kind_coherence must surface the \
23066             foreign-code-slot diagnostic byte-equal to the standalone \
23067             LayoutError::foreign_code_slot ctor on the same \
23068             declared_foreign_code_slots list",
23069        );
23070    }
23071
23072    #[test]
23073    fn validate_foreign_code_kind_coherence_exe_arm_precedes_servicos_arm() {
23074        // Cross-arm ordering pin on the fold's accumulator: a fixture
23075        // carrying BOTH a declared `:exe` AND a declared `:servicos`
23076        // on a kind foreign to both (a `:kind Biblioteca` here —
23077        // foreign to both the Binario arm and the Servico arm)
23078        // surfaces `:exe` first in the `ForeignCodeSlot`'s slots
23079        // list. Pins the canonical `:exe` → `:servicos` diagnostic
23080        // order [`Caixa::declared_foreign_code_slots`] establishes,
23081        // as a property of the substrate primitive rather than an
23082        // implicit accumulator convention. A silent reordering
23083        // regression at the accumulator would surface here as a
23084        // wrong-first-slot list before landing at a downstream
23085        // consumer's diagnostic-ordering expectation.
23086        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23087        c.kind = CaixaKind::Biblioteca;
23088        c.exe = vec!["exe/demo".into()];
23089        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
23090        let err = c.validate_foreign_code_kind_coherence().unwrap_err();
23091        let crate::LayoutError::ForeignCodeSlot { slots, .. } = &err else {
23092            panic!("expected ForeignCodeSlot variant, got {err:?}");
23093        };
23094        assert!(
23095            slots.starts_with(":exe"),
23096            "expected the :exe arm to precede the :servicos arm in the \
23097             ForeignCodeSlot slots list under the canonical :exe → :servicos \
23098             order, got slots = {slots:?}",
23099        );
23100        assert!(
23101            slots.contains(":servicos"),
23102            "expected the :servicos arm to also fire in the ForeignCodeSlot \
23103             slots list on a fixture carrying both foreign code surfaces, \
23104             got slots = {slots:?}",
23105        );
23106    }
23107
23108    #[test]
23109    fn validate_foreign_code_kind_coherence_accepts_native_slot_on_owner_kind() {
23110        // Positive control on the native-slot identity element: each
23111        // code-surface slot's owner kind passes the fold trivially
23112        // when it declares only its native code surface. `:kind
23113        // Binario` with a declared `:exe` and no `:servicos` passes
23114        // (the `!requires_exe()` guard short-circuits the arm inside
23115        // [`Caixa::declared_foreign_code_slots`], so the accumulator
23116        // returns empty); `:kind Servico` with a declared `:servicos`
23117        // and no `:exe` passes for the mirror reason. Pins the fold's
23118        // native-slot identity element on both arms — a silent
23119        // regression that dropped either per-arm `!requires_<slot>()`
23120        // predicate would surface here as a false-positive rejection
23121        // of every native-slot declaration on its owner kind. Peer
23122        // with the
23123        // `validate_kind_slot_coherence_accepts_owner_kind_on_every_arm`
23124        // identity-element pin on the sibling cross-family fold.
23125        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23126        bin.kind = CaixaKind::Binario;
23127        bin.bibliotecas = vec![];
23128        bin.exe = vec!["exe/bin".into()];
23129        bin.servicos = vec![];
23130        bin.validate_foreign_code_kind_coherence().expect(
23131            "a :kind Binario caixa with a declared native :exe and no \
23132             :servicos must pass the compound coherence gate — Binario is \
23133             the :exe slot's owner kind and the fold's native-slot identity \
23134             element on that arm",
23135        );
23136
23137        let mut svc = bare_servico_fixture("svc");
23138        svc.exe = vec![];
23139        svc.validate_foreign_code_kind_coherence().expect(
23140            "a :kind Servico caixa with a declared native :servicos and no \
23141             :exe must pass the compound coherence gate — Servico is the \
23142             :servicos slot's owner kind and the fold's native-slot identity \
23143             element on that arm",
23144        );
23145    }
23146
23147    #[test]
23148    fn validate_foreign_code_kind_coherence_accepts_bare_caixa_on_every_kind() {
23149        // Positive control on the empty-slot identity element: a
23150        // bare caixa (no declared `:exe` and no declared `:servicos`)
23151        // passes the compound gate on every kind. Pins the fold's
23152        // identity element on the empty-accumulator axis — the outer
23153        // `is_empty` short-circuit fires before the wrap dispatch on
23154        // every kind, so a bare caixa of any kind surfaces no
23155        // foreign-code-slot diagnostic. A silent regression that
23156        // dropped the emptiness guard would surface here as a
23157        // false-positive rejection of every no-code-slot caixa
23158        // across the whole kind axis. Peer with the
23159        // `validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind`
23160        // identity-element pin on the sibling cross-family fold.
23161        for kind in CaixaKind::ALL {
23162            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23163            c.kind = *kind;
23164            c.bibliotecas = vec![];
23165            c.exe = vec![];
23166            c.servicos = vec![];
23167            c.validate_foreign_code_kind_coherence()
23168                .unwrap_or_else(|err| {
23169                    panic!(
23170                        "a bare :kind {kind:?} caixa (no declared :exe / \
23171                         :servicos) must pass the compound coherence gate — \
23172                         the fold's identity element on the empty-accumulator \
23173                         axis is the outer Vec::is_empty short-circuit, got \
23174                         {err:?}",
23175                    )
23176                });
23177        }
23178    }
23179
23180    #[test]
23181    fn validate_required_kind_slot_folds_binario_arm_matches_gate() {
23182        // Fail-before-pass-after per-arm equivalence pin on the
23183        // `Binario` required-`:exe` arm of the required-slot fold:
23184        // a `:kind Binario` caixa carrying no declared `:exe` entry
23185        // surfaces the same
23186        // [`crate::LayoutError::BinarioWithoutExe`] variant through
23187        // both the compound gate
23188        // [`Caixa::validate_required_kind_slot`] and the standalone
23189        // constructor [`crate::LayoutError::binario_without_exe`].
23190        // Pins the fold — a silent regression that de-folded the
23191        // `Binario` arm would surface here as a mismatch between
23192        // the two dispatches. Sibling in shape to the peer
23193        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
23194        // per-arm equivalence pin on the reciprocal code-surface
23195        // fold.
23196        let mut c = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23197        c.kind = CaixaKind::Binario;
23198        c.bibliotecas = vec![];
23199        c.exe = vec![];
23200        let via_method = c.validate_required_kind_slot().unwrap_err();
23201        let via_standalone = crate::LayoutError::binario_without_exe(&c);
23202        assert_eq!(
23203            via_method, via_standalone,
23204            "Caixa::validate_required_kind_slot must surface the \
23205             Binario arm's diagnostic byte-equal to the standalone \
23206             LayoutError::binario_without_exe ctor",
23207        );
23208    }
23209
23210    #[test]
23211    fn validate_required_kind_slot_folds_servico_arm_matches_gate() {
23212        // Per-arm equivalence pin on the `Servico` required-
23213        // `:servicos` arm — the sibling of the Binario arm on the
23214        // required-slot fold. A `:kind Servico` caixa carrying no
23215        // declared `:servicos` entry surfaces the same
23216        // [`crate::LayoutError::ServicoWithoutServicos`] variant
23217        // through both dispatches.
23218        let mut c = Caixa::from_lisp(&Caixa::template("svc")).unwrap();
23219        c.kind = CaixaKind::Servico;
23220        c.bibliotecas = vec![];
23221        c.servicos = vec![];
23222        let via_method = c.validate_required_kind_slot().unwrap_err();
23223        let via_standalone = crate::LayoutError::servico_without_servicos(&c);
23224        assert_eq!(
23225            via_method, via_standalone,
23226            "Caixa::validate_required_kind_slot must surface the \
23227             Servico arm's diagnostic byte-equal to the standalone \
23228             LayoutError::servico_without_servicos ctor",
23229        );
23230    }
23231
23232    #[test]
23233    fn validate_required_kind_slot_folds_acao_arm_matches_gate() {
23234        // Per-arm equivalence pin on the `Acao` required-`:ci` arm
23235        // — the third and last arm on the required-slot fold. A
23236        // `:kind Acao` caixa carrying no declared `:ci` slot
23237        // surfaces the same [`crate::LayoutError::MissingCi`]
23238        // variant through both dispatches. The three per-arm pins
23239        // collectively cover every required-slot axis and every
23240        // owner kind of the arm dispatch.
23241        let mut c = Caixa::from_lisp(&Caixa::template("acao")).unwrap();
23242        c.kind = CaixaKind::Acao;
23243        c.bibliotecas = vec![];
23244        c.ci = None;
23245        let via_method = c.validate_required_kind_slot().unwrap_err();
23246        let via_standalone = crate::LayoutError::missing_ci(&c);
23247        assert_eq!(
23248            via_method, via_standalone,
23249            "Caixa::validate_required_kind_slot must surface the \
23250             Acao arm's diagnostic byte-equal to the standalone \
23251             LayoutError::missing_ci ctor",
23252        );
23253    }
23254
23255    #[test]
23256    fn validate_required_kind_slot_accepts_owner_kind_with_required_slot_present() {
23257        // Positive control on the owner-kind-with-slot-present
23258        // identity element: each of the three owner kinds
23259        // (`Binario` with a non-empty `:exe`, `Servico` with a
23260        // non-empty `:servicos`, `Acao` with `ci = Some(_)`)
23261        // passes the compound gate cleanly when it declares its
23262        // required slot. Pins the fold's second identity element
23263        // — the paired `is_empty` / `is_none` short-circuit fires
23264        // on every owner kind whose required slot is present, so
23265        // a caixa with its native required slot surfaces no
23266        // diagnostic. A silent regression that dropped the paired
23267        // `is_empty` / `is_none` short-circuit guard on any arm
23268        // would surface here as a false-positive rejection of the
23269        // corresponding owner kind. Peer with the
23270        // `validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis`
23271        // identity-element pin on the sibling code-surface fold.
23272        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23273        bin.kind = CaixaKind::Binario;
23274        bin.bibliotecas = vec![];
23275        bin.exe = vec!["exe/bin".into()];
23276        bin.validate_required_kind_slot().expect(
23277            "a :kind Binario caixa with declared :exe must pass the \
23278             required-slot gate — Binario's required slot is present",
23279        );
23280
23281        let svc = bare_servico_fixture("svc");
23282        svc.validate_required_kind_slot().expect(
23283            "a :kind Servico caixa with declared :servicos must pass \
23284             the required-slot gate — Servico's required slot is present",
23285        );
23286
23287        let acao = acao_fixture("acao");
23288        acao.validate_required_kind_slot().expect(
23289            "a :kind Acao caixa with declared :ci must pass the \
23290             required-slot gate — Acao's required slot is present",
23291        );
23292    }
23293
23294    #[test]
23295    fn validate_required_kind_slot_accepts_non_owner_kinds() {
23296        // Positive control on the non-owner-kind identity element:
23297        // every kind that is not one of the three owner kinds
23298        // (`Binario` / `Servico` / `Acao`) passes the compound gate
23299        // trivially — each per-arm predicate is
23300        // `self.kind().requires_<slot>()`, which returns `true`
23301        // only for the owner kind of that arm, so a non-owner kind
23302        // short-circuits every per-arm dispatch. Bibliotheca,
23303        // Supervisor, and Aplicacao are the three non-owner kinds
23304        // this pin exercises — none of them owns a required slot in
23305        // this fold (`Biblioteca`'s `:bibliotecas` default-file
23306        // fallback stays on the layout-side `MissingLib` fs-oracle
23307        // gate outside this fold; `Supervisor`'s `:children` and
23308        // `Aplicacao`'s `:membros` are carried by
23309        // [`CaixaKind::requires_children`] /
23310        // [`CaixaKind::requires_membros`] without a paired
23311        // layout-side wire-up). A silent regression that swapped a
23312        // per-arm predicate for a non-`requires_*` guard would
23313        // surface here as a false-positive rejection of the
23314        // corresponding non-owner kind. Peer with the
23315        // `validate_ci_kind_coherence_accepts_absent_ci_on_every_kind`
23316        // identity-element pin on the sibling `:ci` fold.
23317        for kind in CaixaKind::ALL {
23318            if kind.requires_exe() || kind.requires_servicos() || kind.requires_ci() {
23319                continue;
23320            }
23321            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23322            c.kind = *kind;
23323            c.bibliotecas = vec![];
23324            c.exe = vec![];
23325            c.servicos = vec![];
23326            c.ci = None;
23327            c.validate_required_kind_slot().unwrap_or_else(|err| {
23328                panic!(
23329                    "a :kind {kind:?} caixa (a non-owner kind on every \
23330                     required-slot arm) must pass the compound gate — the \
23331                     fold's identity element is the paired \
23332                     `self.kind().requires_<slot>()` short-circuit, got \
23333                     {err:?}",
23334                )
23335            });
23336        }
23337    }
23338
23339    // ── `manifest_code_path_slot_path_ctors!` — the paired `{ slot:
23340    //    &'static str, path: PathBuf }` two-slot envelope on
23341    //    `ManifestError`, strict sibling of the peer
23342    //    [`crate::behavior::behavior_slot_path_ctors!`] (67c31ec) on the
23343    //    sibling `BehaviorError` envelope's identical
23344    //    `{ slot: &'static str, path: PathBuf }` two-slot shape.
23345    //    Five-variant lift closing the five open-coded ctor sites
23346    //    remaining on the `:bibliotecas` / `:exe` / `:servicos`
23347    //    code-path-list value-shape trajectory this envelope carries.
23348
23349    #[test]
23350    fn code_path_absolute_ctor_matches_struct_literal_wrap() {
23351        let path = Path::new("/abs/lib/x.lisp");
23352        assert_eq!(
23353            ManifestError::code_path_absolute(":bibliotecas", path),
23354            ManifestError::CodePathAbsolute {
23355                slot: ":bibliotecas",
23356                path: path.to_path_buf(),
23357            },
23358            "generated code_path_absolute ctor must produce byte-equal \
23359             `ManifestError::CodePathAbsolute` to the pre-lift \
23360             struct-literal wrap on the same `(&'static str, &Path)` \
23361             fixture",
23362        );
23363    }
23364
23365    #[test]
23366    fn code_path_parent_escape_ctor_matches_struct_literal_wrap() {
23367        let path = Path::new("lib/../../etc/x.lisp");
23368        assert_eq!(
23369            ManifestError::code_path_parent_escape(":bibliotecas", path),
23370            ManifestError::CodePathParentEscape {
23371                slot: ":bibliotecas",
23372                path: path.to_path_buf(),
23373            },
23374            "generated code_path_parent_escape ctor must produce \
23375             byte-equal `ManifestError::CodePathParentEscape` to the \
23376             pre-lift struct-literal wrap on the same `(&'static str, \
23377             &Path)` fixture",
23378        );
23379    }
23380
23381    #[test]
23382    fn code_path_non_lisp_extension_ctor_matches_struct_literal_wrap() {
23383        let path = Path::new("lib/x.txt");
23384        assert_eq!(
23385            ManifestError::code_path_non_lisp_extension(":bibliotecas", path),
23386            ManifestError::CodePathNonLispExtension {
23387                slot: ":bibliotecas",
23388                path: path.to_path_buf(),
23389            },
23390            "generated code_path_non_lisp_extension ctor must produce \
23391             byte-equal `ManifestError::CodePathNonLispExtension` to \
23392             the pre-lift struct-literal wrap on the same \
23393             `(&'static str, &Path)` fixture",
23394        );
23395    }
23396
23397    #[test]
23398    fn code_path_non_computeunit_yaml_extension_ctor_matches_struct_literal_wrap() {
23399        let path = Path::new("servicos/x.yaml");
23400        assert_eq!(
23401            ManifestError::code_path_non_computeunit_yaml_extension(":servicos", path),
23402            ManifestError::CodePathNonComputeUnitYamlExtension {
23403                slot: ":servicos",
23404                path: path.to_path_buf(),
23405            },
23406            "generated code_path_non_computeunit_yaml_extension ctor \
23407             must produce byte-equal \
23408             `ManifestError::CodePathNonComputeUnitYamlExtension` to \
23409             the pre-lift struct-literal wrap on the same \
23410             `(&'static str, &Path)` fixture",
23411        );
23412    }
23413
23414    #[test]
23415    fn code_path_duplicate_ctor_matches_struct_literal_wrap() {
23416        let path = Path::new("lib/x.lisp");
23417        assert_eq!(
23418            ManifestError::code_path_duplicate(":bibliotecas", path),
23419            ManifestError::CodePathDuplicate {
23420                slot: ":bibliotecas",
23421                path: path.to_path_buf(),
23422            },
23423            "generated code_path_duplicate ctor must produce byte-equal \
23424             `ManifestError::CodePathDuplicate` to the pre-lift \
23425             struct-literal wrap on the same `(&'static str, &Path)` \
23426             fixture",
23427        );
23428    }
23429
23430    #[test]
23431    fn manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly() {
23432        // Cross-axis routing pin: sweep the two constructor input axes
23433        // (`slot: &'static str`, `path: &Path`) through non-default
23434        // fixtures against every generated arm in the
23435        // [`manifest_code_path_slot_path_ctors!`] macro, so any
23436        // wrapper-side lowercase / trim / truncate / canonicalization at
23437        // codegen time — or a silent field re-name away from the
23438        // canonical `slot` / `path` axes on any one variant, or a `slot`
23439        // axis silently rerouted through `.to_string()` instead of
23440        // passed as `&'static str` verbatim, or a `path` axis silently
23441        // rerouted through `.canonicalize()` / `PathBuf::from(<lossy
23442        // string>)` instead of `.to_path_buf()` — surfaces here rather
23443        // than at a downstream diagnostic-shape mismatch. Peer of the
23444        // sibling
23445        // [`crate::behavior::tests::behavior_slot_path_ctors_route_slot_and_path_through_uniformly`]
23446        // pin (67c31ec) on the sibling `BehaviorError` envelope's
23447        // identical two-slot family.
23448        //
23449        // The `path` fixture carries three distinguishing traits at
23450        // once: a non-`root/`-relative leading segment (`weird/`), a
23451        // `..` component (a canonicalization trap that would collapse
23452        // to `weird/x.lisp` under `.canonicalize()`), and a mixed-case
23453        // extension (a lowercase-normalization trap that would collapse
23454        // `.LISP` to `.lisp` under any `to_ascii_lowercase()` codegen)
23455        // so a routing regression on any one of the three trap axes
23456        // surfaces at assert time. Similarly the `slot` fixture
23457        // sweeps the three canonical code-path author-key literals
23458        // (`:bibliotecas` / `:exe` / `:servicos`) so a silent lookup
23459        // against a per-variant const roster would surface here.
23460        let path = Path::new("weird/../nested/x.LISP");
23461        let cases: [(ManifestError, ManifestError); 5] = [
23462            (
23463                ManifestError::code_path_absolute(":bibliotecas", path),
23464                ManifestError::CodePathAbsolute {
23465                    slot: ":bibliotecas",
23466                    path: path.to_path_buf(),
23467                },
23468            ),
23469            (
23470                ManifestError::code_path_parent_escape(":exe", path),
23471                ManifestError::CodePathParentEscape {
23472                    slot: ":exe",
23473                    path: path.to_path_buf(),
23474                },
23475            ),
23476            (
23477                ManifestError::code_path_non_lisp_extension(":servicos", path),
23478                ManifestError::CodePathNonLispExtension {
23479                    slot: ":servicos",
23480                    path: path.to_path_buf(),
23481                },
23482            ),
23483            (
23484                ManifestError::code_path_non_computeunit_yaml_extension(":bibliotecas", path),
23485                ManifestError::CodePathNonComputeUnitYamlExtension {
23486                    slot: ":bibliotecas",
23487                    path: path.to_path_buf(),
23488                },
23489            ),
23490            (
23491                ManifestError::code_path_duplicate(":exe", path),
23492                ManifestError::CodePathDuplicate {
23493                    slot: ":exe",
23494                    path: path.to_path_buf(),
23495                },
23496            ),
23497        ];
23498        for (via_ctor, via_struct_literal) in cases {
23499            assert_eq!(
23500                via_ctor, via_struct_literal,
23501                "manifest_code_path_slot_path_ctors!-generated ctor \
23502                 must pass `slot` verbatim onto the canonical \
23503                 `&'static str` `slot` field and route `path` through \
23504                 `.to_path_buf()` onto the canonical `PathBuf` `path` \
23505                 field — a field-rename, silent-conversion, or \
23506                 axis-swap regression surfaces here rather than at a \
23507                 downstream diagnostic-shape mismatch",
23508            );
23509        }
23510    }
23511
23512    // Per-variant equivalence pin for the [`ManifestError::code_path_empty`]
23513    // one-slot inherent constructor (see the paired doc-block above the impl
23514    // definition) — the constructor folds the uniform
23515    // `Self::CodePathEmpty { slot }` one-field struct-literal onto one
23516    // substrate primitive. The equivalence pin below (fail-before-pass-after
23517    // by construction — a byte-mismatched constructor body would trip this pin
23518    // first) locks the generated constructor to its struct-literal peer under
23519    // `PartialEq`, so the wire-up at
23520    // [`Caixa::validate_code_path_lists`]'s per-slot
23521    // [`PathShapeViolation::Empty`] arm on this variant produces a byte-equal
23522    // `ManifestError` to the pre-lift open-coded struct-literal. The
23523    // cross-axis pin that follows (`slot: &'static str` sweep over every
23524    // canonical `:bibliotecas` / `:exe` / `:servicos` code-path author-key
23525    // label) routes the constructor input axis verbatim (`slot` as
23526    // `&'static str` without conversion), so the fold does not silently
23527    // collapse onto a fixed `slot` value.
23528    //
23529    // Peer of the sibling `code_path_absolute_ctor_matches_struct_literal_wrap`
23530    // / `code_path_parent_escape_ctor_matches_struct_literal_wrap` /
23531    // `code_path_non_lisp_extension_ctor_matches_struct_literal_wrap` /
23532    // `code_path_non_computeunit_yaml_extension_ctor_matches_struct_literal_wrap`
23533    // / `code_path_duplicate_ctor_matches_struct_literal_wrap` /
23534    // `manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly`
23535    // equivalence + cross-axis pins the peer
23536    // [`manifest_code_path_slot_path_ctors!`] family (de11917) established on
23537    // the paired `{ slot: &'static str, path: PathBuf }` two-slot envelope of
23538    // the same `ManifestError` — the per-slot [`PathShapeViolation`] cascade
23539    // at [`Caixa::validate_code_path_lists`] now carries a substrate-primitive
23540    // equivalence pin at every arm rather than five pinned arms plus a
23541    // hand-written open-coded sixth. Mirror-symmetric sibling of the peer
23542    // [`crate::behavior::tests::empty_path_ctor_matches_struct_literal_wrap`]
23543    // / `empty_path_ctor_routes_slot_verbatim_across_every_on_star_key` pins
23544    // on the sibling M2 `:behavior` envelope's identical one-slot shape.
23545
23546    #[test]
23547    fn code_path_empty_ctor_matches_struct_literal_wrap() {
23548        let slot = ":bibliotecas";
23549        assert_eq!(
23550            ManifestError::code_path_empty(slot),
23551            ManifestError::CodePathEmpty { slot },
23552            "generated code_path_empty ctor must produce byte-equal \
23553             `ManifestError::CodePathEmpty` to the open-coded struct-literal \
23554             wrap on the same `&'static str` fixture",
23555        );
23556    }
23557
23558    #[test]
23559    fn code_path_empty_ctor_routes_slot_verbatim_across_every_code_path_key() {
23560        // Cross-axis pin: sweep the constructor's single input axis
23561        // (`slot: &'static str`) through every canonical code-path
23562        // author-key label the outer per-slot iterator at
23563        // [`Caixa::validate_code_path_lists`] threads through so any
23564        // wrapper-side lowercase / trim / truncate / fixed-slot substitution
23565        // on the one-field construction surfaces here rather than at a
23566        // downstream diagnostic-shape mismatch. Peer of the sibling
23567        // [`manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly`]
23568        // cross-axis pin on the two-slot envelope of the same
23569        // `ManifestError` — extended here onto the one-slot envelope so
23570        // both slot-only and slot+path constructor input axes carry a
23571        // per-code-path-label sweep. Mirror-symmetric sibling of the peer
23572        // [`crate::behavior::tests::empty_path_ctor_routes_slot_verbatim_across_every_on_star_key`]
23573        // sweep on the sibling M2 `:behavior` envelope's identical one-slot
23574        // shape.
23575        for slot in [":bibliotecas", ":exe", ":servicos"] {
23576            assert_eq!(
23577                ManifestError::code_path_empty(slot),
23578                ManifestError::CodePathEmpty { slot },
23579            );
23580        }
23581    }
23582
23583    // ── `manifest_field_reason_ctors!` — the paired `{ <field>: String,
23584    //    reason: String }` two-slot envelope on `ManifestError`, direct
23585    //    sibling of the peer
23586    //    [`crate::aplicacao::aplicacao_field_reason_ctors!`] (981060b)
23587    //    on the M3 mesh `AplicacaoError` envelope's identical two-slot
23588    //    shape and of the peer [`crate::dep::dep_nome_axis_reason_ctors!`]
23589    //    (5621f8a) on the sibling `:deps` envelope's mirror-symmetric
23590    //    three-slot shape (the `nome` axis added at the per-dep-owned
23591    //    altitude). Ten-variant lift closing the ten open-coded ctor
23592    //    sites at the per-axis [`Caixa::validate_*`] cascade — the tenth
23593    //    (`restart_window_malformed => RestartWindowMalformed
23594    //    { restart_window }`) closes the last open-coded four-line
23595    //    `.map_err(|reason| ManifestError::RestartWindowMalformed
23596    //    { restart_window: s.to_string(), reason })` block at
23597    //    [`Caixa::validate_restart_window`] onto the same substrate
23598    //    primitive per typed variant.
23599
23600    #[test]
23601    fn nome_invalid_ctor_matches_struct_literal_wrap() {
23602        let nome = "cart-svc";
23603        let reason = "sample reason text";
23604        assert_eq!(
23605            ManifestError::nome_invalid(nome, reason),
23606            ManifestError::NomeInvalid {
23607                nome: nome.to_string(),
23608                reason: reason.to_string(),
23609            },
23610            "generated nome_invalid ctor must produce byte-equal \
23611             `ManifestError::NomeInvalid` to the pre-lift struct-literal \
23612             wrap on the same `(&str, &str)` fixture",
23613        );
23614    }
23615
23616    #[test]
23617    fn nome_chart_name_budget_exceeded_ctor_matches_struct_literal_wrap() {
23618        let nome = "a-very-long-cart-service-name";
23619        let reason = "sample reason text";
23620        assert_eq!(
23621            ManifestError::nome_chart_name_budget_exceeded(nome, reason),
23622            ManifestError::NomeChartNameBudgetExceeded {
23623                nome: nome.to_string(),
23624                reason: reason.to_string(),
23625            },
23626            "generated nome_chart_name_budget_exceeded ctor must produce \
23627             byte-equal `ManifestError::NomeChartNameBudgetExceeded` to \
23628             the pre-lift struct-literal wrap on the same `(&str, &str)` \
23629             fixture",
23630        );
23631    }
23632
23633    #[test]
23634    fn versao_invalid_ctor_matches_struct_literal_wrap() {
23635        let versao = "0.1";
23636        let reason = "sample reason text";
23637        assert_eq!(
23638            ManifestError::versao_invalid(versao, reason),
23639            ManifestError::VersaoInvalid {
23640                versao: versao.to_string(),
23641                reason: reason.to_string(),
23642            },
23643            "generated versao_invalid ctor must produce byte-equal \
23644             `ManifestError::VersaoInvalid` to the pre-lift \
23645             struct-literal wrap on the same `(&str, &str)` fixture",
23646        );
23647    }
23648
23649    #[test]
23650    fn etiqueta_invalid_ctor_matches_struct_literal_wrap() {
23651        let etiqueta = "MyKeyword";
23652        let reason = "sample reason text";
23653        assert_eq!(
23654            ManifestError::etiqueta_invalid(etiqueta, reason),
23655            ManifestError::EtiquetaInvalid {
23656                etiqueta: etiqueta.to_string(),
23657                reason: reason.to_string(),
23658            },
23659            "generated etiqueta_invalid ctor must produce byte-equal \
23660             `ManifestError::EtiquetaInvalid` to the pre-lift \
23661             struct-literal wrap on the same `(&str, &str)` fixture",
23662        );
23663    }
23664
23665    #[test]
23666    fn autor_invalid_ctor_matches_struct_literal_wrap() {
23667        let autor = "Ada Lovelace";
23668        let reason = "sample reason text";
23669        assert_eq!(
23670            ManifestError::autor_invalid(autor, reason),
23671            ManifestError::AutorInvalid {
23672                autor: autor.to_string(),
23673                reason: reason.to_string(),
23674            },
23675            "generated autor_invalid ctor must produce byte-equal \
23676             `ManifestError::AutorInvalid` to the pre-lift struct-literal \
23677             wrap on the same `(&str, &str)` fixture",
23678        );
23679    }
23680
23681    #[test]
23682    fn repositorio_invalid_ctor_matches_struct_literal_wrap() {
23683        let repositorio = "https://example.com/no-dot-git";
23684        let reason = "sample reason text";
23685        assert_eq!(
23686            ManifestError::repositorio_invalid(repositorio, reason),
23687            ManifestError::RepositorioInvalid {
23688                repositorio: repositorio.to_string(),
23689                reason: reason.to_string(),
23690            },
23691            "generated repositorio_invalid ctor must produce byte-equal \
23692             `ManifestError::RepositorioInvalid` to the pre-lift \
23693             struct-literal wrap on the same `(&str, &str)` fixture",
23694        );
23695    }
23696
23697    #[test]
23698    fn descricao_invalid_ctor_matches_struct_literal_wrap() {
23699        let descricao = "some description";
23700        let reason = "sample reason text";
23701        assert_eq!(
23702            ManifestError::descricao_invalid(descricao, reason),
23703            ManifestError::DescricaoInvalid {
23704                descricao: descricao.to_string(),
23705                reason: reason.to_string(),
23706            },
23707            "generated descricao_invalid ctor must produce byte-equal \
23708             `ManifestError::DescricaoInvalid` to the pre-lift \
23709             struct-literal wrap on the same `(&str, &str)` fixture",
23710        );
23711    }
23712
23713    #[test]
23714    fn licenca_invalid_ctor_matches_struct_literal_wrap() {
23715        let licenca = "not-an-spdx";
23716        let reason = "sample reason text";
23717        assert_eq!(
23718            ManifestError::licenca_invalid(licenca, reason),
23719            ManifestError::LicencaInvalid {
23720                licenca: licenca.to_string(),
23721                reason: reason.to_string(),
23722            },
23723            "generated licenca_invalid ctor must produce byte-equal \
23724             `ManifestError::LicencaInvalid` to the pre-lift \
23725             struct-literal wrap on the same `(&str, &str)` fixture",
23726        );
23727    }
23728
23729    #[test]
23730    fn edicao_invalid_ctor_matches_struct_literal_wrap() {
23731        let edicao = "26";
23732        let reason = "sample reason text";
23733        assert_eq!(
23734            ManifestError::edicao_invalid(edicao, reason),
23735            ManifestError::EdicaoInvalid {
23736                edicao: edicao.to_string(),
23737                reason: reason.to_string(),
23738            },
23739            "generated edicao_invalid ctor must produce byte-equal \
23740             `ManifestError::EdicaoInvalid` to the pre-lift \
23741             struct-literal wrap on the same `(&str, &str)` fixture",
23742        );
23743    }
23744
23745    #[test]
23746    fn restart_window_malformed_ctor_matches_struct_literal_wrap() {
23747        let restart_window = "1.5s";
23748        let reason = "sample reason text";
23749        assert_eq!(
23750            ManifestError::restart_window_malformed(restart_window, reason),
23751            ManifestError::RestartWindowMalformed {
23752                restart_window: restart_window.to_string(),
23753                reason: reason.to_string(),
23754            },
23755            "generated restart_window_malformed ctor must produce byte-equal \
23756             `ManifestError::RestartWindowMalformed` to the pre-lift \
23757             struct-literal wrap on the same `(&str, &str)` fixture",
23758        );
23759    }
23760
23761    // Routing pin against the actual [`Caixa::validate_restart_window`]
23762    // wire-up: the codec surfaces its parse error as `Result<Duration, String>`,
23763    // and the pre-lift `.map_err(|reason| ManifestError::RestartWindowMalformed
23764    // { restart_window: s.to_string(), reason })` closure passed the owned
23765    // `String` verbatim onto the `reason: String` slot. The lifted
23766    // `restart_window_malformed(&str, impl Into<String>)` ctor must produce
23767    // byte-equal output on the same `(offending_value, owned_reason)` pair a
23768    // real parse-failure fixture surfaces, so a silent regression on the
23769    // owned-`String` axis (a future `reason` bound change dropping the
23770    // `Into<String>` route the owned reason threads through) surfaces here
23771    // rather than at a downstream diagnostic-shape drift.
23772    #[test]
23773    fn restart_window_malformed_ctor_matches_wire_up_owned_reason_shape() {
23774        let raw = "1.5s";
23775        let reason: String = crate::supervisor::duration_codec::parse(raw)
23776            .expect_err("fractional-seconds `1.5s` must fail the shared codec");
23777        assert_eq!(
23778            ManifestError::restart_window_malformed(raw, reason.clone()),
23779            ManifestError::RestartWindowMalformed {
23780                restart_window: raw.to_string(),
23781                reason: reason.clone(),
23782            },
23783            "generated restart_window_malformed ctor must accept the owned \
23784             `String` the [`crate::supervisor::duration_codec::parse`] parse-\
23785             error carrier surfaces (the exact shape the \
23786             [`Caixa::validate_restart_window`] `.map_err(|reason| ...)` \
23787             closure passes into it) and produce byte-equal \
23788             `ManifestError::RestartWindowMalformed` to the pre-lift \
23789             struct-literal wrap on the same `(offending_value, owned_reason)` \
23790             pair",
23791        );
23792    }
23793
23794    // Cross-family invariance pin — the ten sibling ctors all route
23795    // `reason: impl Into<String>` + `<field>: &str` verbatim onto their
23796    // respective typed variants through the shared
23797    // [`manifest_field_reason_ctors!`] macro. Sweeps three fixture
23798    // shapes for `reason` (`&str` literal, owned `String`, `format!(…)`
23799    // output — the three shapes every in-crate wire-up threads through:
23800    // the parser-shaped `String` every `Result<(), String>` predicate
23801    // returns, the `e.to_string()` owned `String` the
23802    // `semver::Version::parse` arm passes, and the literal-shape reason
23803    // the `EdicaoInvalid` direct arm passes) against every generated arm
23804    // so any per-arm wrapper transformation drift surfaces here rather
23805    // than at a downstream diagnostic-shape mismatch. Peer of the
23806    // sibling
23807    // [`crate::aplicacao::tests::aplicacao_field_reason_ctors_route_reason_through_into_uniformly`]
23808    // pin (981060b) on the sibling `AplicacaoError` envelope's identical
23809    // two-slot family.
23810    #[test]
23811    fn manifest_field_reason_ctors_route_reason_through_into_uniformly() {
23812        let via_literal = "literal reason text";
23813        let via_owned: String = String::from("literal reason text");
23814        let via_format = format!("{} reason text", "literal");
23815        assert_eq!(
23816            ManifestError::nome_invalid("n", via_literal),
23817            ManifestError::nome_invalid("n", via_owned.clone()),
23818        );
23819        assert_eq!(
23820            ManifestError::nome_invalid("n", via_literal),
23821            ManifestError::nome_invalid("n", via_format.clone()),
23822        );
23823        assert_eq!(
23824            ManifestError::nome_chart_name_budget_exceeded("n", via_literal),
23825            ManifestError::nome_chart_name_budget_exceeded("n", via_owned.clone()),
23826        );
23827        assert_eq!(
23828            ManifestError::versao_invalid("0.1", via_literal),
23829            ManifestError::versao_invalid("0.1", via_owned.clone()),
23830        );
23831        assert_eq!(
23832            ManifestError::etiqueta_invalid("k", via_literal),
23833            ManifestError::etiqueta_invalid("k", via_owned.clone()),
23834        );
23835        assert_eq!(
23836            ManifestError::autor_invalid("a", via_literal),
23837            ManifestError::autor_invalid("a", via_owned.clone()),
23838        );
23839        assert_eq!(
23840            ManifestError::repositorio_invalid("r", via_literal),
23841            ManifestError::repositorio_invalid("r", via_owned.clone()),
23842        );
23843        assert_eq!(
23844            ManifestError::descricao_invalid("d", via_literal),
23845            ManifestError::descricao_invalid("d", via_owned.clone()),
23846        );
23847        assert_eq!(
23848            ManifestError::licenca_invalid("l", via_literal),
23849            ManifestError::licenca_invalid("l", via_owned.clone()),
23850        );
23851        assert_eq!(
23852            ManifestError::edicao_invalid("26", via_literal),
23853            ManifestError::edicao_invalid("26", via_owned.clone()),
23854        );
23855        assert_eq!(
23856            ManifestError::edicao_invalid("26", via_literal),
23857            ManifestError::edicao_invalid("26", via_format.clone()),
23858        );
23859        assert_eq!(
23860            ManifestError::restart_window_malformed("1.5s", via_literal),
23861            ManifestError::restart_window_malformed("1.5s", via_owned),
23862        );
23863        assert_eq!(
23864            ManifestError::restart_window_malformed("1.5s", via_literal),
23865            ManifestError::restart_window_malformed("1.5s", via_format),
23866        );
23867    }
23868
23869    // Cross-arm routing pin — the ten sibling ctors accept both `&str`
23870    // (from the [`Caixa::nome`] / [`Caixa::versao`] / [`Caixa::repositorio`]
23871    // / [`Caixa::descricao`] / [`Caixa::licenca`] / [`Caixa::edicao`]
23872    // accessors that return `&str`) and `&String` (from the
23873    // [`Caixa::etiquetas`] / [`Caixa::autores`] slice iterators that yield
23874    // `&String`) at the `<field>: &str` parameter via Deref coercion. This
23875    // pin sweeps both call shapes against the two accessors' actual
23876    // wire-up postures so a future rebrand of the etiquetas / autores
23877    // slice-iterator type (a lift from `&[String]` to `&[Cow<'_, str>]`,
23878    // a `smol_str::SmolStr` per-entry swap) that silently broke the
23879    // Deref-coercion path surfaces at this pin rather than at a
23880    // recompile-time type-mismatch far from the ctor family.
23881    #[test]
23882    fn manifest_field_reason_ctors_accept_both_str_and_string_slice_iters() {
23883        let owned: String = String::from("MyKeyword");
23884        // `&str` literal — the canonical accessor-return shape
23885        // ([`Caixa::nome`] etc. yield `&str`).
23886        assert_eq!(
23887            ManifestError::etiqueta_invalid("MyKeyword", "r"),
23888            ManifestError::EtiquetaInvalid {
23889                etiqueta: "MyKeyword".to_string(),
23890                reason: "r".to_string(),
23891            },
23892        );
23893        // `&String` — the canonical slice-iterator-yield shape
23894        // ([`Caixa::etiquetas`] / [`Caixa::autores`] yield `&String`).
23895        assert_eq!(
23896            ManifestError::etiqueta_invalid(&owned, "r"),
23897            ManifestError::EtiquetaInvalid {
23898                etiqueta: owned.clone(),
23899                reason: "r".to_string(),
23900            },
23901        );
23902        // Both call shapes must produce byte-equal
23903        // [`ManifestError::EtiquetaInvalid`] values on the same
23904        // underlying `String`, so a wire-up threading `etiqueta: &String`
23905        // through the same ctor as a peer wire-up threading `nome: &str`
23906        // through it collapses onto one canonical shape.
23907        assert_eq!(
23908            ManifestError::etiqueta_invalid("MyKeyword", "r"),
23909            ManifestError::etiqueta_invalid(&owned, "r"),
23910        );
23911    }
23912
23913    // ── `manifest_field_only_ctors!` — the paired `{ <field>: String }`
23914    //    single-slot envelope on `ManifestError`, direct sibling of the
23915    //    peer [`crate::aplicacao::aplicacao_caixa_only_ctors!`] (d9f6867,
23916    //    `{ caixa: String }` on `AplicacaoError`) and
23917    //    [`crate::aplicacao::aplicacao_path_only_ctors!`] (3ba8de6,
23918    //    `{ path: String }` on `AplicacaoError`) on the M3 mesh envelope,
23919    //    of the peer [`crate::supervisor::supervisor_caixa_only_ctors!`]
23920    //    (db09650, `{ caixa: String }` on `SupervisorError`), and of the
23921    //    peer [`crate::dep::dep_nome_only_ctors!`] (792aa92,
23922    //    `{ nome: String }` on `DepError`) folds on their sibling
23923    //    envelopes. Two-variant lift closing the last two open-coded
23924    //    single-`String`-slot ctor sites at
23925    //    [`Caixa::validate_etiquetas`] and [`Caixa::validate_autores`].
23926
23927    #[test]
23928    fn etiqueta_duplicate_ctor_matches_struct_literal_wrap() {
23929        assert_eq!(
23930            ManifestError::etiqueta_duplicate("mesh"),
23931            ManifestError::EtiquetaDuplicate {
23932                etiqueta: "mesh".to_string(),
23933            },
23934            "generated etiqueta_duplicate ctor must produce byte-equal \
23935             `ManifestError::EtiquetaDuplicate` to the pre-lift \
23936             struct-literal wrap on the same `&str` fixture",
23937        );
23938    }
23939
23940    #[test]
23941    fn autor_duplicate_ctor_matches_struct_literal_wrap() {
23942        assert_eq!(
23943            ManifestError::autor_duplicate("pleme-io"),
23944            ManifestError::AutorDuplicate {
23945                autor: "pleme-io".to_string(),
23946            },
23947            "generated autor_duplicate ctor must produce byte-equal \
23948             `ManifestError::AutorDuplicate` to the pre-lift \
23949             struct-literal wrap on the same `&str` fixture",
23950        );
23951    }
23952
23953    #[test]
23954    fn manifest_field_only_ctors_route_field_through_to_string() {
23955        // Cross-axis pin: sweep the sole constructor input axis
23956        // (`<field>: &str`) through a non-default fixture value against
23957        // every generated arm in the [`manifest_field_only_ctors!`]
23958        // macro, so any wrapper-side lowercase / trim / truncate / silent
23959        // constant-substitution on the `<field>.to_string()` sole-field
23960        // construction surfaces here rather than at a downstream
23961        // diagnostic-shape mismatch. Peer of the sibling
23962        // [`crate::aplicacao::tests::aplicacao_caixa_only_ctors_route_caixa_through_to_string`]
23963        // (d9f6867) and
23964        // [`crate::aplicacao::tests::aplicacao_path_only_ctors_route_path_through_to_string`]
23965        // (3ba8de6) cross-axis pins on the peer `AplicacaoError`
23966        // single-`String`-slot envelopes.
23967        let value = "cache-v2";
23968        assert_eq!(
23969            ManifestError::etiqueta_duplicate(value),
23970            ManifestError::EtiquetaDuplicate {
23971                etiqueta: value.to_string(),
23972            },
23973        );
23974        assert_eq!(
23975            ManifestError::autor_duplicate(value),
23976            ManifestError::AutorDuplicate {
23977                autor: value.to_string(),
23978            },
23979        );
23980    }
23981
23982    #[test]
23983    fn manifest_field_only_ctors_accept_both_str_and_string_slice_iters() {
23984        // The two wire-up sites at [`Caixa::validate_etiquetas`] and
23985        // [`Caixa::validate_autores`] each thread a `&String` loop head
23986        // through the ctor via Deref coercion at the `<field>: &str`
23987        // parameter — this pin locks that call shape's byte-equality
23988        // against the direct `&str` shape so a future rebrand of the
23989        // `:etiquetas` / `:autores` slice-iterator type that silently
23990        // broke the Deref-coercion path surfaces here rather than at a
23991        // recompile-time type-mismatch far from the ctor family. Peer of
23992        // the sibling
23993        // [`manifest_field_reason_ctors_accept_both_str_and_string_slice_iters`]
23994        // pin on the peer two-slot `{ <field>: String, reason: String }`
23995        // envelope.
23996        let etiqueta: String = String::from("mesh");
23997        assert_eq!(
23998            ManifestError::etiqueta_duplicate("mesh"),
23999            ManifestError::etiqueta_duplicate(&etiqueta),
24000        );
24001        let autor: String = String::from("pleme-io");
24002        assert_eq!(
24003            ManifestError::autor_duplicate("pleme-io"),
24004            ManifestError::autor_duplicate(&autor),
24005        );
24006    }
24007
24008    #[test]
24009    fn dialeto_estrangeiro_ctor_matches_struct_literal_wrap() {
24010        // Byte-identity pin against the pre-lift open-coded
24011        // `Self::DialetoEstrangeiro { dialeto }` one-field struct-literal —
24012        // a future silent de-lift of [`Caixa::from_lisp`]'s foreign-dialect
24013        // wire-up back to an inline struct-literal (or a divergence between
24014        // the ctor's stored-field wrapping and the struct-literal shape
24015        // downstream consumers still read through `matches!`
24016        // destructuring) trips at caixa-core test time rather than at a
24017        // downstream `LeituraError::to_string()` diagnostic-shape drift on
24018        // a consumer far from the wire-up commit. Peer of the sibling
24019        // [`crate::dialeto::tests::cabeca_errada_ctor_matches_struct_literal_wrap`]
24020        // (38d5159) byte-identity pin the peer single-slot
24021        // [`crate::dialeto::DialetoError::cabeca_errada`] ctor carries.
24022        for dialeto in [
24023            crate::dialeto::CaixaDialeto::Molde,
24024            crate::dialeto::CaixaDialeto::MoldePosicional,
24025        ] {
24026            let via_ctor = LeituraError::dialeto_estrangeiro(dialeto);
24027            let via_struct_literal = LeituraError::DialetoEstrangeiro { dialeto };
24028            assert!(
24029                matches!(
24030                    (&via_ctor, &via_struct_literal),
24031                    (
24032                        LeituraError::DialetoEstrangeiro { dialeto: a },
24033                        LeituraError::DialetoEstrangeiro { dialeto: b },
24034                    ) if a == b && *a == dialeto
24035                ),
24036                "LeituraError::dialeto_estrangeiro({dialeto:?}) must \
24037                 byte-match the open-coded `LeituraError::DialetoEstrangeiro \
24038                 {{ dialeto: {dialeto:?} }}` struct-literal — a future \
24039                 silent de-lift back to the struct-literal, or a divergence \
24040                 in the field's stored shape, would surface here",
24041            );
24042            assert_eq!(
24043                via_ctor.to_string(),
24044                via_struct_literal.to_string(),
24045                "Display byte-string must be identical between the ctor \
24046                 and struct-literal forms — a divergence would mean the \
24047                 ctor wired the field through a different projection than \
24048                 the struct-literal, silently splitting the two paths' \
24049                 diagnostic shape. dialect: {dialeto:?}",
24050            );
24051        }
24052    }
24053
24054    #[test]
24055    fn dialeto_estrangeiro_routes_dialeto_verbatim_across_every_caixa_dialeto_arm() {
24056        // Boundary-covering fixture sweep on the sole
24057        // [`crate::dialeto::CaixaDialeto`] axis the variant carries —
24058        // every arm in [`crate::dialeto::CaixaDialeto::ALL`] (including the
24059        // non-[`crate::dialeto::CaixaDialeto::is_molde_family`] arms the
24060        // [`Caixa::from_lisp`] wire-up never reaches today, since the ctor
24061        // is a substrate primitive independent of any single caller's
24062        // dispatch gate) round-trips through the ctor byte-equal to the
24063        // input and byte-equal to the open-coded struct-literal wrap. Any
24064        // wrapper-side silent transformation (a `dialeto.normalize()`
24065        // rewrite, a `dialeto.into()` divergence, an accidental field
24066        // rebrand on the ctor body) surfaces at assert time rather than
24067        // at a downstream consumer that reads `err.dialeto` back and
24068        // gets a different arm than the one it stored. Peer of the sibling
24069        // [`crate::dialeto::tests::cabeca_errada_routes_encontrado_verbatim_across_boundary_inputs`]
24070        // (38d5159) boundary-sweep pin on the peer single-slot ctor.
24071        for &dialeto in crate::dialeto::CaixaDialeto::ALL {
24072            let via_ctor = LeituraError::dialeto_estrangeiro(dialeto);
24073            match via_ctor {
24074                LeituraError::DialetoEstrangeiro { dialeto: stored } => {
24075                    assert_eq!(
24076                        stored, dialeto,
24077                        "LeituraError::dialeto_estrangeiro({dialeto:?}) \
24078                         must route the input arm verbatim into the \
24079                         stored `dialeto:` field — any silent \
24080                         normalization on the ctor path would surface \
24081                         here rather than at a downstream consumer that \
24082                         branches on `err.dialeto`",
24083                    );
24084                }
24085                other => panic!(
24086                    "dialeto_estrangeiro({dialeto:?}) must construct the \
24087                     DialetoEstrangeiro variant; got: {other:?}"
24088                ),
24089            }
24090        }
24091    }
24092
24093    #[test]
24094    fn from_lisp_foreign_dialect_gate_routes_through_dialeto_estrangeiro_ctor() {
24095        // End-to-end pin refusing a silent regression that de-folds the
24096        // [`Caixa::from_lisp`] production wire-up back to
24097        // `Err(LeituraError::DialetoEstrangeiro { dialeto })` at the
24098        // foreign-dialect classification arm — for every arm in
24099        // [`crate::dialeto::CaixaDialeto::ALL`] the
24100        // [`crate::dialeto::CaixaDialeto::is_molde_family`] partition
24101        // returns `true` for (the [`crate::dialeto::CaixaDialeto::Molde`]
24102        // and [`crate::dialeto::CaixaDialeto::MoldePosicional`]
24103        // canonical two-arity closure), the observed
24104        // [`Caixa::from_lisp`] `Err` byte-equals the value returned by
24105        // `LeituraError::dialeto_estrangeiro(dialeto)`. Peer of the sibling
24106        // [`crate::dialeto::tests::classify_form_wrong_head_routes_through_cabeca_errada_ctor`]
24107        // (38d5159) end-to-end wire-up pin on the sibling
24108        // [`crate::dialeto::classify_form`] wrong-head gate.
24109        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
24110            (
24111                crate::dialeto::CaixaDialeto::Molde,
24112                r#"
24113                  (defcaixa
24114                    :name "base64"
24115                    :kind :Biblioteca
24116                    :ecosystem :rust-single-crate
24117                    :package {:name "base64" :version "0.22.1"})
24118                "#,
24119            ),
24120            (
24121                crate::dialeto::CaixaDialeto::MoldePosicional,
24122                r#"
24123                  (defcaixa todoku-go
24124                    :kind :Biblioteca
24125                    :ecosystem :go
24126                    :package {:name "todoku-go" :version "0.3.0"})
24127                "#,
24128            ),
24129        ];
24130
24131        for &(expected, src) in fixtures {
24132            let observed = Caixa::from_lisp(src.trim())
24133                .expect_err("foreign-dialect source must not parse as Pacote");
24134            let via_ctor = LeituraError::dialeto_estrangeiro(expected);
24135            assert!(
24136                matches!(
24137                    (&observed, &via_ctor),
24138                    (
24139                        LeituraError::DialetoEstrangeiro { dialeto: a },
24140                        LeituraError::DialetoEstrangeiro { dialeto: b },
24141                    ) if a == b && *a == expected
24142                ),
24143                "Caixa::from_lisp on {expected:?} source must byte-equal \
24144                 LeituraError::dialeto_estrangeiro({expected:?}) — a silent \
24145                 de-lift of the production wire-up back to the open-coded \
24146                 struct-literal, or a divergence between the ctor and the \
24147                 gate's construction shape, would surface here rather than \
24148                 at a downstream diagnostic consumer",
24149            );
24150            assert_eq!(
24151                observed.to_string(),
24152                via_ctor.to_string(),
24153                "from_lisp's observed `Err` and \
24154                 `dialeto_estrangeiro({expected:?})` must render the same \
24155                 Display byte-string — any drift means the two \
24156                 construction paths projected the same axis through \
24157                 different display shapes",
24158            );
24159        }
24160    }
24161}