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
277/// Substrate-canonical universal-axis per-[`Caixa`] `:licenca` SPDX-shaped
278/// license-expression fallback for the `Option<String>` `:licenca` slot —
279/// the `"MIT"` SPDX identifier every [`caixa-helm`]-rendered
280/// `lareira-<nome>` Helm chart's `README.md` `## License` section folds an
281/// author-omitted (`None`) `:licenca` slot through, extracted as a typed
282/// `pub const` so every substrate-side consumer that resolves "what license
283/// scalar does an author-omitted `:licenca` degrade onto?" reaches for
284/// exactly one substrate-primitive `&'static str`.
285///
286/// The `:licenca` fallback axis has one production consumer today — the
287/// [`caixa-helm`] `build_readme` fold at `caixa-helm/src/lib.rs`'s
288/// `caixa.licenca().unwrap_or(CAIXA_LICENCA_DEFAULT)` `README.md`
289/// `## License` section body — with three sibling caixa-core sites that
290/// cite the `"MIT"` fallback in prose (this crate's [`Caixa::licenca`]
291/// accessor's docstring, [`Self::validate_licenca`]'s docstring, and the
292/// [`ManifestError::LicencaEmpty`] `#[error]` template's user-facing text)
293/// all quoting the exact byte-string a future substrate-side rebrand of the
294/// fallback (a tightening to `"Apache-2.0"` as the substrate absorbs the
295/// wasm-component-model conventions the `wasi:*` WIT worlds already carry,
296/// a per-cluster license-default overlay the M4 CR materializer resolves
297/// per-CR, a promotion to the plain `Option<String>` byte-string into a
298/// richer `SpdxExpression` enum once the SPDX-expression parser lands per
299/// [`Self::validate_licenca`]'s docstring roadmap) would silently split
300/// against — the caixa-helm renderer would emit the new byte, the
301/// docstrings would still cite the prior byte, and every author who reads
302/// the accessor docstring before authoring would file a fresh
303/// `:licenca "MIT"` verbatim rather than defer to the substrate default,
304/// with the drift surfacing at chart-README-audit time far from the
305/// substrate rebrand commit.
306///
307/// Prior to this lift the sole production emitter (`build_readme`) carried
308/// an inline `"MIT"` byte literal at
309/// `caixa-helm/src/lib.rs:1018`'s `.unwrap_or("MIT")` fallback arm — one
310/// occurrence of the same load-bearing per-`Caixa` universal-axis
311/// SPDX-shaped license-expression convention as the four sibling caixa-core
312/// docstring citations, drift-prone by construction ahead of the second
313/// occurrence the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
314/// materializer's per-Aplicacao registry-annotation synthesis (the
315/// [`Self::validate_licenca`] roadmap already names the `Chart.yaml
316/// annotations["artifacthub.io/license"]` axis every registry-facing chart
317/// carries as the second consumer) will surface.
318///
319/// The `"MIT"` value pins the canonical CAIXA-SDLC §I license scaffold
320/// every `feira init`-emitted [`Self::template`] carries verbatim
321/// (`:licenca "MIT"`) and every substrate-side renderer fixture
322/// ([`caixa-helm`]'s `sample_caixa`, [`caixa-flux`]'s renderer fixtures,
323/// [`caixa-mesh`]'s renderer fixtures) seeds by construction, matching the
324/// pleme-io repo `LICENSE` header this workspace itself ships under. The
325/// alternatives an author declares explicitly (compound SPDX expressions
326/// like `"Apache-2.0 OR MIT"`, permissive-family peers like
327/// `"Apache-2.0"` / `"BSD-3-Clause"`, license-with-exception forms like
328/// `"Apache-2.0 WITH LLVM-exception"`) express deliberate license postures
329/// an author declares explicitly, never a posture an author-omitted slot
330/// should silently assume by default.
331///
332/// Lifted as a typed `pub const` so the substrate's chosen license
333/// fallback has exactly one source of truth on the `:licenca` fallback
334/// axis, on the same substrate-primitive lift discipline the peer
335/// per-`Caixa` load-bearing-scalar constants
336/// ([`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`],
337/// [`crate::version::DEFAULT_GIT_REMOTE`],
338/// [`crate::version::DEFAULT_PLEME_GIT_ORG`]) already carry on the sibling
339/// per-`Caixa` universal-axis publish-side convention surface, and the
340/// same discipline the sibling M2 per-supervisor default set carries
341/// end-to-end ([`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`],
342/// [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`],
343/// [`crate::supervisor::SUPERVISOR_RESTART_WINDOW_DEFAULT`],
344/// [`crate::supervisor::SUPERVISOR_CHILD_RESTART_DEFAULT`]) and the M3
345/// per-`:placement` default set already carries
346/// ([`crate::aplicacao::PLACEMENT_ESTRATEGIA_DEFAULT`]) on the paired
347/// M2 / M3 typed-slot-default axes. First typed default on the outer
348/// top-level [`Caixa`] universal-axis surface to converge onto the
349/// substrate-primitive-lift discipline the M2 / M3 typed-slot families
350/// already carry.
351pub const CAIXA_LICENCA_DEFAULT: &str = "MIT";
352
353impl Caixa {
354    /// Parse a `caixa.lisp` source string to a typed `Caixa`.
355    ///
356    /// Classifies the dialect **before** parsing. A `(defcaixa …)` of another
357    /// declaration is [`LeituraError::DialetoEstrangeiro`], naming what it is
358    /// and who reads it, instead of an unknown-keyword rejection that reads as
359    /// "your manifest is broken".
360    ///
361    /// The ordering is load-bearing. Handing a foreign dialect to the derive
362    /// first and interpreting the failure afterwards would mean guessing from
363    /// an error message, and the guess would be wrong for every file whose
364    /// first unknown slot happens to be one both schemas could plausibly carry.
365    pub fn from_lisp(src: &str) -> Result<Self, LeituraError> {
366        use tatara_lisp::domain::TataraDomain;
367        let forms = tatara_lisp::read(src).map_err(LeituraError::Leitura)?;
368        let first = forms.first().ok_or(crate::dialeto::DialetoError::Vazio)?;
369
370        // Route the foreign-dialect rejection gate through the lifted
371        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
372        // typed predicate rather than the pre-lift hand-rolled three-arm
373        // `match { Pacote => {}, Desconhecido => {}, foreign => Err(…) }`
374        // literal — the `defmolde` declaration-family partition (the two-
375        // arity closure of [`crate::dialeto::CaixaDialeto::Molde`] and
376        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two arms
377        // whose sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
378        // projection already collapses onto `"defmolde"` and whose sibling
379        // [`crate::dialeto::CaixaDialeto::consumidor`] projection already
380        // collapses onto `"pleme-doc-gen"`) resolves through one dispatch
381        // on the substrate primitive. `Pacote` (the tatara-lisp package
382        // manifest this derive can parse) and `Desconhecido` (deliberately
383        // falls through to the derive rather than short-circuiting: a
384        // `(defcaixa …)` matching neither schema is most likely a genuine
385        // package manifest with a typo in `:nome`, and the derive's
386        // diagnostic — which names the offending keyword and suggests the
387        // nearest slot — is far better than anything this classifier
388        // could say) both return `false` from `is_molde_family()` and fall
389        // through to the derive. Only the typed dialect flows into the
390        // error — the three user-facing projections (canonical keyword,
391        // description, consumer) are read at Display time through
392        // [`crate::dialeto::CaixaDialeto`]'s own accessors, so the
393        // variant cannot carry a snapshot that drifts from
394        // [`crate::dialeto::CaixaDialeto::palavra_canonica`] /
395        // `descricao` / `consumidor`. A future fifth dialect the
396        // [`crate::dialeto`] module doc's "third dialect" hazard
397        // actualises that belongs to the `defmolde` family lands one
398        // match arm at [`crate::dialeto::CaixaDialeto::is_molde_family`]
399        // and this gate picks up the new arm by construction — the pre-
400        // lift wildcard `foreign =>` was compile-time-anonymous and would
401        // silently absorb any hypothetical fifth `defcaixa`-family arm as
402        // foreign; routing the partition through the typed predicate
403        // closes both drift surfaces.
404        let dialeto = crate::dialeto::classify_form(first)?;
405        if dialeto.is_molde_family() {
406            return Err(LeituraError::DialetoEstrangeiro { dialeto });
407        }
408
409        Self::compile_from_sexp(first).map_err(LeituraError::Leitura)
410    }
411
412    /// Register `Caixa` with the global tatara-lisp domain registry so
413    /// `defcaixa` is dispatchable from any tatara-lisp binary that seeds
414    /// the registry (e.g. `tatara-check`).
415    ///
416    /// Returns the typed [`tatara_lisp::KeywordCollision`] on the second
417    /// (and every subsequent) call in the same process — one keyword,
418    /// one type, per process is a hard invariant of the upstream
419    /// registry, and a caller that hits it must fix its crate graph
420    /// rather than swallowing the error. Peer of the sibling per-crate
421    /// `register()` entry points at `caixa-flake/src/flake.rs`,
422    /// `caixa-fmt/src/lisp_config.rs`, `caixa-lacre/src/lock.rs`,
423    /// `caixa-lint/src/lisp_config.rs`, `caixa-resolver/src/lisp_config.rs`
424    /// — every substrate crate that owns a tatara-lisp keyword now
425    /// propagates the same typed error verbatim, so a downstream binary
426    /// that seeds the registry (`tatara-check`, the future LSP) reaches
427    /// for one shape at every call site.
428    ///
429    /// # Errors
430    ///
431    /// [`tatara_lisp::KeywordCollision`] when a peer type has already
432    /// claimed the `defcaixa` keyword in this process.
433    pub fn register() -> Result<(), tatara_lisp::KeywordCollision> {
434        tatara_lisp::domain::register::<Self>()
435    }
436
437    /// Substrate-canonical per-`Caixa` `:licenca` SPDX-expression scalar
438    /// accessor every consumer of the top-level manifest's license axis
439    /// keys off — returns the author-declared `:licenca` byte-string
440    /// verbatim as an `Option<&str>`, borrowed from the typed slot's own
441    /// `Option<String>` storage. `None` when the slot is absent (the
442    /// canonical "omit to defer to the caixa-helm renderer's `MIT`
443    /// fallback" shape [`Self::validate_licenca`] documents at
444    /// caixa-core/src/manifest.rs:1560; the peer [`caixa-helm`]
445    /// `build_readme` fold at caixa-helm/src/lib.rs:962 reads this
446    /// predicate too, so an authored-but-unset `:licenca` round-trips to
447    /// a rendered `lareira-<nome>` chart's `README.md` `## License`
448    /// section structurally identical to one that omits the slot).
449    ///
450    /// The `:licenca` slot carries the universal-axis SPDX-expression
451    /// license identifier every kind of caixa emits under (CAIXA-SDLC
452    /// §I — the author-facing surface every `defcaixa` form supplies) —
453    /// the typed slot's `Option<String>` accept-set (empty-string
454    /// rejected through [`ManifestError::LicencaEmpty`], SPDX-alphabet-
455    /// invalid rejected through [`ManifestError::LicencaInvalid`]) maps
456    /// onto the `lareira-<nome>` Helm chart's `README.md` `## License`
457    /// section (caixa-helm/src/lib.rs:962) and (through future
458    /// tightening documented at [`Self::validate_licenca`]) the
459    /// Chart.yaml `annotations["artifacthub.io/license"]` axis every
460    /// registry-facing chart carries. Every downstream consumer that
461    /// reads the license byte-string keys off this scalar (the
462    /// [`Self::validate_licenca`] empty-arm + SPDX-shape gate that
463    /// routes through `self.licenca.as_deref()`, the caixa-helm
464    /// `build_readme` `unwrap_or_else(|| "MIT".into())` fold that keys
465    /// the fallback off the `Option::is_none()` arm, every future
466    /// per-`Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
467    /// acknowledges).
468    ///
469    /// Prior to this lift the `.licenca` field was accessed inline at
470    /// two production sites — [`Self::validate_licenca`]'s
471    /// `self.licenca.as_deref()` empty-and-shape gate binding and the
472    /// caixa-helm `build_readme` `caixa.licenca.clone().unwrap_or_else(||
473    /// "MIT".into())` `README.md` `## License` fold — two open-coded
474    /// field-accesses that expressed no compile-time link back to the
475    /// typed slot. A future extension of the `:licenca` axis to a
476    /// richer author surface — a per-`:licenca` structured SPDX
477    /// expression parser + license-id allowlist (the future tightening
478    /// [`Self::validate_licenca`]'s docstring acknowledges), a
479    /// per-cluster license-default overlay the M4 CR materializer
480    /// resolves per-CR (the "cluster policy pins `Apache-2.0` for every
481    /// unlisted caixa" arm), a promotion of the plain
482    /// `Option<String>` byte-string to a richer `SpdxExpression` enum
483    /// once the SPDX-expression parser lands — would have had to be
484    /// threaded through both open-coded copies in lockstep or the
485    /// validate gate and the caixa-helm emit path would silently
486    /// disagree on which license a given [`Caixa`] resolves to (an
487    /// author's `:licenca "MIT OR Apache-2.0"` would satisfy validate
488    /// while the emit path silently rendered a stale `MIT` fallback,
489    /// or vice versa). Lifting the resolution to a typed method on the
490    /// substrate primitive means every downstream consumer of the
491    /// caixa's per-`Caixa` license surface reaches for exactly one
492    /// typed dispatch — the resolver's accept-set migrates as a unit
493    /// on any future axis addition.
494    ///
495    /// First `Option<&str>`-return top-level [`Caixa`] scalar accessor —
496    /// opens the "outer [`Caixa`] `Option<&str>` scalar" projection
497    /// pattern the sibling per-`Caixa` `:descricao` / `:repositorio` /
498    /// `:edicao` future lifts fold on. Same "one typed dispatch on the
499    /// substrate primitive, thin projections at each consumer"
500    /// discipline the peer per-`:placement` [`crate::aplicacao::Placement::shard_key`]
501    /// (7cd2a28) / [`crate::aplicacao::Placement::affinity`] (74ec2d3)
502    /// / per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
503    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
504    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
505    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
506    /// typed-slot atom axes, extended here to the outer top-level
507    /// `Caixa` universal-axis surface. Named `licenca()` to match the
508    /// storage field's name; the accessor's identity maps onto the
509    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
510    /// carries.
511    #[must_use]
512    pub const fn licenca(&self) -> Option<&str> {
513        match &self.licenca {
514            Some(s) => Some(s.as_str()),
515            None => None,
516        }
517    }
518
519    /// Substrate-canonical per-`Caixa` `:repositorio` git-repo-URL scalar
520    /// accessor every consumer of the top-level manifest's homepage /
521    /// source-of-truth axis keys off — returns the author-declared
522    /// `:repositorio` byte-string verbatim as an `Option<&str>`, borrowed
523    /// from the typed slot's own `Option<String>` storage. `None` when
524    /// the slot is absent (the canonical "omit to defer to the renderer's
525    /// per-target placeholder" shape — [`caixa-helm`]'s `ChartYaml.home`
526    /// carries the `Option<String>` through verbatim so an author-omitted
527    /// `:repositorio` renders a `Chart.yaml` without a `home:` field
528    /// (`skip_serializing_if = "Option::is_none"`), while [`caixa-flux`]'s
529    /// `ClusterBundleOpts::for_caixa` folds the omitted slot through a
530    /// `format!("https://github.com/{DEFAULT_PLEME_GIT_ORG}/{nome}")`
531    /// fallback derived from `caixa.nome`).
532    ///
533    /// The `:repositorio` slot carries the universal-axis git-repo-URL
534    /// homepage identifier every kind of caixa emits under (CAIXA-SDLC
535    /// §I — the author-facing surface every `defcaixa` form supplies) —
536    /// the typed slot's `Option<String>` accept-set (empty-string
537    /// rejected through [`ManifestError::RepositorioEmpty`], git-repo-URL-
538    /// shape-invalid rejected through [`ManifestError::RepositorioInvalid`]
539    /// past the shared [`crate::render::is_git_repo_url`] predicate the
540    /// peer per-`:deps :fonte :repo` axis also routes through) maps onto
541    /// four load-bearing downstream consumers:
542    ///
543    ///   - [`Self::validate_repositorio`]'s empty-arm + shape-predicate
544    ///     gate binding at caixa-core/src/manifest.rs:1456 — the
545    ///     universal-axis identity gate wired at caixa-build time.
546    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.home` fold at
547    ///     caixa-helm/src/lib.rs:840 — the rendered `lareira-<nome>`
548    ///     Helm chart's `Chart.yaml` `home:` field, which every registry
549    ///     that ingests the chart (ArtifactHub, chartmuseum,
550    ///     `helm search repo`) surfaces as the chart's canonical source-
551    ///     of-truth link.
552    ///   - [`caixa-helm`]'s `build_readme` `## Source` fold at
553    ///     caixa-helm/src/lib.rs:957 — the rendered `lareira-<nome>`
554    ///     chart's `README.md` header link back to the source repo,
555    ///     which every author who inspects the rendered chart bundle
556    ///     lands at.
557    ///   - [`caixa-flux`]'s `ClusterBundleOpts::for_caixa`
558    ///     `GitRepository.spec.url` fold at caixa-flux/src/lib.rs:2006 —
559    ///     the rendered `GitRepository` CR's `spec.url` field, which
560    ///     FluxCD's `source-controller` polls to reconcile the caixa's
561    ///     manifest bundle from git.
562    ///
563    /// Prior to this lift the `.repositorio` field was accessed inline
564    /// at four production sites — [`Self::validate_repositorio`]'s
565    /// `self.repositorio.as_deref()` empty-and-shape gate binding, the
566    /// caixa-helm `build_chart_yaml` `caixa.repositorio.clone()`
567    /// `Chart.yaml` `home:` field fold, the caixa-helm `build_readme`
568    /// `caixa.repositorio.clone().unwrap_or_else(|| caixa.nome.clone())`
569    /// `README.md` `## Source` fold, and the caixa-flux
570    /// `ClusterBundleOpts::for_caixa`
571    /// `caixa.repositorio.clone().unwrap_or_else(|| format!(...))`
572    /// `GitRepository.spec.url` fold — four open-coded field-accesses
573    /// that expressed no compile-time link back to the typed slot. A
574    /// future extension of the `:repositorio` axis to a richer author
575    /// surface — a per-`:repositorio` structured
576    /// [`crate::render::GitRepoUrl`]-shaped scheme+host+path parse
577    /// (the future tightening [`Self::validate_repositorio`]'s
578    /// docstring anticipates alongside the peer per-`:deps :fonte
579    /// :repo` axis), a per-cluster repo-mirror overlay the M4 CR
580    /// materializer resolves per-CR (the "cluster policy rewrites
581    /// `github:pleme-io/...` to `git.internal/mirror/pleme-io/...`"
582    /// arm the private-registry story acknowledges), a promotion of
583    /// the plain `Option<String>` byte-string to a richer
584    /// `RepoUrl` enum discriminated on scheme — would have had to be
585    /// threaded through all four open-coded copies in lockstep or the
586    /// validate gate and the three emit paths would silently disagree
587    /// on which URL a given [`Caixa`] resolves to (an author's
588    /// `:repositorio "github:pleme-io/checkout"` would satisfy validate
589    /// while one of the emit paths silently rendered a stale URL, or
590    /// vice versa). Lifting the resolution to a typed method on the
591    /// substrate primitive means every downstream consumer of the
592    /// caixa's per-`Caixa` repo-URL surface reaches for exactly one
593    /// typed dispatch — the resolver's accept-set migrates as a unit on
594    /// any future axis addition.
595    ///
596    /// Second outer top-level [`Caixa`] `Option<&str>`-return scalar
597    /// accessor — sibling of [`Self::licenca`] (6d5bc28), the accessor
598    /// that opened the "outer [`Caixa`] `Option<&str>` scalar"
599    /// projection pattern this lift folds on. Same "one typed dispatch
600    /// on the substrate primitive, thin projections at each consumer"
601    /// discipline the peer per-`:placement`
602    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
603    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
604    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
605    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
606    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
607    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
608    /// typed-slot atom axes, extended here to the second outer top-level
609    /// `Caixa` universal-axis surface. Named `repositorio()` to match
610    /// the storage field's name; the accessor's identity maps onto the
611    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
612    /// carries.
613    #[must_use]
614    pub const fn repositorio(&self) -> Option<&str> {
615        match &self.repositorio {
616            Some(s) => Some(s.as_str()),
617            None => None,
618        }
619    }
620
621    /// Substrate-canonical per-`Caixa` **resolved-git-repo-URL** composer —
622    /// returns the caixa's canonical git-source-of-truth URL as an owned
623    /// [`String`], author-declared `:repositorio` byte-string verbatim on
624    /// the `Some` arm and the substrate's canonical pleme-org github URL
625    /// fallback ([`crate::DEFAULT_PLEME_GIT_ORG`] and [`Self::nome`]
626    /// interpolated into `https://github.com/<org>/<nome>`) on the
627    /// `None` arm. Every substrate-side consumer that resolves
628    /// "which git URL does this caixa's source live at?" reaches for
629    /// exactly one typed dispatch on the substrate primitive — the raw
630    /// `caixa.repositorio().map(str::to_owned).unwrap_or_else(|| format!(
631    /// "https://github.com/{org}/{nome}", org = DEFAULT_PLEME_GIT_ORG,
632    /// nome = caixa.nome()))` open-coded composition every prior caller
633    /// re-derived collapses onto one canonical arm.
634    ///
635    /// Distinct from [`Self::repositorio`] (`Option<&str>`, exposes the
636    /// author-omitted / author-declared partition to the caller) — this
637    /// accessor is the **resolved** URL surface, folding the fallback in
638    /// at the substrate-primitive boundary. Every consumer that keys off
639    /// the `Option::is_none()` discriminator (a [`Chart.yaml`] `home:`
640    /// field emit that must omit the field entirely on an author-omitted
641    /// `:repositorio`, per the [`Self::repositorio`] docstring's
642    /// documented four-consumer list) reaches through the raw
643    /// [`Self::repositorio`] `Option<&str>` accessor by construction — the
644    /// resolved-URL composer sits alongside it as the second projection
645    /// on the same underlying `:repositorio` slot rather than replacing
646    /// the raw accessor.
647    ///
648    /// The fallback branch is the exact byte-image of the prior inline
649    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url` composer at
650    /// caixa-flux/src/lib.rs:2080 — pinned by the sibling caixa-flux
651    /// byte-parity test
652    /// `cluster_bundle_opts_for_caixa_git_url_routes_through_canonical_git_url_accessor`
653    /// against a future implementation of this method that reordered the
654    /// `format!` template arguments, migrated the `<org>` segment to a
655    /// different constant (the [`crate::DEFAULT_PLEME_GIT_ORG`] axis a
656    /// future substrate-side git-org migration may split off), or
657    /// silently absorbed the empty-string arm (a hypothetical
658    /// `Some("") → fallback` collapse the raw [`Self::repositorio`]
659    /// accessor's docstring explicitly rejects on the sibling raw
660    /// accessor).
661    ///
662    /// Peer of the sibling per-`&Caixa`-axis composed helpers
663    /// [`caixa-flux::cluster_bundle_for_caixa`] (06d52d7) on the sibling
664    /// substrate-side renderer surface — same "close the composed
665    /// substrate-primitive at one canonical arm on the single-`&Caixa`
666    /// dispatch, converge every prior open-coded caller onto the arm"
667    /// discipline extended onto the resolved-git-URL projection of the
668    /// per-`Caixa` `:repositorio` axis. Owns per-call [`String`]
669    /// allocation on both arms (the `Some` arm's `str::to_owned` and the
670    /// `None` arm's `format!`) — the by-value return matches every
671    /// downstream consumer's field-fill shape (the caixa-flux
672    /// `ClusterBundleOpts::git_url: String` field, every future
673    /// `Chart.yaml` `home:` fold's `Option<String>` field-fill on the
674    /// `Some` arm).
675    #[must_use]
676    pub fn canonical_git_url(&self) -> String {
677        self.repositorio().map_or_else(
678            || {
679                format!(
680                    "https://github.com/{org}/{nome}",
681                    org = crate::DEFAULT_PLEME_GIT_ORG,
682                    nome = self.nome(),
683                )
684            },
685            str::to_owned,
686        )
687    }
688
689    /// Substrate-canonical per-`Caixa` **resolved-publish-tag** composer —
690    /// returns the caixa's canonical Zig-style git-publish-tag as an owned
691    /// [`String`], derived by concatenating
692    /// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] with the typed
693    /// [`Self::versao`] byte-string on a single `format!` template.
694    /// Every substrate-side consumer that resolves "which git tag does this
695    /// caixa publish under?" reaches for exactly one typed dispatch on the
696    /// substrate primitive — the raw `format!("{prefix}{versao}", prefix =
697    /// caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao = caixa.versao())`
698    /// open-coded composition every prior caller re-derived collapses onto
699    /// one canonical arm.
700    ///
701    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
702    /// git-URL composer on the paired per-`Caixa` git-remote axis — same
703    /// "close the composed substrate-primitive at one canonical arm on the
704    /// single-`&Caixa` dispatch, converge every prior open-coded caller
705    /// onto the arm" discipline extended from the resolved-URL projection
706    /// of the per-`Caixa` `:repositorio` axis onto the resolved-tag
707    /// projection of the per-`Caixa` `:versao` axis. The two accessors
708    /// jointly close the pair of scalars every `FluxCD` `GitRepository` CR
709    /// keys off (`spec.url` via [`Self::canonical_git_url`],
710    /// `spec.ref.tag` via [`Self::publish_tag`]) at the substrate primitive
711    /// — a downstream consumer that reaches through both accessors reads
712    /// the complete published-git-identity of a caixa through two typed
713    /// dispatches, not four open-coded field accesses.
714    ///
715    /// The reader-side (`caixa-flux::cluster_bundle` /
716    /// `ClusterBundleOpts::for_caixa`'s `git_ref` field, every future
717    /// per-cluster snapshot bundle emitter, the future M4
718    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's tag-carrier
719    /// slot on the tatara `Process` intent) always resolves the tag under
720    /// the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] prefix — this
721    /// method encodes that reader-side convention. The writer-side
722    /// (`caixa-feira`'s `feira publish` `--prefix` clap flag) allows the
723    /// operator to override the prefix at publish time; the two surfaces
724    /// intentionally sit on the "canonical default + operator override"
725    /// pair the sibling [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] constant's
726    /// own docstring documents — a `feira publish --prefix release/`
727    /// override is the operator's explicit opt-out from the substrate
728    /// default, not a supported drift axis.
729    ///
730    /// The composition body is the exact byte-image of the prior inline
731    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_ref` composer at
732    /// caixa-flux/src/lib.rs:2105 — pinned by the sibling caixa-flux
733    /// byte-parity test
734    /// `cluster_bundle_opts_for_caixa_git_ref_routes_through_publish_tag_accessor`
735    /// against a future implementation of this method that reordered the
736    /// `format!` template arguments, migrated the `<prefix>` segment to a
737    /// different constant (the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] axis
738    /// a future Zig-style-tag rebrand may split off — the constant's own
739    /// docstring anticipates a substrate-side move to `release/<versao>`
740    /// or bare `<versao>` shapes once a sibling forge convention adopts a
741    /// slash-namespaced or bare-scalar form), interposed a canonicalization
742    /// pass on the `:versao` axis (a SemVer-2 build-metadata strip an OCI-
743    /// tag normalizer might apply once the M4 registry-alignment slot
744    /// lands), or silently absorbed an empty `:versao` arm (which cannot
745    /// occur past the [`Self::validate_versao`] gate but which a
746    /// hypothetical bypass on the accessor path must not silently paper
747    /// over).
748    ///
749    /// Owns per-call [`String`] allocation via the single `format!`
750    /// invocation — the by-value return matches every downstream
751    /// consumer's field-fill shape (the caixa-flux `GitRefSpec::Tag(String)`
752    /// variant's owned payload, every future `intent.aplicacao.tag: String`
753    /// field-fill on the M4 CR materializer's tag-carrier slot).
754    #[must_use]
755    pub fn publish_tag(&self) -> String {
756        format!(
757            "{prefix}{versao}",
758            prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
759            versao = self.versao(),
760        )
761    }
762
763    /// Substrate-canonical per-`Caixa` **resolved-Helm-chart-name** composer
764    /// — returns the caixa's canonical `lareira-<nome>` per-Servico Helm
765    /// chart identity as an owned [`String`], derived by dispatching through
766    /// the substrate-canonical [`crate::lareira_chart_name`] helper against
767    /// the typed [`Self::nome`] byte-string. Every substrate-side consumer
768    /// that resolves "which Helm chart identity does this caixa render
769    /// under?" reaches for exactly one typed dispatch on the substrate
770    /// primitive — the raw `caixa_core::lareira_chart_name(caixa.nome())`
771    /// two-step compose every prior caller re-derived collapses onto one
772    /// canonical arm on the single-`&Caixa` dispatch.
773    ///
774    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
775    /// git-URL composer + [`Self::publish_tag`] (07e05b8) resolved-publish-
776    /// tag composer on the paired per-`Caixa` published-artifact-identity
777    /// axis — same "close the composed substrate-primitive at one canonical
778    /// arm on the single-`&Caixa` dispatch, converge every prior open-coded
779    /// caller onto the arm" discipline extended from the resolved-URL /
780    /// resolved-tag projections of the `:repositorio` / `:versao` axes onto
781    /// the resolved-chart-name projection of the `:nome` axis. The three
782    /// accessors jointly close the triple of scalars every per-Servico
783    /// deploy artifact keys off (git source URL via
784    /// [`Self::canonical_git_url`], git source tag via
785    /// [`Self::publish_tag`], per-Servico Helm chart identity via
786    /// [`Self::lareira_chart_name`]) at the substrate primitive — a
787    /// downstream consumer that reaches through all three reads the
788    /// complete deploy-artifact identity of a caixa through three typed
789    /// dispatches, not six open-coded compositions across three renderer
790    /// crates.
791    ///
792    /// The reader-side (three production sites at the time of the lift —
793    /// [`caixa-helm::render_chart_for_servico_with`]'s `ChartDir.name`
794    /// composer at caixa-helm/src/lib.rs:778, the peer
795    /// [`caixa-flux::cluster_bundle`]'s per-CR `chart_name` binding at
796    /// caixa-flux/src/lib.rs:2219, and
797    /// [`caixa-tatara::process_for_aplicacao`]'s `release_name`
798    /// composer at caixa-tatara/src/lib.rs:227, plus every future
799    /// per-Servico OCI publish emitter the CAIXA-SDLC §II
800    /// `caixa-publish.yml` reusable workflow's `skopeo push` step keys
801    /// off, the future per-cluster snapshot bundle emitter, the future
802    /// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
803    /// per-member chart-carrier slot on the tatara `Process` intent) —
804    /// always resolves the chart name under the canonical
805    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] prefix; this method encodes
806    /// that reader-side convention. The joint-length invariant the peer
807    /// [`Self::validate_nome_chart_name_budget`] gate enforces at
808    /// caixa-build time (author-declared `:nome` + fixed prefix ≤
809    /// [`crate::DNS_1123_LABEL_MAX_LEN`]) is verified on the input to
810    /// this composer by construction, so the produced `lareira-<nome>`
811    /// string is a valid Helm chart-name segment on every accept-set
812    /// input.
813    ///
814    /// The composition body is the exact byte-image of the prior inline
815    /// `caixa_core::lareira_chart_name(caixa.nome())` two-step form every
816    /// prior caller re-derived — pinned by the sibling caixa-helm /
817    /// caixa-flux / caixa-tatara byte-parity tests
818    /// `<crate>_lareira_chart_name_routes_through_caixa_accessor` against
819    /// a future implementation of this method that reordered the
820    /// composition arguments, migrated the `<prefix>` segment to a
821    /// different constant (the [`crate::LAREIRA_CHART_NAME_PREFIX`] axis a
822    /// future substrate-side chart-family rebrand may split off — the
823    /// constant's own docstring anticipates a substrate-side move once
824    /// the `lareira-` scoping intent outlives the family it names),
825    /// interposed a canonicalization pass on the `:nome` axis (a per-
826    /// registry namespace-qualification an M4 CR materializer might apply
827    /// per-CR — the "`pleme-io/checkout` vs `partner-org/checkout`
828    /// collision" arm the multi-tenant-registry story acknowledges), or
829    /// silently absorbed an empty `:nome` arm (which cannot occur past
830    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
831    /// on the accessor path must not silently paper over).
832    ///
833    /// Owns per-call [`String`] allocation via the single
834    /// [`crate::lareira_chart_name`] `format!` invocation — the by-value
835    /// return matches every downstream consumer's field-fill shape (the
836    /// caixa-helm `ChartDir.name: String` field, the caixa-flux per-CR
837    /// `chart_name: String` binding, the caixa-tatara
838    /// `AplicacaoIntent.release_name: Option<String>` field-fill on the
839    /// `Some` arm).
840    #[must_use]
841    pub fn lareira_chart_name(&self) -> String {
842        crate::lareira_chart_name(self.nome())
843    }
844
845    /// Substrate-canonical per-`Caixa` **resolved-OCI-chart-ref** composer
846    /// — returns the caixa's canonical `oci://<registry>/lareira-<nome>`
847    /// per-Servico Helm chart OCI artifact reference as an owned
848    /// [`String`], derived by dispatching through the substrate-canonical
849    /// [`crate::oci_chart_ref`] helper (which itself composes
850    /// [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied `registry` +
851    /// [`crate::lareira_chart_name`]-of-[`Self::nome`]) against the
852    /// caller-supplied `registry` and the typed [`Self::nome`] byte-string.
853    /// Every substrate-side consumer that resolves "which OCI chart
854    /// artifact does this caixa publish under, in this registry?" reaches
855    /// for exactly one typed dispatch on the substrate primitive — the raw
856    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step compose
857    /// every prior caller re-derived collapses onto one canonical arm on
858    /// the single-`(&Caixa, &str)` dispatch.
859    ///
860    /// Fourth member of the paired per-`Caixa` published-artifact-identity
861    /// axis alongside [`Self::canonical_git_url`] (124f864) /
862    /// [`Self::publish_tag`] (07e05b8) / [`Self::lareira_chart_name`]
863    /// (a8f0bee) — same "close the composed substrate-primitive at one
864    /// canonical arm on the single-`&Caixa` dispatch, converge every
865    /// prior open-coded caller onto the arm" discipline extended from the
866    /// resolved-URL / resolved-tag / resolved-chart-name projections of
867    /// the `:repositorio` / `:versao` / `:nome` axes onto the resolved-
868    /// OCI-ref projection over the paired `(registry, :nome)` inputs. The
869    /// four accessors jointly close the per-`Caixa` published-artifact-
870    /// identity surface every downstream consumer of a caixa's published
871    /// deploy artifacts keys off (git source URL via
872    /// [`Self::canonical_git_url`], git source tag via
873    /// [`Self::publish_tag`], per-Servico Helm chart identity via
874    /// [`Self::lareira_chart_name`], per-registry OCI chart artifact
875    /// reference via [`Self::oci_chart_ref`]) at the substrate primitive
876    /// — a downstream consumer that reaches through all four reads the
877    /// complete deploy-artifact identity of a caixa through four typed
878    /// dispatches, not eight open-coded compositions across four renderer
879    /// crates. The unique-signature dispatch (`(&Caixa, &str)` on this
880    /// method vs. `&Caixa` on the sibling three) reflects the extra input
881    /// axis this composer folds in: unlike the git-URL / git-tag / chart-
882    /// name axes (each derived purely from a `&Caixa`), the OCI-ref axis
883    /// pairs the caixa's per-`:nome` chart identity with the caller-
884    /// supplied per-registry authority segment, so the accessor threads
885    /// the registry byte-string through as a positional `&str`.
886    ///
887    /// The reader-side (one production site at the time of the lift —
888    /// [`caixa-tatara::process_for_aplicacao`]'s `derive_chart_ref` helper
889    /// at caixa-tatara/src/lib.rs:333 that composes the emitted
890    /// `AplicacaoIntent.chart_ref` scalar the tatara-reconciler feeds into
891    /// `helm install`, plus every future per-Servico OCI publish emitter
892    /// the CAIXA-SDLC §II `caixa-publish.yml` reusable workflow's
893    /// `skopeo push` step keys off, the future per-cluster snapshot bundle
894    /// emitter's per-CR `oci://…` field-fill on the M4 registry-alignment
895    /// slot, the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
896    /// materializer's per-member `chart_ref` slot on the tatara `Process`
897    /// intent, the `FluxCD` `HelmRelease` `spec.chart.spec.chart` field-fill
898    /// on the OCI-source path an M4 per-cluster registry-rewrite overlay
899    /// applies per-CR) — always resolves the OCI ref under the canonical
900    /// [`crate::OCI_SCHEME_PREFIX`] scheme prefix + the canonical
901    /// [`Self::lareira_chart_name`] chart-name segment; this method
902    /// encodes that reader-side convention.
903    ///
904    /// The composition body is the exact byte-image of the prior inline
905    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step form
906    /// every prior caller re-derived — pinned by the sibling caixa-tatara
907    /// byte-parity test
908    /// `derive_chart_ref_routes_through_caixa_oci_chart_ref_accessor`
909    /// against a future implementation of this method that reordered the
910    /// composition arguments, migrated the `<scheme>` segment to a
911    /// different constant (the [`crate::OCI_SCHEME_PREFIX`] axis a future
912    /// substrate-side registry-protocol rebrand may split off — the
913    /// constant's own docstring anticipates a substrate-side move once
914    /// Helm 3 / `FluxCD` introduce a successor scheme past `oci://`),
915    /// migrated the `<chart>` segment off the paired
916    /// [`crate::lareira_chart_name`] composer (a per-registry
917    /// namespace-qualification an M4 CR materializer might apply per-CR),
918    /// interposed a canonicalization pass on the `registry` axis (an OCI-
919    /// authority normalization once the M4 registry-alignment slot lands),
920    /// or silently absorbed an empty `:nome` arm (which cannot occur past
921    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
922    /// on the accessor path must not silently paper over).
923    ///
924    /// Owns per-call [`String`] allocation via the single
925    /// [`crate::oci_chart_ref`] `format!` invocation — the by-value return
926    /// matches every downstream consumer's field-fill shape (the caixa-
927    /// tatara `AplicacaoIntent.chart_ref: String` field-fill, every
928    /// future `intent.aplicacao.chart_ref: String` field-fill on the M4
929    /// CR materializer's chart-ref-carrier slot, every future
930    /// `HelmRelease.spec.chart.spec.chart: String` field-fill on the OCI-
931    /// source path).
932    #[must_use]
933    pub fn oci_chart_ref(&self, registry: &str) -> String {
934        crate::oci_chart_ref(registry, self.nome())
935    }
936
937    /// Substrate-canonical per-`Caixa` `:descricao` free-form-prose
938    /// chart-description scalar accessor every consumer of the top-level
939    /// manifest's Chart.yaml `description:` axis keys off — returns the
940    /// author-declared `:descricao` byte-string verbatim as an
941    /// `Option<&str>`, borrowed from the typed slot's own
942    /// `Option<String>` storage. `None` when the slot is absent (the
943    /// canonical "omit to defer to the per-renderer `caixa.nome`-derived
944    /// fallback" shape — [`caixa-helm`]'s `build_chart_yaml` folds the
945    /// omitted slot through a `format!("Generated chart for caixa Servico
946    /// {}", caixa.nome)` fallback, [`caixa-helm`]'s `build_readme` folds
947    /// it through a `format!("caixa Servico {}", caixa.nome)` fallback,
948    /// and [`caixa-feira`]'s `render_flake` folds it through a
949    /// `format!("caixa {}", c.nome)` `flake.nix` `description = ""`
950    /// fallback — each derived from `caixa.nome` on the null-carrier arm).
951    ///
952    /// The `:descricao` slot carries the universal-axis free-form-prose
953    /// chart-description identifier every kind of caixa emits under
954    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa` form
955    /// supplies) — the typed slot's `Option<String>` accept-set
956    /// (empty-string rejected through [`ManifestError::DescricaoEmpty`],
957    /// chart-description-shape-invalid rejected through
958    /// [`ManifestError::DescricaoInvalid`] past the shared
959    /// [`crate::render::is_chart_description_shape`] predicate the peer
960    /// per-`Caixa` `:descricao` axis also routes through) maps onto four
961    /// load-bearing downstream consumers:
962    ///
963    ///   - [`Self::validate_descricao`]'s empty-arm + shape-predicate
964    ///     gate binding — the universal-axis identity gate wired at
965    ///     caixa-build time.
966    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.description`
967    ///     `Chart.yaml` field fold — the rendered `lareira-<nome>` Helm
968    ///     chart's `Chart.yaml` `description:` field, which
969    ///     `apiVersion: v2` charts require non-empty (`helm lint` fires
970    ///     `WARNING [chart.metadata.description]: description is required`
971    ///     when absent) and which every registry that ingests the chart
972    ///     (ArtifactHub, chartmuseum, `helm search repo`) surfaces as the
973    ///     chart's canonical one-line prose descriptor.
974    ///   - [`caixa-helm`]'s `build_readme` chart-`README.md` header fold
975    ///     — the rendered `lareira-<nome>` chart's `README.md` prose
976    ///     header directly beneath the `# <chart-name>` title, which
977    ///     every author who inspects the rendered chart bundle lands at.
978    ///   - [`caixa-feira`]'s `render_flake` `flake.nix` `description = ""`
979    ///     top-level fold — the emitted `flake.nix`'s `description`
980    ///     field, which every Nix consumer (`nix flake show`,
981    ///     `nix flake metadata`, downstream flake-registry ingestors)
982    ///     surfaces as the flake's canonical descriptor.
983    ///
984    /// Prior to this lift the `.descricao` field was accessed inline at
985    /// four production sites — [`Self::validate_descricao`]'s
986    /// `self.descricao.as_deref()` empty-and-shape gate binding, the
987    /// caixa-helm `build_chart_yaml`
988    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
989    /// `Chart.yaml` `description:` fold, the caixa-helm `build_readme`
990    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
991    /// `README.md` header fold, and the caixa-feira `render_flake`
992    /// `c.descricao.clone().unwrap_or_else(|| format!(...))` `flake.nix`
993    /// `description = ""` fold — four open-coded field-accesses that
994    /// expressed no compile-time link back to the typed slot. A future
995    /// extension of the `:descricao` axis to a richer author surface —
996    /// a per-`:descricao` locale-tagged multi-language descriptor map
997    /// (the "one caixa, N language-tagged prose descriptions" arm
998    /// author-tooling internationalization anticipates), a
999    /// per-registry-target length-and-shape overlay the M4 CR
1000    /// materializer resolves per-CR (the "ArtifactHub caps description
1001    /// at 512 bytes but the internal registry caps at 256" arm), a
1002    /// promotion of the plain `Option<String>` byte-string to a richer
1003    /// `ChartDescription` newtype guaranteeing the
1004    /// `is_chart_description_shape` predicate at the type level — would
1005    /// have had to be threaded through all four open-coded copies in
1006    /// lockstep or the validate gate and the three emit paths would
1007    /// silently disagree on which prose string a given [`Caixa`]
1008    /// resolves to (an author's
1009    /// `:descricao "Checkout flow orchestration."` would satisfy
1010    /// validate while one of the emit paths silently rendered a stale
1011    /// `caixa.nome`-derived fallback, or vice versa). Lifting the
1012    /// resolution to a typed method on the substrate primitive means
1013    /// every downstream consumer of the caixa's per-`Caixa`
1014    /// chart-description surface reaches for exactly one typed dispatch
1015    /// — the resolver's accept-set migrates as a unit on any future
1016    /// axis addition.
1017    ///
1018    /// Third outer top-level [`Caixa`] `Option<&str>`-return scalar
1019    /// accessor — sibling of [`Self::licenca`] (6d5bc28) and
1020    /// [`Self::repositorio`] (cc7332d), the accessors that opened the
1021    /// "outer [`Caixa`] `Option<&str>` scalar" projection pattern this
1022    /// lift folds on. Same "one typed dispatch on the substrate
1023    /// primitive, thin projections at each consumer" discipline the
1024    /// peer per-`:placement`
1025    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1026    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1027    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1028    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1029    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1030    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1031    /// typed-slot atom axes, extended here to the third outer top-level
1032    /// `Caixa` universal-axis surface. Named `descricao()` to match the
1033    /// storage field's name; the accessor's identity maps onto the
1034    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1035    /// carries. The one remaining universal `Option<String>` slot
1036    /// (`:edicao`) folds on this pattern next.
1037    #[must_use]
1038    pub const fn descricao(&self) -> Option<&str> {
1039        match &self.descricao {
1040            Some(s) => Some(s.as_str()),
1041            None => None,
1042        }
1043    }
1044
1045    /// Substrate-canonical per-`Caixa` `:edicao` language-edition scalar
1046    /// accessor every consumer of the top-level manifest's tatara-lisp
1047    /// edition-selector axis keys off — returns the author-declared
1048    /// `:edicao` byte-string verbatim as an `Option<&str>`, borrowed from
1049    /// the typed slot's own `Option<String>` storage. `None` when the
1050    /// slot is absent (the canonical "omit the slot to defer to the
1051    /// substrate's default edition" shape every existing
1052    /// [`caixa-resolver`] integration test fixture carries via
1053    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`;
1054    /// the peer [`Self::validate_edicao`] gate is a no-op on the omitted
1055    /// arm by construction, so an author-omitted `:edicao` round-trips
1056    /// to a build without triggering the year-shape predicate).
1057    ///
1058    /// The `:edicao` slot carries the universal-axis 4-digit-ASCII-
1059    /// decimal-year language-edition identifier every kind of caixa
1060    /// emits under (CAIXA-SDLC §I — the author-facing surface every
1061    /// `defcaixa` form supplies) — the typed slot's `Option<String>`
1062    /// accept-set (empty-string rejected through
1063    /// [`ManifestError::EdicaoEmpty`], year-shape-invalid rejected
1064    /// through [`ManifestError::EdicaoInvalid`] past the 4-digit-ASCII-
1065    /// decimal-year predicate [`Self::validate_edicao`] enforces) maps
1066    /// onto one load-bearing downstream consumer today
1067    /// ([`Self::validate_edicao`]'s empty-arm + year-shape-predicate
1068    /// gate binding at caixa-core/src/manifest.rs:1959) plus every
1069    /// future edition-aware substrate consumer the CAIXA-SDLC §I
1070    /// roadmap anticipates (the tatara-lisp compiler's macro-surface
1071    /// selector every edition-aware build step keys off, the future
1072    /// per-edition compatibility-flag overlay the M4 CR materializer
1073    /// resolves per-CR, the peer [`Caixa::template`] canonical
1074    /// `:edicao "2026"` scaffold every `feira init` emits verbatim,
1075    /// and the renderer-side fixtures at `caixa-helm/src/lib.rs:978` /
1076    /// `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208` that
1077    /// carry `edicao: Some("2026".into())` by construction).
1078    ///
1079    /// Prior to this lift the `.edicao` field was accessed inline at
1080    /// one production site — [`Self::validate_edicao`]'s
1081    /// `self.edicao.as_deref()` empty-and-shape gate binding — one
1082    /// open-coded field-access that expressed no compile-time link
1083    /// back to the typed slot. A future extension of the `:edicao`
1084    /// axis to a richer author surface — a per-`:edicao` known-
1085    /// edition allowlist (the future tightening
1086    /// [`Self::validate_edicao`]'s docstring acknowledges past the
1087    /// structural year-shape floor, rejecting year-shaped values that
1088    /// don't name a tatara-lisp edition the substrate actually
1089    /// understands — `"1999"` is year-shaped but no `1999` edition
1090    /// exists), a per-edition compatibility-flag overlay the M4 CR
1091    /// materializer resolves per-CR (the "edition `"2026"` enables
1092    /// macro-surface features the sibling `"2018"` gates behind a
1093    /// feature flag" arm the edition-selector story anticipates), a
1094    /// promotion of the plain `Option<String>` byte-string to a
1095    /// richer `CaixaEdition` enum discriminated on year once a sibling
1096    /// edition to `"2026"` lands — would have had to be threaded
1097    /// through the open-coded copy in lockstep with every future
1098    /// edition-aware consumer, or the validate gate and the future
1099    /// edition-aware consumer path would silently disagree on which
1100    /// edition a given [`Caixa`] resolves to (an author's
1101    /// `:edicao "2026"` would satisfy validate while a future
1102    /// edition-aware consumer silently defaulted to a stale edition,
1103    /// or vice versa). Lifting the resolution to a typed method on
1104    /// the substrate primitive means every downstream consumer of the
1105    /// caixa's per-`Caixa` edition surface reaches for exactly one
1106    /// typed dispatch — the resolver's accept-set migrates as a unit
1107    /// on any future axis addition.
1108    ///
1109    /// Fourth and final outer top-level [`Caixa`] `Option<&str>`-return
1110    /// scalar accessor — sibling of [`Self::licenca`] (6d5bc28),
1111    /// [`Self::repositorio`] (cc7332d), and [`Self::descricao`]
1112    /// (3f16e2f), the accessors that opened the "outer [`Caixa`]
1113    /// `Option<&str>` scalar" projection pattern this lift folds on.
1114    /// Same "one typed dispatch on the substrate primitive, thin
1115    /// projections at each consumer" discipline the peer per-`:placement`
1116    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1117    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1118    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1119    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1120    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1121    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1122    /// typed-slot atom axes, extended here to close the outer top-level
1123    /// `Caixa` universal-axis surface's last unlifted `Option<String>`
1124    /// slot. Named `edicao()` to match the storage field's name; the
1125    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1126    /// vocabulary the slot's docstring already carries.
1127    #[must_use]
1128    pub const fn edicao(&self) -> Option<&str> {
1129        match &self.edicao {
1130            Some(s) => Some(s.as_str()),
1131            None => None,
1132        }
1133    }
1134
1135    /// Substrate-canonical per-`Caixa` `:nome` universal-axis DNS-1123-
1136    /// label caixa-identity scalar accessor every consumer of the top-
1137    /// level manifest's identity axis keys off — returns the author-
1138    /// declared `:nome` byte-string verbatim as an `&str`, borrowed from
1139    /// the typed slot's own `String` storage. Non-optional (`:nome` is
1140    /// a required-axis scalar every `defcaixa` form must supply; the
1141    /// [`Self::from_lisp`] derive rejects an omitted / non-string
1142    /// `:nome` at parse time, so a `Caixa` past parse definitionally
1143    /// carries a non-`None` `:nome`).
1144    ///
1145    /// The `:nome` slot carries the universal-axis DNS-1123-label
1146    /// caixa-identity every kind of caixa emits under (CAIXA-SDLC §I —
1147    /// the primary identity axis every `defcaixa` form supplies
1148    /// alongside `:versao` / `:kind`; the substrate-wide identity every
1149    /// other typed surface that names a caixa reaches through — `:deps`
1150    /// entries, `:membros` entries, `:children` entries, the
1151    /// `lareira-<nome>` Helm chart name every per-Servico renderer
1152    /// derives, the `pleme-program-<nome>` label every per-Aplicacao
1153    /// renderer emits) — the typed slot's `String` accept-set (empty
1154    /// rejected through [`ManifestError::NomeEmpty`], DNS-1123-shape-
1155    /// invalid rejected through [`ManifestError::NomeInvalid`] past
1156    /// the shared [`crate::render::require_valid_dns_1123_label`] gate
1157    /// the peer name axes each land on, joint-length-with-`lareira-`-
1158    /// prefix rejected through
1159    /// [`ManifestError::NomeChartNameBudgetExceeded`] past
1160    /// [`crate::render::is_lareira_chart_name_shape`]) maps onto every
1161    /// load-bearing downstream consumer the substrate carries — the
1162    /// two universal-axis validate gates at caixa-build time
1163    /// ([`Self::validate_nome`] + [`Self::validate_nome_chart_name_budget`]),
1164    /// [`crate::lareira_chart_name`]'s `lareira-<nome>` Helm chart-name
1165    /// derivation every per-Servico renderer keys off, the caixa-helm
1166    /// `Chart.yaml`'s `name:` axis, caixa-flux's `programs.yaml` entry
1167    /// `name:` axis, caixa-mesh's Cilium `CiliumNetworkPolicy` /
1168    /// `HTTPRoute` per-Aplicacao name axes at
1169    /// caixa-mesh/src/lib.rs:{2650, 2797, 2919, 2925},
1170    /// [`crate::pleme_program_selector`] /
1171    /// [`crate::pleme_program_in_aplicacao_selector`] label-selector
1172    /// derivations, and every future substrate renderer that emits an
1173    /// artifact keyed by the caixa's identity.
1174    ///
1175    /// Prior to this lift the `.nome` field was accessed inline at a
1176    /// dozen production sites across `caixa-core` (the two universal-
1177    /// axis validate gates + [`Dep::validate`]-adjacent duplicate
1178    /// tracking), `caixa-helm` (the `lareira_chart_name` fold, the
1179    /// `ChartYaml.name` / `ChartYaml.description` / `Chart.yaml`
1180    /// `keywords` fallback), `caixa-flux` (the `programs.yaml`
1181    /// entry `name:` fold, the `flux_kustomization_source_subtree`
1182    /// per-cluster subpath derivation), and `caixa-mesh` (the
1183    /// `pleme_program_in_aplicacao_selector` label-selector fold, the
1184    /// `cilium_network_policy_name` / `gateway_api_http_route_name`
1185    /// per-CR name derivations, the `LABEL_APLICACAO` labels-map
1186    /// insert) — a dozen open-coded field-accesses that expressed no
1187    /// compile-time link back to the typed slot. A future extension of
1188    /// the `:nome` axis to a richer author surface — a per-`:nome`
1189    /// structured `CaixaIdentity` newtype that carries the joint-
1190    /// length-with-prefix invariant [`Self::validate_nome_chart_name_budget`]
1191    /// enforces at the type level (rather than as a validate-time
1192    /// gate), a per-registry `:nome` namespacing overlay the M4 CR
1193    /// materializer resolves per-CR (the "`pleme-io/checkout` vs
1194    /// `partner-org/checkout` collision" arm the multi-tenant-registry
1195    /// story acknowledges), a promotion of the plain `String` byte-
1196    /// string to a richer `CaixaNome` newtype discriminated on
1197    /// namespace prefix — would have had to be threaded through every
1198    /// open-coded copy in lockstep or the two validate gates and the
1199    /// dozen emit paths would silently disagree on which identity a
1200    /// given [`Caixa`] resolves to (an author's `:nome "checkout"`
1201    /// would satisfy validate while one of the emit paths silently
1202    /// rendered a drifted other identity, or vice versa). Lifting the
1203    /// resolution to a typed method on the substrate primitive means
1204    /// every downstream consumer of the caixa's per-`Caixa` identity
1205    /// surface reaches for exactly one typed dispatch — the resolver's
1206    /// accept-set migrates as a unit on any future axis addition.
1207    ///
1208    /// First outer top-level [`Caixa`] `&str`-return required-scalar
1209    /// accessor — opens the "outer [`Caixa`] `&str` required-scalar"
1210    /// projection pattern the sibling per-`Caixa` `:versao` future lift
1211    /// folds on. Sibling in shape to the peer per-`:membros`
1212    /// [`crate::aplicacao::Membro::nome`] (4a32abf) / per-`:contratos`
1213    /// [`crate::aplicacao::WitContract::source`] /
1214    /// [`crate::aplicacao::WitContract::destination`] (7f0fd43),
1215    /// [`crate::aplicacao::WitContract::world_ref`] (0804823),
1216    /// [`crate::aplicacao::Membro::versao_requirement`] (a40b0e3),
1217    /// [`crate::aplicacao::Entrada::destination`] (6db982c),
1218    /// [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062),
1219    /// per-sub-struct required-axis accessors carry on the sibling M3
1220    /// mesh-slot-atom scalar-value axes, extended here to open the
1221    /// outer top-level [`Caixa`] `&str`-return required-scalar surface.
1222    /// Named `nome()` to match the storage field's name; the accessor's
1223    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1224    /// slot's docstring already carries.
1225    #[must_use]
1226    pub const fn nome(&self) -> &str {
1227        self.nome.as_str()
1228    }
1229
1230    /// Substrate-canonical per-`Caixa` `:versao` universal-axis SemVer-2
1231    /// pinned-version scalar accessor every consumer of the top-level
1232    /// manifest's version axis keys off — returns the author-declared
1233    /// `:versao` byte-string verbatim as an `&str`, borrowed from the
1234    /// typed slot's own `String` storage. Non-optional (`:versao` is a
1235    /// required-axis scalar every `defcaixa` form must supply alongside
1236    /// `:nome` / `:kind`; the [`Self::from_lisp`] derive rejects an
1237    /// omitted / non-string `:versao` at parse time, so a `Caixa` past
1238    /// parse definitionally carries a non-`None` `:versao`).
1239    ///
1240    /// The `:versao` slot carries the universal-axis SemVer-2
1241    /// concrete-version body every kind of caixa emits under
1242    /// (CAIXA-SDLC §I — the required-scalar every `defcaixa` form
1243    /// supplies alongside `:nome` / `:kind`; the substrate-wide
1244    /// pinned-version every downstream artifact-emitting consumer
1245    /// composes under — the `lareira-<nome>` Helm chart's `Chart.yaml`
1246    /// `version:` + `appVersion:` axes, the `feira publish` Zig-style
1247    /// `v<versao>` git tag the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
1248    /// prefix composes on top of, the programs.yaml entry's `versao:`
1249    /// value the `lareira-fleet-programs` aggregator carries onto each
1250    /// rendered `ComputeUnit`, the OCI image's `:v<versao>` / `:latest`
1251    /// tags every substrate-side `skopeo push` writes, the lacre
1252    /// closure's pinned `concrete_versao`, and the `:upgrade-from :from`
1253    /// prior-version references peers in the exact same SemVer-2 shape).
1254    /// The typed slot's `String` accept-set (empty rejected through
1255    /// [`ManifestError::VersaoEmpty`], SemVer-2-shape-invalid rejected
1256    /// through [`ManifestError::VersaoInvalid`] past
1257    /// [`semver::Version::parse`]) maps onto every load-bearing
1258    /// downstream consumer the substrate carries — the [`Self::validate_versao`]
1259    /// universal-axis validate gate at caixa-build time, the
1260    /// [`crate::CaixaVersion::parse`] typed-wrapper resolver,
1261    /// [`caixa-helm`]'s `Chart.yaml` `version:` / `appVersion:` fold,
1262    /// [`caixa-flux`]'s `programs.yaml` entry `versao:` fold + the
1263    /// `cluster_bundle` `GitRepository` `ref: { tag: v<versao> }`
1264    /// derivation, [`caixa-mesh`]'s per-Aplicacao `programs.yaml` fan-
1265    /// out entry `versao:` fold, [`caixa-feira`]'s `feira publish` git-
1266    /// tag derivation (`format!("{prefix}{versao}")`), and every future
1267    /// substrate renderer that emits an artifact keyed by the caixa's
1268    /// pinned version.
1269    ///
1270    /// Prior to this lift the `.versao` field was accessed inline at a
1271    /// dozen production sites across `caixa-core` (the universal-axis
1272    /// [`Self::validate_versao`] gate + [`Dep::validate`]-adjacent
1273    /// version-shape gates), `caixa-helm` (the `ChartYaml.version` /
1274    /// `ChartYaml.app_version` folds), `caixa-flux` (the `programs.yaml`
1275    /// entry `versao:` fold, the `cluster_bundle` `GitRepository` `ref:
1276    /// { tag: v<versao> }` derivation), `caixa-mesh` (the per-Aplicacao
1277    /// `programs.yaml` fan-out entry `versao:` fold), and `caixa-feira`
1278    /// (the `feira publish` git-tag derivation + the `feira app graph` /
1279    /// `feira app deploy` diagnostic renderers) — a dozen open-coded
1280    /// field-accesses that expressed no compile-time link back to the
1281    /// typed slot. A future extension of the `:versao` axis to a richer
1282    /// author surface — a per-`:versao` structured `CaixaVersion` at the
1283    /// storage layer (the substrate already carries a `CaixaVersion`
1284    /// newtype at [`crate::version::CaixaVersion`], deferred until the
1285    /// serde-transparent-newtype-through-DeriveTataraDomain path lands),
1286    /// a per-registry `:versao` immutability overlay the M4 CR
1287    /// materializer enforces per-CR, a promotion of the plain `String`
1288    /// byte-string to a richer `PinnedVersao` newtype discriminated on
1289    /// SemVer-2 pre-release / build-metadata presence — would have had
1290    /// to be threaded through every open-coded copy in lockstep or the
1291    /// validate gate and the dozen emit paths would silently disagree
1292    /// on which version a given [`Caixa`] resolves to (an author's
1293    /// `:versao "0.1.0"` would satisfy validate while one of the emit
1294    /// paths silently rendered a drifted other version, or vice versa).
1295    /// Lifting the resolution to a typed method on the substrate
1296    /// primitive means every downstream consumer of the caixa's
1297    /// per-`Caixa` pinned-version surface reaches for exactly one typed
1298    /// dispatch — the resolver's accept-set migrates as a unit on any
1299    /// future axis addition.
1300    ///
1301    /// Second outer top-level [`Caixa`] `&str`-return required-scalar
1302    /// accessor — folds on the "outer [`Caixa`] `&str` required-scalar"
1303    /// projection pattern the sibling per-`Caixa` [`Self::nome`]
1304    /// (e6b7d97) opened. Sibling in shape to the peer per-`:membros`
1305    /// [`crate::aplicacao::Membro::versao_requirement`] (4127bb6) /
1306    /// per-`:children` [`crate::supervisor::ChildSpec::versao_requirement`]
1307    /// (2c053c8) / per-`:upgrade-from` [`crate::UpgradeFromEntry::prior_versao`]
1308    /// (75d27a8) per-sub-struct `:versao`-shaped `&str`-return accessors
1309    /// on the sibling per-typed-slot version-carrier axes, extended here
1310    /// to close the second outer top-level [`Caixa`] required-`&str`-
1311    /// carrying axis so the two universal-axis identity-carrying
1312    /// scalars every `defcaixa` form supplies (`:nome` + `:versao`)
1313    /// share the same "one typed dispatch per axis" discipline. Named
1314    /// `versao()` to match the storage field's name; the accessor's
1315    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1316    /// slot's docstring already carries.
1317    #[must_use]
1318    pub const fn versao(&self) -> &str {
1319        self.versao.as_str()
1320    }
1321
1322    /// Substrate-canonical per-`Caixa` `:kind` universal-axis
1323    /// closed-set-enum discriminant accessor every consumer of the top-
1324    /// level manifest's kind axis keys off — returns the author-declared
1325    /// `:kind` variant verbatim as a [`CaixaKind`], `Copy`-projected
1326    /// from the typed slot's own [`CaixaKind`] storage. Non-optional
1327    /// (`:kind` is a required-axis discriminant every `defcaixa` form
1328    /// must supply alongside `:nome` / `:versao`; the [`Self::from_lisp`]
1329    /// derive rejects an omitted / non-symbol `:kind` at parse time, so
1330    /// a `Caixa` past parse definitionally carries a valid [`CaixaKind`]
1331    /// variant).
1332    ///
1333    /// The `:kind` slot carries the universal-axis closed-set typed-
1334    /// discriminant every substrate-side dispatch keys off (CAIXA-SDLC
1335    /// §I — the primary shape gate every renderer / verifier /
1336    /// operator branches on; the five variants `Biblioteca` /
1337    /// `Binario` / `Servico` / `Supervisor` / `Aplicacao` partition
1338    /// the caixa surface into disjoint runtime contracts) — the typed
1339    /// slot's [`CaixaKind`] accept-set (parse-time-rejected non-symbol
1340    /// values through the derive-macro's symbol-arm gate, exhaustively
1341    /// matched at every downstream dispatch site) maps onto every
1342    /// load-bearing downstream consumer the substrate carries:
1343    ///
1344    ///   - [`crate::render::require_kind`]'s per-renderer entry-gate
1345    ///     predicate — the canonical two-line
1346    ///     `require_kind(caixa, Servico)?` prelude every per-Servico
1347    ///     renderer (`caixa-helm`, `caixa-flux`, the future `caixa-otel`
1348    ///     / per-Servico OCI packager / M4 `wasm.pleme.io/v1alpha1/
1349    ///     ComputeUnit` CR materializer) runs at its entry-point,
1350    ///     alongside the [`crate::render::KindMismatch`] error carrier's
1351    ///     `actual:` field the diagnostic surfaces to name the offending
1352    ///     caixa's variant.
1353    ///   - [`Self::aplicacao_view`]'s + [`Self::supervisor_view`]'s
1354    ///     per-view kind-gate binding — the two `Option<TypedSpec>`
1355    ///     `_view` composers that fold the flat mesh-slot / supervisor-
1356    ///     slot columns into their typed sub-spec only when the kind
1357    ///     matches (returns `None` otherwise); the future per-Servico
1358    ///     M2-view composer (`servico_view`) will follow the same shape.
1359    ///   - [`Self::declared_foreign_code_slots`]'s per-slot kind-
1360    ///     coherence gate — the `!self.kind.requires_exe()` /
1361    ///     `!self.kind.requires_servicos()` predicates that fence
1362    ///     each code-surface slot from the wrong owning kind.
1363    ///   - [`crate::LayoutInvariants::verify`]'s kind ↔ code-surface
1364    ///     coherence gates — the six `caixa.kind == CaixaKind::X` /
1365    ///     `caixa.kind != CaixaKind::X` predicates and the four kind-
1366    ///     coherence error carriers (`SupervisorOwnsCode` /
1367    ///     `AplicacaoOwnsCode` / `MeshSlotsOnNonAplicacao` /
1368    ///     `SupervisorSlotsOnNonSupervisor` / `ServicoSlotsOnNonServico`
1369    ///     / `ForeignCodeSlot`) which each name the offending caixa's
1370    ///     variant in their `kind:` field.
1371    ///
1372    /// Prior to this lift the `.kind` field was accessed inline at
1373    /// twenty-plus production sites across `caixa-core` (the
1374    /// [`crate::render::require_kind`] entry-gate predicate + the
1375    /// [`crate::render::KindMismatch`] `actual:` field, the two `_view`
1376    /// composers, the `declared_foreign_code_slots` per-slot kind-
1377    /// coherence gate, and the six [`crate::LayoutInvariants::verify`]
1378    /// kind ↔ code-surface predicates + four error carriers) — a score
1379    /// of open-coded field-accesses that expressed no compile-time link
1380    /// back to the typed slot. A future extension of the `:kind` axis
1381    /// to a richer author surface — a per-`:kind` sub-variant discriminant
1382    /// (e.g. `Servico(ServicoRuntime)` splitting the current single
1383    /// variant across the wasm-component / legacy-container / native-
1384    /// binary runtime axes the M5 roadmap acknowledges), a per-cluster
1385    /// kind-overlay the M4 CR materializer resolves per-CR (the
1386    /// "cluster policy demotes `Aplicacao` to `Servico` on a single-
1387    /// tenant cluster" arm), a promotion of the plain [`CaixaKind`]
1388    /// enum to a richer `KindWithRuntime` discriminated on the
1389    /// component-model world axis — would have had to be threaded
1390    /// through every open-coded copy in lockstep or the entry gate,
1391    /// the view composers, and the layout invariants would silently
1392    /// disagree on which kind a given [`Caixa`] resolves to. Lifting
1393    /// the resolution to a typed method on the substrate primitive
1394    /// means every downstream consumer of the caixa's per-`Caixa`
1395    /// kind surface reaches for exactly one typed dispatch — the
1396    /// resolver's accept-set migrates as a unit on any future axis
1397    /// addition.
1398    ///
1399    /// First outer top-level [`Caixa`] `Copy`-return required-enum-
1400    /// discriminant accessor — opens the "outer [`Caixa`] `Copy`-return
1401    /// required-discriminant" projection pattern. Sibling in shape to
1402    /// the peer per-`:supervisor` [`crate::supervisor::SupervisorSpec::estrategia`]
1403    /// (eafb619), per-`:placement` [`crate::aplicacao::Placement::estrategia`]
1404    /// (921fe1b), and per-`:children` [`crate::supervisor::ChildSpec::restart`]
1405    /// (dfb4a81) `Copy`-return closed-set-enum discriminant accessors
1406    /// on the sibling nested-spec typed-slot discriminator axes,
1407    /// extended here to the outer top-level [`Caixa`] universal-axis
1408    /// surface. Named `kind()` to match the storage field's name;
1409    /// the accessor's identity maps onto the canonical CAIXA-SDLC §I
1410    /// vocabulary the slot's docstring already carries.
1411    #[must_use]
1412    pub const fn kind(&self) -> CaixaKind {
1413        self.kind
1414    }
1415
1416    /// Substrate-canonical per-`Caixa` `:autores` universal-axis
1417    /// maintainer-name-list slice-accessor every consumer of the top-
1418    /// level manifest's maintainer axis keys off — returns the author-
1419    /// declared `:autores` list verbatim as a `&[String]` slice-view over
1420    /// the same backing buffer the raw `self.autores.as_slice()` field
1421    /// access borrows from. Empty-list-carrying (`:autores` is a default-
1422    /// empty axis every `defcaixa` form supplies with an empty `()` when
1423    /// unset; the [`Self::from_lisp`] derive folds an omitted `:autores`
1424    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1425    /// parse definitionally carries a `Vec<String>` slot — possibly
1426    /// empty — and the returned `&[String]` degenerates to an empty
1427    /// slice on that arm without any silent `None` collapse).
1428    ///
1429    /// The `:autores` slot carries the universal-axis maintainer-name
1430    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
1431    /// facing surface every `defcaixa` form supplies alongside `:nome` /
1432    /// `:versao` / `:kind`; the substrate-wide contact-carrying axis
1433    /// every downstream registry-facing artifact emits under) — the
1434    /// typed slot's `Vec<String>` accept-set (empty-per-entry rejected
1435    /// through [`ManifestError::AutorEmpty`], non-chart-maintainer-shape
1436    /// rejected through [`ManifestError::AutorInvalid`], cross-entry
1437    /// duplicate rejected through [`ManifestError::AutorDuplicate`]) maps
1438    /// onto every load-bearing downstream consumer the substrate carries
1439    /// — the [`Self::validate_autores`] universal-axis empty-per-entry +
1440    /// shape + duplicate gate at caixa-core/src/manifest.rs, the
1441    /// caixa-helm `build_chart_yaml` `maintainers:` fold at
1442    /// caixa-helm/src/lib.rs that walks each entry into a `Maintainer {
1443    /// name, email: None }` record, every future per-`Caixa` registry-
1444    /// facing renderer the CAIXA-SDLC §I roadmap acknowledges (the
1445    /// future `artifacthub.io/maintainers` `Chart.yaml` annotation the
1446    /// caixa-helm docstring alludes to at [`Self::validate_licenca`],
1447    /// the future per-cluster author-notification overlay the M4 CR
1448    /// materializer resolves per-CR).
1449    ///
1450    /// Prior to this lift the `.autores` field was accessed inline at
1451    /// two production sites — [`Self::validate_autores`]'s `for autor
1452    /// in &self.autores` walk that gates every entry through
1453    /// [`ManifestError::AutorEmpty`] / `AutorInvalid` / `AutorDuplicate`,
1454    /// and the caixa-helm `build_chart_yaml` `caixa.autores.iter().map(|a|
1455    /// Maintainer { name: a.clone(), email: None }).collect()` fold that
1456    /// materializes every entry into a `Chart.yaml` `maintainers:` row —
1457    /// two open-coded field-accesses that expressed no compile-time link
1458    /// back to the typed slot. A future extension of the `:autores` axis
1459    /// to a richer author surface — a per-`:autores` structured
1460    /// `Maintainer { name, email, url }` at the storage layer once the
1461    /// substrate absorbs `artifacthub.io/maintainers`' name+email+url
1462    /// tuple, a per-registry `:autores` allowlist the M4 CR materializer
1463    /// enforces per-CR (the "cluster policy demands every author declare
1464    /// an on-file `mailto:` contact" arm), a promotion of the plain
1465    /// `Vec<String>` byte-string list to a richer
1466    /// `Vec<ChartMaintainer>` newtype discriminated on the RFC-5322
1467    /// `<name> [<email>]` grammar the `is_chart_maintainer_name_shape`
1468    /// predicate already resolves through — would have had to be
1469    /// threaded through both open-coded copies in lockstep or the
1470    /// validate gate and the caixa-helm emit path would silently
1471    /// disagree on which authors a given [`Caixa`] resolves to (an
1472    /// author's `:autores ("alice" "bob")` would satisfy validate while
1473    /// the caixa-helm emit path silently rendered a drifted other
1474    /// maintainer list, or vice versa). Lifting the resolution to a
1475    /// typed method on the substrate primitive means every downstream
1476    /// consumer of the caixa's per-`Caixa` maintainer surface reaches
1477    /// for exactly one typed dispatch — the resolver's accept-set
1478    /// migrates as a unit on any future axis addition.
1479    ///
1480    /// First outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1481    /// opens the "outer [`Caixa`] `&[T]` slice" projection pattern the
1482    /// sibling per-`Caixa` `:etiquetas` / `:deps` / `:deps-dev` / `:exe`
1483    /// / `:bibliotecas` / `:servicos` / `:upgrade-from` / `:children`
1484    /// future lifts fold on. Sibling in shape to the peer per-`:supervisor`
1485    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce), per-`:placement`
1486    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7), per-`:membros`
1487    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36), per-`:contratos`
1488    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1489    /// per-`:upgrade-from :instructions` [`crate::upgrade::UpgradeFromEntry::instructions`]
1490    /// (0137e5a) `&[T]`-return slice accessors on the sibling per-M2 /
1491    /// per-M3 typed-slot list axes, extended here to the outer top-level
1492    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1493    /// `&Vec<String>`) because every downstream consumer of the author
1494    /// list treats it as a read-only sequence — the slice-view is the
1495    /// narrowest borrow that supports every present + roadmapped consumer
1496    /// (`.iter()`, `.len()`, `.is_empty()`) without leaking the backing
1497    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
1498    /// reaches for (the storage-side `Vec` remains reachable through the
1499    /// `pub autores` field for the mutation-carrying serde round-trip and
1500    /// per-test fixture-mutation paths). Named `autores()` to match the
1501    /// storage field's name; the accessor's identity maps onto the
1502    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1503    /// carries.
1504    #[must_use]
1505    pub const fn autores(&self) -> &[String] {
1506        self.autores.as_slice()
1507    }
1508
1509    /// Substrate-canonical per-`Caixa` `:etiquetas` universal-axis
1510    /// registry-search-tag-list slice-accessor every consumer of the
1511    /// top-level manifest's topical-tag axis keys off — returns the
1512    /// author-declared `:etiquetas` list verbatim as a `&[String]`
1513    /// slice-view over the same backing buffer the raw
1514    /// `self.etiquetas.as_slice()` field access borrows from. Empty-
1515    /// list-carrying (`:etiquetas` is a default-empty axis every
1516    /// `defcaixa` form supplies with an empty `()` when unset; the
1517    /// [`Self::from_lisp`] derive folds an omitted `:etiquetas` through
1518    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1519    /// definitionally carries a `Vec<String>` slot — possibly empty —
1520    /// and the returned `&[String]` degenerates to an empty slice on
1521    /// that arm without any silent `None` collapse).
1522    ///
1523    /// The `:etiquetas` slot carries the universal-axis topical-tag
1524    /// list every kind of caixa emits under (CAIXA-SDLC §I — the
1525    /// author-facing surface every `defcaixa` form supplies alongside
1526    /// `:nome` / `:versao` / `:kind`; the substrate-wide registry-
1527    /// search-facing axis every downstream registry-facing artifact
1528    /// emits under) — the typed slot's `Vec<String>` accept-set
1529    /// (empty-per-entry rejected through [`ManifestError::EtiquetaEmpty`],
1530    /// non-chart-keyword-shape rejected through
1531    /// [`ManifestError::EtiquetaInvalid`], cross-entry duplicate
1532    /// rejected through [`ManifestError::EtiquetaDuplicate`]) maps onto
1533    /// every load-bearing downstream consumer the substrate carries —
1534    /// the [`Self::validate_etiquetas`] universal-axis empty-per-entry
1535    /// + shape + duplicate gate at caixa-core/src/manifest.rs, the
1536    /// caixa-helm `build_chart_yaml` `keywords:` fold at
1537    /// caixa-helm/src/lib.rs that walks each entry into the rendered
1538    /// `Chart.yaml` `keywords:` array (chained with the
1539    /// [`crate::LAREIRA_CHART_KEYWORDS`] substrate-wide floor set and
1540    /// dedup'd through a `BTreeSet` at emit time), every future per-
1541    /// `Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
1542    /// acknowledges (the future `artifacthub.io/keywords` `Chart.yaml`
1543    /// annotation, the future per-cluster tag-notification overlay the
1544    /// M4 CR materializer resolves per-CR).
1545    ///
1546    /// Prior to this lift the `.etiquetas` field was accessed inline at
1547    /// two production sites — [`Self::validate_etiquetas`]'s `for
1548    /// etiqueta in &self.etiquetas` walk that gates every entry through
1549    /// [`ManifestError::EtiquetaEmpty`] / `EtiquetaInvalid` /
1550    /// `EtiquetaDuplicate`, and the caixa-helm `build_chart_yaml`
1551    /// `caixa.etiquetas.iter().cloned().chain(...)` fold that
1552    /// materializes every entry into a `Chart.yaml` `keywords:` row —
1553    /// two open-coded field-accesses that expressed no compile-time
1554    /// link back to the typed slot. A future extension of the
1555    /// `:etiquetas` axis to a richer tag surface — a per-`:etiquetas`
1556    /// structured `ChartKeyword { name, uri, category }` at the storage
1557    /// layer once the substrate absorbs `artifacthub.io/keywords`
1558    /// richer tag tuple, a per-registry `:etiquetas` allowlist the M4
1559    /// CR materializer enforces per-CR (the "cluster policy demands
1560    /// every tag come from a substrate-approved taxonomy" arm), a
1561    /// promotion of the plain `Vec<String>` byte-string list to a
1562    /// richer `Vec<ChartKeyword>` newtype discriminated on the DNS-
1563    /// 1123-label-shaped grammar the `is_chart_keyword_shape` predicate
1564    /// already resolves through — would have had to be threaded through
1565    /// both open-coded copies in lockstep or the validate gate and the
1566    /// caixa-helm emit path would silently disagree on which tags a
1567    /// given [`Caixa`] resolves to (an author's `:etiquetas ("demo"
1568    /// "aplicacao")` would satisfy validate while the caixa-helm emit
1569    /// path silently rendered a drifted other keyword list, or vice
1570    /// versa). Lifting the resolution to a typed method on the
1571    /// substrate primitive means every downstream consumer of the
1572    /// caixa's per-`Caixa` topical-tag surface reaches for exactly one
1573    /// typed dispatch — the resolver's accept-set migrates as a unit
1574    /// on any future axis addition.
1575    ///
1576    /// Second outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1577    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1578    /// [`Self::autores`] (b5d813f) opened, sibling in shape and
1579    /// idiom. The remaining unlifted outer-`Caixa` slice-carrying axes
1580    /// (`:deps` / `:deps-dev` / `:exe` / `:bibliotecas` / `:servicos`
1581    /// / `:upgrade-from` / `:children` / `:membros` / `:contratos`)
1582    /// fold onto the same pattern in future lifts. Sibling in shape to
1583    /// the peer per-`:supervisor`
1584    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1585    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1586    /// (a6e18d7), per-`:membros`
1587    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1588    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1589    /// (0dcc926), and per-`:upgrade-from :instructions`
1590    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1591    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1592    /// typed-slot list axes, extended here to the outer top-level
1593    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1594    /// `&Vec<String>`) because every downstream consumer of the tag
1595    /// list treats it as a read-only sequence — the slice-view is the
1596    /// narrowest borrow that supports every present + roadmapped
1597    /// consumer (`.iter()`, `.len()`, `.is_empty()`) without leaking
1598    /// the backing `Vec`'s grow/push/reserve surface no consumer of
1599    /// the typed view reaches for (the storage-side `Vec` remains
1600    /// reachable through the `pub etiquetas` field for the mutation-
1601    /// carrying serde round-trip and per-test fixture-mutation paths).
1602    /// Named `etiquetas()` to match the storage field's name; the
1603    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1604    /// vocabulary the slot's docstring already carries.
1605    #[must_use]
1606    pub const fn etiquetas(&self) -> &[String] {
1607        self.etiquetas.as_slice()
1608    }
1609
1610    /// Substrate-canonical per-`Caixa` `:bibliotecas` universal-axis
1611    /// library-source-path-list slice-accessor every consumer of the
1612    /// top-level manifest's Biblioteca-source axis keys off — returns
1613    /// the author-declared `:bibliotecas` list verbatim as a
1614    /// `&[String]` slice-view over the same backing buffer the raw
1615    /// `self.bibliotecas.as_slice()` field access borrows from. Empty-
1616    /// list-carrying (`:bibliotecas` is a default-empty axis every
1617    /// `defcaixa` form supplies with an empty `()` when unset; the
1618    /// [`Self::from_lisp`] derive folds an omitted `:bibliotecas`
1619    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1620    /// parse definitionally carries a `Vec<String>` slot — possibly
1621    /// empty — and the returned `&[String]` degenerates to an empty
1622    /// slice on that arm without any silent `None` collapse).
1623    ///
1624    /// The `:bibliotecas` slot carries the universal-axis lisp-library
1625    /// entry-path list every `:kind Biblioteca` caixa emits under
1626    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1627    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1628    /// substrate-wide library-carrier axis every downstream
1629    /// authoring-facing consumer keys off) — the typed slot's
1630    /// `Vec<String>` accept-set (empty-per-entry rejected through
1631    /// [`ManifestError::CodePathEmpty { slot: ":bibliotecas" }`],
1632    /// non-sandboxed-relative-shape rejected through
1633    /// [`ManifestError::CodePathShape`], non-`.lisp`-extension rejected
1634    /// through [`ManifestError::CodePathNonLispExtension`], cross-entry
1635    /// duplicate rejected through [`ManifestError::CodePathDuplicate`])
1636    /// maps onto every load-bearing downstream consumer the substrate
1637    /// carries — the [`crate::LayoutInvariants`] Biblioteca-arm
1638    /// empty-check + per-entry file-exists loop at
1639    /// caixa-core/src/layout.rs that gates each entry through
1640    /// [`crate::LayoutError::MissingLib`] / `MissingEntry`, the
1641    /// [`Self::validate_code_paths`] per-slot shape gate at
1642    /// caixa-core/src/manifest.rs that walks each entry through the
1643    /// sandbox-relative / `.lisp`-extension / cross-entry duplicate
1644    /// gates, the `feira build` per-entry `tatara_lisp::read` parse
1645    /// walk at caixa-feira/src/cmd/build.rs that phase-1-checks each
1646    /// declared library file for lexical / structural errors before
1647    /// downstream `importar` resolution, every future per-`Caixa`
1648    /// library-facing renderer the CAIXA-SDLC §I roadmap acknowledges
1649    /// (the future `tatara-lispc` compilation entry the docstring at
1650    /// caixa-feira/src/cmd/build.rs alludes to, the future per-cluster
1651    /// bytecode-caching overlay the M4 CR materializer resolves per-CR,
1652    /// the future `caixa-lsp` per-library semantic-token stream the
1653    /// caixa-lsp docstring roadmaps).
1654    ///
1655    /// Prior to this lift the `.bibliotecas` field was accessed inline
1656    /// at three production sites — [`crate::LayoutInvariants`]'s
1657    /// `caixa.bibliotecas.is_empty()` `MissingLib`-arm gate + `for p
1658    /// in &caixa.bibliotecas` `MissingEntry` walk that gates each
1659    /// declared library path through the on-disk-existence check,
1660    /// the compound-code-path `has_code = !caixa.bibliotecas.is_empty()
1661    /// || !caixa.exe.is_empty() || !caixa.servicos.is_empty()` OR-fold
1662    /// on the [`crate::LayoutError::SupervisorOwnsCode`] /
1663    /// `AplicacaoOwnsCode` kind-coherence gate, and the `feira build`
1664    /// per-entry `for entry in &caixa.bibliotecas` + `caixa.bibliotecas.
1665    /// len()` phase-1 tatara-lispc-precursor parse walk — three open-
1666    /// coded field-accesses that expressed no compile-time link back
1667    /// to the typed slot. A future extension of the `:bibliotecas`
1668    /// axis to a richer library surface — a per-`:bibliotecas`
1669    /// structured `BibliotecaEntry { path, edition, exports }` at the
1670    /// storage layer once the substrate absorbs the per-library
1671    /// language-edition + explicit-exports tuple the tatara-lisp
1672    /// module-system roadmap acknowledges, a per-registry
1673    /// `:bibliotecas` allowlist the M4 CR materializer enforces
1674    /// per-CR (the "cluster policy demands every biblioteca declare
1675    /// its own :edicao" arm), a promotion of the plain `Vec<String>`
1676    /// byte-string list to a richer `Vec<LibraryPath>` newtype
1677    /// discriminated on the `lib/<nome>.lisp`-shape grammar the
1678    /// [`crate::render::is_sandboxed_relative_path`] +
1679    /// [`crate::render::is_lisp_extension`] predicates already resolve
1680    /// through — would have had to be threaded through all three
1681    /// open-coded copies in lockstep or the layout gate, the shape
1682    /// validator, and the `feira build` phase-1 parse walk would
1683    /// silently disagree on which library paths a given [`Caixa`]
1684    /// resolves to (an author's `:bibliotecas ("lib/foo.lisp"
1685    /// "lib/bar.lisp")` would satisfy layout while `feira build`
1686    /// silently parsed a drifted other list, or vice versa). Lifting
1687    /// the resolution to a typed method on the substrate primitive
1688    /// means every downstream consumer of the caixa's per-`Caixa`
1689    /// library-source surface reaches for exactly one typed dispatch
1690    /// — the resolver's accept-set migrates as a unit on any future
1691    /// axis addition.
1692    ///
1693    /// Third outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1694    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1695    /// [`Self::autores`] (b5d813f) opened and [`Self::etiquetas`]
1696    /// (78c7d3c) folded on, sibling in shape and idiom. The remaining
1697    /// unlifted outer-`Caixa` slice-carrying axes (`:deps` /
1698    /// `:deps-dev` / `:exe` / `:servicos` / `:upgrade-from` /
1699    /// `:children` / `:membros` / `:contratos`) fold onto the same
1700    /// pattern in future lifts. Sibling in shape to the peer
1701    /// per-`:supervisor`
1702    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1703    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1704    /// (a6e18d7), per-`:membros`
1705    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1706    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1707    /// (0dcc926), and per-`:upgrade-from :instructions`
1708    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1709    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1710    /// typed-slot list axes, extended here to the outer top-level
1711    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1712    /// `&Vec<String>`) because every downstream consumer of the
1713    /// library-source list treats it as a read-only sequence — the
1714    /// slice-view is the narrowest borrow that supports every
1715    /// present + roadmapped consumer (`.iter()`, `.len()`,
1716    /// `.is_empty()`) without leaking the backing `Vec`'s
1717    /// grow/push/reserve surface no consumer of the typed view
1718    /// reaches for (the storage-side `Vec` remains reachable through
1719    /// the `pub bibliotecas` field for the mutation-carrying serde
1720    /// round-trip and per-test fixture-mutation paths). Named
1721    /// `bibliotecas()` to match the storage field's name; the
1722    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1723    /// vocabulary the slot's docstring already carries.
1724    #[must_use]
1725    pub const fn bibliotecas(&self) -> &[String] {
1726        self.bibliotecas.as_slice()
1727    }
1728
1729    /// Substrate-canonical per-`Caixa` `:exe` universal-axis
1730    /// nix-built-executable-entry-path-list slice-accessor every consumer
1731    /// of the top-level manifest's Binario-executable axis keys off —
1732    /// returns the author-declared `:exe` list verbatim as a `&[String]`
1733    /// slice-view over the same backing buffer the raw
1734    /// `self.exe.as_slice()` field access borrows from. Empty-list-
1735    /// carrying (`:exe` is a default-empty axis every `defcaixa` form
1736    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
1737    /// derive folds an omitted `:exe` through `#[serde(default)]` to
1738    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
1739    /// `Vec<String>` slot — possibly empty — and the returned `&[String]`
1740    /// degenerates to an empty slice on that arm without any silent
1741    /// `None` collapse).
1742    ///
1743    /// The `:exe` slot carries the universal-axis nix-built executable
1744    /// entry-path list every `:kind Binario` caixa emits under
1745    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1746    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1747    /// substrate-wide `exe/`-directory-fenced entry-carrier axis every
1748    /// downstream flake-build-facing consumer keys off) — the typed
1749    /// slot's `Vec<String>` accept-set (empty-per-entry rejected
1750    /// through [`ManifestError::CodePathEmpty { slot: ":exe" }`],
1751    /// non-sandboxed-relative-shape rejected through
1752    /// [`ManifestError::CodePathShape`], cross-entry duplicate rejected
1753    /// through [`ManifestError::CodePathDuplicate`], out-of-`exe/`-
1754    /// directory paths rejected past the layout's
1755    /// [`crate::LayoutError::ExeOutsideDir`] `starts_with` fence) maps
1756    /// onto every load-bearing downstream consumer the substrate carries
1757    /// — the [`crate::LayoutInvariants`] Binario-arm empty-check +
1758    /// per-entry file-exists + `exe/`-directory-fence loop at
1759    /// caixa-core/src/layout.rs that gates each entry through
1760    /// [`crate::LayoutError::BinarioWithoutExe`] / `MissingEntry` /
1761    /// `ExeOutsideDir`, the compound `has_code` OR-fold on the
1762    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1763    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1764    /// that fences code-surface slots off from the two no-code kinds,
1765    /// [`Self::declared_foreign_code_slots`]'s `!self.exe.is_empty()`
1766    /// arm on the [`crate::LayoutError::ForeignCodeSlot`] gate that
1767    /// fences the `:exe` code surface off from every non-Binario code-
1768    /// running kind, [`Self::validate_code_paths`]'s per-slot shape gate
1769    /// that walks each entry through the sandbox-relative / cross-entry
1770    /// duplicate gates, every future per-`Caixa` executable-facing
1771    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1772    /// `caixa-flake` per-Binario `packages.<system>.<nome>` derivation
1773    /// entry the caixa-flake docstring roadmaps, the future per-cluster
1774    /// `nix-store` overlay the M4 CR materializer resolves per-CR, the
1775    /// future `feira nix` per-executable Binario-target emit path).
1776    ///
1777    /// Prior to this lift the `.exe` field was accessed inline at three
1778    /// production sites — the compound-code-path `has_code =
1779    /// !caixa.bibliotecas().is_empty() || !caixa.exe.is_empty() ||
1780    /// !caixa.servicos.is_empty()` OR-fold on the
1781    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1782    /// `AplicacaoOwnsCode` kind-coherence gate, the Binario-arm
1783    /// `caixa.exe.is_empty()` [`crate::LayoutError::BinarioWithoutExe`]
1784    /// gate, the per-entry `for p in &caixa.exe`
1785    /// `MissingEntry`/`ExeOutsideDir` walk, and the
1786    /// [`Self::declared_foreign_code_slots`]'s
1787    /// `!self.exe.is_empty()` arm on the `ForeignCodeSlot` gate — four
1788    /// open-coded field-accesses that expressed no compile-time link
1789    /// back to the typed slot. A future extension of the `:exe` axis
1790    /// to a richer executable surface — a per-`:exe` structured
1791    /// `BinarioEntry { path, wrapper, capabilities }` at the storage
1792    /// layer once the substrate absorbs the per-executable
1793    /// nix-wrapper + linux-capabilities tuple the CAIXA-SDLC §I
1794    /// executable roadmap acknowledges, a per-registry `:exe` allowlist
1795    /// the M4 CR materializer enforces per-CR (the "cluster policy
1796    /// demands every Binario declare an explicit `:wrapper`" arm), a
1797    /// promotion of the plain `Vec<String>` byte-string list to a
1798    /// richer `Vec<ExecutablePath>` newtype discriminated on the
1799    /// `exe/<nome>`-shape grammar the layout's `starts_with(exe_dir)`
1800    /// fence already resolves through — would have had to be threaded
1801    /// through all four open-coded copies in lockstep or the layout
1802    /// gate, the shape validator, and the `feira nix` emit path would
1803    /// silently disagree on which executable paths a given [`Caixa`]
1804    /// resolves to (an author's `:exe ("exe/cli" "exe/serve")` would
1805    /// satisfy layout while `feira nix` silently packaged a drifted
1806    /// other list, or vice versa). Lifting the resolution to a typed
1807    /// method on the substrate primitive means every downstream
1808    /// consumer of the caixa's per-`Caixa` executable-source surface
1809    /// reaches for exactly one typed dispatch — the resolver's accept-
1810    /// set migrates as a unit on any future axis addition.
1811    ///
1812    /// Fourth outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1813    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1814    /// [`Self::autores`] (b5d813f) opened, [`Self::etiquetas`]
1815    /// (78c7d3c) folded on, and [`Self::bibliotecas`] (8a36c23) closed
1816    /// the universal-axis text-tag family of. Opens the outer-`Caixa`
1817    /// foreign-code-slot `&[T]` sub-family the sibling `:servicos`
1818    /// future lift closes onto (per the trio of code-surface list slots
1819    /// the [`Self::validate_code_paths`] per-slot dispatch tuple
1820    /// already carries — `:bibliotecas` + `:exe` + `:servicos`, of which
1821    /// `:bibliotecas` landed at 8a36c23 and `:servicos` remains as the
1822    /// last unlifted code-surface slot). Sibling in shape to the peer
1823    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
1824    /// (bc92bce), per-`:placement`
1825    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
1826    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
1827    /// (6c77e36), per-`:contratos`
1828    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1829    /// per-`:upgrade-from :instructions`
1830    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1831    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1832    /// typed-slot list axes, extended here to the outer top-level
1833    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1834    /// `&Vec<String>`) because every downstream consumer of the
1835    /// executable-source list treats it as a read-only sequence — the
1836    /// slice-view is the narrowest borrow that supports every
1837    /// present + roadmapped consumer (`.iter()`, `.len()`,
1838    /// `.is_empty()`) without leaking the backing `Vec`'s
1839    /// grow/push/reserve surface no consumer of the typed view
1840    /// reaches for (the storage-side `Vec` remains reachable through
1841    /// the `pub exe` field for the mutation-carrying serde
1842    /// round-trip and per-test fixture-mutation paths). Named `exe()`
1843    /// to match the storage field's name; the accessor's identity
1844    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
1845    /// docstring already carries.
1846    #[must_use]
1847    pub const fn exe(&self) -> &[String] {
1848        self.exe.as_slice()
1849    }
1850
1851    /// Substrate-canonical per-`Caixa` `:servicos` universal-axis
1852    /// ComputeUnit-CR-YAML-entry-path-list slice-accessor every consumer
1853    /// of the top-level manifest's Servico-component axis keys off —
1854    /// returns the author-declared `:servicos` list verbatim as a
1855    /// `&[String]` slice-view over the same backing buffer the raw
1856    /// `self.servicos.as_slice()` field access borrows from. Empty-list-
1857    /// carrying (`:servicos` is a default-empty axis every `defcaixa`
1858    /// form supplies with an empty `()` when unset; the
1859    /// [`Self::from_lisp`] derive folds an omitted `:servicos` through
1860    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1861    /// definitionally carries a `Vec<String>` slot — possibly empty —
1862    /// and the returned `&[String]` degenerates to an empty slice on
1863    /// that arm without any silent `None` collapse).
1864    ///
1865    /// The `:servicos` slot carries the universal-axis
1866    /// `.computeunit.yaml` ComputeUnit-CR entry-path list every
1867    /// `:kind Servico` caixa emits under (CAIXA-SDLC §I — the
1868    /// author-facing surface every `defcaixa` form supplies alongside
1869    /// `:nome` / `:versao` / `:kind`; the substrate-wide
1870    /// `servicos/`-directory-fenced entry-carrier axis every downstream
1871    /// Servico-facing renderer keys off) — the typed slot's
1872    /// `Vec<String>` accept-set (empty-per-entry rejected through
1873    /// [`ManifestError::CodePathEmpty { slot: ":servicos" }`],
1874    /// non-sandboxed-relative-shape rejected through
1875    /// [`ManifestError::CodePathShape`], non-`.computeunit.yaml`
1876    /// extension rejected through
1877    /// [`ManifestError::CodePathNonComputeUnitYamlExtension`], cross-
1878    /// entry duplicate rejected through
1879    /// [`ManifestError::CodePathDuplicate`], `len != 1` rejected by the
1880    /// V0 [`crate::ServicoCountMismatch`] gate on the per-Servico
1881    /// renderer entry-points, out-of-`servicos/`-directory paths
1882    /// rejected past the layout's [`crate::LayoutError::ServicoOutsideDir`]
1883    /// `starts_with` fence) maps onto every load-bearing downstream
1884    /// consumer the substrate carries — the [`crate::LayoutInvariants`]
1885    /// Servico-arm empty-check + per-entry file-exists + `servicos/`-
1886    /// directory-fence loop at caixa-core/src/layout.rs that gates each
1887    /// entry through [`crate::LayoutError::ServicoWithoutServicos`] /
1888    /// `MissingEntry` / `ServicoOutsideDir`, the compound `has_code`
1889    /// OR-fold on the [`crate::LayoutError::SupervisorOwnsCode`] /
1890    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1891    /// that fences code-surface slots off from the two no-code kinds,
1892    /// [`Self::declared_foreign_code_slots`]'s
1893    /// `!self.servicos.is_empty()` arm on the
1894    /// [`crate::LayoutError::ForeignCodeSlot`] gate that fences the
1895    /// `:servicos` code surface off from every non-Servico code-running
1896    /// kind, [`Self::validate_code_paths`]'s per-slot shape gate that
1897    /// walks each entry through the sandbox-relative / `.computeunit.
1898    /// yaml`-extension / cross-entry duplicate gates, the
1899    /// [`crate::require_single_servico`] V0 singularity gate every
1900    /// per-Servico renderer entry-point runs through
1901    /// [`crate::require_v0_servico_shape`], the `feira chart` /
1902    /// `feira deploy` per-verb `first_servico_path` walk at
1903    /// caixa-feira/src/cmd/chart.rs that resolves the singleton
1904    /// ComputeUnit-CR file, every future per-`Caixa` Servico-facing
1905    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1906    /// per-Servico OCI packager, the future M4
1907    /// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer, the future
1908    /// per-Servico OTel collector-config emit).
1909    ///
1910    /// Prior to this lift the `.servicos` field was accessed inline at
1911    /// five production sites — the compound-code-path `has_code =
1912    /// !caixa.bibliotecas().is_empty() || !caixa.exe().is_empty() ||
1913    /// !caixa.servicos.is_empty()` OR-fold on the
1914    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1915    /// `AplicacaoOwnsCode` kind-coherence gate, the Servico-arm
1916    /// `caixa.servicos.is_empty()`
1917    /// [`crate::LayoutError::ServicoWithoutServicos`] gate, the
1918    /// per-entry `for p in &caixa.servicos`
1919    /// `MissingEntry`/`ServicoOutsideDir` walk, the
1920    /// [`Self::declared_foreign_code_slots`]'s
1921    /// `!self.servicos.is_empty()` arm on the `ForeignCodeSlot` gate,
1922    /// and the [`crate::require_single_servico`] V0 count gate's
1923    /// `caixa.servicos.len() == 1` / `caixa.servicos.len()` count
1924    /// projection (both the accept-arm predicate and the
1925    /// diagnostic-carrying `ServicoCountMismatch { count }`
1926    /// projection) — five open-coded field-accesses across three
1927    /// crates that expressed no compile-time link back to the typed
1928    /// slot. A future extension of the `:servicos` axis to a richer
1929    /// component surface — a per-`:servicos` structured
1930    /// `ServicoEntry { path, world, capabilities }` at the storage
1931    /// layer once the substrate absorbs the per-component WIT-world +
1932    /// capability-set tuple the CAIXA-SDLC §I Servico roadmap
1933    /// acknowledges, a per-registry `:servicos` allowlist the M4 CR
1934    /// materializer enforces per-CR (the "cluster policy demands every
1935    /// Servico declare an explicit `:world`" arm), a promotion of the
1936    /// plain `Vec<String>` byte-string list to a richer
1937    /// `Vec<ComputeUnitPath>` newtype discriminated on the
1938    /// `servicos/<nome>.computeunit.yaml`-shape grammar the layout's
1939    /// `starts_with(servicos_dir)` fence and the
1940    /// [`crate::render::is_computeunit_yaml_extension`] predicate
1941    /// already resolve through, a promotion of the V0 singleton
1942    /// contract to a multi-component `Vec<ComputeUnitPath>` past the M5
1943    /// component-model multi-world boundary — would have had to be
1944    /// threaded through all five open-coded copies in lockstep or the
1945    /// layout gate, the shape validator, the V0 count gate, and the
1946    /// `feira chart` / `feira deploy` entry-point walks would silently
1947    /// disagree on which ComputeUnit-CR paths a given [`Caixa`]
1948    /// resolves to (an author's `:servicos ("servicos/foo.computeunit.
1949    /// yaml")` would satisfy layout while `feira chart` silently
1950    /// packaged a drifted other list, or vice versa). Lifting the
1951    /// resolution to a typed method on the substrate primitive means
1952    /// every downstream consumer of the caixa's per-`Caixa`
1953    /// ComputeUnit-CR-source surface reaches for exactly one typed
1954    /// dispatch — the resolver's accept-set migrates as a unit on any
1955    /// future axis addition.
1956    ///
1957    /// Fifth and final outer top-level [`Caixa`] `&[T]`-return slice-
1958    /// accessor — folds on the "outer [`Caixa`] `&[T]` slice"
1959    /// projection pattern [`Self::autores`] (b5d813f) opened,
1960    /// [`Self::etiquetas`] (78c7d3c) folded on, [`Self::bibliotecas`]
1961    /// (8a36c23) closed the universal-axis text-tag family of, and
1962    /// [`Self::exe`] (65d9527) opened the foreign-code-slot sub-family
1963    /// of. Closes the outer-`Caixa` foreign-code-slot `&[T]` sub-family
1964    /// — with `:bibliotecas`, `:exe`, and `:servicos` now each carrying
1965    /// a substrate-canonical slice accessor, the trio of code-surface
1966    /// list slots the [`Self::validate_code_paths`] per-slot dispatch
1967    /// tuple carries is complete on the typed dispatch surface (the
1968    /// internal `[(":bibliotecas", &self.bibliotecas, ..), (":exe",
1969    /// &self.exe, ..), (":servicos", &self.servicos, ..)]` per-slot
1970    /// dispatch tuple's homogeneous `&Vec<String>`-typed shape blocks a
1971    /// per-element accessor swap in isolation — a future companion lift
1972    /// promotes the tuple's element type to `&[String]` and threads the
1973    /// triple of typed dispatches through as a unit). Sibling in shape
1974    /// to the peer per-`:supervisor`
1975    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1976    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1977    /// (a6e18d7), per-`:membros`
1978    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1979    /// per-`:contratos`
1980    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1981    /// per-`:upgrade-from :instructions`
1982    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1983    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1984    /// typed-slot list axes, extended here to the outer top-level
1985    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1986    /// `&Vec<String>`) because every downstream consumer of the
1987    /// ComputeUnit-CR-source list treats it as a read-only sequence —
1988    /// the slice-view is the narrowest borrow that supports every
1989    /// present + roadmapped consumer (`.iter()`, `.len()`,
1990    /// `.is_empty()`, `.first()`) without leaking the backing `Vec`'s
1991    /// grow/push/reserve surface no consumer of the typed view reaches
1992    /// for (the storage-side `Vec` remains reachable through the
1993    /// `pub servicos` field for the mutation-carrying serde round-trip
1994    /// and per-test fixture-mutation paths, and for the
1995    /// [`Self::validate_code_paths`] per-slot dispatch tuple whose
1996    /// homogeneous-element-type shape carries the raw field access
1997    /// until the trio-closure lift promotes the tuple as a unit).
1998    /// Named `servicos()` to match the storage field's name; the
1999    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
2000    /// vocabulary the slot's docstring already carries.
2001    #[must_use]
2002    pub const fn servicos(&self) -> &[String] {
2003        self.servicos.as_slice()
2004    }
2005
2006    /// Substrate-canonical per-`Caixa` `:deps` universal-axis
2007    /// runtime-dependency-declaration-list slice-accessor every consumer
2008    /// of the top-level manifest's runtime-dep-graph axis keys off —
2009    /// returns the author-declared `:deps` list verbatim as a `&[Dep]`
2010    /// slice-view over the same backing buffer the raw
2011    /// `self.deps.as_slice()` field access borrows from. Empty-list-
2012    /// carrying (`:deps` is a default-empty axis every `defcaixa` form
2013    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
2014    /// derive folds an omitted `:deps` through `#[serde(default)]` to
2015    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
2016    /// `Vec<Dep>` slot — possibly empty — and the returned `&[Dep]`
2017    /// degenerates to an empty slice on that arm without any silent
2018    /// `None` collapse).
2019    ///
2020    /// The `:deps` slot carries the universal-axis runtime dependency
2021    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
2022    /// facing surface every `defcaixa` form supplies alongside `:nome` /
2023    /// `:versao` / `:kind`; the substrate-wide runtime-closure-input axis
2024    /// every downstream resolver-facing artifact emits under) — the
2025    /// typed slot's `Vec<Dep>` accept-set (empty-`:nome` rejected through
2026    /// [`DepError::NomeEmpty`], non-DNS-1123-label `:nome` rejected
2027    /// through [`DepError::NomeInvalid`], malformed `:versao` rejected
2028    /// through [`DepError::VersaoInvalid`], empty `:fonte.repo` rejected
2029    /// through [`DepError::FonteRepoEmpty`], within-list duplicate `:nome`
2030    /// rejected through [`DepError::DuplicateNome { list: ":deps" }`])
2031    /// maps onto every load-bearing downstream consumer the substrate
2032    /// carries — the [`Self::validate_deps`] per-entry
2033    /// [`Dep::validate`] + within-list dedup walk at
2034    /// caixa-core/src/manifest.rs, the [`crate::dep::validate_no_self_dep`]
2035    /// cross-list self-reference gate at caixa-core/src/layout.rs that
2036    /// checks each entry against the caixa's own `:nome`, the
2037    /// caixa-resolver `for dep in &root.deps` closure walk at
2038    /// caixa-resolver/src/resolve.rs that seeds every git-clone target
2039    /// through the resolver's [`crate::Dep`]-keyed pipeline, the
2040    /// caixa-crd `caixa.deps.iter().map(dep_into_ref).collect()` fold at
2041    /// caixa-crd/src/conversion.rs that materializes each entry into the
2042    /// K8s `Caixa` CR's `spec.deps` field, every future per-`Caixa`
2043    /// resolver-facing renderer the CAIXA-SDLC §I roadmap acknowledges
2044    /// (the future per-cluster runtime-closure-audit overlay the M4 CR
2045    /// materializer resolves per-CR, the future `lacre.lisp` BLAKE3-
2046    /// closure emit walk the caixa-resolver docstring roadmaps).
2047    ///
2048    /// First outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2049    /// opens the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2050    /// sibling `:deps-dev` future lift closes on. Peer of the closed
2051    /// outer-`Caixa` foreign-code-slot `&[String]` sub-family
2052    /// ([`Self::bibliotecas`] 8a36c23, [`Self::exe`] 65d9527,
2053    /// [`Self::servicos`] 611f78b) and the outer-`Caixa` universal-axis
2054    /// text-tag family ([`Self::autores`] b5d813f, [`Self::etiquetas`]
2055    /// 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice" projection
2056    /// pattern onto a novel element-type axis (`Dep` composite vs the
2057    /// prior sibling family's `String` scalar). Sibling in shape to the
2058    /// peer per-`:supervisor`
2059    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2060    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2061    /// (a6e18d7), per-`:membros`
2062    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2063    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
2064    /// (0dcc926), and per-`:upgrade-from :instructions`
2065    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2066    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2067    /// typed-slot list axes, extended here to the outer top-level
2068    /// [`Caixa`] universal-axis dep-graph surface. Returns `&[Dep]`
2069    /// (not `&Vec<Dep>`) because every downstream consumer of the
2070    /// runtime-dep list treats it as a read-only sequence — the slice-
2071    /// view is the narrowest borrow that supports every present +
2072    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2073    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2074    /// of the typed view reaches for (the storage-side `Vec` remains
2075    /// reachable through the `pub deps` field for the mutation-carrying
2076    /// serde round-trip and per-test fixture-mutation paths). Named
2077    /// `deps()` to match the storage field's name; the accessor's
2078    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
2079    /// slot's docstring already carries.
2080    #[must_use]
2081    pub const fn deps(&self) -> &[Dep] {
2082        self.deps.as_slice()
2083    }
2084
2085    /// Substrate-canonical per-`Caixa` `:deps-dev` universal-axis
2086    /// development-only-dependency-declaration-list slice-accessor every
2087    /// consumer of the top-level manifest's dev-dep-graph axis keys off —
2088    /// returns the author-declared `:deps-dev` list verbatim as a `&[Dep]`
2089    /// slice-view over the same backing buffer the raw
2090    /// `self.deps_dev.as_slice()` field access borrows from. Empty-list-
2091    /// carrying (`:deps-dev` is a default-empty axis every `defcaixa`
2092    /// form supplies with an empty `()` when unset; the
2093    /// [`Self::from_lisp`] derive folds an omitted `:deps-dev` through
2094    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
2095    /// definitionally carries a `Vec<Dep>` slot — possibly empty — and
2096    /// the returned `&[Dep]` degenerates to an empty slice on that arm
2097    /// without any silent `None` collapse).
2098    ///
2099    /// The `:deps-dev` slot carries the universal-axis dev-only
2100    /// dependency list every kind of caixa emits under (CAIXA-SDLC §I —
2101    /// the author-facing sibling of `:deps` that every `defcaixa` form
2102    /// supplies to declare tests / lint / bench closures the runtime
2103    /// `:deps` axis does not carry; the substrate-wide dev-closure-input
2104    /// axis every downstream test-facing artifact emits under, matching
2105    /// Cargo's `[dev-dependencies]` table's dev-time-only visibility
2106    /// contract) — the typed slot's `Vec<Dep>` accept-set (empty-`:nome`
2107    /// rejected through [`DepError::NomeEmpty`], non-DNS-1123-label
2108    /// `:nome` rejected through [`DepError::NomeInvalid`], malformed
2109    /// `:versao` rejected through [`DepError::VersaoInvalid`], empty
2110    /// `:fonte.repo` rejected through [`DepError::FonteRepoEmpty`],
2111    /// within-list duplicate `:nome` rejected through
2112    /// [`DepError::DuplicateNome { list: ":deps-dev" }`]) maps onto every
2113    /// load-bearing downstream consumer the substrate carries — the
2114    /// [`Self::validate_deps`] per-entry [`Dep::validate`] + within-list
2115    /// dedup walk at caixa-core/src/manifest.rs, the
2116    /// [`crate::dep::validate_no_self_dep`] cross-list self-reference
2117    /// gate at caixa-core/src/layout.rs that checks each entry against
2118    /// the caixa's own `:nome`, the caixa-resolver
2119    /// `for dep in &root.deps_dev` closure walk at
2120    /// caixa-resolver/src/resolve.rs that seeds every dev-only git-clone
2121    /// target through the resolver's [`crate::Dep`]-keyed pipeline, and
2122    /// every future per-`Caixa` resolver-facing renderer the CAIXA-SDLC
2123    /// §I roadmap acknowledges (the future per-cluster dev-closure-audit
2124    /// overlay the M4 CR materializer resolves per-CR, the future
2125    /// `lacre.lisp` BLAKE3-closure emit walk the caixa-resolver docstring
2126    /// roadmaps).
2127    ///
2128    /// Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2129    /// closes the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2130    /// sibling [`Self::deps`] (ad34b4e) opened on. The two accessors
2131    /// jointly close the two-list dep-graph surface every downstream
2132    /// resolver-facing consumer keys off (runtime `:deps` +
2133    /// dev-only `:deps-dev`, the canonical Cargo-shaped dependency-table
2134    /// pair the [`Self::validate_deps`] gate already walks in canonical
2135    /// order). Peer of the closed outer-`Caixa` foreign-code-slot
2136    /// `&[String]` sub-family ([`Self::bibliotecas`] 8a36c23,
2137    /// [`Self::exe`] 65d9527, [`Self::servicos`] 611f78b) and the outer-
2138    /// `Caixa` universal-axis text-tag family ([`Self::autores`]
2139    /// b5d813f, [`Self::etiquetas`] 78c7d3c) — folds the "outer
2140    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
2141    /// dev-dep composite-element axis (`Dep` composite, matching the
2142    /// [`Self::deps`] element type). Sibling in shape to the peer
2143    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
2144    /// (bc92bce), per-`:placement`
2145    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
2146    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
2147    /// (6c77e36), per-`:contratos`
2148    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2149    /// per-`:upgrade-from :instructions`
2150    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2151    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2152    /// typed-slot list axes, folded here to the outer top-level
2153    /// [`Caixa`] universal-axis dev-dep-graph surface. Returns `&[Dep]`
2154    /// (not `&Vec<Dep>`) because every downstream consumer of the
2155    /// dev-dep list treats it as a read-only sequence — the slice-view
2156    /// is the narrowest borrow that supports every present +
2157    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2158    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2159    /// of the typed view reaches for (the storage-side `Vec` remains
2160    /// reachable through the `pub deps_dev` field for the mutation-
2161    /// carrying serde round-trip and per-test fixture-mutation paths).
2162    /// Named `deps_dev()` to match the storage field's `snake_case` name;
2163    /// the kebab-case author-surface tag `:deps-dev` is the same axis
2164    /// after tatara-lisp's kebab↔snake fold and the accessor's identity
2165    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
2166    /// docstring already carries.
2167    #[must_use]
2168    pub const fn deps_dev(&self) -> &[Dep] {
2169        self.deps_dev.as_slice()
2170    }
2171
2172    /// Substrate-canonical per-[`Caixa`] typed-dispatch read accessor
2173    /// every consumer that walks one of the two dep-list axes keyed on a
2174    /// [`crate::dep::DepList`] discriminant reaches for — routes the
2175    /// `(list: DepList) -> &[Dep]` projection through one typed method on
2176    /// the substrate primitive rather than the prior open-coded
2177    /// `match list { Prod => caixa.deps(), Dev => caixa.deps_dev() }`
2178    /// inline dispatch every per-axis walker would otherwise carry.
2179    /// Returns the author-declared per-list `Vec<Dep>` verbatim as a
2180    /// `&[Dep]` slice-view over the same backing buffer the sibling
2181    /// [`Self::deps`] (`Prod`) / [`Self::deps_dev`] (`Dev`) per-slot
2182    /// accessors borrow from, preserving the empty-list-carrying invariant
2183    /// each per-slot accessor already establishes (`:deps` / `:deps-dev`
2184    /// are default-empty axes every `defcaixa` form supplies with an empty
2185    /// `()` when unset; the [`Self::from_lisp`] derive folds an omitted
2186    /// list through `#[serde(default)]` to `Vec::new()`, so both arms
2187    /// definitionally carry a `Vec<Dep>` slot — possibly empty — and the
2188    /// returned `&[Dep]` degenerates to an empty slice on either arm
2189    /// without any silent `None` collapse).
2190    ///
2191    /// The [`crate::dep::DepList`] closed-set typed enum is the
2192    /// substrate's canonical discriminator for the "runtime-closure
2193    /// `:deps` vs dev-only-closure `:deps-dev`" axis every dep-list
2194    /// consumer dispatches on — the compiler-checked exhaustiveness on
2195    /// the enum's `match` arms is the build-time guarantee that no future
2196    /// per-list read-site regresses to a bare-`bool`-flag inline dispatch
2197    /// that a future third dep-list axis (a `:deps-build` build-only
2198    /// closure once the substrate grows cross-artifact heterogeneous
2199    /// dep-graphs, per CAIXA-SDLC §I) would silently split at every
2200    /// consumer. Prior to this the read side carried two per-slot
2201    /// accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`]) and no
2202    /// typed dispatch that a per-axis walker could parametrise on, so
2203    /// every per-list walker (the [`Self::validate_deps`] per-list
2204    /// [`crate::render::insert_first_seen`] dedup walk, a future
2205    /// `feira app graph` per-list dep summary, a future M4 per-cluster
2206    /// dev-closure-audit overlay the CR materializer resolves per-CR)
2207    /// open-coded the same two-block "run over `:deps`, then run over
2208    /// `:deps-dev`" pattern — a silent duplication that a future third
2209    /// dep-list axis would have had to grow a third block at every site.
2210    ///
2211    /// Peer of the sibling [`Self::push_dep`] typed-mutation dispatch
2212    /// (359fba5) — closes the two-side dispatch symmetry on the outer
2213    /// [`Caixa`] two-list dep-graph surface: `push_dep` on the mutation
2214    /// side, `deps_of` on the read side, both keyed on the same
2215    /// [`crate::dep::DepList`] discriminator. Same "one typed dispatch on
2216    /// the substrate primitive, thin projections at each consumer"
2217    /// discipline the sibling per-slot read accessors ([`Self::nome`]
2218    /// e6b7d97, [`Self::versao`], [`Self::kind`]) carry — extended onto
2219    /// the outer-[`Caixa`] typed-dispatch read surface.
2220    ///
2221    /// Declared `pub const fn` — every operator in the body is already
2222    /// `const`-callable (the [`crate::dep::DepList`] enum is a plain
2223    /// closed-set `#[derive(Copy)]` discriminator so the `match` arms
2224    /// are const-evaluable, and each arm forwards through the sibling
2225    /// `pub const fn` [`Self::deps`] / [`Self::deps_dev`] per-slot
2226    /// slice accessor). Pinned load-bearing by the paired
2227    /// [`caixa_deps_of_is_const_fn`][pin] wrapper test (a
2228    /// `const fn deps_of_via_const_fn(c: &Caixa, l: DepList) -> &[Dep]`
2229    /// that forwards through this accessor) — any future accidental
2230    /// downgrade to non-`const` fails the wrapper at caixa-core build
2231    /// time with E0015 (`cannot call non-const method`), strictly
2232    /// stronger than a runtime `assert!` and side-stepping the
2233    /// destructor-in-const restriction the `Caixa` fixture's owning
2234    /// carriers rule out on the direct-`const _: () = assert!(…)`
2235    /// residence. Peer of the sibling per-`Dep` outer-accessor
2236    /// family's parallel `const`-eval-surface pass and of the outer-
2237    /// `Caixa` slice-return accessor family's earlier pass (231a968)
2238    /// — same "one canonical dispatch per axis, `const`-eval posture
2239    /// pinned at the substrate primitive, thin projections at each
2240    /// consumer" discipline extended onto the outer-`Caixa`
2241    /// typed-dispatch read surface on the [`DepList`]-keyed dep-list
2242    /// axis.
2243    ///
2244    /// [DepList]: crate::dep::DepList
2245    /// [pin]: tests::caixa_deps_of_is_const_fn
2246    #[must_use]
2247    pub const fn deps_of(&self, list: crate::dep::DepList) -> &[Dep] {
2248        match list {
2249            crate::dep::DepList::Prod => self.deps(),
2250            crate::dep::DepList::Dev => self.deps_dev(),
2251        }
2252    }
2253
2254    /// Substrate-canonical per-[`Caixa`] typed-mutation dispatch every
2255    /// consumer that appends to one of the two dep-list axes keys off
2256    /// — routes the `(list: DepList, dep: Dep)` tuple through one typed
2257    /// method on the substrate primitive rather than the prior
2258    /// `feira add`-side open-coded `if self.dev { &mut caixa.deps_dev }
2259    /// else { &mut caixa.deps }` inline dispatch + open-coded
2260    /// `.iter().any(|d| d.nome == …)` dup-check cascade. Refuses the
2261    /// mutation with the canonical typed [`DepError::DuplicateNome`] on
2262    /// a within-list name collision — the same `list: &'static str`
2263    /// diagnostic shape [`Self::validate_deps`]'s per-list
2264    /// [`crate::render::insert_first_seen`] walk raises on the peer
2265    /// parse-time within-list dedup axis, so a future author reading a
2266    /// `feira add` refusal and a `feira build` refusal reaches for the
2267    /// same corrective surface without switching diagnostic idioms.
2268    ///
2269    /// The two-arm [`crate::dep::DepList`] enum is the substrate's
2270    /// closed-set typed carrier for the "runtime-closure `:deps` vs
2271    /// dev-only-closure `:deps-dev`" axis every dep-list consumer
2272    /// dispatches on — the compiler-checked exhaustiveness on the
2273    /// enum's `match` arms is the build-time guarantee that no future
2274    /// per-list mutation-site regresses to a bare-`bool`-flag
2275    /// (`is_dev: bool`) inline dispatch that a future third
2276    /// dep-list axis (a `:deps-build` build-only closure once the
2277    /// substrate grows cross-artifact heterogeneous dep-graphs, per
2278    /// CAIXA-SDLC §I) would silently split at every consumer.
2279    ///
2280    /// Same "one typed dispatch on the substrate primitive, thin
2281    /// projections at each consumer" discipline the sibling per-slot
2282    /// read accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`],
2283    /// [`Self::nome`] e6b7d97, [`Self::versao`], [`Self::kind`])
2284    /// carry — extended onto the outer-[`Caixa`] typed-mutation surface,
2285    /// the substrate's first typed-mutation dispatch on the top-level
2286    /// manifest. The prior `feira add` open-coded `&mut caixa.deps` /
2287    /// `&mut caixa.deps_dev` inline field-access + `bail!` string-
2288    /// diagnostic path routed no through-line back to the typed slot,
2289    /// so a future extension of either dep-list axis to a richer author
2290    /// surface (a per-cluster override the operator pins through a
2291    /// future `:placement`-scoped dep-list slot the CAIXA-SDLC §I
2292    /// roadmap acknowledges, an M4
2293    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
2294    /// admission-webhook that normalized the list at admission time)
2295    /// would have had to be threaded through the `feira add` mutation
2296    /// site in lockstep with every read consumer or one path would
2297    /// silently disagree with the other on which list a given dep lands
2298    /// in. Lifting the resolution rule to a typed method on the
2299    /// substrate primitive means every downstream dep-list-mutating
2300    /// consumer of the top-level manifest reaches for exactly one typed
2301    /// dispatch — the resolver's accept-set migrates as a unit on any
2302    /// future axis addition.
2303    ///
2304    /// # Errors
2305    ///
2306    /// Returns [`DepError::DuplicateNome`] with `list = list.as_str()`
2307    /// when another entry in the same list already carries the same
2308    /// `:nome` — the mutation is refused and the caller can surface the
2309    /// typed diagnostic to the author (the `feira add` verb routes the
2310    /// error through `anyhow::Error::from`, which preserves the
2311    /// canonical `#[error(...)]`-templated diagnostic body).
2312    pub fn push_dep(&mut self, list: crate::dep::DepList, dep: Dep) -> Result<(), DepError> {
2313        let target = match list {
2314            crate::dep::DepList::Prod => &mut self.deps,
2315            crate::dep::DepList::Dev => &mut self.deps_dev,
2316        };
2317        if target.iter().any(|d| d.nome() == dep.nome()) {
2318            return Err(DepError::DuplicateNome {
2319                nome: dep.nome().to_string(),
2320                list: list.as_str(),
2321            });
2322        }
2323        target.push(dep);
2324        Ok(())
2325    }
2326
2327    /// Substrate-canonical per-`Caixa` `:limits` M2 typed-slot outer-
2328    /// composite Lunatic-per-process wasm32-sandboxing-composite optional-
2329    /// composite-reference accessor every consumer of the top-level
2330    /// manifest's per-Servico [`LimitsSpec`] outer-composite reader keys
2331    /// off — returns the author-declared `:limits` typed composite
2332    /// verbatim as an `Option<&LimitsSpec>` reference over the same
2333    /// backing storage the raw `self.limits.as_ref()` field access
2334    /// borrows from, with `None` naming the "no `:limits` block
2335    /// authored — every per-axis Lunatic-sandbox cap defers to the
2336    /// wasm-engine-default arm named on the per-axis
2337    /// [`LimitsSpec::memory`] / [`LimitsSpec::fuel`] /
2338    /// [`LimitsSpec::wall_clock`] / [`LimitsSpec::cpu`] scalar-accessor
2339    /// docstrings" partition every downstream Servico-M2-overlay
2340    /// emitter treats as "emit nothing" and the sibling
2341    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate
2342    /// treats as "skip the per-axis
2343    /// [`crate::LimitsError::MemoryZero`] / `MemoryBelowWasm32Page` /
2344    /// `FuelZero` / `WallClockZero` / `CpuZero` refusal cascade".
2345    ///
2346    /// The outer `:limits` slot carries the M2 Servico-runtime typed
2347    /// composite — the load-bearing container of every Lunatic-shaped
2348    /// per-process wasm32-sandbox cap axis every long-running wasm
2349    /// component's runtime dispatches on (INSPIRATIONS §III.1 —
2350    /// Lunatic per-process linear-memory / fuel / wall-clock /
2351    /// millicore cap primitives translated onto pleme-io's typed
2352    /// `:limits :memory` / `:limits :fuel` / `:limits :wall-clock` /
2353    /// `:limits :cpu` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2354    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2355    /// chart both fan on). Every per-`:limits` axis threads through a
2356    /// lifted per-slot accessor on the [`LimitsSpec`] type: the
2357    /// [`LimitsSpec::memory`] wasm32 linear-memory byte-cap scalar
2358    /// accessor, the [`LimitsSpec::fuel`] wasmtime fuel-cap scalar
2359    /// accessor, the [`LimitsSpec::wall_clock`] per-call wall-clock
2360    /// deadline scalar accessor, and the [`LimitsSpec::cpu`]
2361    /// K8s-millicore soft-CPU-share scalar accessor. Every downstream
2362    /// consumer that reaches for a limits axis first passes through
2363    /// this outer accessor onto the composite and then dispatches
2364    /// onto the per-axis accessor — the two-level dispatch means
2365    /// every per-`:limits` reader now routes through a typed dispatch
2366    /// on the substrate primitive at both altitudes.
2367    ///
2368    /// Prior to this lift the `.limits` `Option<LimitsSpec>` composite
2369    /// was accessed inline at three production sites — the
2370    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate's
2371    /// `if let Some(l) = &caixa.limits { … }` traversal head
2372    /// (caixa-core/src/layout.rs:882, which drives the per-axis
2373    /// refusal cascade on the composite: the `LimitsError::MemoryZero`
2374    /// / `MemoryBelowWasm32Page` / `MemoryExceedsWasm32Max` /
2375    /// `FuelZero` / `FuelExceedsMax` / `WallClockZero` /
2376    /// `WallClockExceedsMax` / `CpuZero` / `CpuExceedsMax` refusals
2377    /// [`LimitsSpec::validate`] fans onto), the
2378    /// [`crate::render::servico_m2_overlay`] per-Servico M2 overlay
2379    /// emitter's `if let Some(limits) = &caixa.limits { … }` traversal
2380    /// head (caixa-core/src/render.rs:18504, which drives the
2381    /// `M2_KEY_LIMITS`-keyed `limits.is_empty()`-gated `serde_yaml`
2382    /// projection every `caixa-helm` / `caixa-flux` Servico values-
2383    /// block emitter fans on), and the
2384    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2385    /// set enumerator's `self.limits.is_some()` presence probe
2386    /// (caixa-core/src/manifest.rs:1788, which drives the
2387    /// `M2_AUTHOR_KEY_LIMITS` kebab-case author-label push every
2388    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2389    /// gate reads) — three open-coded outer-field accesses that
2390    /// expressed no compile-time link back to the typed slot at the
2391    /// [`Caixa`] altitude. A future extension of the `:limits` outer
2392    /// axis to a richer author surface (a multi-`:limits` list the M4
2393    /// CR materializer resolves per-CR at admission time so a Servico
2394    /// can expose a compute-heavy + IO-heavy limits pair, a per-
2395    /// cluster `:limits-overrides` slot the operator pins so a
2396    /// cluster-specific policy can tighten a caixa-declared cap
2397    /// without re-authoring the `caixa.lisp`, a promotion of the
2398    /// plain `Option<LimitsSpec>` to a richer
2399    /// `{static, dynamic}` partition once the wasm-engine's runtime-
2400    /// resolved dynamic-cap surface lands) would have had to be
2401    /// threaded through all three open-coded copies in lockstep or
2402    /// one consumer would silently disagree with the peers on which
2403    /// limits composite a given Caixa resolves to — the layout gate's
2404    /// per-axis bracket-dispatch seed reading the raw slot while the
2405    /// peer `servico_m2_overlay` emitter read an operator-resolved
2406    /// slot would silently split the build-time sandbox-shape gate
2407    /// from the runtime `ComputeUnit` CR emission gate, a three-
2408    /// consumer split at the layout gate, the M2 overlay emitter, and
2409    /// the declared-slot enumerator far from the source `caixa.lisp`
2410    /// with no field naming the limits-drift root cause. Lifting the
2411    /// resolution rule to a typed method on the substrate primitive
2412    /// means every downstream consumer of the caixa's per-`Caixa`
2413    /// Lunatic-sandboxing outer-composite surface reaches for exactly
2414    /// one typed dispatch — the resolver's accept-set migrates as a
2415    /// unit on any future axis addition.
2416    ///
2417    /// First outer top-level [`Caixa`] `Option<&Composite>`-return
2418    /// composite-reference accessor — opens the outer-`Caixa`
2419    /// `Option<&Composite>` composite-reference projection pattern the
2420    /// sibling per-`Caixa` `:behavior` [`crate::BehaviorSpec`] /
2421    /// `:politicas` [`crate::aplicacao::MeshPolicy`] / `:placement`
2422    /// [`crate::aplicacao::Placement`] / `:entrada`
2423    /// [`crate::aplicacao::Entrada`] future outer-composite lifts
2424    /// fold on. Peer of the M3 mesh-slot outer-composite family the
2425    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2426    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2427    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2428    /// accessors already close on the outer [`crate::AplicacaoSpec`]
2429    /// altitude — extends that "one typed dispatch on the substrate
2430    /// primitive, thin projections at each consumer" discipline onto
2431    /// the outer top-level [`Caixa`] altitude, opening the M2 Servico-
2432    /// runtime slot family's outer-composite axis. Returns
2433    /// `Option<&LimitsSpec>` (not the owning composite by copy or
2434    /// clone) because every downstream consumer of the limits
2435    /// composite treats it as a read-only per-axis dispatch source —
2436    /// the reference-view is the narrowest borrow that supports every
2437    /// present + roadmapped consumer (per-axis accessor dispatch,
2438    /// `.is_empty()`-gated overlay projection, presence-probe early
2439    /// return on the "author-omitted `:limits` ⇒ engine-default
2440    /// applies" partition) without cloning the composite through
2441    /// every consumer's fast path. The `Option` half of the return-
2442    /// type preserves the load-bearing "author-omitted `:limits` ⇒
2443    /// engine-default applies" partition (not a default composite the
2444    /// downstream must reject on emptiness) — the accessor projects
2445    /// the raw `Option<LimitsSpec>` slot's presence bit through the
2446    /// reference-return unchanged. Named `limits()` to match the
2447    /// storage field's name verbatim and the tatara-lisp author-
2448    /// surface term (`:limits`) the field's own docstring already
2449    /// carries.
2450    #[must_use]
2451    pub const fn limits(&self) -> Option<&LimitsSpec> {
2452        self.limits.as_ref()
2453    }
2454
2455    /// Substrate-canonical per-`Caixa` `:behavior` M2 typed-slot outer-
2456    /// composite OTP-`gen_server`-shaped callback-table optional-
2457    /// composite-reference accessor every consumer of the top-level
2458    /// manifest's per-Servico [`BehaviorSpec`] outer-composite reader
2459    /// keys off — returns the author-declared `:behavior` typed
2460    /// composite verbatim as an `Option<&BehaviorSpec>` reference over
2461    /// the same backing storage the raw `self.behavior.as_ref()` field
2462    /// access borrows from, with `None` naming the "no `:behavior`
2463    /// block authored — every per-callback OTP-shaped hook defers to
2464    /// the wasm-engine's runtime default arm named on the per-axis
2465    /// [`BehaviorSpec::on_init`] / [`BehaviorSpec::on_call`] /
2466    /// [`BehaviorSpec::on_cast`] / [`BehaviorSpec::on_info`] /
2467    /// [`BehaviorSpec::on_state_change`] /
2468    /// [`BehaviorSpec::on_terminate`] scalar-accessor docstrings"
2469    /// partition every downstream Servico-M2-overlay emitter treats as
2470    /// "emit nothing" and the sibling [`crate::StandardLayout::verify`]
2471    /// per-`:behavior` shape gate treats as "skip the per-arm
2472    /// [`crate::behavior::BehaviorError`] refusal cascade + the
2473    /// per-callback on-disk `MissingEntry` existence check".
2474    ///
2475    /// The outer `:behavior` slot carries the M2 Servico-runtime typed
2476    /// composite — the load-bearing container of every OTP-shaped
2477    /// per-Servico lifecycle-callback path axis every long-running wasm
2478    /// component's runtime dispatches on (INSPIRATIONS §II.3 — Erlang/
2479    /// OTP `gen_server:init/1` / `handle_call/3` / `handle_cast/2` /
2480    /// `handle_info/2` / `code_change/3` / `terminate/2` primitives
2481    /// translated onto pleme-io's typed `:behavior :on-init` /
2482    /// `:on-call` / `:on-cast` / `:on-info` / `:on-state-change` /
2483    /// `:on-terminate` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2484    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2485    /// chart both fan on). Every per-`:behavior` axis threads through a
2486    /// lifted per-callback accessor on the [`BehaviorSpec`] type
2487    /// (9b4ecde / d66c702 / 156ddbe / 99616ac / 4846cef / 701add7).
2488    /// Every downstream consumer that reaches for a behavior axis
2489    /// first passes through this outer accessor onto the composite
2490    /// and then dispatches onto the per-callback accessor — the
2491    /// two-level dispatch means every per-`:behavior` reader now
2492    /// routes through a typed dispatch on the substrate primitive at
2493    /// both altitudes.
2494    ///
2495    /// Composes cross-slot with the M2 `:upgrade-from` gate: the
2496    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
2497    /// cross-slot composition gate at [`crate::StandardLayout::verify`]
2498    /// keys the "per-version `:state-change` instruction must have a
2499    /// `:on-state-change` callback" precondition off this accessor's
2500    /// composite (the callback-side counterpart to the
2501    /// `:upgrade-from :instructions :state-change :script` refusal at
2502    /// the appup-side). Threading that gate's traversal input through
2503    /// this accessor closes the cross-slot invariant on the substrate
2504    /// primitive, not on the raw field.
2505    ///
2506    /// Prior to this lift the `.behavior` `Option<BehaviorSpec>`
2507    /// composite was accessed inline at four production sites — the
2508    /// [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
2509    /// `if let Some(b) = &caixa.behavior { … }` traversal head
2510    /// (caixa-core/src/layout.rs:896, which drives the per-arm
2511    /// `BehaviorError` refusal cascade + the per-callback on-disk
2512    /// [`crate::LayoutError::MissingEntry`] existence check under
2513    /// [`crate::render::LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`]),
2514    /// the [`crate::upgrade::validate_upgrade_from_against_behavior`]
2515    /// cross-slot composition gate's `caixa.behavior.as_ref()`
2516    /// traversal-input feed (caixa-core/src/layout.rs:1008, which
2517    /// drives the `:state-change` ↔ `:on-state-change` precondition
2518    /// refusal), the [`crate::render::servico_m2_overlay`] per-Servico
2519    /// M2 overlay emitter's `if let Some(behavior) = &caixa.behavior
2520    /// { … }` traversal head (caixa-core/src/render.rs:18513, which
2521    /// drives the `M2_KEY_BEHAVIOR`-keyed `behavior.is_empty()`-gated
2522    /// `serde_yaml` projection every `caixa-helm` / `caixa-flux`
2523    /// Servico values-block emitter fans on), and the
2524    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2525    /// set enumerator's `self.behavior.is_some()` presence probe
2526    /// (caixa-core/src/manifest.rs:1919, which drives the
2527    /// `M2_AUTHOR_KEY_BEHAVIOR` kebab-case author-label push every
2528    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2529    /// gate reads) — four open-coded outer-field accesses that
2530    /// expressed no compile-time link back to the typed slot at the
2531    /// [`Caixa`] altitude. A future extension of the `:behavior`
2532    /// outer axis to a richer author surface (a per-callback overlay
2533    /// resolver the operator materializes at admission time so a
2534    /// cluster-specific policy can inject a per-callback tracing
2535    /// interceptor without re-authoring the `caixa.lisp`, a promotion
2536    /// of the plain `Option<BehaviorSpec>` to a richer `{static,
2537    /// dynamic}` partition once a runtime-resolved behavior-swap
2538    /// surface lands, the M4 per-callback middleware chain the
2539    /// caixa-operator's per-Servico admission webhook keys off) would
2540    /// have had to be threaded through all four open-coded copies in
2541    /// lockstep or one consumer would silently disagree with the
2542    /// peers on which behavior composite a given Caixa resolves to —
2543    /// the layout gate's per-callback existence-check seed reading
2544    /// the raw slot while the peer `servico_m2_overlay` emitter read
2545    /// an operator-resolved slot would silently split the build-time
2546    /// callback-shape gate from the runtime `ComputeUnit` CR emission
2547    /// gate from the cross-slot `:state-change` composition gate from
2548    /// the M2 declared-slot enumerator, a four-consumer split far
2549    /// from the source `caixa.lisp` with no field naming the
2550    /// behavior-drift root cause. Lifting the resolution rule to a
2551    /// typed method on the substrate primitive means every downstream
2552    /// consumer of the caixa's per-`Caixa` OTP-callback-table outer-
2553    /// composite surface reaches for exactly one typed dispatch — the
2554    /// resolver's accept-set migrates as a unit on any future axis
2555    /// addition.
2556    ///
2557    /// Second outer top-level [`Caixa`] `Option<&Composite>`-return
2558    /// composite-reference accessor — sibling to the opening
2559    /// [`Self::limits`] (b2bd9d7) accessor on the outer-`Caixa`
2560    /// `Option<&Composite>` composite-reference sub-family, extends
2561    /// the "one typed dispatch on the substrate primitive, thin
2562    /// projections at each consumer" discipline onto the second of
2563    /// the three M2 Servico-runtime slots. The remaining
2564    /// `Option<&Composite>` axes at the outer top-level [`Caixa`]
2565    /// altitude — the M3 mesh-slot family (`:politicas`,
2566    /// `:placement`, `:entrada` — already closed on the inner
2567    /// [`crate::AplicacaoSpec`] altitude via 534dc21 / 9abb8f0 /
2568    /// d32111c) — remain the future sibling lifts on the outer
2569    /// top-level projection. Returns `Option<&BehaviorSpec>` (not
2570    /// the owning composite by copy or clone) because every
2571    /// downstream consumer of the behavior composite treats it as a
2572    /// read-only per-callback dispatch source — the reference-view is
2573    /// the narrowest borrow that supports every present + roadmapped
2574    /// consumer (per-callback accessor dispatch, `.is_empty()`-gated
2575    /// overlay projection, presence-probe early return on the
2576    /// "author-omitted `:behavior` ⇒ runtime-default applies"
2577    /// partition, cross-slot `:state-change` composition input)
2578    /// without cloning the composite through every consumer's fast
2579    /// path. The `Option` half of the return-type preserves the
2580    /// load-bearing "author-omitted `:behavior` ⇒ runtime-default
2581    /// applies" partition (not a default composite the downstream
2582    /// must reject on emptiness) — the accessor projects the raw
2583    /// `Option<BehaviorSpec>` slot's presence bit through the
2584    /// reference-return unchanged. Named `behavior()` to match the
2585    /// storage field's name verbatim and the tatara-lisp author-
2586    /// surface term (`:behavior`) the field's own docstring already
2587    /// carries.
2588    #[must_use]
2589    pub const fn behavior(&self) -> Option<&crate::BehaviorSpec> {
2590        self.behavior.as_ref()
2591    }
2592
2593    /// Substrate-canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
2594    /// composite MESH-COMPOSITION-shaped mesh-policy optional-composite-
2595    /// reference accessor every consumer of the top-level manifest's
2596    /// per-Aplicacao [`crate::aplicacao::MeshPolicy`] outer-composite
2597    /// reader keys off — returns the author-declared `:politicas` typed
2598    /// composite verbatim as an `Option<&MeshPolicy>` reference over the
2599    /// same backing storage the raw `self.politicas.as_ref()` field
2600    /// access borrows from, with `None` naming the "no `:politicas`
2601    /// block authored — every per-axis mesh-policy scalar defers to the
2602    /// cluster-default arm named on the per-axis
2603    /// [`crate::aplicacao::MeshPolicy::timeout`] /
2604    /// [`crate::aplicacao::MeshPolicy::retries`] /
2605    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] /
2606    /// [`crate::aplicacao::MeshPolicy::mtls_required`] /
2607    /// [`crate::aplicacao::MeshPolicy::rate_limit`] scalar-accessor
2608    /// docstrings" partition every downstream caixa-mesh /
2609    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2610    /// "emit no per-`:politicas` overlay" and the sibling
2611    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2612    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2613    /// arm.
2614    ///
2615    /// The outer `:politicas` slot carries the M3 mesh-slot per-
2616    /// Aplicacao typed composite — the load-bearing container of every
2617    /// mesh-level policy axis every Cilium NetworkPolicy / Gateway API
2618    /// v1.x HTTPRoute / future M4 per-edge policy overlay emitter fans
2619    /// on (MESH-COMPOSITION §III.2 — the Aplicacao's typed mesh-policy
2620    /// composite; §V — the "no infinite blocking" per-call deadline +
2621    /// "sandboxing-by-default" mTLS-enforcement CSE invariants; §III.3
2622    /// — the typed inter-Servico contrato-edge overlay the per-`(:de,
2623    /// :para)` mesh renderer keys off). Every per-`:politicas` axis
2624    /// threads through a lifted per-slot accessor on the
2625    /// [`crate::aplicacao::MeshPolicy`] type: the
2626    /// [`crate::aplicacao::MeshPolicy::mtls_required`] (c0110f1) Cilium
2627    /// mTLS-enforcement toggle, the
2628    /// [`crate::aplicacao::MeshPolicy::retries`] (bdfb399) transient-
2629    /// failure retry budget, the [`crate::aplicacao::MeshPolicy::timeout`]
2630    /// (7073d0f) Gateway-API per-call deadline, the
2631    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] (b0e741a)
2632    /// Envoy-outlier-detection composite. Every downstream consumer
2633    /// that reaches for a mesh-policy axis first passes through this
2634    /// outer accessor onto the composite and then dispatches onto the
2635    /// per-axis accessor — the two-level dispatch means every per-
2636    /// `:politicas` reader now routes through a typed dispatch on the
2637    /// substrate primitive at both altitudes.
2638    ///
2639    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2640    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2641    /// author-omitted arm onto the [`crate::aplicacao::MeshPolicy::default`]
2642    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::politicas`]
2643    /// (534dc21) `&MeshPolicy`-return accessor observes a typed
2644    /// composite whether or not the author declared the outer slot.
2645    /// The outer accessor preserves the "author-omitted vs authored-
2646    /// empty" partition the inner accessor's `is_empty()`-gated
2647    /// renderer overlay collapses — routing the presence bit through
2648    /// this accessor keeps the [`Self::declared_mesh_slots`] M3 kind-
2649    /// coherence enumerator's `M3_AUTHOR_KEY_POLITICAS` push separate
2650    /// from the inner `MeshPolicy::is_empty()`-gated overlay elision.
2651    ///
2652    /// Prior to this lift the `.politicas` `Option<MeshPolicy>`
2653    /// composite was accessed inline at two production sites — the
2654    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2655    /// `self.politicas.clone().unwrap_or_default()` traversal head
2656    /// (caixa-core/src/manifest.rs:1899, which drives the fold onto
2657    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2658    /// arm the inner [`crate::AplicacaoSpec::politicas`] accessor
2659    /// then observes), and the [`Self::declared_mesh_slots`] M3
2660    /// declared-slot-set enumerator's `self.politicas.is_some()`
2661    /// presence probe (caixa-core/src/manifest.rs:1961, which drives
2662    /// the `M3_AUTHOR_KEY_POLITICAS` kebab-case author-label push
2663    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2664    /// coherence gate reads) — two open-coded outer-field accesses
2665    /// that expressed no compile-time link back to the typed slot at
2666    /// the [`Caixa`] altitude. A future extension of the `:politicas`
2667    /// outer axis to a richer author surface (a per-cluster
2668    /// `:politicas-overrides` slot the operator materializes at
2669    /// admission time so a cluster-specific policy can tighten the
2670    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2671    /// promotion of the plain `Option<MeshPolicy>` to a richer
2672    /// `{static, dynamic}` partition once the M4 per-edge
2673    /// contrato-scoped policy-override surface lands, the M5 traffic-
2674    /// shaping composition the caixa-operator's per-Aplicacao mesh
2675    /// admission webhook keys off) would have had to be threaded
2676    /// through both open-coded copies in lockstep or the Aplicacao-
2677    /// composition seed's default-fold arm would silently disagree
2678    /// with the M3 declared-slot enumerator on which policy composite
2679    /// a given Caixa resolves to — the seed reading an operator-
2680    /// resolved slot while the enumerator's presence probe read the
2681    /// raw slot would silently split the build-time mesh-artifact
2682    /// emission gate from the M3 declared-slot enumerator's kind-
2683    /// coherence gate, a two-consumer split far from the source
2684    /// `caixa.lisp` with no field naming the policy-drift root cause.
2685    /// Lifting the resolution rule to a typed method on the substrate
2686    /// primitive means every downstream consumer of the caixa's per-
2687    /// `Caixa` MESH-COMPOSITION mesh-policy outer-composite surface
2688    /// reaches for exactly one typed dispatch — the resolver's
2689    /// accept-set migrates as a unit on any future axis addition.
2690    ///
2691    /// Third outer top-level [`Caixa`] `Option<&Composite>`-return
2692    /// composite-reference accessor — sibling to the opening
2693    /// [`Self::limits`] (b2bd9d7) and [`Self::behavior`] (35d8b52)
2694    /// accessors on the outer-`Caixa` `Option<&Composite>` composite-
2695    /// reference sub-family, extends the "one typed dispatch on the
2696    /// substrate primitive, thin projections at each consumer"
2697    /// discipline onto the first of the three M3 mesh-slot axes.
2698    /// Peer of the closed inner mesh-slot outer-composite family the
2699    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2700    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2701    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2702    /// accessor pins already close on the inner [`crate::AplicacaoSpec`]
2703    /// altitude — opens the outer top-level [`Caixa`] altitude's M3
2704    /// mesh-slot arm of the composite-reference family the remaining
2705    /// two axes (`:placement`, `:entrada`) fold onto in future
2706    /// sibling lifts. Returns `Option<&MeshPolicy>` (not the owning
2707    /// composite by copy or clone) because every downstream consumer
2708    /// of the mesh-policy composite treats it as a read-only per-axis
2709    /// dispatch source — the reference-view is the narrowest borrow
2710    /// that supports every present + roadmapped consumer (per-axis
2711    /// accessor dispatch, `.is_empty()`-gated overlay projection,
2712    /// presence-probe early return on the "author-omitted `:politicas`
2713    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2714    /// seed's default-fold arm) without cloning the composite through
2715    /// every consumer's fast path. The `Option` half of the return-
2716    /// type preserves the load-bearing "author-omitted `:politicas` ⇒
2717    /// cluster-default applies" partition (not a default composite
2718    /// the downstream must reject on emptiness) — the accessor
2719    /// projects the raw `Option<MeshPolicy>` slot's presence bit
2720    /// through the reference-return unchanged. Named `politicas()` to
2721    /// match the storage field's name verbatim and the tatara-lisp
2722    /// author-surface term (`:politicas`) the field's own docstring
2723    /// already carries.
2724    #[must_use]
2725    pub const fn politicas(&self) -> Option<&crate::aplicacao::MeshPolicy> {
2726        self.politicas.as_ref()
2727    }
2728
2729    /// Substrate-canonical per-`Caixa` `:placement` M3 mesh-slot outer-
2730    /// composite MESH-COMPOSITION-shaped distribution optional-composite-
2731    /// reference accessor every consumer of the top-level manifest's
2732    /// per-Aplicacao [`crate::aplicacao::Placement`] outer-composite
2733    /// reader keys off — returns the author-declared `:placement` typed
2734    /// composite verbatim as an `Option<&Placement>` reference over the
2735    /// same backing storage the raw `self.placement.as_ref()` field
2736    /// access borrows from, with `None` naming the "no `:placement`
2737    /// block authored — every per-axis placement scalar defers to the
2738    /// cluster-default arm named on the per-axis
2739    /// [`crate::aplicacao::Placement::estrategia`] /
2740    /// [`crate::aplicacao::Placement::clusters`] /
2741    /// [`crate::aplicacao::Placement::affinity`] /
2742    /// [`crate::aplicacao::Placement::shard_key`] scalar-accessor
2743    /// docstrings" partition every downstream caixa-mesh /
2744    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2745    /// "emit no per-`:placement` overlay" and the sibling
2746    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2747    /// the [`crate::aplicacao::Placement::default`] cluster-default arm.
2748    ///
2749    /// The outer `:placement` slot carries the M3 mesh-slot per-
2750    /// Aplicacao typed distribution composite — the load-bearing
2751    /// container of every where-does-this-Aplicacao-run axis every
2752    /// caixa-mesh programs.yaml per-cluster distribution overlay /
2753    /// caixa-flux per-Aplicacao GitRepository/HelmRelease fan-out /
2754    /// future M4 per-Aplicacao Akka-style cluster-sharding entity-id
2755    /// resolver emitter fans on (MESH-COMPOSITION §II.4 — the
2756    /// Aplicacao's typed distribution composite; §V CSE invariants —
2757    /// "distribution is a first-class typed composite, not a runtime
2758    /// scheduler hint" the per-axis scalars enforce; §III.3 — the
2759    /// typed inter-Servico contrato-edge overlay the per-cluster
2760    /// mesh renderer keys off). Every per-`:placement` axis threads
2761    /// through a lifted per-slot accessor on the
2762    /// [`crate::aplicacao::Placement`] type: the
2763    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
2764    /// MESH-COMPOSITION distribution-strategy scalar, the
2765    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7) per-cluster
2766    /// distribution-target slice, the [`crate::aplicacao::Placement::affinity`]
2767    /// M3-Adaptive-compression-hint optional-scalar, and the
2768    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) Akka-cluster-
2769    /// sharding extractor-expression optional-scalar. Every downstream
2770    /// consumer that reaches for a placement axis first passes through
2771    /// this outer accessor onto the composite and then dispatches onto
2772    /// the per-axis accessor — the two-level dispatch means every per-
2773    /// `:placement` reader now routes through a typed dispatch on the
2774    /// substrate primitive at both altitudes.
2775    ///
2776    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2777    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2778    /// author-omitted arm onto the [`crate::aplicacao::Placement::default`]
2779    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::placement`]
2780    /// (9abb8f0) `&Placement`-return accessor observes a typed composite
2781    /// whether or not the author declared the outer slot. The outer
2782    /// accessor preserves the "author-omitted vs authored-empty" partition
2783    /// the inner accessor collapses at the cluster-default fold —
2784    /// routing the presence bit through this accessor keeps the
2785    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2786    /// `M3_AUTHOR_KEY_PLACEMENT` push separate from the inner
2787    /// [`crate::AplicacaoSpec::validate_placement`]-gated overlay
2788    /// dispatch.
2789    ///
2790    /// Prior to this lift the `.placement` `Option<Placement>`
2791    /// composite was accessed inline at two production sites — the
2792    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2793    /// `self.placement.clone().unwrap_or_default()` traversal head
2794    /// (caixa-core/src/manifest.rs:2036, which drives the fold onto
2795    /// the [`crate::aplicacao::Placement::default`] cluster-default
2796    /// arm the inner [`crate::AplicacaoSpec::placement`] accessor
2797    /// then observes), and the [`Self::declared_mesh_slots`] M3
2798    /// declared-slot-set enumerator's `self.placement.is_some()`
2799    /// presence probe (caixa-core/src/manifest.rs:2100, which drives
2800    /// the `M3_AUTHOR_KEY_PLACEMENT` kebab-case author-label push
2801    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2802    /// coherence gate reads) — two open-coded outer-field accesses
2803    /// that expressed no compile-time link back to the typed slot at
2804    /// the [`Caixa`] altitude. A future extension of the `:placement`
2805    /// outer axis to a richer author surface (a per-cluster
2806    /// `:placement-overrides` slot the operator materializes at
2807    /// admission time so a cluster-specific placement can tighten the
2808    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2809    /// per-tenant placement-alias table the M4
2810    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer resolves
2811    /// per-CR at admission time, a promotion of the plain
2812    /// `Option<Placement>` to a richer `{static, dynamic}` partition
2813    /// once Orleans-style virtual-actor dynamic placement comes into
2814    /// typed scope) would have had to be threaded through both open-
2815    /// coded copies in lockstep or the Aplicacao-composition seed's
2816    /// default-fold arm would silently disagree with the M3 declared-
2817    /// slot enumerator on which distribution composite a given Caixa
2818    /// resolves to — the seed reading an operator-resolved slot while
2819    /// the enumerator's presence probe read the raw slot would
2820    /// silently split the build-time distribution-artifact emission
2821    /// gate from the M3 declared-slot enumerator's kind-coherence
2822    /// gate, a two-consumer split far from the source `caixa.lisp`
2823    /// with no field naming the distribution-drift root cause.
2824    /// Lifting the resolution rule to a typed method on the substrate
2825    /// primitive means every downstream consumer of the caixa's per-
2826    /// `Caixa` MESH-COMPOSITION distribution outer-composite surface
2827    /// reaches for exactly one typed dispatch — the resolver's
2828    /// accept-set migrates as a unit on any future axis addition.
2829    ///
2830    /// Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
2831    /// composite-reference accessor — sibling to the opening
2832    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) M2-
2833    /// Servico-runtime pair and the peer [`Self::politicas`] (5d23d29)
2834    /// M3-mesh-slot arm on the outer-`Caixa` `Option<&Composite>`
2835    /// composite-reference sub-family, folds on the "one typed
2836    /// dispatch on the substrate primitive, thin projections at each
2837    /// consumer" discipline extended onto the second of the three M3
2838    /// mesh-slot axes. Peer of the closed inner mesh-slot outer-
2839    /// composite family the sibling
2840    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2841    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2842    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2843    /// accessor pins already close on the inner
2844    /// [`crate::AplicacaoSpec`] altitude — folds on the outer top-
2845    /// level [`Caixa`] altitude's M3 mesh-slot arm the sibling
2846    /// [`Self::politicas`] opened, extending the discipline onto the
2847    /// second of the three M3 mesh-slot axes. The remaining M3
2848    /// mesh-slot axis (`:entrada`) folds onto this accessor's
2849    /// discipline in the final sibling lift, closing the outer top-
2850    /// level [`Caixa`] `Option<&Composite>` M3 mesh-slot sub-family.
2851    /// Returns `Option<&Placement>` (not the owning composite by copy
2852    /// or clone) because every downstream consumer of the placement
2853    /// composite treats it as a read-only per-axis dispatch source —
2854    /// the reference-view is the narrowest borrow that supports every
2855    /// present + roadmapped consumer (per-axis accessor dispatch,
2856    /// serde composite-serialization on the programs.yaml overlay,
2857    /// presence-probe early return on the "author-omitted `:placement`
2858    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2859    /// seed's default-fold arm) without cloning the composite through
2860    /// every consumer's fast path. The `Option` half of the return-
2861    /// type preserves the load-bearing "author-omitted `:placement` ⇒
2862    /// cluster-default applies" partition (not a default composite
2863    /// the downstream must reject on emptiness) — the accessor
2864    /// projects the raw `Option<Placement>` slot's presence bit
2865    /// through the reference-return unchanged. Named `placement()` to
2866    /// match the storage field's name verbatim and the tatara-lisp
2867    /// author-surface term (`:placement`) the field's own docstring
2868    /// already carries.
2869    #[must_use]
2870    pub const fn placement(&self) -> Option<&crate::aplicacao::Placement> {
2871        self.placement.as_ref()
2872    }
2873
2874    /// Substrate-canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
2875    /// composite MESH-COMPOSITION-shaped external-gateway optional-
2876    /// composite-reference accessor every consumer of the top-level
2877    /// manifest's per-Aplicacao [`crate::aplicacao::Entrada`] outer-
2878    /// composite reader keys off — returns the author-declared
2879    /// `:entrada` typed composite verbatim as an `Option<&Entrada>`
2880    /// reference over the same backing storage the raw
2881    /// `self.entrada.as_ref()` field access borrows from, with `None`
2882    /// naming the "no `:entrada` block authored — this Aplicacao is
2883    /// cluster-internal, no `Gateway`/`HTTPRoute` fan-out emitted"
2884    /// partition every downstream caixa-mesh Gateway-API artifact
2885    /// emitter treats as "emit no gateway-listener + no `HTTPRoute`
2886    /// backend for this Aplicacao" and the sibling
2887    /// [`Self::aplicacao_view`] Aplicacao-composition seed forwards
2888    /// verbatim (unlike the peer `:politicas` / `:placement` arms,
2889    /// `:entrada` has no cluster-default fold — an omitted `:entrada`
2890    /// stays `None` on the projected [`crate::AplicacaoSpec`] and the
2891    /// peer inner [`crate::AplicacaoSpec::entrada`] accessor observes
2892    /// the same `Option<&Entrada>` presence bit unchanged).
2893    ///
2894    /// The outer `:entrada` slot carries the M3 mesh-slot per-
2895    /// Aplicacao typed external-gateway composite — the load-bearing
2896    /// container of every how-does-the-outside-world-reach-this-
2897    /// Aplicacao axis every caixa-mesh `Gateway`/`HTTPRoute` fan-out
2898    /// emitter fans on (MESH-COMPOSITION §II.5 — the Aplicacao's typed
2899    /// external-entry composite; §V CSE invariants — "the external
2900    /// gateway is a first-class typed composite, not a per-Servico
2901    /// ingress annotation" the per-axis scalars enforce; §III.4 — the
2902    /// typed hostname + backend-Servico pair the per-cluster Gateway-
2903    /// API renderer keys off). Every per-`:entrada` axis threads
2904    /// through a lifted per-slot accessor on the
2905    /// [`crate::aplicacao::Entrada`] type: the
2906    /// [`crate::aplicacao::Entrada::host`] Gateway-API `Listener.hostname`
2907    /// scalar, the [`crate::aplicacao::Entrada::para`] backend-Servico
2908    /// caixa-name scalar, the [`crate::aplicacao::Entrada::paths`]
2909    /// per-rule `HTTPPathMatch` list, the [`crate::aplicacao::Entrada::port`]
2910    /// backend `trigger.service.port` scalar, and the
2911    /// [`crate::aplicacao::Entrada::resolved_paths`] URL-path fallback
2912    /// resolver every HTTPRoute-aware renderer consumes. Every
2913    /// downstream consumer that reaches for an entry axis first passes
2914    /// through this outer accessor onto the composite and then
2915    /// dispatches onto the per-axis accessor — the two-level dispatch
2916    /// means every per-`:entrada` reader now routes through a typed
2917    /// dispatch on the substrate primitive at both altitudes.
2918    ///
2919    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2920    /// seed: the Aplicacao-view builder forwards the outer `Option`
2921    /// arm verbatim (no default fold — `:entrada` is inherently
2922    /// optional; a cluster-internal Aplicacao has no external gateway
2923    /// at all, not "an external gateway that defaults to nothing"), so
2924    /// the peer inner [`crate::AplicacaoSpec::entrada`] (d32111c)
2925    /// `Option<&Entrada>`-return accessor observes the same presence
2926    /// bit whether or not the author declared the outer slot. Routing
2927    /// the presence bit through this accessor keeps the
2928    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2929    /// `M3_AUTHOR_KEY_ENTRADA` push separate from the inner
2930    /// [`crate::AplicacaoSpec::validate_entrada`]-gated
2931    /// hostname/backend/path emission dispatch.
2932    ///
2933    /// Prior to this lift the `.entrada` `Option<Entrada>` composite
2934    /// was accessed inline at two production sites — the
2935    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2936    /// `self.entrada.clone()` traversal head (caixa-core/src/manifest.rs:2182,
2937    /// which drives the forward onto the peer inner
2938    /// [`crate::AplicacaoSpec::entrada`] accessor the caixa-mesh
2939    /// Gateway-API fan-out then observes), and the
2940    /// [`Self::declared_mesh_slots`] M3 declared-slot-set enumerator's
2941    /// `self.entrada.is_some()` presence probe (caixa-core/src/manifest.rs:2248,
2942    /// which drives the `M3_AUTHOR_KEY_ENTRADA` kebab-case author-
2943    /// label push every [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
2944    /// kind-coherence gate reads) — two open-coded outer-field
2945    /// accesses that expressed no compile-time link back to the typed
2946    /// slot at the [`Caixa`] altitude. A future extension of the
2947    /// `:entrada` outer axis to a richer author surface (a per-cluster
2948    /// `:entrada-overrides` slot the operator materializes at admission
2949    /// time so a cluster-specific hostname can pin the caixa-declared
2950    /// bound without re-authoring the `caixa.lisp`, a per-tenant
2951    /// gateway-alias table the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
2952    /// CR materializer resolves per-CR at admission time, a promotion
2953    /// of the plain `Option<Entrada>` to a richer
2954    /// `{public, private, internal}` partition once Cilium-identity-
2955    /// scoped internal gateways come into typed scope) would have had
2956    /// to be threaded through both open-coded copies in lockstep or the
2957    /// Aplicacao-composition seed's forward arm would silently
2958    /// disagree with the M3 declared-slot enumerator on which external-
2959    /// gateway composite a given Caixa resolves to — the seed reading
2960    /// an operator-resolved slot while the enumerator's presence probe
2961    /// read the raw slot would silently split the build-time gateway-
2962    /// artifact emission gate from the M3 declared-slot enumerator's
2963    /// kind-coherence gate, a two-consumer split far from the source
2964    /// `caixa.lisp` with no field naming the entry-drift root cause.
2965    /// Lifting the resolution rule to a typed method on the substrate
2966    /// primitive means every downstream consumer of the caixa's per-
2967    /// `Caixa` MESH-COMPOSITION external-gateway outer-composite
2968    /// surface reaches for exactly one typed dispatch — the resolver's
2969    /// accept-set migrates as a unit on any future axis addition.
2970    ///
2971    /// Fifth and final outer top-level [`Caixa`] `Option<&Composite>`-
2972    /// return composite-reference accessor — closes the outer-`Caixa`
2973    /// `Option<&Composite>` composite-reference sub-family opened by
2974    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) on the
2975    /// M2 Servico-runtime arm and extended onto the M3 mesh-slot arm
2976    /// by [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074),
2977    /// folds on the "one typed dispatch on the substrate primitive,
2978    /// thin projections at each consumer" discipline extended onto the
2979    /// third and final M3 mesh-slot axis. Peer of the closed inner
2980    /// mesh-slot outer-composite family the sibling
2981    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2982    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2983    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2984    /// accessor pins already close on the inner
2985    /// [`crate::AplicacaoSpec`] altitude — this lift closes the mirror
2986    /// sub-family on the outer top-level [`Caixa`] altitude, so both
2987    /// altitudes of the outer-composite reference-return discipline
2988    /// (per-`Caixa` outer-slot presence + per-`AplicacaoSpec` inner-
2989    /// slot presence) now carry the full five-arm accept-set behind a
2990    /// typed dispatch on the substrate primitive. Returns
2991    /// `Option<&Entrada>` (not the owning composite by copy or clone)
2992    /// because every downstream consumer of the entrada composite
2993    /// treats it as a read-only per-axis dispatch source — the
2994    /// reference-view is the narrowest borrow that supports every
2995    /// present + roadmapped consumer (per-axis accessor dispatch,
2996    /// serde composite-serialization on the programs.yaml overlay,
2997    /// presence-probe early return on the "author-omitted `:entrada`
2998    /// ⇒ cluster-internal Aplicacao" partition, `Aplicacao`-composition
2999    /// seed's forward arm) without cloning the composite through every
3000    /// consumer's fast path. The `Option` half of the return-type
3001    /// preserves the load-bearing "author-omitted `:entrada` ⇒
3002    /// cluster-internal Aplicacao" partition (not a default composite
3003    /// the downstream must reject on emptiness — a cluster-internal
3004    /// Aplicacao has no external gateway at all, not "a default gateway
3005    /// that emits nothing"); the accessor projects the raw
3006    /// `Option<Entrada>` slot's presence bit through the reference-
3007    /// return unchanged. Named `entrada()` to match the storage field's
3008    /// name verbatim and the tatara-lisp author-surface term
3009    /// (`:entrada`) the field's own docstring already carries.
3010    #[must_use]
3011    pub const fn entrada(&self) -> Option<&crate::aplicacao::Entrada> {
3012        self.entrada.as_ref()
3013    }
3014
3015    /// Substrate-canonical per-`Caixa` `:ci` slot accessor — returns the
3016    /// author-declared typed CI run (`canteiro_types::CiRun`) verbatim as
3017    /// an `Option<&CiRun>`, borrowed from the typed slot's own
3018    /// `Option<CiRun>` storage. `None` when the slot is absent (every
3019    /// non-`Acao` kind, and an `Acao` caixa that hasn't declared `:ci`
3020    /// yet — the latter is caught by [`crate::LayoutError::MissingCi`],
3021    /// not silently accepted).
3022    ///
3023    /// Named `ci()` to match the storage field's name and the
3024    /// tatara-lisp author surface (`:ci`); mirrors the sibling
3025    /// `Option<&Composite>` accessors on this same `Caixa` altitude
3026    /// ([`Self::limits`], [`Self::behavior`], [`Self::politicas`],
3027    /// [`Self::placement`], [`Self::entrada`]) — one typed dispatch on
3028    /// the substrate primitive rather than an open-coded `self.ci.as_ref()`
3029    /// at every consumer.
3030    #[must_use]
3031    pub const fn ci(&self) -> Option<&canteiro_types::CiRun> {
3032        self.ci.as_ref()
3033    }
3034
3035    /// Substrate-canonical per-`Caixa` `:estrategia` M2 supervisor-tree-
3036    /// slot flat-spread OTP-shaped sibling-restart-strategy discriminant
3037    /// accessor every consumer of the top-level manifest's per-Supervisor
3038    /// restart-strategy axis keys off — returns the author-declared
3039    /// `:estrategia` variant verbatim as an `Option<RestartStrategy>`,
3040    /// `Copy`-projected from the typed slot's own
3041    /// `Option<crate::supervisor::RestartStrategy>` storage. Optional
3042    /// (`:estrategia` is a flat-spread supervisor-only slot every
3043    /// non-`Supervisor`-kind `defcaixa` carries as `None` by
3044    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3045    /// still omit to defer to [`RestartStrategy::default`] —
3046    /// [`RestartStrategy::OneForOne`] — through the [`Self::supervisor_view`]
3047    /// `unwrap_or_default()` fold; a returned `None` degenerates to the
3048    /// [`SupervisorSpec::default`]-inherited strategy without any silent
3049    /// promotion to a fresh explicit variant at the accessor boundary).
3050    ///
3051    /// The `:estrategia` slot carries the M2 typed OTP-shaped sibling-
3052    /// restart-strategy discriminant every substrate-side per-Supervisor
3053    /// dispatch fans on (INSPIRATIONS §II.2 — OTP `supervisor:strategy`
3054    /// closed-set `one_for_one | one_for_all | rest_for_one |
3055    /// simple_one_for_one` algebra translated onto pleme-io's typed
3056    /// [`RestartStrategy`] enum; CAIXA-SDLC §II — the M2 supervisor-tree
3057    /// slot algebra the operator's hierarchical reconciliation scheduler
3058    /// fans on). The slot is *flat-spread* on the outer top-level `Caixa`
3059    /// (per the field-shape docstring at caixa-core/src/manifest.rs — "The
3060    /// supervisor slots are flat on Caixa (vs nested under a
3061    /// `SupervisorSpec` sub-form) to keep tatara-lisp authoring at one
3062    /// level of nesting"), so the accessor's altitude is the outer
3063    /// [`Caixa`] surface rather than the composed [`SupervisorSpec`]
3064    /// altitude the sibling [`crate::supervisor::SupervisorSpec::estrategia`]
3065    /// (eafb619) accessor keys off. The two typed axes — the outer
3066    /// author-surface `Option<RestartStrategy>` on the [`Caixa`] altitude
3067    /// (author-omitted arm carried as `None`) and the inner post-
3068    /// composition `RestartStrategy` on the [`SupervisorSpec`] altitude
3069    /// (`Option` collapsed through the [`Self::supervisor_view`]
3070    /// `unwrap_or_default()` fold) — now share one accessor discipline for
3071    /// the shared substrate concept "the author-declared OTP-shaped
3072    /// sibling-restart-strategy variant that partitions the downstream
3073    /// per-Supervisor renderer's per-arm fan-out"; the outer-altitude
3074    /// `None` arm is the pre-composition presence bit every declared-slot
3075    /// enumerator ([`Self::declared_supervisor_slots`]) reads, and the
3076    /// inner-altitude non-`Option` `RestartStrategy` is the post-
3077    /// composition partition-dispatch input every strategy-arm consumer
3078    /// ([`SupervisorSpec::validate`], the future wasm-operator's per-
3079    /// Supervisor sibling-restart branch, the future M4
3080    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
3081    /// webhook) fans on.
3082    ///
3083    /// Prior to this lift the `.estrategia` field was accessed inline at
3084    /// two production sites in `caixa-core/src/manifest.rs` — the
3085    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`
3086    /// presence-probe arm at `if self.estrategia.is_some()` (which drives
3087    /// the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3088    /// coherence gate's per-slot label push) and the [`Self::supervisor_view`]
3089    /// `SupervisorSpec` construction site at `estrategia:
3090    /// self.estrategia.unwrap_or_default()` (which composes the flat-
3091    /// spread outer author-surface `Option<RestartStrategy>` onto the
3092    /// inner post-composition [`SupervisorSpec`] `RestartStrategy` field
3093    /// the [`SupervisorSpec::estrategia`] accessor keys off) — two open-
3094    /// coded field-accesses that expressed no compile-time link back to
3095    /// the typed slot. A future extension of the outer `:estrategia` axis
3096    /// to a richer author surface (a per-cluster strategy override the
3097    /// operator pins through a future `:estrategia-overrides` overlay the
3098    /// MESH-COMPOSITION §III.2 supervision-canary roadmap acknowledges,
3099    /// a per-tenant strategy-alias table the M4 CR materializer resolves
3100    /// per-CR, a per-Supervisor dynamic strategy derivation the future
3101    /// adaptive-supervision engine computes from child-failure-history
3102    /// topology, a per-child-cohort strategy split the future
3103    /// `RestForCohort` extension the INSPIRATIONS.md §II.2 Erlang/OTP
3104    /// absorption roadmap acknowledges, a promotion of the plain
3105    /// `Option<RestartStrategy>` to a richer
3106    /// `AuthorDeclaredStrategy { declared, overlay }` newtype once the
3107    /// operator-resolved overlay lands) would have had to be threaded
3108    /// through both open-coded copies in lockstep or the enumerator's
3109    /// presence probe and the composition site's `unwrap_or_default()`
3110    /// fold would silently disagree on which strategy a given [`Caixa`]
3111    /// resolves to (an author's `:estrategia OneForAll` would satisfy
3112    /// the enumerator's presence probe while the composition site
3113    /// silently rendered a stale `OneForOne`, or vice versa). Lifting
3114    /// the resolution rule to a typed method on the substrate primitive
3115    /// means every downstream consumer of the caixa's per-`Caixa` outer-
3116    /// altitude sibling-restart-strategy surface reaches for exactly one
3117    /// typed dispatch — the resolver's accept-set migrates as a unit on
3118    /// any future axis addition.
3119    ///
3120    /// First outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3121    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3122    /// axes — opens the outer-`Caixa` `Option<Copy>` flat-spread
3123    /// projection pattern the sibling per-`Caixa` `:max-restarts`
3124    /// `Option<u32>` and (through the future duration-newtype landing)
3125    /// `:restart-window` `Option<Duration>` future outer-scalar lifts
3126    /// fold on. Peer of the inner-altitude [`crate::supervisor::SupervisorSpec::estrategia`]
3127    /// (eafb619) `Copy`-return sibling-restart-strategy scalar accessor on
3128    /// the post-composition [`SupervisorSpec`] altitude — same "one
3129    /// typed dispatch on the substrate primitive, thin projections at
3130    /// each consumer" discipline extended onto the pre-composition outer
3131    /// author-surface [`Caixa`] altitude for the same OTP-shaped
3132    /// sibling-restart-strategy axis. Peer of the closed outer-`Caixa`
3133    /// `Option<&Composite>` composite-reference family the sibling
3134    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3135    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3136    /// [`Self::entrada`] (e4128e4) accessor pins already carry on the
3137    /// outer `Option<&Composite>` altitude — extends the outer-`Caixa`
3138    /// typed-slot accessor discipline onto the flat-spread M2 supervisor-
3139    /// tree `Option<Copy>`-discriminant sub-family the sibling M3
3140    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
3141    /// `PlacementStrategy` `Copy`-composite-enum scalar accessor already
3142    /// pins on the inner-altitude per-`:placement` composite. Named
3143    /// `estrategia()` to match the storage field's name and the
3144    /// per-[`SupervisorSpec`] peer [`crate::supervisor::SupervisorSpec::estrategia`]
3145    /// / per-[`crate::aplicacao::Placement`] peer
3146    /// [`crate::aplicacao::Placement::estrategia`] method-name discipline
3147    /// verbatim; the accessor's identity name maps onto the canonical
3148    /// OTP-shape supervision vocabulary the [`RestartStrategy`] enum's
3149    /// docstring already carries.
3150    #[must_use]
3151    pub const fn estrategia(&self) -> Option<crate::supervisor::RestartStrategy> {
3152        self.estrategia
3153    }
3154
3155    /// Substrate-canonical per-`Caixa` `:max-restarts` M2 supervisor-tree-
3156    /// slot flat-spread OTP-`MaxIntensity`-shaped restart-budget-count
3157    /// scalar accessor every consumer of the top-level manifest's per-
3158    /// Supervisor `:max-restarts` restart-budget-count axis keys off —
3159    /// returns the author-declared `:max-restarts` typed `Option<u32>`
3160    /// verbatim, `Copy`-projected from the typed slot's own `Option<u32>`
3161    /// storage (`u32` is `Copy`, so `Option<u32>` is `Copy` and the
3162    /// accessor returns by value; no borrow of `&self` past the call).
3163    /// Optional (`:max-restarts` is a flat-spread supervisor-only slot
3164    /// every non-`Supervisor`-kind `defcaixa` carries as `None` by
3165    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3166    /// still omit to defer to the [`Self::supervisor_view`]
3167    /// `unwrap_or(5)` fold's OTP-canonical `{intensity, 5, 60}` default).
3168    ///
3169    /// The `:max-restarts` slot carries the M2 typed Erlang/OTP-shaped
3170    /// `MaxIntensity` restart-budget count that pairs with the sibling
3171    /// `:restart-window` `Period` to form the `MaxIntensity / Period`
3172    /// restart-intensity ratio the supervisor trips its own escalation on
3173    /// (INSPIRATIONS §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}`
3174    /// worker-supervisor default; RUNTIME-PATTERNS §II.2; CAIXA-SDLC §II
3175    /// — the M2 supervisor-tree slot algebra the operator's hierarchical
3176    /// reconciliation scheduler fans on). The slot is *flat-spread* on
3177    /// the outer top-level `Caixa` (per the field-shape docstring at
3178    /// caixa-core/src/manifest.rs — "The supervisor slots are flat on
3179    /// Caixa (vs nested under a `SupervisorSpec` sub-form)"), so the
3180    /// accessor's altitude is the outer [`Caixa`] surface rather than the
3181    /// composed [`SupervisorSpec`] altitude the sibling
3182    /// [`crate::supervisor::SupervisorSpec::max_restarts`] accessor keys
3183    /// off. The two typed axes — the outer author-surface `Option<u32>`
3184    /// on the [`Caixa`] altitude (author-omitted arm carried as `None`)
3185    /// and the inner post-composition `u32` on the [`SupervisorSpec`]
3186    /// altitude (`Option` collapsed through the [`Self::supervisor_view`]
3187    /// `unwrap_or(5)` fold) — now share one accessor discipline for the
3188    /// shared substrate concept "the author-declared OTP-shaped
3189    /// restart-budget count every downstream per-Supervisor consumer's
3190    /// restart-intensity budget-vs-count comparator fans on".
3191    ///
3192    /// Prior to this lift the `.max_restarts` field was accessed inline
3193    /// at two production sites in `caixa-core/src/manifest.rs` — the
3194    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`
3195    /// presence-probe arm at `if self.max_restarts.is_some()` (which
3196    /// drives the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3197    /// kind-coherence gate's per-slot label push) and the
3198    /// [`Self::supervisor_view`] `SupervisorSpec` construction site at
3199    /// `max_restarts: self.max_restarts.unwrap_or(5)` (which composes the
3200    /// flat-spread outer author-surface `Option<u32>` onto the inner
3201    /// post-composition [`SupervisorSpec`] `u32` field the
3202    /// [`SupervisorSpec::max_restarts`] accessor keys off) — two open-
3203    /// coded field-accesses that expressed no compile-time link back to
3204    /// the typed slot. A future extension of the outer `:max-restarts`
3205    /// axis to a richer author surface (a per-cluster restart-budget
3206    /// override the operator pins through a future `:max-restarts-overrides`
3207    /// overlay the MESH-COMPOSITION §III.2 supervision-canary roadmap
3208    /// acknowledges, a per-tenant restart-budget-alias table the M4 CR
3209    /// materializer resolves per-CR, a per-Supervisor dynamic restart-
3210    /// budget derivation the future adaptive-supervision engine computes
3211    /// from child-failure-history topology, a promotion of the plain
3212    /// `Option<u32>` count to a richer `{MaxR, MaxT}` per-child-cohort
3213    /// restart-budget-partition once the INSPIRATIONS §II.2 Erlang/OTP
3214    /// per-child-cohort roadmap lands) would have had to be threaded
3215    /// through both open-coded copies in lockstep or the enumerator's
3216    /// presence probe and the composition site's `unwrap_or(5)` fold
3217    /// would silently disagree on which restart-budget a given [`Caixa`]
3218    /// resolves to (an author's `:max-restarts 10` would satisfy the
3219    /// enumerator's presence probe while the composition site silently
3220    /// composed the OTP-canonical `5`, or vice versa). Lifting the
3221    /// resolution rule to a typed method on the substrate primitive means
3222    /// every downstream consumer of the caixa's per-`Caixa` outer-altitude
3223    /// restart-budget-count surface reaches for exactly one typed dispatch
3224    /// — the resolver's accept-set migrates as a unit on any future axis
3225    /// addition.
3226    ///
3227    /// Second outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3228    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3229    /// axes — folds on the outer-`Caixa` `Option<Copy>` flat-spread
3230    /// projection pattern the sibling per-`Caixa`
3231    /// [`Self::estrategia`] (ed04d3c) accessor opened, extends the
3232    /// sub-family onto the sibling `Option<u32>` restart-budget-count arm.
3233    /// Peer of the inner-altitude
3234    /// [`crate::supervisor::SupervisorSpec::max_restarts`] `u32` accessor
3235    /// on the post-composition [`SupervisorSpec`] altitude — same "one
3236    /// typed dispatch on the substrate primitive, thin projections at
3237    /// each consumer" discipline extended onto the pre-composition outer
3238    /// author-surface [`Caixa`] altitude for the same OTP-`MaxIntensity`-
3239    /// shaped restart-budget-count axis. Named `max_restarts()` to match
3240    /// the storage field's name and the per-[`SupervisorSpec`] peer
3241    /// [`crate::supervisor::SupervisorSpec::max_restarts`] method-name
3242    /// discipline verbatim; the accessor's identity maps onto the
3243    /// canonical OTP-shape supervision vocabulary the `:max-restarts`
3244    /// field's docstring already carries.
3245    #[must_use]
3246    pub const fn max_restarts(&self) -> Option<u32> {
3247        self.max_restarts
3248    }
3249
3250    /// Substrate-canonical per-`Caixa` `:restart-window` M2 supervisor-
3251    /// tree-slot flat-spread OTP-`Period`-shaped restart-intensity-
3252    /// denominator raw-duration-string scalar accessor every consumer of
3253    /// the top-level manifest's per-Supervisor `:restart-window` sliding-
3254    /// window axis keys off — returns the author-declared `:restart-window`
3255    /// typed `Option<String>` verbatim as an `Option<&str>`, borrowed
3256    /// from the typed slot's own `Option<String>` storage. `None` when
3257    /// the slot is absent (the canonical "never reset — every restart
3258    /// across the supervisor's lifetime counts against the sibling
3259    /// `:max-restarts` budget" sentinel every non-`Supervisor`-kind
3260    /// `defcaixa` carries by `#[serde(default)]` and every
3261    /// `Supervisor`-kind `defcaixa` may still omit to defer to the
3262    /// [`Self::supervisor_view`] `restart_window: None` composition
3263    /// through the [`crate::supervisor::duration_codec::parse`] soft-
3264    /// swallow `.and_then(|s| … .ok())` fold).
3265    ///
3266    /// The `:restart-window` slot carries the raw M2 typed Erlang/OTP-
3267    /// shaped `Period` sliding-observation-interval duration string that
3268    /// pairs with the sibling `:max-restarts` `MaxIntensity` restart-
3269    /// budget count to form the `MaxIntensity / Period` restart-intensity
3270    /// ratio the supervisor trips its own escalation on (INSPIRATIONS
3271    /// §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}` worker-
3272    /// supervisor default; RUNTIME-PATTERNS §II.2). The outer-`Caixa`
3273    /// slot stores the raw duration string (`"60s"`, `"5m"`, `"500ms"`)
3274    /// authored under `:restart-window` — the typed [`SupervisorSpec`]
3275    /// holds an `Option<Duration>` routed through the shared
3276    /// [`crate::supervisor::duration_codec`] via `with = "duration_codec"`
3277    /// — so the outer altitude's accessor returns `Option<&str>` (raw
3278    /// authoring surface) while the inner altitude's
3279    /// [`crate::supervisor::SupervisorSpec::restart_window`] returns
3280    /// `Option<Duration>` (parsed typed surface). The parse-refusal arm
3281    /// is closed by the sibling [`Self::validate_restart_window`] gate
3282    /// that surfaces [`ManifestError::RestartWindowMalformed`] naming
3283    /// the offending value; the view-construction path
3284    /// [`Self::supervisor_view`] soft-swallows the same parse error to
3285    /// `None` to keep the view best-effort.
3286    ///
3287    /// Prior to this lift the `.restart_window` field was accessed inline
3288    /// at three production sites in `caixa-core/src/manifest.rs` — the
3289    /// [`Self::declared_supervisor_slots`]
3290    /// `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` presence-probe arm at
3291    /// `if self.restart_window.is_some()` (which drives the
3292    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3293    /// coherence gate's per-slot label push), the
3294    /// [`Self::validate_restart_window`] `let Some(s) =
3295    /// self.restart_window.as_deref()` empty-and-shape gate binding
3296    /// (which folds the raw string through the shared
3297    /// [`crate::supervisor::duration_codec::parse`] to surface
3298    /// [`ManifestError::RestartWindowMalformed`] naming the offending
3299    /// value), and the [`Self::supervisor_view`] `self.restart_window
3300    /// .as_deref().and_then(…)` view-construction fold (which composes
3301    /// the flat-spread outer author-surface `Option<String>` onto the
3302    /// inner post-composition [`SupervisorSpec`] `Option<Duration>`
3303    /// field the [`SupervisorSpec::restart_window`] accessor keys off) —
3304    /// three open-coded field-accesses that expressed no compile-time
3305    /// link back to the typed slot. A future extension of the outer
3306    /// `:restart-window` axis to a richer author surface (a per-cluster
3307    /// window override, a per-tenant window-alias table, a per-Supervisor
3308    /// dynamic window derivation the future adaptive-supervision engine
3309    /// computes from child-failure-history topology, a promotion of the
3310    /// plain `Option<String>` raw duration to a typed `Option<Duration>`
3311    /// once the future author-surface parser lands at the [`Caixa`]
3312    /// altitude and the raw-string form is retired) would have had to be
3313    /// threaded through every open-coded copy in lockstep or the three
3314    /// consumers would silently disagree on which raw string a given
3315    /// [`Caixa`] resolves to. Lifting the resolution rule to a typed
3316    /// method on the substrate primitive means every downstream consumer
3317    /// of the caixa's per-`Caixa` outer-altitude restart-window raw-
3318    /// string surface reaches for exactly one typed dispatch — the
3319    /// resolver's accept-set migrates as a unit on any future axis
3320    /// addition.
3321    ///
3322    /// Third outer top-level [`Caixa`] supervisor-tree-slot flat-spread
3323    /// accessor — folds on the outer-`Caixa` M2 supervisor-tree flat-
3324    /// spread projection pattern the sibling per-`Caixa`
3325    /// [`Self::estrategia`] (ed04d3c) `Option<Copy>` and
3326    /// [`Self::max_restarts`] `Option<Copy>` accessors opened, extends
3327    /// the sub-family onto the sibling `Option<&str>` raw-duration-
3328    /// string arm (the outer altitude's raw-string form; the inner
3329    /// altitude's parsed [`Duration`] form is the peer
3330    /// [`crate::supervisor::SupervisorSpec::restart_window`] accessor).
3331    /// Peer of the sibling per-`Caixa` `Option<&str>`-return scalar
3332    /// accessors ([`Self::licenca`] / [`Self::repositorio`] /
3333    /// [`Self::descricao`] / [`Self::edicao`]) on the universal-axis
3334    /// outer scalar-projection family the outer-`Caixa` `Option<&str>`
3335    /// sub-family already carries — same "one typed dispatch on the
3336    /// substrate primitive, thin projections at each consumer"
3337    /// discipline extended onto the M2 supervisor-tree flat-spread
3338    /// `Option<&str>` raw-duration-string arm. Named `restart_window()`
3339    /// to match the storage field's name and the per-[`SupervisorSpec`]
3340    /// peer [`crate::supervisor::SupervisorSpec::restart_window`]
3341    /// method-name discipline verbatim; the accessor's identity maps
3342    /// onto the canonical OTP-shape supervision vocabulary the
3343    /// `:restart-window` field's docstring already carries.
3344    #[must_use]
3345    pub const fn restart_window(&self) -> Option<&str> {
3346        match &self.restart_window {
3347            Some(s) => Some(s.as_str()),
3348            None => None,
3349        }
3350    }
3351
3352    /// Substrate-canonical per-`Caixa` `:upgrade-from` M2 typed-slot
3353    /// outer-composite OTP-appup-shaped per-prior-version migration-
3354    /// entry-list slice accessor every consumer of the top-level
3355    /// manifest's per-Servico hot-upgrade-block `&[UpgradeFromEntry]`
3356    /// slice-view keys off — returns the author-declared `:upgrade-from`
3357    /// typed `Vec<UpgradeFromEntry>` verbatim as a
3358    /// `&[UpgradeFromEntry]` slice-view over the same backing buffer
3359    /// the raw `self.upgrade_from.as_slice()` field access borrows
3360    /// from. Empty-slice-carrying (the "no hot-upgrade path declared"
3361    /// arm every `defcaixa` without an `:upgrade-from` block carries;
3362    /// the [`Self::from_lisp`] derive folds an omitted `:upgrade-from`
3363    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
3364    /// parse definitionally carries a `Vec<UpgradeFromEntry>` slot —
3365    /// possibly empty — and the returned `&[UpgradeFromEntry]`
3366    /// degenerates to an empty slice on that arm without any silent
3367    /// `None` collapse).
3368    ///
3369    /// The outer `:upgrade-from` slot carries the M2 typed OTP-appup
3370    /// migration block — the load-bearing container of every per-
3371    /// prior-`:versao` migration-instruction list the wasm-operator
3372    /// dispatches on at hot-upgrade time (INSPIRATIONS §II.4 — OTP
3373    /// `.appup` per-prior-version `LoadModule | StateChange |
3374    /// SoftPurge | Purge | Restart` instruction algebra translated
3375    /// onto pleme-io's typed `:upgrade-from :from` + `:instructions`
3376    /// entry list; CAIXA-SDLC §II — the typed-M2 slot algebra the
3377    /// operator's hot-upgrade dispatch fans on). Every per-entry axis
3378    /// threads through a lifted per-entry accessor on the
3379    /// [`UpgradeFromEntry`] type: the
3380    /// [`UpgradeFromEntry::prior_versao`] SemVer-shaped previous-
3381    /// version scalar accessor and the
3382    /// [`UpgradeFromEntry::instructions`] `&[UpgradeInstruction]`-
3383    /// return per-entry instruction-list accessor (0137e5a). Every
3384    /// downstream consumer of the hot-upgrade path first passes
3385    /// through this outer accessor onto the slice and then dispatches
3386    /// per-entry through the inner accessors — the two-level dispatch
3387    /// means every per-`:upgrade-from` reader now routes through a
3388    /// typed dispatch on the substrate primitive at both altitudes.
3389    ///
3390    /// Prior to this lift the `.upgrade_from` `Vec<UpgradeFromEntry>`
3391    /// slot was accessed inline at production sites across three
3392    /// files — the [`Self::declared_servico_slots`] M2 declared-slot
3393    /// enumerator's `self.upgrade_from.is_empty()` presence probe
3394    /// (caixa-core/src/manifest.rs, which drives the
3395    /// `M2_AUTHOR_KEY_UPGRADE_FROM` kebab-case author-label push every
3396    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
3397    /// gate reads), the [`crate::StandardLayout::verify`] per-
3398    /// `:upgrade-from` three-stage validation pass (caixa-core/src/
3399    /// layout.rs, which fans onto the
3400    /// [`crate::upgrade::validate_upgrade_from`] per-entry shape +
3401    /// cross-entry duplicate gate, the
3402    /// [`crate::upgrade::validate_upgrade_from_against_versao`]
3403    /// SemVer-precedence cross-slot gate, the
3404    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
3405    /// `:state-change` ↔ `:on-state-change` cross-slot composition
3406    /// gate, and the per-instruction script-path existence-probe walk
3407    /// that reads each entry's [`UpgradeFromEntry::instructions`] to
3408    /// resolve every declared migration script against the layout
3409    /// root), and the [`crate::render::servico_m2_overlay`] per-
3410    /// Servico M2 overlay emitter's `!caixa.upgrade_from.is_empty()`
3411    /// presence gate + `serde_yaml::to_value(&caixa.upgrade_from)`
3412    /// projection (caixa-core/src/render.rs, which drives the
3413    /// `M2_KEY_UPGRADE_FROM`-keyed `serde_yaml` projection every
3414    /// `caixa-helm` / `caixa-flux` Servico values-block emitter fans
3415    /// on and lands as the ComputeUnit CR's `spec.upgradeFrom` field).
3416    /// A future extension of the outer `:upgrade-from` axis (a per-
3417    /// cluster `:upgrade-overrides` overlay the wasm-engine operator
3418    /// resolves at admission time so a cluster-specific migration
3419    /// policy can tighten a caixa-declared step without re-authoring
3420    /// the `caixa.lisp`, promotion of the plain
3421    /// `Vec<UpgradeFromEntry>` to a richer `{static, dynamic}`
3422    /// partition once runtime-resolved hot-upgrade instructions land,
3423    /// per-entry priority annotation once multi-strategy fan-out
3424    /// lands) would have had to be threaded through all six open-
3425    /// coded copies in lockstep or one consumer would silently
3426    /// disagree with the peers on which upgrade slice a given Caixa
3427    /// resolves to — a six-consumer split at the enumerator, the
3428    /// three-stage validate pass, the script-path probe walk, and the
3429    /// M2 overlay emitter, far from the source `caixa.lisp` with no
3430    /// field naming the upgrade-drift root cause. Lifting the
3431    /// resolution rule to a typed method on the substrate primitive
3432    /// means every downstream consumer of the caixa's per-`Caixa`
3433    /// OTP-appup outer-slice surface reaches for exactly one typed
3434    /// dispatch — the resolver's accept-set migrates as a unit on any
3435    /// future axis addition.
3436    ///
3437    /// First outer top-level [`Caixa`] `&[Composite]`-return slice
3438    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the
3439    /// outer-`Caixa` `&[Composite]` composite-slice projection
3440    /// pattern the sibling `:children`
3441    /// [`crate::supervisor::ChildSpec`] / `:membros`
3442    /// [`crate::aplicacao::Membro`] / `:contratos`
3443    /// [`crate::aplicacao::WitContract`] future outer-composite-slice
3444    /// lifts fold on. Peer of the closed outer-`Caixa` scalar
3445    /// `Option<&Composite>` composite-reference family the sibling
3446    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3447    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3448    /// [`Self::entrada`] (e4128e4) accessors closed on the outer
3449    /// `Option<&Composite>` altitude, extended here to the outer-
3450    /// `Caixa` `&[Composite]` vec-carry altitude. Peer at the inner
3451    /// altitude of [`crate::upgrade::UpgradeFromEntry::instructions`]
3452    /// (0137e5a) — same "one typed dispatch on the substrate
3453    /// primitive, thin projections at each consumer" discipline
3454    /// folded onto the outer top-level [`Caixa`] altitude, opening the
3455    /// M2 vec-carry slot family's outer-composite-slice axis. Sibling
3456    /// in shape to the peer outer-`Caixa` `&[Dep]`-return
3457    /// [`Self::deps`] (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and
3458    /// `&[String]`-return [`Self::autores`] (b5d813f) /
3459    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`]
3460    /// (8a36c23) / [`Self::exe`] (65d9527) / [`Self::servicos`]
3461    /// (611f78b) slice-accessors on the sibling outer-`Caixa` scalar-
3462    /// element vec-carry axes — folds the "outer [`Caixa`] `&[T]`
3463    /// slice" projection pattern onto the sibling M2 typed-composite-
3464    /// element axis (`UpgradeFromEntry` composite, matching the
3465    /// per-inner [`UpgradeFromEntry::instructions`] element type at a
3466    /// different altitude).
3467    ///
3468    /// Returns `&[UpgradeFromEntry]` (not `&Vec<UpgradeFromEntry>`)
3469    /// because every downstream consumer of the hot-upgrade list
3470    /// treats it as a read-only sequence — the slice-view is the
3471    /// narrowest borrow that supports every present + roadmapped
3472    /// consumer (`.iter()`, `.len()`, `.is_empty()`, `serde` slice-
3473    /// serialization through
3474    /// `serde_yaml::to_value(&[UpgradeFromEntry])`) without leaking
3475    /// the backing `Vec`'s grow/push/reserve surface no consumer of
3476    /// the typed view reaches for (the storage-side `Vec` remains
3477    /// reachable through the `pub upgrade_from` field for the
3478    /// mutation-carrying serde round-trip and per-test fixture-
3479    /// mutation paths). Named `upgrade_from()` to match the storage
3480    /// field's `snake_case` name; the kebab-case author-surface tag
3481    /// `:upgrade-from` is the same axis after tatara-lisp's
3482    /// kebab↔snake fold and the accessor's identity maps onto the
3483    /// canonical CAIXA-SDLC §II vocabulary the slot's docstring
3484    /// already carries.
3485    #[must_use]
3486    pub const fn upgrade_from(&self) -> &[UpgradeFromEntry] {
3487        self.upgrade_from.as_slice()
3488    }
3489
3490    /// Substrate-canonical per-`Caixa` `:children` M2 supervisor-tree-
3491    /// slot outer-composite OTP-shaped per-supervisor static-child-list
3492    /// slice accessor every consumer of the top-level manifest's per-
3493    /// Supervisor `&[ChildSpec]` slice-view keys off — returns the
3494    /// author-declared `:children` typed `Vec<crate::supervisor::ChildSpec>`
3495    /// verbatim as a `&[crate::supervisor::ChildSpec]` slice-view over
3496    /// the same backing buffer the raw `self.children.as_slice()` field
3497    /// access borrows from. Empty-slice-carrying (the "no static children
3498    /// declared" arm every non-`Supervisor`-kind `defcaixa` carries by
3499    /// #[serde(default)] and every `SimpleOneForOne` supervisor carries
3500    /// by [`crate::supervisor::SupervisorError::SimpleOneForOneWithStaticChildren`]
3501    /// gate; the returned `&[ChildSpec]` degenerates to an empty slice
3502    /// on those arms without any silent `None` collapse).
3503    ///
3504    /// The outer `:children` slot carries the M2 typed OTP-supervisor
3505    /// static-child list — the load-bearing container of every per-
3506    /// child `{caixa, versao, restart}` triple the wasm-operator's
3507    /// hierarchical reconciler dispatches on at supervisor-tree
3508    /// materialization time (INSPIRATIONS §II.2 — OTP `supervisor:init/1`
3509    /// static-child list translated onto pleme-io's typed
3510    /// [`crate::supervisor::ChildSpec`] entry list; CAIXA-SDLC §II —
3511    /// the typed-M2 slot algebra the operator's per-supervisor fan-out
3512    /// dispatch fans on). Every per-child axis threads through a lifted
3513    /// per-entry accessor on the [`crate::supervisor::ChildSpec`] type:
3514    /// the [`crate::supervisor::ChildSpec::nome`] DNS-1123-label
3515    /// child-caixa-identity scalar accessor, the peer versao SemVer-2
3516    /// version-requirement scalar accessor, and the
3517    /// [`crate::supervisor::ChildSpec::restart`] `Copy`-composite-enum
3518    /// per-child post-exit restart-decision-policy discriminant
3519    /// accessor (dfb4a81). Every downstream consumer of the supervisor-
3520    /// tree path first passes through this outer accessor onto the
3521    /// slice and then dispatches per-child through the inner accessors
3522    /// — the two-level dispatch means every per-`:children` reader now
3523    /// routes through a typed dispatch on the substrate primitive at
3524    /// both altitudes.
3525    ///
3526    /// Prior to this lift the `.children` `Vec<ChildSpec>` slot was
3527    /// accessed inline at three production sites across two files —
3528    /// the [`Self::declared_supervisor_slots`] supervisor-tree
3529    /// declared-slot enumerator's `!self.children.is_empty()` presence
3530    /// probe (caixa-core/src/manifest.rs, which drives the
3531    /// `SUPERVISOR_AUTHOR_KEY_CHILDREN` kebab-case author-label push
3532    /// every [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3533    /// kind-coherence gate reads), the [`Self::supervisor_view`]
3534    /// per-supervisor typed-view composer's `self.children.clone()`
3535    /// per-child fold-in path (caixa-core/src/manifest.rs, which
3536    /// materializes the typed [`crate::supervisor::SupervisorSpec`]
3537    /// view every [`crate::StandardLayout::verify`] Supervisor-arm gate
3538    /// dispatches on), and the [`crate::StandardLayout::verify`] per-
3539    /// `:children :caixa` self-parent refusal probe's
3540    /// `&caixa.children`-borrowed
3541    /// [`crate::supervisor::validate_no_self_supervision`] input
3542    /// (caixa-core/src/layout.rs, which pins the "no child names the
3543    /// supervisor's own `:nome`" cross-slot coherence gate). A future
3544    /// extension of the outer `:children` axis (a per-cluster
3545    /// `:children-overrides` overlay the wasm-engine operator resolves
3546    /// at admission time so a cluster-specific child-set can tighten
3547    /// a caixa-declared list without re-authoring the `caixa.lisp`,
3548    /// promotion of the plain `Vec<ChildSpec>` to a richer
3549    /// `{static, dynamic}` partition once Erlang/OTP's
3550    /// `simple_one_for_one`-shaped dynamic-child slot lands as a typed
3551    /// axis, per-child priority annotation once multi-strategy fan-out
3552    /// lands) would have had to be threaded through all three open-
3553    /// coded copies in lockstep or one consumer would silently
3554    /// disagree with the peers on which child slice a given Caixa
3555    /// resolves to — the enumerator's presence probe reading the raw
3556    /// slot while the peer view-composer's fold-in path read an
3557    /// operator-resolved slot would silently split the paired
3558    /// declared-slot enumerator and typed-view composition, and the
3559    /// [`crate::supervisor::validate_no_self_supervision`] self-parent
3560    /// refusal probe reading a third borrow would silently drift the
3561    /// cross-slot coherence gate's traversal input from the two peers,
3562    /// a three-consumer split at the enumerator, the view composer,
3563    /// and the self-parent gate far from the source `caixa.lisp` with
3564    /// no field naming the child-set-drift root cause. Lifting the
3565    /// resolution rule to a typed method on the substrate primitive
3566    /// means every downstream consumer of the caixa's per-`Caixa`
3567    /// OTP-supervisor outer-slice surface reaches for exactly one
3568    /// typed dispatch — the resolver's accept-set migrates as a unit
3569    /// on any future axis addition.
3570    ///
3571    /// Second outer top-level [`Caixa`] `&[Composite]`-return slice
3572    /// accessor for M2 / M3 typed-slot vec-carry axes — folds on the
3573    /// outer-`Caixa` `&[Composite]` composite-slice sub-family the
3574    /// sibling [`Self::upgrade_from`] (2a1f907) accessor opened, peer
3575    /// at the outer altitude of the closed inner-`SupervisorSpec`
3576    /// [`crate::SupervisorSpec::children`] (bc92bce) accessor on the
3577    /// same OTP-supervisor static-child-list axis — same "byte-equal,
3578    /// borrow-shared" outer-accessor discipline extended onto the
3579    /// second outer-`Caixa` `&[Composite]` vec-carry axis. Sibling in
3580    /// shape to the peer outer-`Caixa` `&[Dep]`-return [`Self::deps`]
3581    /// (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and `&[String]`-return
3582    /// [`Self::autores`] (b5d813f) / [`Self::etiquetas`] (78c7d3c) /
3583    /// [`Self::bibliotecas`] (8a36c23) / [`Self::exe`] (65d9527) /
3584    /// [`Self::servicos`] (611f78b) slice-accessors on the sibling
3585    /// outer-`Caixa` scalar-element vec-carry axes — folds the "outer
3586    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
3587    /// M2 typed-composite-element axis
3588    /// ([`crate::supervisor::ChildSpec`] composite, matching the
3589    /// per-inner [`crate::SupervisorSpec::children`] element type at a
3590    /// different altitude).
3591    ///
3592    /// Returns `&[crate::supervisor::ChildSpec]` (not
3593    /// `&Vec<ChildSpec>`) because every downstream consumer of the
3594    /// child list treats it as a read-only sequence — the slice-view
3595    /// is the narrowest borrow that supports every present +
3596    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`, the
3597    /// [`crate::supervisor::validate_no_self_supervision`] `&[ChildSpec]`
3598    /// input, `serde` slice-serialization) without leaking the backing
3599    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3600    /// reaches for (the storage-side `Vec` remains reachable through
3601    /// the `pub children` field for the mutation-carrying serde round-
3602    /// trip and per-test fixture-mutation paths, including the
3603    /// [`Self::supervisor_view`] fold-in path that clones the slot
3604    /// into the typed view). Named `children()` to match the storage
3605    /// field's name verbatim and the tatara-lisp author-surface term
3606    /// (`:children`) the field's own docstring already carries; the
3607    /// accessor's identity maps onto the canonical OTP supervision
3608    /// vocabulary the [`Caixa::children`] field's docstring already
3609    /// reaches for ("Static children of a supervisor").
3610    #[must_use]
3611    pub const fn children(&self) -> &[crate::supervisor::ChildSpec] {
3612        self.children.as_slice()
3613    }
3614
3615    /// Substrate-canonical per-`Caixa` `:membros` M3 mesh-slot outer-
3616    /// composite MESH-COMPOSITION-shaped per-Aplicacao member-list slice
3617    /// accessor every consumer of the top-level manifest's per-Aplicacao
3618    /// `&[crate::aplicacao::Membro]` slice-view keys off — returns the
3619    /// author-declared `:membros` typed `Vec<crate::aplicacao::Membro>`
3620    /// verbatim as a `&[crate::aplicacao::Membro]` slice-view over the
3621    /// same backing buffer the raw `self.membros.as_slice()` field access
3622    /// borrows from. Empty-slice-carrying (the "no members declared" arm
3623    /// every non-`Aplicacao`-kind `defcaixa` carries by `#[serde(default)]`
3624    /// and every partially-authored Aplicacao carries before the
3625    /// [`crate::AplicacaoError::MembrosEmpty`] gate fires; the returned
3626    /// `&[Membro]` degenerates to an empty slice on those arms without any
3627    /// silent `None` collapse).
3628    ///
3629    /// The outer `:membros` slot carries the M3 typed MESH-COMPOSITION
3630    /// per-Aplicacao member list — the load-bearing container of every
3631    /// per-member `{caixa, versao}` pair the caixa-mesh renderer's
3632    /// per-Aplicacao program-emission dispatch fans on at mesh-artifact
3633    /// materialization time (MESH-COMPOSITION §III.1 — the typed graph's
3634    /// vertex set the `:contratos` `:de`/`:para` edges resolve against and
3635    /// the `:entrada :para` external-gateway destination validates
3636    /// against; CAIXA-SDLC §II — the typed-M3 slot algebra the operator's
3637    /// per-Aplicacao fan-out dispatch fans on). Every per-member axis
3638    /// threads through a lifted per-entry accessor on the
3639    /// [`crate::aplicacao::Membro`] type: the
3640    /// [`crate::aplicacao::Membro::nome`] DNS-1123-label member-caixa-
3641    /// identity scalar accessor (4a32abf) and the peer
3642    /// [`crate::aplicacao::Membro::versao_requirement`] SemVer-2
3643    /// version-requirement scalar accessor (a40b0e3). Every downstream
3644    /// consumer of the mesh-graph path first passes through this outer
3645    /// accessor onto the slice and then dispatches per-member through
3646    /// the inner accessors — the two-level dispatch means every per-
3647    /// `:membros` reader now routes through a typed dispatch on the
3648    /// substrate primitive at both altitudes.
3649    ///
3650    /// Prior to this lift the `.membros` `Vec<Membro>` slot was accessed
3651    /// inline at three production sites across two files — the
3652    /// [`Self::declared_mesh_slots`] mesh-slot declared-slot
3653    /// enumerator's `!self.membros.is_empty()` presence probe
3654    /// (caixa-core/src/manifest.rs, which drives the
3655    /// `M3_AUTHOR_KEY_MEMBROS` kebab-case author-label push every
3656    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3657    /// gate reads), the [`Self::aplicacao_view`] per-Aplicacao typed-view
3658    /// composer's `self.membros.clone()` per-member fold-in path
3659    /// (caixa-core/src/manifest.rs, which materializes the typed
3660    /// [`crate::aplicacao::AplicacaoSpec`] view every
3661    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate dispatches
3662    /// on), and the [`crate::StandardLayout::verify`] per-`:membros
3663    /// :caixa` self-membership refusal probe's `&caixa.membros`-borrowed
3664    /// [`crate::aplicacao::validate_no_self_membership`] input
3665    /// (caixa-core/src/layout.rs, which pins the "no member names the
3666    /// Aplicacao's own `:nome`" cross-slot coherence gate). A future
3667    /// extension of the outer `:membros` axis (a per-cluster
3668    /// `:membros-overrides` overlay the wasm-engine operator resolves at
3669    /// admission time so a cluster-specific member-set can tighten a
3670    /// caixa-declared list without re-authoring the `caixa.lisp`,
3671    /// promotion of the plain `Vec<Membro>` to a richer
3672    /// `{static, dynamic}` partition once runtime-resolved Aplicacao
3673    /// members land as a typed axis, per-member priority annotation once
3674    /// multi-strategy fan-out lands) would have had to be threaded
3675    /// through all three open-coded copies in lockstep or one consumer
3676    /// would silently disagree with the peers on which member slice a
3677    /// given Caixa resolves to — the enumerator's presence probe reading
3678    /// the raw slot while the peer view-composer's fold-in path read an
3679    /// operator-resolved slot would silently split the paired
3680    /// declared-slot enumerator and typed-view composition, and the
3681    /// [`crate::aplicacao::validate_no_self_membership`] self-membership
3682    /// refusal probe reading a third borrow would silently drift the
3683    /// cross-slot coherence gate's traversal input from the two peers, a
3684    /// three-consumer split at the enumerator, the view composer, and
3685    /// the self-membership gate far from the source `caixa.lisp` with no
3686    /// field naming the member-set-drift root cause. Lifting the
3687    /// resolution rule to a typed method on the substrate primitive
3688    /// means every downstream consumer of the caixa's per-`Caixa`
3689    /// MESH-COMPOSITION outer-slice surface reaches for exactly one
3690    /// typed dispatch — the resolver's accept-set migrates as a unit on
3691    /// any future axis addition.
3692    ///
3693    /// Third outer top-level [`Caixa`] `&[Composite]`-return slice
3694    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the outer-
3695    /// `Caixa` M3 mesh-slot arm of the `&[Composite]` composite-slice
3696    /// sub-family the sibling M2 [`Self::upgrade_from`] (2a1f907) /
3697    /// [`Self::children`] (c17b51e) accessors opened for the M2 vec-carry
3698    /// altitude. Peer at the outer altitude of the closed inner-
3699    /// [`crate::AplicacaoSpec::membros`] (6c77e36) accessor on the same
3700    /// MESH-COMPOSITION per-Aplicacao member-list axis — the two
3701    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3702    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3703    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3704    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3705    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3706    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3707    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3708    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3709    /// pattern onto the sibling M3 typed-composite-element axis
3710    /// ([`crate::aplicacao::Membro`] composite, matching the per-inner
3711    /// [`crate::AplicacaoSpec::membros`] element type at a different
3712    /// altitude).
3713    ///
3714    /// Returns `&[crate::aplicacao::Membro]` (not `&Vec<Membro>`)
3715    /// because every downstream consumer of the member list treats it
3716    /// as a read-only sequence — the slice-view is the narrowest borrow
3717    /// that supports every present + roadmapped consumer (`.iter()`,
3718    /// `.len()`, `.is_empty()`, the
3719    /// [`crate::aplicacao::validate_no_self_membership`] `&[Membro]`
3720    /// input, `serde` slice-serialization) without leaking the backing
3721    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3722    /// reaches for (the storage-side `Vec` remains reachable through the
3723    /// `pub membros` field for the mutation-carrying serde round-trip
3724    /// and per-test fixture-mutation paths, including the
3725    /// [`Self::aplicacao_view`] fold-in path that clones the slot into
3726    /// the typed view). Named `membros()` to match the storage field's
3727    /// name verbatim and the tatara-lisp author-surface term
3728    /// (`:membros`) the field's own docstring already carries; the
3729    /// accessor's identity maps onto the canonical MESH-COMPOSITION
3730    /// vocabulary the [`Caixa::membros`] field's docstring already
3731    /// reaches for ("Member Servicos that make up this Aplicacao").
3732    #[must_use]
3733    pub const fn membros(&self) -> &[crate::aplicacao::Membro] {
3734        self.membros.as_slice()
3735    }
3736
3737    /// Substrate-canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
3738    /// composite MESH-COMPOSITION-shaped per-Aplicacao WIT-typed
3739    /// inter-Servico contract-list slice accessor every consumer of the
3740    /// top-level manifest's per-Aplicacao `&[crate::aplicacao::WitContract]`
3741    /// slice-view keys off — returns the author-declared `:contratos`
3742    /// typed `Vec<crate::aplicacao::WitContract>` verbatim as a
3743    /// `&[crate::aplicacao::WitContract]` slice-view over the same
3744    /// backing buffer the raw `self.contratos.as_slice()` field access
3745    /// borrows from. Empty-slice-carrying (the "no contracts declared"
3746    /// arm every non-`Aplicacao`-kind `defcaixa` carries by
3747    /// `#[serde(default)]` and every leaf Aplicacao carrying only a
3748    /// single member with no inter-Servico edge carries; the returned
3749    /// `&[WitContract]` degenerates to an empty slice on those arms
3750    /// without any silent `None` collapse).
3751    ///
3752    /// The outer `:contratos` slot carries the M3 typed MESH-COMPOSITION
3753    /// per-Aplicacao WIT-typed inter-Servico edge list — the load-bearing
3754    /// container of every per-edge `{de, para, wit, endpoint | subject |
3755    /// slot}` quadruple the caixa-mesh renderer's per-Aplicacao
3756    /// `CiliumNetworkPolicy` fan-out (one L7 policy per edge —
3757    /// MESH-COMPOSITION §III.2 point 2) and per-`(:de, :para)`
3758    /// adjacency-list seed dispatch on at mesh-artifact materialization
3759    /// time (MESH-COMPOSITION §III.1 — the typed graph's edge set the
3760    /// `:membros` vertex set resolves against, closed by the
3761    /// [`crate::AplicacaoError::ContractoUnknownMember`] / cycle-refusal
3762    /// gates in §III.3; CAIXA-SDLC §II — the typed-M3 slot algebra the
3763    /// operator's per-Aplicacao fan-out dispatch fans on). Every
3764    /// per-edge axis threads through a lifted per-entry accessor on the
3765    /// [`crate::aplicacao::WitContract`] type: the peer `de` / `para`
3766    /// DNS-1123-label member-caixa-name endpoint scalar accessors, the
3767    /// [`crate::aplicacao::WitContract::endpoint`] (7020470) HTTP-shape
3768    /// / [`crate::aplicacao::WitContract::subject`] (90de675)
3769    /// NATS-pub-sub-shape / [`crate::aplicacao::WitContract::slot`]
3770    /// (ed22b66) `wasi:keyvalue/store`-shape payload-carrier accessors,
3771    /// and the WIT-world discriminant. Every downstream consumer of the
3772    /// mesh-graph edge path first passes through this outer accessor
3773    /// onto the slice and then dispatches per-contract through the
3774    /// inner accessors — the two-level dispatch means every
3775    /// per-`:contratos` reader now routes through a typed dispatch on
3776    /// the substrate primitive at both altitudes.
3777    ///
3778    /// Prior to this lift the `.contratos` `Vec<WitContract>` slot was
3779    /// accessed inline at two production sites in
3780    /// caixa-core/src/manifest.rs — the [`Self::declared_mesh_slots`]
3781    /// mesh-slot declared-slot enumerator's
3782    /// `!self.contratos.is_empty()` presence probe (which drives the
3783    /// `M3_AUTHOR_KEY_CONTRATOS` kebab-case author-label push every
3784    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3785    /// gate reads) and the [`Self::aplicacao_view`] per-Aplicacao
3786    /// typed-view composer's `self.contratos.clone()` per-contract
3787    /// fold-in path (which materializes the typed
3788    /// [`crate::aplicacao::AplicacaoSpec`] view every
3789    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate and every
3790    /// downstream `caixa-mesh` renderer dispatches on). A future
3791    /// extension of the outer `:contratos` axis (a per-cluster
3792    /// `:contratos-overrides` overlay the wasm-engine operator resolves
3793    /// at admission time so a cluster-specific edge-set can tighten a
3794    /// caixa-declared list without re-authoring the `caixa.lisp`,
3795    /// promotion of the plain `Vec<WitContract>` to a richer
3796    /// `{static, dynamic}` partition once runtime-resolved contract
3797    /// edges land, per-edge policy annotation once the M4 per-edge
3798    /// policy overlay axis lands) would have had to be threaded through
3799    /// both open-coded copies in lockstep or one consumer would
3800    /// silently disagree with the peer on which edge slice a given
3801    /// Caixa resolves to — the enumerator's presence probe reading the
3802    /// raw slot while the peer view-composer's fold-in path read an
3803    /// operator-resolved slot would silently split the paired
3804    /// declared-slot enumerator and typed-view composition, a
3805    /// two-consumer split at the enumerator and the view composer far
3806    /// from the source `caixa.lisp` with no field naming the edge-set-
3807    /// drift root cause. Lifting the resolution rule to a typed method
3808    /// on the substrate primitive means every downstream consumer of
3809    /// the caixa's per-`Caixa` MESH-COMPOSITION outer-slice surface
3810    /// reaches for exactly one typed dispatch — the resolver's
3811    /// accept-set migrates as a unit on any future axis addition.
3812    ///
3813    /// Fourth and final outer top-level [`Caixa`] `&[Composite]`-return
3814    /// slice accessor for M2 / M3 typed-slot vec-carry axes — closes
3815    /// the outer-`Caixa` `&[Composite]` composite-slice sub-family the
3816    /// sibling M2 [`Self::upgrade_from`] (2a1f907) / [`Self::children`]
3817    /// (c17b51e) accessors opened and the M3 [`Self::membros`]
3818    /// (0f26987) accessor folded on, and closes the outer-`Caixa` M3
3819    /// mesh-slot arm of the composite-slice sub-family the sibling
3820    /// [`Self::membros`] accessor opened for the M3 vec-carry altitude.
3821    /// Peer at the outer altitude of the closed inner-
3822    /// [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
3823    /// same MESH-COMPOSITION per-Aplicacao contract-list axis — the two
3824    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3825    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3826    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3827    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3828    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3829    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3830    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3831    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3832    /// pattern onto the sibling M3 typed-composite-element axis
3833    /// ([`crate::aplicacao::WitContract`] composite, matching the
3834    /// per-inner [`crate::AplicacaoSpec::contratos`] element type at a
3835    /// different altitude).
3836    ///
3837    /// Returns `&[crate::aplicacao::WitContract]` (not
3838    /// `&Vec<WitContract>`) because every downstream consumer of the
3839    /// contract list treats it as a read-only sequence — the slice-view
3840    /// is the narrowest borrow that supports every present + roadmapped
3841    /// consumer (`.iter()`, `.len()`, `.is_empty()`, per-edge WIT-world
3842    /// discriminant dispatch, `serde` slice-serialization) without
3843    /// leaking the backing `Vec`'s grow/push/reserve surface no
3844    /// consumer of the typed view reaches for (the storage-side `Vec`
3845    /// remains reachable through the `pub contratos` field for the
3846    /// mutation-carrying serde round-trip and per-test fixture-mutation
3847    /// paths, including the [`Self::aplicacao_view`] fold-in path that
3848    /// clones the slot into the typed view). Named `contratos()` to
3849    /// match the storage field's name verbatim and the tatara-lisp
3850    /// author-surface term (`:contratos`) the field's own docstring
3851    /// already carries; the accessor's identity maps onto the canonical
3852    /// MESH-COMPOSITION vocabulary the [`Caixa::contratos`] field's
3853    /// docstring already reaches for ("WIT-typed inter-Servico
3854    /// contracts").
3855    #[must_use]
3856    pub const fn contratos(&self) -> &[crate::aplicacao::WitContract] {
3857        self.contratos.as_slice()
3858    }
3859
3860    /// Compose the Aplicacao-related flat slots into a single typed
3861    /// [`crate::aplicacao::AplicacaoSpec`] for validation +
3862    /// downstream renderer consumption. Returns `None` when the
3863    /// caixa isn't a `:kind Aplicacao`.
3864    #[must_use]
3865    pub fn aplicacao_view(&self) -> Option<crate::aplicacao::AplicacaoSpec> {
3866        if !self.kind().is_aplicacao() {
3867            return None;
3868        }
3869        Some(crate::aplicacao::AplicacaoSpec {
3870            membros: self.membros().to_vec(),
3871            contratos: self.contratos().to_vec(),
3872            politicas: self.politicas().cloned().unwrap_or_default(),
3873            placement: self.placement().cloned().unwrap_or_default(),
3874            entrada: self.entrada().cloned(),
3875        })
3876    }
3877
3878    /// The kebab-case `:slot` tags of every M3 mesh slot this caixa
3879    /// *declares* a value on, in canonical declaration order
3880    /// (`:membros` → `:contratos` → `:politicas` → `:placement` →
3881    /// `:entrada`). A slot counts as declared when its backing field
3882    /// carries a value — a non-empty `Vec`, or a `Some(...)`.
3883    ///
3884    /// The M3 mesh slots compose the typed graph of a `:kind Aplicacao`
3885    /// (MESH-COMPOSITION §III.1). [`Self::aplicacao_view`] only folds
3886    /// them into a validatable [`crate::aplicacao::AplicacaoSpec`] when
3887    /// the kind matches (returns `None` otherwise), and the caixa-mesh /
3888    /// caixa-flux / caixa-helm renderers only emit them for an
3889    /// Aplicacao. On any *other* kind a declared mesh slot is the
3890    /// manifest field's documented "ignored otherwise" (see the
3891    /// `:membros` … `:entrada` field docs): it silently passes
3892    /// [`Caixa::from_lisp`] and then vanishes — never validated, never
3893    /// rendered — far from the source caixa.lisp.
3894    /// [`crate::StandardLayout::verify`] consults this to reject that
3895    /// silent-drop at caixa-build time
3896    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]), mirroring the
3897    /// `SupervisorOwnsCode` / `AplicacaoOwnsCode` kind-coherence gates:
3898    /// a slot foreign to the kind is a build error, not a silent drop.
3899    ///
3900    /// Lifted as a typed method (rather than an inline disjunction at
3901    /// the verify call site) so the mesh-slot set lives in one place —
3902    /// a future M4 axis added to the Aplicacao surface (per-edge policy
3903    /// overlay, distributed-app takeover config) is one push here, and
3904    /// every consumer reaching for "which mesh slots are set" (the
3905    /// verify gate, a future `feira lint` kind-coherence advisory)
3906    /// inherits the canonical order without rolling its own.
3907    ///
3908    /// Each per-arm kebab-case label is routed through the peer
3909    /// [`crate::M3_AUTHOR_KEY_MEMBROS`] /
3910    /// [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
3911    /// [`crate::M3_AUTHOR_KEY_POLITICAS`] /
3912    /// [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
3913    /// [`crate::M3_AUTHOR_KEY_ENTRADA`] consts declared next to the
3914    /// [`crate::M3_KEY_PLACEMENT`] renderer-side wire-key peer, so both
3915    /// halves of every M3 top-level mesh slot's dual axis (author-facing
3916    /// kebab-case label + renderer-side artifact key) route through one
3917    /// canonical declaration per arm — same discipline the peer
3918    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`]
3919    /// / [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot consts
3920    /// (f49c8b0) establish on the sibling per-Servico M2 top-level slot
3921    /// axis, extended here to close the M3 mesh-slot author-facing-label
3922    /// axis so both altitudes of the typed-slot algebra
3923    /// (per-Servico M2 + per-Aplicacao M3) share the same
3924    /// "one canonical byte-string per arm, next to the axis" discipline.
3925    #[must_use]
3926    pub fn declared_mesh_slots(&self) -> Vec<&'static str> {
3927        let mut slots = Vec::new();
3928        if !self.membros().is_empty() {
3929            slots.push(crate::render::M3_AUTHOR_KEY_MEMBROS);
3930        }
3931        if !self.contratos().is_empty() {
3932            slots.push(crate::render::M3_AUTHOR_KEY_CONTRATOS);
3933        }
3934        if self.politicas().is_some() {
3935            slots.push(crate::render::M3_AUTHOR_KEY_POLITICAS);
3936        }
3937        if self.placement().is_some() {
3938            slots.push(crate::render::M3_AUTHOR_KEY_PLACEMENT);
3939        }
3940        if self.entrada().is_some() {
3941            slots.push(crate::render::M3_AUTHOR_KEY_ENTRADA);
3942        }
3943        slots
3944    }
3945
3946    /// The kebab-case `:slot` tags of every supervisor-tree slot this
3947    /// caixa *declares* a value on, in canonical declaration order
3948    /// (`:estrategia` → `:max-restarts` → `:restart-window` →
3949    /// `:children`). A slot counts as declared when its backing field
3950    /// carries a value — a `Some(...)`, or a non-empty `Vec`.
3951    ///
3952    /// The supervisor-tree slots compose the typed OTP supervisor of a
3953    /// `:kind Supervisor` (INSPIRATIONS §II.2; the `:estrategia` +
3954    /// `:children` field docs above). [`Self::supervisor_view`] only
3955    /// folds them into a validatable [`SupervisorSpec`] when the kind
3956    /// matches (returns `None` otherwise), and the wasm-operator's
3957    /// hierarchical reconciler only consumes them for a Supervisor. On
3958    /// any *other* kind a declared supervisor slot is the manifest
3959    /// field's documented "ignored otherwise" (see the `:estrategia` …
3960    /// `:children` field docs): it silently passes [`Caixa::from_lisp`]
3961    /// and then vanishes — never validated, never reconciled — far from
3962    /// the source caixa.lisp. [`crate::StandardLayout::verify`] consults
3963    /// this to reject that silent-drop at caixa-build time
3964    /// ([`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]), the
3965    /// exact mirror of the [`Self::declared_mesh_slots`] /
3966    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] gate on the
3967    /// Aplicacao-only slot set: a slot foreign to the kind is a build
3968    /// error, not a silent drop.
3969    #[must_use]
3970    pub fn declared_supervisor_slots(&self) -> Vec<&'static str> {
3971        let mut slots = Vec::new();
3972        if self.estrategia().is_some() {
3973            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA);
3974        }
3975        if self.max_restarts().is_some() {
3976            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS);
3977        }
3978        if self.restart_window().is_some() {
3979            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW);
3980        }
3981        if !self.children().is_empty() {
3982            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN);
3983        }
3984        slots
3985    }
3986
3987    /// The kebab-case `:slot` tags of every M2 Servico-runtime slot this
3988    /// caixa *declares* a value on, in canonical declaration order
3989    /// (`:limits` → `:behavior` → `:upgrade-from`). A slot counts as
3990    /// declared when its backing field carries a value — a `Some(...)`,
3991    /// or a non-empty `Vec`.
3992    ///
3993    /// The M2 slots configure the runtime of a long-running wasm
3994    /// component, i.e. a `:kind Servico`: `:limits` is Lunatic
3995    /// per-process sandboxing (INSPIRATIONS §III.1), `:behavior` is the
3996    /// OTP `gen_server` callback set (§II.3), `:upgrade-from` is the OTP
3997    /// appup hot-code-reload table (§II.4). The caixa-helm / caixa-flux
3998    /// renderers gate on [`crate::require_kind`]`(_, Servico)` and only
3999    /// emit these slots for a Servico; on any *other* kind a declared M2
4000    /// slot is the manifest field's documented "ignored otherwise": its
4001    /// well-formedness is checked by [`crate::StandardLayout::verify`]
4002    /// but the value is never rendered into a chart / programs.yaml entry
4003    /// — it silently passes [`Caixa::from_lisp`] + `feira build` and then
4004    /// vanishes, far from the source caixa.lisp.
4005    /// [`crate::StandardLayout::verify`] consults this to reject that
4006    /// silent-drop at caixa-build time
4007    /// ([`crate::LayoutError::ServicoSlotsOnNonServico`]), the exact
4008    /// mirror of the [`Self::declared_mesh_slots`] /
4009    /// [`Self::declared_supervisor_slots`] gates on the peer
4010    /// kind-exclusive slot sets: a slot foreign to the kind is a build
4011    /// error, not a silent drop.
4012    ///
4013    /// Each per-arm kebab-case label is routed through the peer
4014    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
4015    /// [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts declared next to the
4016    /// [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
4017    /// [`crate::M2_KEY_UPGRADE_FROM`] renderer-side wire-key peers, so
4018    /// both halves of the M2 top-level slot's dual axis (author-facing
4019    /// kebab-case label + renderer-side camelCase overlay-container wire
4020    /// key) route through one canonical declaration per arm — same
4021    /// discipline the peer [`crate::M2_BEHAVIOR_AUTHOR_KEY_ON_*`] sub-slot
4022    /// author-label consts (889dc18) establish on the sibling
4023    /// per-callback axis inside the `:behavior` overlay block.
4024    #[must_use]
4025    pub fn declared_servico_slots(&self) -> Vec<&'static str> {
4026        let mut slots = Vec::new();
4027        if self.limits().is_some() {
4028            slots.push(crate::render::M2_AUTHOR_KEY_LIMITS);
4029        }
4030        if self.behavior().is_some() {
4031            slots.push(crate::render::M2_AUTHOR_KEY_BEHAVIOR);
4032        }
4033        if !self.upgrade_from().is_empty() {
4034            slots.push(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM);
4035        }
4036        slots
4037    }
4038
4039    /// The kebab-case `:slot` tags of every code-surface slot this caixa
4040    /// declares a value on that its [`CaixaKind`] doesn't natively own,
4041    /// in canonical declaration order (`:exe` → `:servicos`). A
4042    /// code-surface slot is owned by exactly one kind: `:exe` by
4043    /// [`CaixaKind::Binario`] (the nix-built executable surface), and
4044    /// `:servicos` by [`CaixaKind::Servico`] (the wasm component +
4045    /// `ComputeUnit` daemon surface).
4046    ///
4047    /// Each is silently ignored when declared on the wrong kind: the
4048    /// caixa-helm / caixa-flux / caixa-flake renderers gate on
4049    /// [`crate::require_kind`]`(_, <owning-kind>)`, so on any *other*
4050    /// code-running kind a declared `:exe` / `:servicos` is the manifest
4051    /// field's documented "ignored otherwise" — its path is checked for
4052    /// existence by the layout's `bibliotecas`/`exe`/`servicos` loops
4053    /// (which run after [`Caixa::from_lisp`]), but the value is never
4054    /// rendered into a build target or programs.yaml entry. It silently
4055    /// passes [`Caixa::from_lisp`] + `feira build`, far from the source
4056    /// caixa.lisp, with no field naming which slot is foreign.
4057    ///
4058    /// [`crate::StandardLayout::verify`] consults this to reject that
4059    /// silent-drop at caixa-build time
4060    /// ([`crate::LayoutError::ForeignCodeSlot`]), beside the M2
4061    /// servico-runtime, supervisor-tree, and M3 mesh kind-coherence
4062    /// gates ([`Self::declared_servico_slots`] /
4063    /// [`Self::declared_supervisor_slots`] /
4064    /// [`Self::declared_mesh_slots`]): the fourth kind ↔ slot algebra
4065    /// axis to be closed on the typed surface. The Supervisor /
4066    /// Aplicacao "no code at all" cases ([`crate::LayoutError::SupervisorOwnsCode`]
4067    /// / [`crate::LayoutError::AplicacaoOwnsCode`]) keep their dedicated
4068    /// diagnostics — they fire ahead of this gate on the same `verify`
4069    /// pass, so for Supervisor / Aplicacao the `OwnCode` arm always wins
4070    /// and this method is moot. For Biblioteca / Binario / Servico, this
4071    /// gate fires when a code-running kind declares another code-running
4072    /// kind's exclusive code surface.
4073    ///
4074    /// `:bibliotecas` is deliberately excluded — a Binario or Servico
4075    /// may legitimately ship a `lib/` helper that the underlying
4076    /// substrate (the nix flake for Binario, the wasm component build
4077    /// for Servico) bundles into its build, so the slot's
4078    /// declared-on-wrong-kind cardinality isn't a structural error on
4079    /// either code-running kind. A Biblioteca declaring `:bibliotecas`
4080    /// is the native case (the slot's owning kind). Supervisor /
4081    /// Aplicacao declaring `:bibliotecas` is gated upstream by
4082    /// [`crate::LayoutError::SupervisorOwnsCode`] /
4083    /// [`crate::LayoutError::AplicacaoOwnsCode`].
4084    ///
4085    /// Lifted as a typed method (rather than an inline disjunction at
4086    /// the verify call site) so the foreign-code-slot set lives in one
4087    /// place — a future kind that gains its own code-surface slot is
4088    /// one push here, and every consumer reaching for "which code
4089    /// surfaces are foreign to this kind" (the verify gate, a future
4090    /// `feira lint` kind-coherence advisory, the future `app-operator`'s
4091    /// per-caixa build-target classifier) inherits the canonical order
4092    /// without rolling its own.
4093    #[must_use]
4094    pub fn declared_foreign_code_slots(&self) -> Vec<&'static str> {
4095        let mut slots = Vec::new();
4096        if !self.exe().is_empty() && !self.kind().requires_exe() {
4097            slots.push(":exe");
4098        }
4099        if !self.servicos().is_empty() && !self.kind().requires_servicos() {
4100            slots.push(":servicos");
4101        }
4102        slots
4103    }
4104
4105    /// Validate every entry of `:deps` and `:deps-dev` through
4106    /// [`Dep::validate`] — closing the parity loop with the per-axis
4107    /// `:versao` gates already wired into the typed-graph
4108    /// ([`crate::AplicacaoSpec::validate_membros`] for `:membros`,
4109    /// 9888b13) and typed supervisor tree
4110    /// ([`crate::SupervisorSpec::validate`] for `:children`, b38ff3a).
4111    ///
4112    /// Until this gate landed `:deps :versao` and `:deps-dev :versao`
4113    /// were the only `:versao` axes still untyped past
4114    /// [`Caixa::from_lisp`]: the derive macro stored the requirement
4115    /// as a String without parsing it, so a malformed-but-non-empty
4116    /// requirement (`"^bad-version"`, `"^^0.1"`, `"v0.1"`, `"not-a-req"`)
4117    /// silently passed parse and the `semver::Error` surfaced at
4118    /// lacre-resolve time, far from the source caixa.lisp, with no
4119    /// field naming which `:deps` entry carried the typo. Lifting the
4120    /// gate here makes the four `:versao` typed surfaces (`:deps`,
4121    /// `:deps-dev`, `:membros`, `:children`) structurally equivalent —
4122    /// every requirement string past `validate_deps` is round-trippable
4123    /// through [`crate::parse_requirement`] without re-checking at the
4124    /// resolver layer.
4125    ///
4126    /// Both lists run through the same per-entry validator so a typo
4127    /// in `:deps-dev` surfaces with the same diagnostic as one in
4128    /// `:deps` — neither axis is a second-class citizen of the typed
4129    /// surface.
4130    ///
4131    /// Within each list, [`DepError::DuplicateNome`] closes the
4132    /// set-not-multiset discipline on the `:nome` axis: two entries
4133    /// naming the same caixa carry two `:versao` / `:fonte` / feature
4134    /// triples that the caixa-resolver's lacre pipeline collapses to one
4135    /// via its `HashMap`-keyed-by-`:nome` consumption — the second entry
4136    /// silently overwrites the first at `concrete_versao`-resolve time
4137    /// (the same "second wins / one silently overwrites the other"
4138    /// shape the peer typed-graph duplicate gates already close on every
4139    /// other Vec-shaped authoring surface that keys by name). The
4140    /// duplicate check fires per-list and runs *after* each per-entry
4141    /// [`Dep::validate`] call so a malformed-and-duplicated entry
4142    /// surfaces its narrower per-entry diagnostic
4143    /// ([`DepError::NomeInvalid`], [`DepError::VersaoInvalid`],
4144    /// [`DepError::FonteRepoEmpty`], …) before the cross-entry duplicate
4145    /// diagnostic — the canonical "per-entry shape before cross-entry
4146    /// uniqueness" precedence the peer `:children :caixa`
4147    /// ([`crate::SupervisorSpec::validate`]), `:membros :caixa`
4148    /// ([`crate::AplicacaoSpec::validate_membros`]), `:contratos`
4149    /// ([`crate::AplicacaoSpec::validate`]), `:placement :clusters`
4150    /// ([`crate::AplicacaoSpec::validate_placement`]),
4151    /// `:entrada :paths` ([`crate::AplicacaoSpec::validate`]),
4152    /// `:upgrade-from :from` ([`crate::upgrade::validate_upgrade_from`]),
4153    /// and the within-`:upgrade-from`-entry per-instruction-class
4154    /// singularity gates ([`crate::UpgradeError::DuplicateLoadModule`],
4155    /// [`crate::UpgradeError::DuplicateStateChange`],
4156    /// [`crate::UpgradeError::DuplicateCleanup`]) all establish.
4157    ///
4158    /// Cross-list (`:deps` ↔ `:deps-dev`) coincidence is *not* gated
4159    /// here: Cargo's `[dependencies]` + `[dev-dependencies]` accept the
4160    /// same name in both tables (the dev table's pin overrides the
4161    /// runtime table's pin in test/dev contexts), and caixa's surface
4162    /// mirrors that convention until a deliberate choice retires the
4163    /// override pattern. Only within-list duplicates are structurally
4164    /// incoherent — those are what this gate closes.
4165    ///
4166    /// Compound per-`Caixa` entry gate on the dep-graph axis: folds the
4167    /// two standalone dep-list validators — the per-entry + within-list
4168    /// duplicate-`:nome` walk (the [`Dep::validate`] +
4169    /// [`crate::render::insert_first_seen`] cascade this method opened
4170    /// on) and the cross-slot self-edge gate
4171    /// ([`crate::dep::validate_no_self_dep`]) — onto one substrate
4172    /// primitive on [`Caixa`]. The two arms run in the same canonical
4173    /// order the layout pipeline
4174    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4175    /// author-time gate) has always sequenced them (per-entry +
4176    /// cross-entry duplicate → cross-slot self-edge), so the fold is
4177    /// byte-for-byte equivalent to the pre-fold two-block cascade at
4178    /// that call site (pinned by the paired
4179    /// `validate_deps_folds_per_entry_arm_matches_gate` /
4180    /// `validate_deps_folds_self_edge_arm_matches_gate` equivalence
4181    /// pins and the `validate_deps_per_entry_arm_fires_before_self_edge_arm`
4182    /// ordering pin). Self-contained on `&self` — resolves its three
4183    /// inputs ([`Self::deps`], [`Self::deps_dev`], [`Self::nome`])
4184    /// through the substrate primitives' own accessor family, the same
4185    /// posture every peer per-slot compound gate
4186    /// ([`crate::AplicacaoSpec::validate_contratos`],
4187    /// [`crate::MeshPolicy::validate`],
4188    /// [`crate::SupervisorSpec::validate_children`],
4189    /// [`Self::validate_upgrade_from`]) already carries.
4190    ///
4191    /// Prior to this lift [`crate::dep::validate_no_self_dep`] lived
4192    /// only open-coded at the layout wire-up site
4193    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs)
4194    /// as a standalone two-arg dispatch immediately after this method's
4195    /// per-entry + cross-entry walk, both wrapped through the same
4196    /// [`crate::LayoutError::DepsViolation`] envelope: every future
4197    /// consumer that wanted to gate the dep-graph as a whole — the
4198    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4199    /// per-CR admission webhook re-checking `:deps` / `:deps-dev` after
4200    /// a per-entry patch, a future `feira validate --deps` per-caixa
4201    /// admission verb, a per-`:deps` overlay resolver a per-cluster
4202    /// overlay lift would materialize (each the deferred consumer this
4203    /// method's peer [`Self::deps`] / [`Self::deps_dev`] accessors'
4204    /// docstrings already name) — was structurally forced to either
4205    /// re-inline the two-dispatch cascade in lockstep with the layout
4206    /// wire-up (the duplication the PRIME DIRECTIVE names as a bug) or
4207    /// call the whole [`crate::layout::StandardLayout::verify`] pipeline
4208    /// and pay every peer per-Caixa gate to re-check one slot. Post-fold
4209    /// each such consumer reaches the two-arm compound gate through one
4210    /// call on the substrate primitive.
4211    pub fn validate_deps(&self) -> Result<(), DepError> {
4212        for &list in crate::dep::DepList::ALL {
4213            let mut seen = std::collections::HashSet::new();
4214            for dep in self.deps_of(list) {
4215                dep.validate()?;
4216                crate::render::insert_first_seen(&mut seen, dep.nome(), || {
4217                    DepError::DuplicateNome {
4218                        nome: dep.nome().to_string(),
4219                        list: list.as_str(),
4220                    }
4221                })?;
4222            }
4223        }
4224        crate::dep::validate_no_self_dep(self.deps(), self.deps_dev(), self.nome())?;
4225        Ok(())
4226    }
4227
4228    /// Reject `:nome` values the K8s apiserver would refuse at admission
4229    /// time. The top-level Caixa identity flows directly into every
4230    /// substrate-side artifact's `metadata.name` axis: the
4231    /// `lareira-<nome>` Helm chart name ([`caixa-helm::lib::chart_name`]),
4232    /// the programs.yaml `name:` entry the `lareira-fleet-programs`
4233    /// aggregator keys ComputeUnit derivation off
4234    /// ([`caixa-flux::lib::programs_yaml_entry`]), the
4235    /// `LABEL_APLICACAO` label value carried on every Aplicacao-owned
4236    /// pod and the per-`:contratos` CiliumNetworkPolicy `metadata.name`
4237    /// (`<aplicacao>-<de>-to-<para>`) and the per-`:entrada`
4238    /// `<aplicacao>-<para>` HTTPRoute `metadata.name`
4239    /// ([`caixa-mesh::lib::cilium_network_policies`],
4240    /// [`caixa-mesh::lib::gateway_routes`]), and the default
4241    /// `lib/<nome>.lisp` / `exe/<nome>` layout paths
4242    /// ([`crate::StandardLayout::verify`]). Each K8s apiserver-side
4243    /// schema enforces the DNS-1123 label rule on admission; a
4244    /// structurally invalid `:nome` (`"MyApp"` — the canonical
4245    /// "I copied the display name verbatim" footgun, `"my_app"` — the
4246    /// Python-/Postgres-leak, `"team.app"` — `:nome` is a single label
4247    /// not a subdomain, `"-app"` / `"app-"` — DNS-1123 boundary
4248    /// violations, `"my app"` — the paste-from-doc footgun, `"café"` —
4249    /// IDN must be pre-encoded as Punycode, the 64-byte UUID-shaped
4250    /// over-cap slug) silently passed [`Caixa::from_lisp`] and the
4251    /// failure surfaced at `kubectl apply` time as a `metadata.name:
4252    /// Invalid value` rejection on whichever derived artifact admitted
4253    /// first, far from the source `caixa.lisp` and without any field
4254    /// naming the offending `:nome`.
4255    ///
4256    /// Thin wrapper around [`crate::render::is_dns_1123_label`] (the
4257    /// substrate-side predicate the per-axis name gates already share:
4258    /// `:membros :caixa` 3f9d7a0, `:placement :clusters` 6cbb900,
4259    /// `:children :caixa` 31bfa43) that maps the shared parser-shaped
4260    /// reason into the [`ManifestError::NomeInvalid`] variant, so the
4261    /// diagnostic is self-locating (the offending `:nome` is named
4262    /// verbatim) and the author can grep their `caixa.lisp` for
4263    /// `:nome "<value>"` and fix it in one edit. Same diagnostic shape
4264    /// every per-axis sibling gate already exposes
4265    /// ([`crate::AplicacaoError::MembroCaixaInvalid`],
4266    /// [`crate::AplicacaoError::PlacementClusterInvalid`],
4267    /// [`crate::SupervisorError::ChildCaixaInvalid`]).
4268    ///
4269    /// Empty `:nome` (which [`Caixa::from_lisp`] does not reject — the
4270    /// derive macro stores the raw String) is gated by the narrower
4271    /// [`ManifestError::NomeEmpty`] arm before the predicate is
4272    /// consulted, mirroring the empty-first cascade every per-axis
4273    /// name gate already uses (e.g. `MembroCaixaEmpty` before
4274    /// `MembroCaixaInvalid`, `EmptyChildName` before `ChildCaixaInvalid`).
4275    pub fn validate_nome(&self) -> Result<(), ManifestError> {
4276        // Routes through the shared
4277        // [`crate::render::require_valid_dns_1123_label`] gate the peer
4278        // name axes each land on so drift between the eight axes'
4279        // accepted DNS-1123-label sets is structurally impossible.
4280        let nome = self.nome();
4281        crate::render::require_valid_dns_1123_label(
4282            nome,
4283            || ManifestError::NomeEmpty,
4284            |reason| ManifestError::NomeInvalid {
4285                nome: nome.to_string(),
4286                reason,
4287            },
4288        )
4289    }
4290
4291    /// Reject `:nome` values whose joint length with the canonical
4292    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] (`"lareira-"`) overflows
4293    /// the K8s DNS-1123 label cap [`crate::DNS_1123_LABEL_MAX_LEN`]
4294    /// (63 bytes). Every per-Servico / per-Aplicacao renderer the
4295    /// substrate carries materializes the caixa's `:nome` through the
4296    /// canonical [`crate::lareira_chart_name`] helper (f7320d7) into a
4297    /// `lareira-<nome>` artifact that lands as a K8s `metadata.name` /
4298    /// Helm chart name / `HelmRelease` `release_name`: `caixa-helm`'s
4299    /// `ChartDir.name` + `Chart.yaml::name`
4300    /// (caixa-helm/src/lib.rs:207), `caixa-flux`'s `cluster_bundle`
4301    /// `HelmRelease` `chart:` slot (caixa-flux/src/lib.rs:329),
4302    /// `caixa-tatara`'s `process_for_aplicacao` `release_name` +
4303    /// `oci://<registry>/lareira-<nome>` chart ref
4304    /// (caixa-tatara/src/lib.rs:124,178). Helm's own `Chart.yaml::name`
4305    /// admission rule strict-parses against DNS-1123-label, the Helm
4306    /// operator's tracking-secret name is derived from `release_name`
4307    /// and is itself DNS-1123-label-bounded, and the rendered chart's
4308    /// K8s object `metadata.name` axes embed the chart name as a
4309    /// prefix — every one fails admission on a > 63-byte chart name.
4310    ///
4311    /// The per-axis [`Self::validate_nome`] gate (6c992f8) already
4312    /// caps `:nome` itself at 63 bytes via [`is_dns_1123_label`], so a
4313    /// `:nome` of 56–63 bytes silently passed validate (the inner
4314    /// DNS-1123 check accepts the bare `:nome`) but produced a
4315    /// `lareira-<nome>` of 64–71 bytes that the apiserver / `helm lint`
4316    /// rejected at admission — far from the source `caixa.lisp`, with
4317    /// no field naming the overflow root cause. The
4318    /// [`lareira_chart_name`] helper's own doc comment
4319    /// (caixa-core/src/render.rs:3198) explicitly deferred the fix:
4320    /// "the M4 admission webhook will pin the joint-length invariant
4321    /// when it lands". This gate lands the invariant at the
4322    /// manifest-validate layer rather than waiting for the apiserver
4323    /// — the same fail-at-the-source posture every peer per-axis
4324    /// value-shape gate (DNS-1123 on `:nome`, SemVer-2 on `:versao`,
4325    /// SPDX-expression-shape on `:licenca`, 4-digit decimal year on
4326    /// `:edicao`, etc.) takes.
4327    ///
4328    /// Thin wrapper around
4329    /// [`crate::render::is_lareira_chart_name_shape`] (the
4330    /// substrate-side predicate that composes [`lareira_chart_name`] +
4331    /// [`is_dns_1123_label`] via the lifted
4332    /// [`crate::LAREIRA_CHART_NAME_NOME_MAX_LEN`] budget); maps the
4333    /// shared parser-shaped reason into the
4334    /// [`ManifestError::NomeChartNameBudgetExceeded`] variant so the
4335    /// diagnostic is self-locating (the offending `:nome` is named
4336    /// verbatim alongside the rendered chart name and the budget) and
4337    /// the author can shorten in one edit. The gate runs across every
4338    /// `:kind` — `:nome` is the substrate-wide identity axis any
4339    /// future renderer the substrate adds can derive a
4340    /// `lareira-<nome>` artifact from, and uniform enforcement closes
4341    /// the drift footgun where a future kind grows a chart-emitting
4342    /// render path while the validate cascade doesn't catch it.
4343    ///
4344    /// Runs *after* [`Self::validate_nome`] so the narrower
4345    /// `NomeEmpty` / `NomeInvalid` shape diagnostics fire first — a
4346    /// structurally-malformed `:nome` (empty, uppercase, underscore,
4347    /// dot, leading/trailing hyphen, Unicode, > 63 bytes) surfaces its
4348    /// specific shape error rather than the chart-name-budget error,
4349    /// preserving the legitimate "well-shaped `:nome` that happens to
4350    /// overflow the joint cap" arm for this gate.
4351    pub fn validate_nome_chart_name_budget(&self) -> Result<(), ManifestError> {
4352        let nome = self.nome();
4353        crate::render::is_lareira_chart_name_shape(nome).map_err(|reason| {
4354            ManifestError::NomeChartNameBudgetExceeded {
4355                nome: nome.to_string(),
4356                reason,
4357            }
4358        })
4359    }
4360
4361    /// Reject `:versao` values that don't parse as [`semver::Version`].
4362    /// The top-level Caixa version flows directly into every
4363    /// substrate-side artifact that carries a "this is which version of
4364    /// the caixa" axis: the `lareira-<nome>` Helm chart's `Chart.yaml`
4365    /// `version:` + `appVersion:` axes ([`caixa-helm::lib`] —
4366    /// SemVer-2-strict at `helm template` / `helm install` time per
4367    /// https://helm.sh/docs/topics/charts/#charts-and-versioning), the
4368    /// `feira publish` Zig-style `v<versao>` git tag
4369    /// ([`caixa-flux::lib::programs_yaml_entry`] / the
4370    /// `caixa-publish.yml` reusable workflow), the programs.yaml entry's
4371    /// `versao:` value the `lareira-fleet-programs` aggregator carries
4372    /// onto each rendered ComputeUnit, the OCI image's `:v<versao>` /
4373    /// `:latest` tags the substrate's `wasi-service-flake` builds with
4374    /// `skopeo push`, the lacre closure's pinned versions
4375    /// ([`caixa-resolver`] keys `concrete_versao`), and the
4376    /// `:upgrade-from :from` references peers in this exact `versao`
4377    /// shape (`semver::Version`, not `VersionReq`). Each consumer
4378    /// expects a strict three-part `MAJOR.MINOR.PATCH` (optionally
4379    /// `-prerelease` and/or `+build`); a structurally invalid `:versao`
4380    /// (`"0.1"` — missing patch, the canonical "I shortened it" footgun;
4381    /// `"v0.1.0"` — the git-tag-shape-leaking-into-versao typo;
4382    /// `"latest"` / `"main"` — the "I confused it with a docker tag"
4383    /// footgun; `"^0.1"` / `"~0.1.2"` — the requirement-shape leaking
4384    /// into the version field a peer `:deps :versao` accepts;
4385    /// `"0.1.0.0"` — the four-part Java/Microsoft convention DNS
4386    /// SemVer-2 forbids) silently passed [`Caixa::from_lisp`] (the
4387    /// derive macro stores the raw String) and the failure surfaced at
4388    /// the *first* downstream consumer that strict-parses it: at
4389    /// `helm install` time as a chart-version rejection, at
4390    /// `feira publish` time as a malformed git tag, at lacre-resolve
4391    /// time as a `semver::Error` not naming the offending caixa, at
4392    /// `feira upgrade --to <versao>` time as an unresolvable
4393    /// `:upgrade-from :from` match — far from the source `caixa.lisp`
4394    /// and without any field naming the offending `:versao`.
4395    ///
4396    /// Thin wrapper around [`semver::Version::parse`] — the same parser
4397    /// [`crate::CaixaVersion::parse`] (the typed `:versao` accessor)
4398    /// and [`crate::UpgradeFromEntry::validate`] (the peer
4399    /// `:upgrade-from :from` axis, 26da2c7) consume. Maps the
4400    /// `semver::Error` reason into the [`ManifestError::VersaoInvalid`]
4401    /// variant, carrying the offending `:versao` verbatim + a
4402    /// parser-shaped reason naming the specific violation, so the
4403    /// diagnostic is self-locating (the author can grep their
4404    /// `caixa.lisp` for `:versao "<value>"` and fix it in one edit).
4405    /// Same diagnostic shape as [`ManifestError::NomeInvalid`]
4406    /// (6c992f8) and [`crate::UpgradeError::FromInvalid`]
4407    /// (b0c8389) on the peer axes. With this gate, the typed `:versao`
4408    /// surfaces — top-level `:versao`, `:upgrade-from :from` — are
4409    /// now structurally equivalent (every value past validate is
4410    /// round-trippable through [`semver::Version::parse`] without
4411    /// re-checking at the renderer, resolver, or operator hot-upgrade
4412    /// layer), peer with the four `:versao` requirement axes (`:deps`,
4413    /// `:deps-dev`, `:membros`, `:children`) the prior commits
4414    /// (2420c44, 9888b13, b38ff3a) wired through `parse_requirement`.
4415    ///
4416    /// Empty `:versao` (which [`Caixa::from_lisp`] does not reject —
4417    /// the derive macro stores the raw String) is gated by the
4418    /// narrower [`ManifestError::VersaoEmpty`] arm before the parser is
4419    /// consulted, mirroring the empty-first cascade every per-axis
4420    /// version gate already uses (e.g. `MembroVersaoEmpty` before
4421    /// `MembroVersaoInvalid`, `EmptyChildVersion` before
4422    /// `ChildVersaoInvalid`, `NomeEmpty` before `NomeInvalid`).
4423    pub fn validate_versao(&self) -> Result<(), ManifestError> {
4424        let versao = self.versao();
4425        if versao.is_empty() {
4426            return Err(ManifestError::VersaoEmpty);
4427        }
4428        semver::Version::parse(versao).map_err(|e| ManifestError::VersaoInvalid {
4429            versao: versao.to_string(),
4430            reason: e.to_string(),
4431        })?;
4432        Ok(())
4433    }
4434
4435    /// Compound per-`Caixa` entry gate on the M2 `:upgrade-from` slot:
4436    /// folds the three [`crate::upgrade`] top-level validators — the
4437    /// per-entry shape + cross-entry duplicate-`:from` gate
4438    /// ([`crate::upgrade::validate_upgrade_from`]), the cross-slot
4439    /// `:from < :versao` SemVer-2 precedence gate
4440    /// ([`crate::upgrade::validate_upgrade_from_against_versao`]), and the
4441    /// cross-slot `:state-change` ↔ `:on-state-change` composition gate
4442    /// ([`crate::upgrade::validate_upgrade_from_against_behavior`]) — onto
4443    /// one substrate primitive on [`Caixa`]. The three dispatches run in
4444    /// the same order the layout pipeline
4445    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4446    /// author-time gate) has always sequenced them, so the fold is
4447    /// byte-for-byte equivalent to the pre-fold three-block cascade at
4448    /// that call site (pinned by the per-arm
4449    /// `validate_upgrade_from_folds_per_entry_arm_matches_gate` /
4450    /// `_folds_versao_arm_matches_gate` / `_folds_behavior_arm_matches_gate`
4451    /// equivalence pins and by the cross-arm
4452    /// `validate_upgrade_from_per_entry_arm_fires_before_versao_arm` /
4453    /// `_versao_arm_fires_before_behavior_arm` ordering pins).
4454    ///
4455    /// Prior to this lift the three [`crate::upgrade`] top-level validators
4456    /// lived only open-coded at the layout wire-up site
4457    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4458    /// each threaded through the same `self.upgrade_from()` slice and each
4459    /// paired with the same [`crate::LayoutError::UpgradeViolation`]-wrap
4460    /// envelope: every future consumer that wanted to gate `:upgrade-from`
4461    /// as a whole — the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
4462    /// materializer's per-CR admission webhook re-checking `:upgrade-from`
4463    /// after a per-`(:from … :instructions …)` patch, a future `feira
4464    /// validate --upgrade` per-caixa admission verb, a per-`:upgrade-from`
4465    /// overlay resolver a per-cluster overlay lift would materialize —
4466    /// was structurally forced to either re-inline the three-dispatch
4467    /// cascade in lockstep with the layout wire-up (the duplication the
4468    /// PRIME DIRECTIVE names as a bug) or call the whole
4469    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4470    /// peer per-Caixa gate to re-check one slot. Post-fold each such
4471    /// consumer reaches the three-arm compound gate through one call on
4472    /// the substrate primitive.
4473    ///
4474    /// The three arms together name one contract with three axes:
4475    ///
4476    ///   - **per-entry + cross-entry graph-edge invariant** — every entry's
4477    ///     `:from` parses as SemVer-2 and every per-instruction / within-
4478    ///     entry ordering / singularity gate on each entry's
4479    ///     `:instructions` list passes, and no two entries share the same
4480    ///     parsed `:from` (the wasm-operator's OTP appup
4481    ///     `release_handler:install_release/1` analog picks at most one
4482    ///     matching block per running version — two entries with the same
4483    ///     parsed semver are an ambiguous edge in the typed upgrade graph).
4484    ///   - **cross-slot reachability invariant** — every entry's `:from`
4485    ///     is strictly less than the caixa's own `:versao` under SemVer-2
4486    ///     precedence. An entry whose `:from >= :versao` is structurally
4487    ///     unreachable by the operator's `:from`-match dispatch (the
4488    ///     operator loads the current `:versao` and matches the *running*
4489    ///     version against each entry's `:from`; an entry whose `:from >=
4490    ///     :versao` is never reached because the operator never runs a
4491    ///     version >= the current one that it could then upgrade *to* the
4492    ///     current one).
4493    ///   - **cross-slot composition invariant** — every entry carrying a
4494    ///     `(:state-change …)` instruction has a `:behavior
4495    ///     :on-state-change` callback declared on the same caixa. The
4496    ///     per-version migration script is the `gen_server:code_change/3`
4497    ///     analog and the runtime hook it is delivered through during hot
4498    ///     upgrade is the `:on-state-change` callback (the upgrade.rs
4499    ///     module doc pins the composition verbatim: "Composes with the
4500    ///     `:behavior :on-state-change` callback to deliver state migration
4501    ///     during hot upgrades").
4502    ///
4503    /// All three axes must hold together — every consumer's
4504    /// `:upgrade-from` accept-set past this compound gate is the same
4505    /// set the `feira build` author-time gate admits.
4506    ///
4507    /// The per-slot compound entry gate discipline lifted here onto the
4508    /// M2 `:upgrade-from` axis is the sibling of the peer per-kind
4509    /// compound entry gates ([`crate::render::require_supervisor_view`]
4510    /// / [`crate::render::require_aplicacao_view`] /
4511    /// [`crate::render::require_v0_servico_shape`]) that fold every
4512    /// per-kind cascade at the per-kind altitude, and of the peer
4513    /// per-slot compound gates ([`crate::AplicacaoSpec::validate_contratos`],
4514    /// [`crate::MeshPolicy::validate`],
4515    /// [`crate::SupervisorSpec::validate_children`]) that fold every
4516    /// structural axis on their slot onto one substrate primitive.
4517    /// Extended here to the last unlifted compound-cascade wire-up at
4518    /// the layout-pipeline altitude — the three-dispatch M2
4519    /// `:upgrade-from` cascade that lived only open-coded at the layout
4520    /// wire-up site.
4521    ///
4522    /// The per-instruction script-path on-disk existence-probe walk that
4523    /// [`crate::layout::StandardLayout::verify`] runs immediately after
4524    /// this gate (which resolves each entry's `:instructions
4525    /// (:state-change :script)` against the layout root) stays open-coded
4526    /// at the layout wire-up site — that arm needs the filesystem oracle
4527    /// on the [`crate::LayoutInvariants`] trait, not the pure per-Caixa
4528    /// typed-shape surface this compound gate folds. Same posture the
4529    /// peer [`Self::validate_code_paths`] takes on the sibling code-path
4530    /// axes: the typed-shape gate fires on the per-Caixa surface, the
4531    /// on-disk existence check fires on the [`crate::StandardLayout`]
4532    /// surface.
4533    ///
4534    /// # Errors
4535    ///
4536    /// Returns [`crate::UpgradeError::FromInvalid`] /
4537    /// [`crate::UpgradeError::ModuleEmpty`] /
4538    /// [`crate::UpgradeError::ModuleInvalid`] /
4539    /// [`crate::UpgradeError::EmptyScript`] /
4540    /// [`crate::UpgradeError::AbsoluteScript`] /
4541    /// [`crate::UpgradeError::ParentEscapeScript`] /
4542    /// [`crate::UpgradeError::NonLispExtensionScript`] /
4543    /// [`crate::UpgradeError::RestartNotExclusive`] /
4544    /// [`crate::UpgradeError::StateChangeWithoutPriorLoad`] /
4545    /// [`crate::UpgradeError::PurgeWithoutPriorLoad`] /
4546    /// [`crate::UpgradeError::StateChangeAfterCleanup`] /
4547    /// [`crate::UpgradeError::DuplicateLoadModule`] /
4548    /// [`crate::UpgradeError::DuplicateStateChange`] /
4549    /// [`crate::UpgradeError::DuplicateCleanup`] /
4550    /// [`crate::UpgradeError::DuplicateFrom`] on the per-entry +
4551    /// cross-entry axis; [`crate::UpgradeError::FromNotBeforeVersao`] on
4552    /// the cross-slot `:from ↔ :versao` axis;
4553    /// [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
4554    /// on the cross-slot `:state-change ↔ :on-state-change` axis.
4555    pub fn validate_upgrade_from(&self) -> Result<(), crate::UpgradeError> {
4556        crate::upgrade::validate_upgrade_from(self.upgrade_from())?;
4557        crate::upgrade::validate_upgrade_from_against_versao(self.upgrade_from(), self.versao())?;
4558        crate::upgrade::validate_upgrade_from_against_behavior(
4559            self.upgrade_from(),
4560            self.behavior(),
4561        )?;
4562        Ok(())
4563    }
4564
4565    /// Compound per-`Caixa` entry gate on the M2 `:limits` slot — folds
4566    /// the [`crate::LimitsSpec::validate`] four-axis cascade (`:memory`
4567    /// wasm32 zero-floor / below-page / above-cap / non-page-multiple;
4568    /// `:fuel` zero-floor / cap; `:wall-clock` zero-floor / cap; `:cpu`
4569    /// zero-floor / cap) onto one substrate primitive on [`Caixa`]. The
4570    /// `#[serde(default)]` absent-slot arm (`limits: None`, the
4571    /// canonical "no bound declared — engine-default applies" author
4572    /// shape [`crate::LimitsSpec::is_empty`]'s per-axis `None` cascade
4573    /// reads) is the fold's identity element and passes trivially; the
4574    /// present-slot arm (`limits: Some(l)`) dispatches to
4575    /// [`crate::LimitsSpec::validate`] verbatim, threading its per-axis
4576    /// [`crate::LimitsError`] Display through untouched.
4577    ///
4578    /// Prior to this lift the M2 `:limits` slot lived only wired
4579    /// open-coded at the layout wire-up site
4580    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4581    /// through the `if let Some(l) = caixa.limits() { l.validate() … }`
4582    /// three-line `Option::None → Ok(()) | Some(_) → …` unwrap-and-
4583    /// dispatch pattern paired with the same
4584    /// [`crate::LayoutError::LimitsViolation`]-wrap envelope: every
4585    /// future consumer that wanted to gate `:limits` as a whole — the
4586    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4587    /// per-CR admission webhook re-checking `:limits` after a per-
4588    /// `{:memory, :fuel, :wall-clock, :cpu}` patch (the exact case the
4589    /// [`Self::limits`] accessor docstring names as the second
4590    /// consumer of the slot), a future `feira validate --limits` per-
4591    /// caixa admission verb, a per-`:limits` overlay resolver a per-
4592    /// cluster `:limits-overrides` overlay lift would materialize — was
4593    /// structurally forced to either re-inline the two-line
4594    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4595    /// pattern in lockstep with the layout wire-up (the duplication the
4596    /// PRIME DIRECTIVE names as a bug) or call the whole
4597    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4598    /// peer per-Caixa gate ([`Self::validate_nome`],
4599    /// [`Self::validate_versao`], [`Self::validate_deps`],
4600    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4601    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4602    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4603    /// [`Self::validate_upgrade_from`], [`Self::validate_code_paths`],
4604    /// plus the per-kind `require_supervisor_view` /
4605    /// `require_aplicacao_view` gates, plus the on-disk existence
4606    /// walks) to re-check one slot. Post-lift each such consumer
4607    /// reaches the [`crate::LimitsSpec::validate`] four-axis cascade
4608    /// (and its identity-element on the absent slot) through one call
4609    /// on the substrate primitive.
4610    ///
4611    /// The per-slot compound entry-gate discipline lifted here onto the
4612    /// M2 `:limits` axis is the sibling of the peer per-slot compound
4613    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4614    /// [`crate::MeshPolicy::validate`],
4615    /// [`crate::SupervisorSpec::validate_children`],
4616    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`]) that
4617    /// fold every structural + cross-slot axis on their slot onto one
4618    /// substrate primitive. Extended here to the M2 `:limits` slot, the
4619    /// first of the two M2 typed slots (`:limits`, `:behavior`) whose
4620    /// per-Caixa compound-gate wire-up still lived open-coded at the
4621    /// layout altitude after the [`Self::validate_upgrade_from`] lift
4622    /// (d6801df) closed the sibling M2 slot's cascade.
4623    ///
4624    /// # Errors
4625    ///
4626    /// Returns every [`crate::LimitsError`] variant on the present-slot
4627    /// arm — verbatim from [`crate::LimitsSpec::validate`]. Passes
4628    /// trivially on the absent-slot arm (`limits: None`, the fold's
4629    /// identity element).
4630    pub fn validate_limits(&self) -> Result<(), crate::LimitsError> {
4631        match self.limits() {
4632            Some(l) => l.validate(),
4633            None => Ok(()),
4634        }
4635    }
4636
4637    /// Compound per-`Caixa` entry gate on the M2 `:behavior` slot's
4638    /// pure typed-shape surface — folds the
4639    /// [`crate::BehaviorSpec::validate`] six-slot value-shape cascade
4640    /// (each declared `:on-init` / `:on-call` / `:on-cast` / `:on-info`
4641    /// / `:on-state-change` / `:on-terminate` callback-path is
4642    /// non-empty / relative / no-`..`-parent-escape / terminating-
4643    /// `.lisp`-extension, routed through the shared
4644    /// [`crate::render::require_sandboxed_lisp_path`] arm-set) onto one
4645    /// substrate primitive on [`Caixa`]. The `#[serde(default)]`
4646    /// absent-slot arm (`behavior: None`, the canonical "no callback
4647    /// declared — the runtime falls back to the wasm-engine's default
4648    /// callback per arm" author shape [`crate::BehaviorSpec::is_empty`]'s
4649    /// per-slot `None` cascade reads) is the fold's identity element
4650    /// and passes trivially; the present-slot arm (`behavior: Some(b)`)
4651    /// dispatches to [`crate::BehaviorSpec::validate`] verbatim,
4652    /// threading its per-slot [`crate::BehaviorError`] Display through
4653    /// untouched.
4654    ///
4655    /// Scope note — the on-disk callback-path existence walk paired
4656    /// with the value-shape gate at
4657    /// [`crate::layout::StandardLayout::verify`] stays open-coded at
4658    /// the layout altitude, because it needs the
4659    /// [`crate::layout::LayoutInvariants`] filesystem oracle
4660    /// ([`crate::layout::LayoutInvariants::exists`]) that the pure
4661    /// per-Caixa typed-shape surface this compound gate folds onto has
4662    /// no reference to. Same posture the peer M2 `:upgrade-from`
4663    /// per-Caixa compound gate ([`Self::validate_upgrade_from`]
4664    /// d6801df) already carries: the pure typed-shape surface folds
4665    /// onto the substrate primitive; the per-instruction script-path
4666    /// existence probe on the paired axis (there `:state-change
4667    /// :script`; here `:on-*`) stays at the layout altitude.
4668    ///
4669    /// Prior to this lift the pure value-shape surface of the M2
4670    /// `:behavior` slot lived only wired open-coded at the layout
4671    /// wire-up site ([`crate::layout::StandardLayout::verify`],
4672    /// caixa-core/src/layout.rs), through the
4673    /// `if let Some(b) = caixa.behavior() { b.validate() … }`
4674    /// unwrap-and-dispatch pattern paired with the same
4675    /// [`crate::LayoutError::BehaviorViolation`]-wrap envelope: every
4676    /// future consumer that wanted to gate the `:behavior` slot's
4677    /// value-shape as a whole — the deferred
4678    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
4679    /// admission webhook re-checking `:behavior` after a per-`{:on-init,
4680    /// :on-call, :on-cast, :on-info, :on-state-change, :on-terminate}`
4681    /// patch (the exact case the peer `:on-*` accessor docstrings on
4682    /// [`crate::BehaviorSpec`] already name as deferred consumers of
4683    /// the slot), a future `feira validate --behavior` per-caixa
4684    /// admission verb, a per-`:behavior` overlay resolver a future
4685    /// per-cluster callback-overlay lift would materialize — was
4686    /// structurally forced to either re-inline the two-line
4687    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4688    /// pattern in lockstep with the layout wire-up (the duplication the
4689    /// PRIME DIRECTIVE names as a bug) or call the whole
4690    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4691    /// peer per-Caixa gate ([`Self::validate_nome`],
4692    /// [`Self::validate_versao`], [`Self::validate_deps`],
4693    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4694    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4695    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4696    /// [`Self::validate_limits`], [`Self::validate_upgrade_from`],
4697    /// [`Self::validate_code_paths`], plus the per-kind
4698    /// `require_supervisor_view` / `require_aplicacao_view` gates, plus
4699    /// the on-disk existence walks) to re-check one slot. Post-lift
4700    /// each such consumer reaches the [`crate::BehaviorSpec::validate`]
4701    /// six-slot cascade (and its identity-element on the absent slot)
4702    /// through one call on the substrate primitive.
4703    ///
4704    /// The per-slot compound entry-gate discipline lifted here onto the
4705    /// M2 `:behavior` axis is the sibling of the peer per-slot compound
4706    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4707    /// [`crate::MeshPolicy::validate`],
4708    /// [`crate::SupervisorSpec::validate_children`],
4709    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`],
4710    /// [`Self::validate_limits`]) that fold every structural + cross-
4711    /// slot axis on their slot onto one substrate primitive. Extended
4712    /// here to the M2 `:behavior` slot, the last of the four M2 typed
4713    /// slots (`:limits`, `:behavior`, `:upgrade-from`, plus the
4714    /// supervisor-only `:children` peer) whose per-Caixa compound-gate
4715    /// wire-up still lived open-coded at the layout altitude after the
4716    /// [`Self::validate_limits`] lift (baa4688) closed the sibling M2
4717    /// `:limits` slot's cascade. With this lift the "one named per-slot
4718    /// / per-Caixa compound gate per typed slot folding every structural
4719    /// axis on that slot (plus the `Option::None` identity element for
4720    /// the `Option`-shaped slots) onto one substrate primitive"
4721    /// discipline spans every M2 typed slot uniformly, so a reader who
4722    /// has learned any peer M2 gate reads `:behavior` without a per-
4723    /// slot exception carve-out.
4724    ///
4725    /// # Errors
4726    ///
4727    /// Returns every [`crate::BehaviorError`] variant on the present-
4728    /// slot arm — verbatim from [`crate::BehaviorSpec::validate`].
4729    /// Passes trivially on the absent-slot arm (`behavior: None`, the
4730    /// fold's identity element).
4731    pub fn validate_behavior(&self) -> Result<(), crate::BehaviorError> {
4732        match self.behavior() {
4733            Some(b) => b.validate(),
4734            None => Ok(()),
4735        }
4736    }
4737
4738    /// Reject `:restart-window` values the shared
4739    /// [`crate::supervisor::duration_codec::parse`] refuses. The flat
4740    /// `restart_window: Option<String>` slot on [`Caixa`] is stored
4741    /// raw by the derive macro (the typed [`SupervisorSpec`] holds an
4742    /// `Option<Duration>` routed through the shared codec via `with =
4743    /// "duration_codec"`); the inline `Caixa → SupervisorSpec`
4744    /// view-construction path ([`Self::supervisor_view`]) folds the
4745    /// raw string through the same shared codec and soft-swallows the
4746    /// parse error as `None` to keep the view best-effort. Without
4747    /// this gate a malformed `:restart-window` (`"1.5s"` — the
4748    /// fractional-seconds drift class; `"1.0s"` — the decimal-shaped
4749    /// integer drift; `"0.5m"` — the unit-fraction drift; `"+30s"` /
4750    /// `"-30s"` — the leading-sign drift; `"30x"` — the unknown-unit
4751    /// footgun; `"abc"` — pure garbage; `""` — the empty-after-trim
4752    /// edge case) silently produced a `SupervisorSpec` with
4753    /// `restart_window: None`, indistinguishable from the canonical
4754    /// "omit the slot to express no reset" authoring shape — Erlang/OTP's
4755    /// `MaxIntensity / Period` invariant turns into a never-reset
4756    /// supervisor far from the source `caixa.lisp`, with no field
4757    /// naming the offending `:restart-window`. Lifting the gate to a
4758    /// Caixa-level validator mirrors the trajectory of the peer
4759    /// per-axis identity gates ([`Self::validate_nome`] 6c992f8,
4760    /// [`Self::validate_versao`] 1fdaa02, [`Self::validate_deps`]
4761    /// a7f0d8c) and the ABSORPTION-ROADMAP.md M2.2 test pin
4762    /// (line 196: "reject invalid `:restart-window` (non-duration)").
4763    ///
4764    /// Thin wrapper around [`crate::supervisor::duration_codec::parse`]
4765    /// (the shared codec backing `:supervisor :restart-window` as
4766    /// serde-routed on [`SupervisorSpec`], `:politicas :timeout`, and
4767    /// `:politicas :circuit-breaker :window` — all three covered by
4768    /// the integer-magnitude gate 1c55a2a). Maps the codec's parse
4769    /// error verbatim into the [`ManifestError::RestartWindowMalformed`]
4770    /// variant, carrying the offending raw string + a parser-shaped
4771    /// reason naming the canonical authoring form, so the diagnostic
4772    /// is self-locating (the author can grep their `caixa.lisp` for
4773    /// `:restart-window "<value>"` and fix it in one edit) and
4774    /// uniform with every other manifest-level validate diagnostic.
4775    /// With this gate the four `:restart-window`-shaped surfaces (the
4776    /// flat raw string on [`Caixa`], the typed `Option<Duration>` on
4777    /// [`SupervisorSpec`], the two `MeshPolicy` peer durations) are
4778    /// now structurally equivalent — every value past the codec is in
4779    /// one accepted set, by construction.
4780    ///
4781    /// `None` (the canonical "omit the slot to express no reset"
4782    /// shape) is accepted trivially — the gate is a no-op when the
4783    /// author didn't author a window. The empty string is rejected by
4784    /// the shared codec (its digit-only gate refuses an empty
4785    /// magnitude), surfacing the same `RestartWindowMalformed`
4786    /// diagnostic as every other rejected non-canonical shape.
4787    pub fn validate_restart_window(&self) -> Result<(), ManifestError> {
4788        let Some(s) = self.restart_window() else {
4789            return Ok(());
4790        };
4791        crate::supervisor::duration_codec::parse(s)
4792            .map(|_| ())
4793            .map_err(|reason| ManifestError::RestartWindowMalformed {
4794                restart_window: s.to_string(),
4795                reason,
4796            })
4797    }
4798
4799    /// Reject per-entry values on the three Caixa-level code-surface
4800    /// path lists (`:bibliotecas`, `:exe`, `:servicos`) that the
4801    /// layout checker's `root.join(p)` sandbox would silently subvert.
4802    /// Same three structural footguns the peer
4803    /// [`BehaviorSpec::validate`] (b0c8389) and
4804    /// [`crate::UpgradeInstruction::validate`] `StateChange` arm
4805    /// (26da2c7) already close on the M2 `:behavior :on-*` and
4806    /// `:upgrade-from :state-change :script` axes, here lifted onto
4807    /// the three top-level code-path axes through the shared
4808    /// [`is_sandboxed_relative_path`] predicate:
4809    ///
4810    ///   - empty entry (`(:bibliotecas (""))` / `(:exe (""))` /
4811    ///     `(:servicos (""))`): `PathBuf::new()` round-trips through
4812    ///     [`Path::join`] as the base itself — `root.join("")` ==
4813    ///     `root`, so the existence check (`self.exists(&root)`)
4814    ///     trivially passes (the project root exists), and the layout
4815    ///     silently treats the project root as a biblioteca / exe /
4816    ///     servico entry. The `:bibliotecas` loop then hands the root
4817    ///     to `tatara_lisp::read` at `feira build` time as if the root
4818    ///     directory itself were a Lisp source file — a parse error
4819    ///     far from the source `caixa.lisp` with no field naming the
4820    ///     offending entry.
4821    ///   - absolute path (`(:bibliotecas ("/etc/passwd"))`):
4822    ///     [`Path::join`] *replaces* the base when the right-hand side
4823    ///     is absolute, so `root.join("/etc/passwd")` resolves to
4824    ///     `"/etc/passwd"` and escapes the project sandbox entirely.
4825    ///     The existence check then silently consults whatever the
4826    ///     escaped path resolves to — for `:bibliotecas`, the layout
4827    ///     has no `starts_with`-fence (only `:exe` is fenced under
4828    ///     `exe/` and `:servicos` under `servicos/`), so an absolute
4829    ///     `:bibliotecas` entry that happens to resolve on disk
4830    ///     silently passes. For `:exe` / `:servicos` the fence catches
4831    ///     the absolute case downstream as `ExeOutsideDir` /
4832    ///     `ServicoOutsideDir` (or `MissingEntry` if the absolute path
4833    ///     doesn't exist), but with a downstream-shaped diagnostic
4834    ///     that names the resolved escape path rather than the
4835    ///     authoring footgun at the source.
4836    ///   - parent-escape (`(:bibliotecas ("../sibling/x.lisp"))` /
4837    ///     `(:exe ("exe/../../escape.lisp"))`): a [`PathBuf`] with any
4838    ///     [`std::path::Component::ParentDir`] anywhere round-trips
4839    ///     through [`Path::join`] as a traversal above the caixa root.
4840    ///     The `:exe` / `:servicos` `starts_with(<dir>)` fence is
4841    ///     *component-aware* (not canonical-path-aware), so
4842    ///     `root.join("exe/../../escape.lisp")` `starts_with(exe_dir)`
4843    ///     is **true** even though the canonical resolution
4844    ///     `{parent of root}/escape.lisp` lives outside the caixa root
4845    ///     — the fence silently lets the parent-escape through, and
4846    ///     the existence check passes if that escape-target happens
4847    ///     to exist. Caught regardless of where the `..` sits
4848    ///     (leading, mid-path, trailing) so the gate matches the peer
4849    ///     predicate's full coverage.
4850    ///
4851    /// Same `Empty` → `Absolute` → `ParentEscape` arm-ordering every peer
4852    /// `is_sandboxed_relative_path` consumer follows (b0c8389 / 26da2c7);
4853    /// same per-slot diagnostic shape every peer per-axis path-gate
4854    /// exposes (`*Empty { slot }` / `*Absolute { slot, path }` /
4855    /// `*ParentEscape { slot, path }`). Cross-slot precedence is
4856    /// `:bibliotecas` → `:exe` → `:servicos` — the same declaration
4857    /// order [`Caixa::declared_foreign_code_slots`] uses for its
4858    /// canonical foreign-code-slot diagnostic, so a manifest with
4859    /// multiple malformed slots surfaces the lexicographically-earliest
4860    /// slot's diagnostic deterministically.
4861    ///
4862    /// Lifted to the typed surface as a Caixa-level validator (peer
4863    /// of [`Self::validate_nome`] / [`Self::validate_versao`] /
4864    /// [`Self::validate_deps`] / [`Self::validate_restart_window`])
4865    /// and wired into [`crate::StandardLayout::verify`] before the
4866    /// existence-check loops so the diagnostic names the offending
4867    /// slot at the source caixa.lisp rather than reporting a
4868    /// downstream `MissingEntry` / `ExeOutsideDir` /
4869    /// `ServicoOutsideDir` against the resolved sandbox-escape path.
4870    /// The fourth typed code-path surface — every author-supplied
4871    /// path on the manifest — is now structurally accept-shaped
4872    /// past validate, peer with `:behavior :on-*` and
4873    /// `:upgrade-from :state-change :script`.
4874    pub fn validate_code_paths(&self) -> Result<(), ManifestError> {
4875        /// Per-slot file-type contract for the three Caixa-level
4876        /// code-path surfaces (`:bibliotecas`, `:exe`, `:servicos`).
4877        /// Each variant names the predicate the per-entry file-type
4878        /// gate consults; [`Self::None`] opts the slot out of any
4879        /// file-type contract. Lifted as a typed local enum so the
4880        /// per-slot dispatch is exhaustive at the `match` — adding a
4881        /// future axis to the typed-substrate `:` slot set (the
4882        /// future `:assets` resource axis the M5 roadmap names, the
4883        /// future `:nix-flake` derivation axis the caixa-flake
4884        /// emitter consults) lands as one variant + one `match` arm,
4885        /// not a coordinated rewrite of every per-slot bool flag.
4886        ///
4887        /// Peer of the typed-substrate per-slot variant disciplines
4888        /// already established on this surface
4889        /// ([`crate::supervisor::RestartStrategy`] +
4890        /// [`crate::supervisor::RestartPolicy`] on the OTP-shape
4891        /// supervision-tree axis,
4892        /// [`crate::aplicacao::PlacementStrategy`] on the §III.1
4893        /// placement axis, [`crate::aplicacao::WitTarget`] on the
4894        /// `:contratos` payload-target axis): the typed `enum` is
4895        /// the substrate's single source of truth for the per-axis
4896        /// dispatch, and every consumer (the per-arm body here, the
4897        /// future feira-lint per-slot diagnostic renderer, the M4
4898        /// per-axis admission webhook) reaches for the same typed
4899        /// surface rather than re-deriving the partition from inline
4900        /// flag combinations.
4901        enum CodePathFileType {
4902            /// `:exe` — nix-build derivation output, no terminating-
4903            /// extension contract (the canonical `"exe/<name>"`
4904            /// fixtures the layout's `ExeOutsideDir` error message
4905            /// documents carry no extension by convention).
4906            None,
4907            /// `:bibliotecas` — tatara-lisp source files the
4908            /// `feira build` loop reads through `tatara_lisp::read`
4909            /// at parse time. Routes to [`is_lisp_extension`].
4910            LispSource,
4911            /// `:servicos` — ComputeUnit-CR YAML files the
4912            /// caixa-helm / caixa-flux renderers consume through
4913            /// `serde_yaml::from_str`. Routes to
4914            /// [`is_computeunit_yaml_extension`].
4915            ComputeUnitYaml,
4916        }
4917
4918        // The per-slot [`CodePathFileType`] selects which axes carry the
4919        // lifted file-type predicate. `:bibliotecas` is the tatara-lisp
4920        // source axis (the `feira build` loop at
4921        // `caixa-feira/src/cmd/build.rs:33` reads each entry through
4922        // `tatara_lisp::read` at parse time) — the lifted
4923        // [`is_lisp_extension`] predicate gates the `.lisp` extension.
4924        // `:exe` is the nix-built executable surface (per the canonical
4925        // `"exe/<name>"`-shaped fixtures the layout's `ExeOutsideDir`
4926        // error message documents and every in-tree
4927        // `caixa_with_code_paths` positive control uses) — its file-type
4928        // contract is "nix-build derivation output", not a typed source
4929        // file, so [`CodePathFileType::None`] opts the slot out of any
4930        // file-type gate. `:servicos` is the `.computeunit.yaml`
4931        // ComputeUnit-CR axis (the peer caixa-helm / caixa-flux
4932        // renderers consume each entry through `serde_yaml::from_str` as
4933        // a typed `ComputeUnit` CR) — the lifted
4934        // [`is_computeunit_yaml_extension`] predicate gates the compound
4935        // `.computeunit.yaml` suffix. All three axes are surfaced through
4936        // the same iteration so the sandbox-shape + duplicate gates
4937        // apply uniformly; the typed file-type dispatch fires per-slot
4938        // exactly where the downstream consumer's accepted set demands
4939        // it. The third file-type variant ([`ComputeUnitYaml`]) is the
4940        // compounding lift on the peer 64772a9 `:bibliotecas`
4941        // `.lisp`-gate trajectory — the second of the three code-path
4942        // axes to land on a typed compound-suffix gate, with the same
4943        // self-locating per-slot diagnostic shape every peer per-axis
4944        // file-type lift uses (`*NonLispExtension { slot, path }` /
4945        // `*NonComputeUnitYamlExtension { slot, path }`).
4946        for (slot, list, file_type) in [
4947            (
4948                ":bibliotecas",
4949                &self.bibliotecas,
4950                CodePathFileType::LispSource,
4951            ),
4952            (":exe", &self.exe, CodePathFileType::None),
4953            (
4954                ":servicos",
4955                &self.servicos,
4956                CodePathFileType::ComputeUnitYaml,
4957            ),
4958        ] {
4959            // Per-slot set-not-multiset gate on the typed code-path axis.
4960            // Every peer Vec-shaped author-supplied list past validate is
4961            // a set, not a multiset: `:membros :caixa`
4962            // ([`crate::AplicacaoError::MembroDuplicate`]), `:placement
4963            // :clusters` ([`crate::AplicacaoError::PlacementClusterDuplicate`]),
4964            // `:entrada :paths` ([`crate::AplicacaoError::EntradaPathDuplicate`]),
4965            // `:contratos` ([`crate::AplicacaoError::ContratoDuplicate`]),
4966            // `:children :caixa` ([`crate::SupervisorError::DuplicateChild`]),
4967            // `:deps` / `:deps-dev` `:nome` ([`crate::DepError::DuplicateNome`]
4968            // per 359fba5), `:upgrade-from :from` ([`crate::UpgradeError::DuplicateFrom`]),
4969            // `:etiquetas` ([`ManifestError::EtiquetaDuplicate`] per 360a499),
4970            // `:autores` ([`ManifestError::AutorDuplicate`] per 86c769b) —
4971            // the three code-path lists are the last Vec-shaped author-
4972            // supplied slots on the typed Caixa surface still admitting a
4973            // duplicate entry silently. Scope is per-list (`:bibliotecas`
4974            // duplicates are flagged within `:bibliotecas`, not across
4975            // `:bibliotecas` ↔ `:exe`) — the same per-list scope `:deps`
4976            // ↔ `:deps-dev` use (a `:nome` present in both lists is a
4977            // legitimate dev-vs-runtime shape on the dep axis, fenced
4978            // separately by [`crate::dep::validate_no_self_dep`]). On the
4979            // code-path axis a cross-slot collision is structurally
4980            // impossible by the layout's `starts_with(<exe|servicos>_dir)`
4981            // fence — `:exe` and `:servicos` entries are confined to their
4982            // own directory trees, so the only way a string could appear
4983            // on two code-path lists is the (rare, structurally invalid)
4984            // case where `:bibliotecas` carries an `"exe/<x>"` or
4985            // `"servicos/<x>.yaml"`-shaped path.
4986            //
4987            // Without the gate three authoring footguns silently passed:
4988            //
4989            //   - `:bibliotecas ("lib/foo.lisp" "lib/foo.lisp")` — the
4990            //     canonical copy-paste-the-wrong-file footgun. `feira
4991            //     build` (`caixa-feira/src/cmd/build.rs:33`) walks the
4992            //     list and re-parses the same file twice, wasting work
4993            //     and silently masking the author's intent to declare a
4994            //     *second* biblioteca.
4995            //   - `:exe ("exe/cli" "exe/cli")` — the same footgun on the
4996            //     Binario surface. The future `caixa-flake` `nix flake`
4997            //     emitter that materializes each `:exe` entry as a flake
4998            //     `packages.<exe-name>` derivation would collide on the
4999            //     duplicate package name and surface a flake-eval error
5000            //     far from the source `caixa.lisp`.
5001            //   - `:servicos ("servicos/x.computeunit.yaml"
5002            //     "servicos/x.computeunit.yaml")` — the same footgun on
5003            //     the Servico surface. The peer `caixa-helm` / `caixa-flux`
5004            //     renderers already refuse `:servicos.len() != 1` with
5005            //     the narrower [`UnsupportedServicoCount`] diagnostic, but
5006            //     that diagnostic surfaces "too many servicos" without
5007            //     naming "duplicate entry" — the typed self-locating
5008            //     "which entry is the duplicate" framing only lands at
5009            //     this gate.
5010            //
5011            // Same `seen.insert(entry.as_str())` shape every peer per-list
5012            // duplicate gate uses (`:etiquetas` 360a499, `:autores`
5013            // 86c769b, `:deps` 359fba5) and the same "structural shape
5014            // checks fire before the duplicate check on the same entry"
5015            // ordering (a `(:bibliotecas ("" "lib/x.lisp" "lib/x.lisp"))`
5016            // shape surfaces the narrower [`Self::CodePathEmpty`] for the
5017            // empty entry first, not the duplicate on the later pair).
5018            let mut seen = std::collections::HashSet::new();
5019            for entry in list {
5020                let path = Path::new(entry);
5021                match is_sandboxed_relative_path(path) {
5022                    Ok(()) => {}
5023                    Err(PathShapeViolation::Empty) => {
5024                        return Err(ManifestError::CodePathEmpty { slot });
5025                    }
5026                    Err(PathShapeViolation::Absolute) => {
5027                        return Err(ManifestError::CodePathAbsolute {
5028                            slot,
5029                            path: path.to_path_buf(),
5030                        });
5031                    }
5032                    Err(PathShapeViolation::ParentEscape) => {
5033                        return Err(ManifestError::CodePathParentEscape {
5034                            slot,
5035                            path: path.to_path_buf(),
5036                        });
5037                    }
5038                }
5039                // The per-slot file-type gate dispatched through the
5040                // typed [`CodePathFileType`] selector above. Each variant
5041                // routes to the lifted predicate the downstream consumer
5042                // demands:
5043                //
5044                //   - [`LispSource`] → [`is_lisp_extension`] for
5045                //     `:bibliotecas` (the `feira build` loop's
5046                //     `tatara_lisp::read` consumer);
5047                //   - [`ComputeUnitYaml`] → [`is_computeunit_yaml_extension`]
5048                //     for `:servicos` (the caixa-helm / caixa-flux
5049                //     `serde_yaml::from_str` consumer's `ComputeUnit` CR
5050                //     accepted set);
5051                //   - [`None`] for `:exe` — the nix-build derivation-
5052                //     output axis has no terminating-extension contract.
5053                //
5054                // Fires after the sandbox-shape arms so a path that is
5055                // *both* sandbox-escaping and wrong-extension surfaces
5056                // the more fundamental sandbox-shape diagnostic first
5057                // (mirrors the peer `EmptyPath` → `AbsolutePath` →
5058                // `ParentEscape` → `NonLispExtension` arm-ordering on
5059                // `:behavior :on-*` c97815a, and `EmptyScript` →
5060                // `AbsoluteScript` → `ParentEscapeScript` →
5061                // `NonLispExtensionScript` on
5062                // `:upgrade-from :state-change :script` 33cc830), and
5063                // before the duplicate gate so the narrower per-entry
5064                // file-type shape dominates the cross-entry uniqueness
5065                // diagnostic (a
5066                // `("servicos/x.yaml" "servicos/x.yaml")` shape on
5067                // `:servicos` surfaces
5068                // `CodePathNonComputeUnitYamlExtension` on the first
5069                // entry rather than `CodePathDuplicate` on the pair —
5070                // peer with the 64772a9 `:bibliotecas`
5071                // `("lib/x.txt" "lib/x.txt")` ordering).
5072                match file_type {
5073                    CodePathFileType::None => {}
5074                    CodePathFileType::LispSource => {
5075                        if !is_lisp_extension(path) {
5076                            return Err(ManifestError::CodePathNonLispExtension {
5077                                slot,
5078                                path: path.to_path_buf(),
5079                            });
5080                        }
5081                    }
5082                    CodePathFileType::ComputeUnitYaml => {
5083                        if !is_computeunit_yaml_extension(path) {
5084                            return Err(ManifestError::CodePathNonComputeUnitYamlExtension {
5085                                slot,
5086                                path: path.to_path_buf(),
5087                            });
5088                        }
5089                    }
5090                }
5091                crate::render::insert_first_seen(&mut seen, entry.as_str(), || {
5092                    ManifestError::CodePathDuplicate {
5093                        slot,
5094                        path: path.to_path_buf(),
5095                    }
5096                })?;
5097            }
5098        }
5099        Ok(())
5100    }
5101
5102    /// Reject `:etiquetas` lists with an empty entry or with two entries
5103    /// agreeing on the same string. `:etiquetas` is the universal
5104    /// registry-search-tag axis on [`Caixa`] (every kind carries the
5105    /// `Vec<String>` slot) and lands verbatim as the Helm chart
5106    /// `Chart.yaml` `keywords:` array on every Servico (caixa-helm's
5107    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:236` folds it through
5108    /// a [`std::collections::BTreeSet`] alongside the four substrate-
5109    /// fixed tags `lareira` / `wasm` / `tatara-lisp` / `caixa-servico`).
5110    /// Two authoring footguns silently passed validate without this gate:
5111    ///
5112    ///   - Empty entry (`(:etiquetas (""))` — the canonical paste-from-
5113    ///     blank-doc footgun) rendered as `keywords: ["", "caixa-servico",
5114    ///     "lareira", "tatara-lisp", "wasm"]` in `Chart.yaml`. Helm's
5115    ///     `chart.metadata.keywords` admits the value without a strict
5116    ///     parser-side gate, but the empty keyword has no operational
5117    ///     meaning — it indexes nothing in the future caixa-registry
5118    ///     search axis and clutters the rendered chart with a no-op tag.
5119    ///   - Duplicate entries (`(:etiquetas ("demo" "demo"))` — the
5120    ///     copy-paste-the-wrong-tag footgun) silently passed validate
5121    ///     and were silently dedup'd by caixa-helm's `BTreeSet` collect
5122    ///     at chart render — a "second wins / one silently disappears"
5123    ///     shape divergent from every peer typed-graph set gate
5124    ///     ([`crate::AplicacaoError::MembroDuplicate`] on `:membros`,
5125    ///     [`crate::AplicacaoError::PlacementClusterDuplicate`] on
5126    ///     `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
5127    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
5128    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
5129    ///     `:deps` / `:deps-dev` per 359fba5, [`crate::UpgradeError::DuplicateFrom`]
5130    ///     on `:upgrade-from`, the per-instruction-class singularity
5131    ///     gates [`crate::UpgradeError::DuplicateLoadModule`] /
5132    ///     [`crate::UpgradeError::DuplicateStateChange`] /
5133    ///     [`crate::UpgradeError::DuplicateCleanup`]). The typed-graph
5134    ///     discipline is uniform: every Vec-shaped author-supplied list
5135    ///     past validate is set-not-multiset, by construction.
5136    ///
5137    /// Past the empty arm the gate enforces the chart-keyword shape
5138    /// predicate via [`crate::render::is_chart_keyword_shape`]: Cargo's
5139    /// crates.io `[package] keywords` grammar — 1..=20 bytes, starts
5140    /// with an ASCII letter, ASCII alphanumeric / `_` / `-`
5141    /// continuation. Closes the canonical paste-from-doc footguns the
5142    /// bare empty + duplicate arms left open: paste-from-aligned-doc
5143    /// whitespace (`" mesh"`, `"mesh "`), paste-from-multiline-doc
5144    /// newline (`"mesh\nhttp"` — the author pasted a multi-tag block
5145    /// into one entry instead of splitting), paste-from-Windows-CRLF-doc
5146    /// carriage return, CSV-list-separator confusion (`"mesh,http,grpc"`
5147    /// — the author meant three separate list entries), path-separator
5148    /// confusion (`"caixa/servico"`), namespace-suffix (`"http.1"`),
5149    /// leading-digit (`"1foo"`), kebab-leak (`"-foo"`), snake-leak
5150    /// (`"_foo"`), non-ASCII (`"café"`), and paste-from-binary-blob
5151    /// control bytes that would silently land as malformed search tags
5152    /// in the rendered Chart.yaml `keywords:` array and break the
5153    /// Artifact Hub keyword index lookup far from the source caixa.lisp.
5154    /// Mirrors the [`Self::validate_autores`] shape-predicate cascade
5155    /// established on the sibling universal-axis `Vec<String>` surface
5156    /// — the second universal-axis Vec<String> surface to land the
5157    /// empty-first-then-shape-then-duplicate per-entry cascade.
5158    ///
5159    /// Same empty-first cascade discipline every peer per-axis gate
5160    /// uses: the per-entry empty arm fires before the per-entry shape
5161    /// arm fires before the cross-entry duplicate arm, so an
5162    /// `("" "mesh" "mesh")` authoring shape surfaces the narrower
5163    /// [`ManifestError::EtiquetaEmpty`] (the structural "this entry
5164    /// has no value" defect) before either the shape or the duplicate
5165    /// diagnostic. Walks the list in declaration order so the
5166    /// first-collision diagnostic surfaces the lexicographically-
5167    /// earliest offending position, peer with every other duplicate
5168    /// gate on this surface.
5169    ///
5170    /// Universal-axis (every kind carries `:etiquetas`), so wired at the
5171    /// caixa-build gate alongside the peer universal gates
5172    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5173    /// [`Self::validate_deps`] / [`Self::validate_code_paths`] — before
5174    /// the kind-coherence gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]
5175    /// / [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5176    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5177    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
5178    /// slot sets. The future caixa-registry search axis can reach for
5179    /// `caixa.etiquetas` knowing every entry is a non-empty distinct
5180    /// chart-keyword-shaped string without re-deriving the precondition.
5181    pub fn validate_etiquetas(&self) -> Result<(), ManifestError> {
5182        let mut seen = std::collections::HashSet::new();
5183        for etiqueta in self.etiquetas() {
5184            if etiqueta.is_empty() {
5185                return Err(ManifestError::EtiquetaEmpty);
5186            }
5187            crate::render::is_chart_keyword_shape(etiqueta).map_err(|reason| {
5188                ManifestError::EtiquetaInvalid {
5189                    etiqueta: etiqueta.clone(),
5190                    reason,
5191                }
5192            })?;
5193            crate::render::insert_first_seen(&mut seen, etiqueta.as_str(), || {
5194                ManifestError::EtiquetaDuplicate {
5195                    etiqueta: etiqueta.clone(),
5196                }
5197            })?;
5198        }
5199        Ok(())
5200    }
5201
5202    /// Reject `:autores` lists with an empty entry or with two entries
5203    /// agreeing on the same string. `:autores` is the universal
5204    /// maintainer-axis on [`Caixa`] (every kind carries the
5205    /// `Vec<String>` slot) and lands verbatim as the Helm chart
5206    /// `Chart.yaml` `maintainers:` array on every Servico (caixa-helm's
5207    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:251` maps each entry
5208    /// to a `Maintainer { name, email: None }` without dedup). Two
5209    /// authoring footguns silently passed validate without this gate:
5210    ///
5211    ///   - Empty entry (`(:autores (""))` — the canonical paste-from-
5212    ///     blank-doc footgun) rendered as
5213    ///     `maintainers: [{name: "", email: null}]` in `Chart.yaml`. The
5214    ///     empty maintainer name has no operational meaning — it
5215    ///     identifies no one in the substrate's authorship index and
5216    ///     clutters the rendered chart with a no-op maintainer.
5217    ///   - Duplicate entries (`(:autores ("pleme-io" "pleme-io"))` —
5218    ///     the copy-paste-the-wrong-author footgun) silently passed
5219    ///     validate and rendered as two identical maintainer entries.
5220    ///     Unlike the [`Self::validate_etiquetas`] peer (caixa-helm's
5221    ///     `BTreeSet`-collect on `:etiquetas` silently dedups the
5222    ///     rendered `keywords:` array at chart-render time), the
5223    ///     `maintainers:` rendering has *no* dedup — duplicate `:autores`
5224    ///     entries stack verbatim in the chart, divergent from every
5225    ///     peer typed-graph set gate ([`crate::AplicacaoError::MembroDuplicate`]
5226    ///     on `:membros`, [`crate::AplicacaoError::PlacementClusterDuplicate`]
5227    ///     on `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
5228    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
5229    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
5230    ///     `:deps` / `:deps-dev`, [`crate::UpgradeError::DuplicateFrom`]
5231    ///     on `:upgrade-from`, [`ManifestError::EtiquetaDuplicate`] on
5232    ///     `:etiquetas`).
5233    ///
5234    /// Past the empty arm the gate enforces the chart-maintainer-name
5235    /// shape predicate via [`crate::render::is_chart_maintainer_name_shape`]:
5236    /// the structural single-line printable-UTF-8 floor every realistic
5237    /// Helm chart maintainer name carries — 1..=128 bytes, no leading
5238    /// or trailing whitespace, no ASCII control characters anywhere,
5239    /// Unicode bytes accepted. Closes the canonical paste-from-doc
5240    /// footguns the bare empty + duplicate arms left open:
5241    /// paste-from-aligned-doc whitespace (`" pleme-io"`, `"pleme-io "`),
5242    /// paste-from-multiline-doc newline (`"alice\nbob"` — the author
5243    /// pasted a multi-line block of author records into one `:autores`
5244    /// entry instead of splitting into one entry per author),
5245    /// paste-from-Windows-CRLF-doc carriage return, tab-from-aligned-doc,
5246    /// and the paste-from-binary-blob control bytes that would silently
5247    /// land as YAML-illegal byte sequences in the rendered Chart.yaml
5248    /// `maintainers:` array. Mirrors the shape-predicate cascade
5249    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
5250    /// [`Self::validate_edicao`] / [`Self::validate_repositorio`]
5251    /// establish past their own empty arms on the sibling universal-axis
5252    /// `Option<String>` surfaces — the first universal-axis Vec<String>
5253    /// surface to land the empty-first-then-shape-then-duplicate per-entry
5254    /// cascade.
5255    ///
5256    /// Same empty-first cascade discipline every peer per-axis gate
5257    /// uses: the per-entry empty arm fires before the per-entry shape
5258    /// arm before the cross-entry duplicate arm. Walks the list in
5259    /// declaration order so the first-collision diagnostic surfaces the
5260    /// lexicographically-earliest offending position, peer with every
5261    /// other duplicate gate on this surface.
5262    ///
5263    /// Universal-axis (every kind carries `:autores`), so wired at the
5264    /// caixa-build gate alongside the peer universal gates
5265    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5266    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5267    /// [`Self::validate_code_paths`] — before the kind-coherence gates
5268    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5269    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5270    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5271    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
5272    /// slot sets.
5273    pub fn validate_autores(&self) -> Result<(), ManifestError> {
5274        let mut seen = std::collections::HashSet::new();
5275        for autor in self.autores() {
5276            if autor.is_empty() {
5277                return Err(ManifestError::AutorEmpty);
5278            }
5279            crate::render::is_chart_maintainer_name_shape(autor).map_err(|reason| {
5280                ManifestError::AutorInvalid {
5281                    autor: autor.clone(),
5282                    reason,
5283                }
5284            })?;
5285            crate::render::insert_first_seen(&mut seen, autor.as_str(), || {
5286                ManifestError::AutorDuplicate {
5287                    autor: autor.clone(),
5288                }
5289            })?;
5290        }
5291        Ok(())
5292    }
5293
5294    /// Reject `:repositorio` values whose shape the shared
5295    /// [`crate::render::is_git_repo_url`] predicate refuses. The flat
5296    /// `repositorio: Option<String>` slot on [`Caixa`] is the
5297    /// universal git-shaped homepage axis every kind carries — the
5298    /// substrate routes the same string through two load-bearing
5299    /// consumers:
5300    ///
5301    ///   - [`caixa-helm`] folds it verbatim into the rendered
5302    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `home:` field
5303    ///     (`build_chart_yaml` at `caixa-helm/src/lib.rs:268`) and into
5304    ///     the chart `README.md` `repo = …` interpolation
5305    ///     (`caixa-helm/src/lib.rs:359`).
5306    ///   - [`caixa-flux`] folds it verbatim into the standalone
5307    ///     `ClusterBundleOpts::for_caixa` `git_url:` field
5308    ///     (`caixa-flux/src/lib.rs:293`), which becomes the `FluxCD`
5309    ///     `GitRepository.spec.url` the cluster's source-controller
5310    ///     polls — the load-bearing deploy-time axis.
5311    ///
5312    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
5313    /// substitute a placeholder when the slot is absent (`None` → the
5314    /// fallback fires); a `Some("")` *skips the fallback* and silently
5315    /// passes the empty string through to `Chart.yaml home: ""` /
5316    /// `GitRepository url: ""` — Helm's chart lint and `FluxCD`'s source
5317    /// controller both reject the empty URL far from the source
5318    /// `caixa.lisp`, with no field naming the offending `:repositorio`.
5319    /// Similarly a malformed `:repositorio` (whitespace, control char,
5320    /// missing `:` separator, leading `-`) silently lands in the
5321    /// rendered artifacts and breaks at `git clone` / `helm template`
5322    /// / `flux reconcile` time.
5323    ///
5324    /// Thin wrapper around [`crate::render::is_git_repo_url`] — the
5325    /// same shared predicate the peer [`crate::DepSource::validate`]
5326    /// routes the `:fonte (:tipo git :repo …)` axis through. With this
5327    /// gate the two `git URL`-shaped surfaces on the typed Caixa
5328    /// (`:repositorio` here, `:deps :fonte :repo` peer) are
5329    /// structurally equivalent: every value past validate is
5330    /// guaranteed-acceptable by the predicate's union of constraints
5331    /// (non-empty, length-bounded, no leading `-`, no whitespace, no
5332    /// control chars, ASCII only, no leading `:`, contains a `:`
5333    /// separator). The predicate accepts every documented authoring
5334    /// shape — `github:org/repo` shorthand, `https://host/path`,
5335    /// `ssh://[user@]host/path`, `git://host/path`, `git@host:path`
5336    /// scp-style SSH, `file:///path` — and refuses the canonical
5337    /// paste-from-blank-doc / paste-from-multiline-doc / CLI-arg-
5338    /// injection footguns at validate time. Maps the predicate's
5339    /// `String` reason verbatim into the
5340    /// [`ManifestError::RepositorioInvalid`] variant, carrying the
5341    /// offending value + parser-shaped reason so the diagnostic is
5342    /// self-locating (the author can grep their `caixa.lisp` for
5343    /// `:repositorio "<value>"` and fix it in one edit).
5344    ///
5345    /// `None` (the canonical "omit the slot to express no published
5346    /// homepage" shape) is accepted trivially — the gate is a no-op
5347    /// when the author didn't declare a value. `Some("")` is gated by
5348    /// the narrower [`ManifestError::RepositorioEmpty`] arm before the
5349    /// shape predicate is consulted, mirroring the empty-first cascade
5350    /// every peer per-axis identity gate uses
5351    /// ([`ManifestError::NomeEmpty`] → [`ManifestError::NomeInvalid`],
5352    /// [`ManifestError::VersaoEmpty`] → [`ManifestError::VersaoInvalid`],
5353    /// [`crate::DepError::FonteRepoEmpty`] →
5354    /// [`crate::DepError::FonteRepoInvalid`]).
5355    ///
5356    /// Universal-axis (every kind carries `:repositorio`), so wired at
5357    /// the caixa-build gate alongside the peer universal gates
5358    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5359    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5360    /// [`Self::validate_autores`] / [`Self::validate_code_paths`] —
5361    /// before the kind-coherence gates
5362    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5363    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5364    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5365    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5366    /// specific slot sets.
5367    pub fn validate_repositorio(&self) -> Result<(), ManifestError> {
5368        let Some(s) = self.repositorio() else {
5369            return Ok(());
5370        };
5371        if s.is_empty() {
5372            return Err(ManifestError::RepositorioEmpty);
5373        }
5374        is_git_repo_url(s).map_err(|reason| ManifestError::RepositorioInvalid {
5375            repositorio: s.to_string(),
5376            reason,
5377        })
5378    }
5379
5380    /// Reject `:descricao` values that are the empty string. The flat
5381    /// `descricao: Option<String>` slot on [`Caixa`] is the universal
5382    /// free-form-prose homepage axis every kind carries — the
5383    /// substrate routes the same string through two load-bearing
5384    /// consumers in the [`caixa-helm`] renderer:
5385    ///
5386    ///   - `build_chart_yaml` folds it verbatim into the rendered
5387    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `description:`
5388    ///     field (`caixa-helm/src/lib.rs:232-235`).
5389    ///   - `build_readme` folds it verbatim into the rendered chart
5390    ///     `README.md` header (`caixa-helm/src/lib.rs:333-336`).
5391    ///
5392    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
5393    /// substitute a `caixa.nome`-derived placeholder when the slot is
5394    /// absent (`None` → the fallback fires); a `Some("")` *skips the
5395    /// fallback* and silently passes the empty string through to
5396    /// `Chart.yaml description: ""` / a blank chart `README.md`
5397    /// header. Helm's chart spec requires a non-empty `description:`
5398    /// field on `apiVersion: v2` charts (`helm lint` surfaces it as
5399    /// `WARNING [chart.metadata.description]: description is required`),
5400    /// so the empty `Some("")` silently lands in the rendered
5401    /// artifacts and breaks at `helm lint` / `helm install` time far
5402    /// from the source `caixa.lisp`, with no field naming the
5403    /// offending `:descricao`.
5404    ///
5405    /// `None` (the canonical "omit the slot to defer to the renderer's
5406    /// `caixa.nome`-derived fallback" shape) is accepted trivially —
5407    /// the gate is a no-op when the author didn't declare a value.
5408    /// `Some("")` is gated by the narrower
5409    /// [`ManifestError::DescricaoEmpty`] arm, mirroring the empty-arm
5410    /// shape every peer per-axis empty gate uses
5411    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
5412    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
5413    /// [`ManifestError::RepositorioEmpty`]).
5414    ///
5415    /// Universal-axis (every kind carries `:descricao`), so wired at
5416    /// the caixa-build gate alongside the peer universal gates
5417    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5418    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5419    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
5420    /// [`Self::validate_code_paths`] — before the kind-coherence
5421    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5422    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5423    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5424    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5425    /// specific slot sets.
5426    ///
5427    /// Past the empty arm the gate enforces the chart-description
5428    /// shape predicate via [`crate::render::is_chart_description_shape`]:
5429    /// the structural single-line UTF-8 floor every realistic chart
5430    /// description in the wild matches — 1..=512 bytes, no leading
5431    /// or trailing whitespace, no ASCII control characters anywhere
5432    /// (`0x00..=0x1F` plus `0x7F` DEL — banning tab, newline,
5433    /// carriage return, and every other control byte), Unicode
5434    /// continuation bytes accepted (the canonical fixtures carry
5435    /// `→` and `—`). Closes the canonical paste-from-doc footguns
5436    /// the bare empty-arm gate left open: paste-from-aligned-doc
5437    /// leading / trailing whitespace (`" Checkout flow."`,
5438    /// `"Checkout flow. "`), paste-from-multiline-doc newline
5439    /// (`"Checkout\nflow."`), paste-from-Windows-CRLF-doc CR
5440    /// (`"Checkout\rflow."`), tab-from-aligned-doc
5441    /// (`"Checkout\tflow."`), and paste-from-binary-blob NUL / BEL /
5442    /// ESC / DEL bytes. Mirrors the shape-predicate cascade
5443    /// [`Self::validate_repositorio`] / [`Self::validate_licenca`] /
5444    /// [`Self::validate_edicao`] establish past their own empty arms
5445    /// on the sibling universal-axis `Option<String>` Caixa-level
5446    /// value-shape surfaces.
5447    ///
5448    /// The empty-first cascade discipline mirrors every peer per-axis
5449    /// identity gate: [`ManifestError::DescricaoEmpty`] runs before
5450    /// [`ManifestError::DescricaoInvalid`], so the narrower empty
5451    /// diagnostic surfaces on `Some("")` rather than the broader
5452    /// shape-predicate diagnostic — peer with how
5453    /// [`ManifestError::LicencaEmpty`] runs before
5454    /// [`ManifestError::LicencaInvalid`],
5455    /// [`ManifestError::EdicaoEmpty`] runs before
5456    /// [`ManifestError::EdicaoInvalid`],
5457    /// [`ManifestError::RepositorioEmpty`] runs before
5458    /// [`ManifestError::RepositorioInvalid`].
5459    pub fn validate_descricao(&self) -> Result<(), ManifestError> {
5460        let Some(s) = self.descricao() else {
5461            return Ok(());
5462        };
5463        if s.is_empty() {
5464            return Err(ManifestError::DescricaoEmpty);
5465        }
5466        crate::render::is_chart_description_shape(s).map_err(|reason| {
5467            ManifestError::DescricaoInvalid {
5468                descricao: s.to_string(),
5469                reason,
5470            }
5471        })?;
5472        Ok(())
5473    }
5474
5475    /// Reject `:licenca` values that are the empty string. The flat
5476    /// `licenca: Option<String>` slot on [`Caixa`] is the universal
5477    /// SPDX-shaped license-expression axis every kind carries — the
5478    /// substrate routes the same string through the [`caixa-helm`]
5479    /// renderer's `build_readme` which folds it verbatim into the
5480    /// rendered `lareira-<nome>` Helm chart's `README.md` `## License`
5481    /// section (`caixa-helm/src/lib.rs:361`) via
5482    /// `caixa.licenca.clone().unwrap_or_else(|| "MIT".into())`. The
5483    /// fallback only fires on `None`; a `Some("")` *skips the
5484    /// fallback* and silently passes the empty string through to a
5485    /// chart `README.md` whose `License` section renders as the bare
5486    /// trailing period (`.\n`) — peer footgun with the
5487    /// `Some("")`-skips-`unwrap_or_else` shape the
5488    /// [`Self::validate_descricao`] and [`Self::validate_repositorio`]
5489    /// gates close on the sibling free-form-prose and git-URL axes.
5490    ///
5491    /// `None` (the canonical "omit the slot to defer to the
5492    /// renderer's `MIT` fallback" shape every existing fixture
5493    /// carries) is accepted trivially — the gate is a no-op when the
5494    /// author didn't declare a value. `Some("")` is gated by the
5495    /// narrower [`ManifestError::LicencaEmpty`] arm, mirroring the
5496    /// empty-arm shape every peer per-axis empty gate uses
5497    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
5498    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
5499    /// [`ManifestError::RepositorioEmpty`],
5500    /// [`ManifestError::DescricaoEmpty`]).
5501    ///
5502    /// Universal-axis (every kind carries `:licenca`), so wired at
5503    /// the caixa-build gate alongside the peer universal gates
5504    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5505    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5506    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
5507    /// [`Self::validate_descricao`] / [`Self::validate_code_paths`]
5508    /// — before the kind-coherence gates
5509    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5510    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5511    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5512    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5513    /// specific slot sets.
5514    ///
5515    /// Past the empty arm the gate enforces the SPDX-expression shape
5516    /// predicate via [`crate::render::is_spdx_expression_shape`]: the
5517    /// structural alphabet floor every realistic SPDX expression in
5518    /// the wild uses — ASCII alphanumeric plus `.`, `-`, `+`, `(`,
5519    /// `)`, `:` (the `DocumentRef-…:LicenseRef-…` separator), and a
5520    /// single ASCII space (token separator). Closes the canonical
5521    /// paste-from-doc footguns the bare empty-arm gate left open:
5522    /// paste-from-doc whitespace (`"MIT "`, `" MIT"`), paste-from-
5523    /// multiline-doc CRLF (`"MIT\n"`), tab-from-aligned-doc
5524    /// (`"MIT\tOR Apache-2.0"`), non-ASCII smart-quote paste,
5525    /// underscore-instead-of-hyphen typo (`"Apache_2.0"`),
5526    /// comma-instead-of-`OR`-keyword colloquial idiom (`"MIT,
5527    /// Apache-2.0"`), slash-dual-license colloquial idiom (`"MIT/
5528    /// Apache-2.0"`), and semicolon-list-separator confusion
5529    /// (`"MIT; Apache-2.0"`). Mirrors the shape-predicate cascade
5530    /// [`Self::validate_repositorio`] / [`Self::validate_edicao`]
5531    /// establish past their own empty arms.
5532    ///
5533    /// The empty-first cascade discipline mirrors every peer per-axis
5534    /// identity gate: [`ManifestError::LicencaEmpty`] runs before
5535    /// [`ManifestError::LicencaInvalid`], so the narrower empty
5536    /// diagnostic surfaces on `Some("")` rather than the broader
5537    /// shape-predicate diagnostic — peer with how
5538    /// [`ManifestError::EdicaoEmpty`] runs before
5539    /// [`ManifestError::EdicaoInvalid`],
5540    /// [`ManifestError::RepositorioEmpty`] runs before
5541    /// [`ManifestError::RepositorioInvalid`].
5542    ///
5543    /// A future tightening on this axis can extend the alphabet
5544    /// floor into a full SPDX expression parser + license-id
5545    /// allowlist (rejecting alphabet-valid values that don't name a
5546    /// real SPDX license identifier — e.g., `"NotAReal"` is
5547    /// alphabet-valid but no `NotAReal` license-id exists). That
5548    /// parser only becomes meaningful past a real SPDX-spec
5549    /// dependency; this gate establishes the structural floor by
5550    /// refusing every non-SPDX-alphabet value at validate time.
5551    pub fn validate_licenca(&self) -> Result<(), ManifestError> {
5552        let Some(s) = self.licenca() else {
5553            return Ok(());
5554        };
5555        if s.is_empty() {
5556            return Err(ManifestError::LicencaEmpty);
5557        }
5558        crate::render::is_spdx_expression_shape(s).map_err(|reason| {
5559            ManifestError::LicencaInvalid {
5560                licenca: s.to_string(),
5561                reason,
5562            }
5563        })?;
5564        Ok(())
5565    }
5566
5567    /// Reject `:edicao` values that are the empty string. The flat
5568    /// `edicao: Option<String>` slot on [`Caixa`] is the universal
5569    /// language-edition axis every kind carries — it determines the
5570    /// tatara-lisp macro surface + compatibility flags the substrate
5571    /// applies when building a caixa, and lands verbatim in the
5572    /// `Caixa::template` author-time scaffold (the canonical
5573    /// `:edicao "2026"` line every `feira init` emits via
5574    /// [`Caixa::template`] at `caixa-core/src/manifest.rs:1193`) and
5575    /// in every renderer-side fixture (`caixa-helm/src/lib.rs:375`,
5576    /// `caixa-flux/src/lib.rs:445`, `caixa-mesh/src/lib.rs:629`,
5577    /// `caixa-core/src/render.rs:2510`) via
5578    /// `edicao: Some("2026".into())`.
5579    ///
5580    /// `None` (the canonical "omit the slot to defer to the
5581    /// substrate's default edition" shape every existing
5582    /// [`caixa-resolver`] integration test fixture carries via
5583    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
5584    /// is accepted trivially — the gate is a no-op when the author
5585    /// didn't declare a value. `Some("")` is gated by the narrower
5586    /// [`ManifestError::EdicaoEmpty`] arm, mirroring the empty-arm
5587    /// shape every peer per-axis empty gate uses
5588    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
5589    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
5590    /// [`ManifestError::RepositorioEmpty`],
5591    /// [`ManifestError::DescricaoEmpty`], [`ManifestError::LicencaEmpty`]).
5592    ///
5593    /// Universal-axis (every kind carries `:edicao`), so wired at
5594    /// the caixa-build gate alongside the peer universal gates
5595    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5596    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5597    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
5598    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
5599    /// [`Self::validate_code_paths`] — before the kind-coherence
5600    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5601    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5602    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5603    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5604    /// specific slot sets.
5605    ///
5606    /// Past the empty arm the gate enforces the canonical year-shape
5607    /// predicate: every documented tatara-lisp edition is a 4-digit
5608    /// ASCII decimal year (`"2026"` is the only edition currently
5609    /// minted; future-introduced siblings will follow the same
5610    /// shape, peer with Cargo's `[package] edition` grammar which
5611    /// every value Cargo has ever accepted matches — `"2015"`,
5612    /// `"2018"`, `"2021"`, `"2024"`). Any value that's not exactly
5613    /// 4 ASCII decimal bytes is rejected with the narrower
5614    /// [`ManifestError::EdicaoInvalid`] arm, mirroring the
5615    /// shape-predicate cascade [`Self::validate_repositorio`]
5616    /// establishes past its own empty arm
5617    /// ([`ManifestError::RepositorioEmpty`] →
5618    /// [`ManifestError::RepositorioInvalid`]). Closes the canonical
5619    /// paste-from-doc footguns the bare empty-arm gate left open:
5620    ///
5621    ///   - leading / trailing whitespace from a paste-from-doc
5622    ///     (`"2026 "`, `" 2026"`)
5623    ///   - control characters / CRLF from a paste-from-multiline-doc
5624    ///     (`"2026\n"`)
5625    ///   - non-ASCII look-alikes from a fullwidth keyboard
5626    ///     (`"2026"`) which would silently land as a non-ASCII
5627    ///     string in the rendered caixa.lisp
5628    ///   - free-form non-year values (`"x"`, `"latest"`,
5629    ///     `"nightly"`) that have no operational meaning on the
5630    ///     substrate's build-time edition selector
5631    ///   - leading non-digit prefixes (`"v2026"`, `"e2026"`,
5632    ///     `"r2026"`) — common version-tag idioms that don't apply
5633    ///     to the year-shaped edition axis
5634    ///   - decimal-shaped values (`"2026.1"`, `"2026.0"`) — every
5635    ///     edition is a year, not a fractional version
5636    ///   - wrong-length numeric values (`"26"`, `"202"`, `"20260"`,
5637    ///     `"00026"`) that don't name a year
5638    ///
5639    /// `None` (the canonical "omit the slot to defer to the
5640    /// substrate's default edition" shape every existing
5641    /// [`caixa-resolver`] integration test fixture carries via
5642    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
5643    /// is accepted trivially — the gate is a no-op when the author
5644    /// didn't declare a value. The empty-first cascade discipline
5645    /// mirrors every peer per-axis identity gate:
5646    /// [`ManifestError::EdicaoEmpty`] runs before
5647    /// [`ManifestError::EdicaoInvalid`], so the narrower empty
5648    /// diagnostic surfaces on `Some("")` rather than the broader
5649    /// shape-predicate diagnostic — peer with how
5650    /// [`ManifestError::NomeEmpty`] runs before
5651    /// [`ManifestError::NomeInvalid`],
5652    /// [`ManifestError::VersaoEmpty`] runs before
5653    /// [`ManifestError::VersaoInvalid`],
5654    /// [`ManifestError::RepositorioEmpty`] runs before
5655    /// [`ManifestError::RepositorioInvalid`].
5656    ///
5657    /// A future tightening on this axis can extend the shape
5658    /// predicate into a known-edition allowlist (rejecting
5659    /// year-shaped values that don't name a tatara-lisp edition
5660    /// the substrate actually understands — e.g., `"1999"` is
5661    /// year-shaped but no `1999` edition exists). That allowlist
5662    /// only becomes meaningful past the introduction of a sibling
5663    /// edition to `"2026"`; this gate establishes the structural
5664    /// floor by refusing every non-year-shaped value at validate
5665    /// time.
5666    pub fn validate_edicao(&self) -> Result<(), ManifestError> {
5667        let Some(s) = self.edicao() else {
5668            return Ok(());
5669        };
5670        if s.is_empty() {
5671            return Err(ManifestError::EdicaoEmpty);
5672        }
5673        if s.len() != 4 || !s.bytes().all(|b| b.is_ascii_digit()) {
5674            return Err(ManifestError::EdicaoInvalid {
5675                edicao: s.to_string(),
5676                reason: "must be a 4-digit ASCII decimal year (canonical \"2026\")".to_string(),
5677            });
5678        }
5679        Ok(())
5680    }
5681
5682    /// Compose the supervisor-related flat slots into a single
5683    /// [`SupervisorSpec`] for validation. Returns `None` when the
5684    /// caixa isn't a `:kind Supervisor`.
5685    ///
5686    /// The flat representation in [`Caixa`] keeps tatara-lisp authoring
5687    /// simple (one form, no nested `:supervisor (…)` block); this view
5688    /// is the "typed shape" the operator + supervisor reconciler
5689    /// consume.
5690    #[must_use]
5691    pub fn supervisor_view(&self) -> Option<SupervisorSpec> {
5692        if !self.kind().is_supervisor() {
5693            return None;
5694        }
5695        // Fold through the shared `supervisor::duration_codec::parse`
5696        // — the same parser the serde-routed `with = "duration_codec"`
5697        // on `SupervisorSpec::restart_window`, the `:politicas
5698        // :timeout` codec, and the `:politicas :circuit-breaker
5699        // :window` codec all consume. The prior inline f64-shaped
5700        // duplicate (`parse_window_inline`) admitted every magnitude
5701        // the integer-magnitude gate (1c55a2a) rejects on the three
5702        // serde-routed siblings — `"1.5s"`, `"1.0s"`, `"0.5m"`,
5703        // `"+30s"`, `"-30s"` — and silently dropped malformed input as
5704        // `None` (i.e. "no reset"), divergent from the shared codec's
5705        // integer-magnitude discipline by construction. The fold
5706        // closes the divergence: every value the typed
5707        // `SupervisorSpec` carries past `supervisor_view` is in the
5708        // shared codec's accepted set. The `.ok()` here preserves the
5709        // existing soft-swallow shape on this view-construction path;
5710        // the new [`Caixa::validate_restart_window`] (sibling of
5711        // [`Self::validate_nome`] / [`Self::validate_versao`]) names
5712        // the offending raw string at build time so authoring tools
5713        // (`feira lint`, the future layout-side wire-up) surface a
5714        // self-locating diagnostic instead of a silently dropped
5715        // window.
5716        let restart_window = self
5717            .restart_window()
5718            .and_then(|s| crate::supervisor::duration_codec::parse(s).ok());
5719        Some(SupervisorSpec {
5720            // Route the author-omitted `:estrategia` arm through the
5721            // substrate-canonical
5722            // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
5723            // `pub const` rather than the transitively-derived
5724            // [`RestartStrategy::default`] route the prior
5725            // `.unwrap_or_default()` fold reached for — one source of
5726            // truth for the Erlang/OTP `one_for_one` half of Learn You
5727            // Some Erlang's `{one_for_one, intensity, 5, 60}` worker-
5728            // supervisor canonical default that also backs the
5729            // [`crate::supervisor::Default for RestartStrategy`] impl
5730            // and the [`crate::supervisor::Default for SupervisorSpec`]
5731            // impl's struct-literal `estrategia` field, all now routed
5732            // through the same lifted constant. Prior to the lift the
5733            // composition site carried `.unwrap_or_default()` with no
5734            // compile-time link back to the shared OTP-canonical
5735            // default that the peer paired
5736            // `.unwrap_or(SUPERVISOR_MAX_RESTARTS_DEFAULT)` (b698ec0)
5737            // arm on the sibling `:max-restarts` axis routes through —
5738            // so a future rebrand of the OTP-canonical strategy default
5739            // (a widening to `rest_for_one` once the substrate
5740            // discovers startup-order-coupled child cohorts as the more
5741            // common shape, a per-cluster overlay the operator pins
5742            // through the MESH-COMPOSITION §III.2 supervision-canary
5743            // `:estrategia-overrides` roadmap slot) would have had to
5744            // migrate the paired `MaxIntensity` + `Period` halves
5745            // through the lifted constants and the `one_for_one` half
5746            // through a `RestartStrategy::default()` route in lockstep
5747            // or the three halves of the same OTP-canonical default
5748            // would silently drift out of pairing. Byte-parity against
5749            // the lifted constant closes the split. Pinned by
5750            // [`supervisor_view_estrategia_fallback_routes_through_lifted_default`]
5751            // in the tests module.
5752            estrategia: self
5753                .estrategia()
5754                .unwrap_or(crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT),
5755            // Route the author-omitted `:max-restarts` arm through the
5756            // substrate-canonical [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`]
5757            // typed `pub const` rather than the raw `5` literal — one
5758            // source of truth for the Erlang/OTP-canonical
5759            // `{intensity, 5, 60}` `MaxIntensity` default that also
5760            // backs the serde-side wire-format author-omitted arm on
5761            // [`crate::supervisor::SupervisorSpec::max_restarts`] via
5762            // `#[serde(default = "default_max_restarts")]` and the
5763            // [`Default for SupervisorSpec`] impl's struct-literal
5764            // default field. Prior to the lift the composition site
5765            // carried a raw `5` with no compile-time link back to the
5766            // serde-side default, so a future rebrand of the OTP-
5767            // canonical default (a tightening to Elixir's `3`, a
5768            // widening to a per-cluster overlay the operator pins
5769            // through the MESH-COMPOSITION §III.2 supervision-canary
5770            // `:supervisor :max-restarts-overrides` roadmap slot)
5771            // would have had to be threaded through both open-coded
5772            // copies in lockstep or the wire-format author-omitted arm
5773            // and this view-construction author-omitted arm would
5774            // silently disagree on which restart-budget an omitted
5775            // `:max-restarts` resolves to. Pinned by
5776            // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
5777            // in the tests module.
5778            max_restarts: self
5779                .max_restarts()
5780                .unwrap_or(crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT),
5781            restart_window,
5782            children: self.children().to_vec(),
5783        })
5784    }
5785
5786    /// A minimal starter manifest emitted by `feira init`.
5787    #[must_use]
5788    pub fn template(nome: &str) -> String {
5789        format!(
5790            "(defcaixa\n  \
5791               :nome        {nome:?}\n  \
5792               :versao      \"0.1.0\"\n  \
5793               :kind        Biblioteca\n  \
5794               :edicao      \"2026\"\n  \
5795               :descricao   \"FIXME — describe this caixa\"\n  \
5796               :autores     ()\n  \
5797               :etiquetas   ()\n  \
5798               :deps        ()\n  \
5799               :deps-dev    ()\n  \
5800               :bibliotecas (\"lib/{nome}.lisp\"))\n"
5801        )
5802    }
5803
5804    /// Serialize to a canonical `caixa.lisp` source — suitable for writing
5805    /// back after mutation (e.g. `feira add`).
5806    ///
5807    /// Goes through serde JSON → canonical Sexp → per-field pretty print.
5808    /// The derive-macro `compile_from_sexp` path is the inverse, so any
5809    /// `Caixa` round-trips through `to_lisp` + `from_lisp`.
5810    #[must_use]
5811    pub fn to_lisp(&self) -> String {
5812        let json = serde_json::to_value(self).expect("Caixa serialize");
5813        let sexp = tatara_lisp::domain::json_to_sexp(&json);
5814        let tatara_lisp::Sexp::List(items) = sexp else {
5815            return format!("(defcaixa {sexp})\n");
5816        };
5817        let mut out = String::from("(defcaixa");
5818        let mut i = 0;
5819        while i + 1 < items.len() {
5820            out.push_str("\n  ");
5821            out.push_str(&items[i].to_string());
5822            out.push(' ');
5823            out.push_str(&items[i + 1].to_string());
5824            i += 2;
5825        }
5826        out.push_str(")\n");
5827        out
5828    }
5829}
5830
5831/// Errors raised by top-level [`Caixa`] validators that don't fit
5832/// the per-axis [`DepError`] / [`crate::AplicacaoError`] /
5833/// [`crate::SupervisorError`] / [`crate::LayoutError`] families —
5834/// the Caixa's own identity axes (`:nome`, `:versao`) that flow
5835/// through every substrate-side artifact's `metadata.name` /
5836/// version derivation.
5837///
5838/// A future top-level sum (the M4 `CaixaError` the [`DepError`]
5839/// doc-comment anticipates) can hold one of each per-axis error
5840/// family without reshaping individual diagnostics; this enum is
5841/// the first such per-Caixa-identity family.
5842#[derive(Debug, Error, PartialEq, Eq)]
5843pub enum ManifestError {
5844    #[error(
5845        ":nome is empty (every caixa must name itself; the value flows \
5846         into every K8s artifact's `metadata.name` derivation and into \
5847         the default `lib/<nome>.lisp` / `exe/<nome>` layout paths)"
5848    )]
5849    NomeEmpty,
5850    #[error(
5851        ":nome {nome:?} is not a valid DNS-1123 label: {reason} (the K8s \
5852         apiserver enforces this rule on every `metadata.name` the \
5853         caixa's substrate-side renderers derive from `:nome` — the \
5854         `lareira-<nome>` Helm chart name, the programs.yaml entry \
5855         name, the `LABEL_APLICACAO` label value, the `<aplicacao>-<de>-to-<para>` \
5856         CiliumNetworkPolicy name, the `<aplicacao>-<para>` HTTPRoute \
5857         name; use a lowercase alphanumeric + hyphen identifier like \
5858         `\"checkout\"` or `\"cart-v2\"`)"
5859    )]
5860    NomeInvalid { nome: String, reason: String },
5861    #[error(
5862        ":nome {nome:?} overflows the joint-length budget on the canonical \
5863         `lareira-<nome>` chart-name shape: {reason} (every per-Servico / \
5864         per-Aplicacao renderer the substrate carries — `caixa-helm`'s \
5865         `Chart.yaml::name`, `caixa-flux`'s `cluster_bundle` HelmRelease \
5866         `chart:` slot, `caixa-tatara`'s `release_name` + \
5867         `oci://<registry>/lareira-<nome>` chart ref — derives the same \
5868         joint name through the canonical `lareira_chart_name` helper, and \
5869         Helm's `Chart.yaml::name` admission rule + the K8s apiserver's \
5870         DNS-1123 label cap on every chart-name-derived `metadata.name` \
5871         reject any joint name exceeding 63 bytes; the narrower \
5872         `:nome` shape (`NomeInvalid`) gates the bare-`:nome` budget, this \
5873         arm gates the chart-name budget downstream renderers inherit)"
5874    )]
5875    NomeChartNameBudgetExceeded { nome: String, reason: String },
5876    #[error(
5877        ":versao is empty (every caixa must pin its own version; the value flows \
5878         into the `lareira-<nome>` Helm chart's `Chart.yaml` version + appVersion, \
5879         the `feira publish` `v<versao>` git tag, the OCI image's `:v<versao>` / \
5880         `:latest` tags, the lacre closure's `concrete_versao`, and the \
5881         `:upgrade-from :from` peers — use a SemVer-2 literal like `\"0.1.0\"`)"
5882    )]
5883    VersaoEmpty,
5884    #[error(
5885        ":versao {versao:?} is not a valid SemVer-2 version: {reason} (the substrate \
5886         consumes this string as `semver::Version` — three-part `MAJOR.MINOR.PATCH` \
5887         with optional `-prerelease` and `+build` — across every artifact derived \
5888         from `:versao`: the `lareira-<nome>` Helm chart's `Chart.yaml` version + \
5889         appVersion (Helm SemVer-2-strict), the `feira publish` `v<versao>` git tag, \
5890         the OCI image's `:v<versao>` tag, the lacre closure's `concrete_versao`, \
5891         and the `:upgrade-from :from` peers that match against this exact shape; \
5892         use a literal like `\"0.1.0\"`, `\"0.2.0-rc.1\"`, or `\"1.0.0+build.42\"` — \
5893         not a git-tag-shape like `\"v0.1.0\"`, a docker-tag-shape like `\"latest\"`, \
5894         a requirement-shape like `\"^0.1\"`, or a four-part `\"0.1.0.0\"`)"
5895    )]
5896    VersaoInvalid { versao: String, reason: String },
5897    #[error(
5898        ":restart-window {restart_window:?} is not a valid duration: {reason} (the \
5899         substrate consumes this string through the shared \
5900         `supervisor::duration_codec` — the same parser routed via `with = \
5901         \"duration_codec\"` onto the typed `SupervisorSpec::restart_window`, \
5902         `:politicas :timeout`, and `:politicas :circuit-breaker :window` slots; \
5903         the canonical authoring form is `<integer><unit>` where the unit is one \
5904         of `ms` / `s` / `m` / `h` and the magnitude has no decimal point and no \
5905         leading `+` / `-` sign — e.g. `\"60s\"`, `\"5m\"`, `\"1h\"`, `\"500ms\"`. \
5906         Without this gate a malformed `:restart-window` silently produced a \
5907         supervisor with `restart_window: None` (\"never reset\"), turning OTP's \
5908         `MaxIntensity / Period` invariant into a never-reset supervisor far from \
5909         the source `caixa.lisp`; the gate moves the diagnostic to the manifest \
5910         layer with the offending value named verbatim. Omit the slot entirely to \
5911         express \"no reset\"; carry a positive integer duration to express the \
5912         sliding window)"
5913    )]
5914    RestartWindowMalformed {
5915        restart_window: String,
5916        reason: String,
5917    },
5918    #[error(
5919        "{slot} entry is an empty path string — every {slot} entry must name \
5920         a file relative to the caixa root; omit the entry to omit the file \
5921         (the layout checker's `root.join(\"\")` resolves to the caixa root \
5922         itself, so an empty entry silently aliases the project root as a \
5923         declared {slot} file, then fails downstream at parse / existence \
5924         time with a diagnostic that names the root rather than the offending \
5925         entry)"
5926    )]
5927    CodePathEmpty { slot: &'static str },
5928    #[error(
5929        "{slot} entry {} is an absolute path — entries must be relative to \
5930         the caixa root, since `Path::join` replaces the base with an absolute \
5931         right-hand side and `root.join(\"/abs/...\")` resolves to \"/abs/...\" \
5932         outside the caixa root sandbox; rewrite the entry as a relative path \
5933         under the caixa root (e.g. `\"lib/<name>.lisp\"`, `\"exe/<name>\"`, \
5934         `\"servicos/<name>.computeunit.yaml\"`)",
5935        path.display()
5936    )]
5937    CodePathAbsolute { slot: &'static str, path: PathBuf },
5938    #[error(
5939        "{slot} entry {} contains a `..` component — entries must not traverse \
5940         above the caixa root (the layout's `starts_with(<dir>)` fence on \
5941         `:exe` / `:servicos` is component-aware, not canonical-path-aware, \
5942         so a mid-path `..` silently traverses the sandbox; `:bibliotecas` \
5943         has no such fence, so a leading `..` escapes unconditionally if the \
5944         resolved target happens to exist)",
5945        path.display()
5946    )]
5947    CodePathParentEscape { slot: &'static str, path: PathBuf },
5948    #[error(
5949        "{slot} entry {} does not terminate in the `.lisp` extension — every \
5950         `:bibliotecas` entry is a tatara-lisp source file the `feira build` \
5951         loop reads through `tatara_lisp::read` at parse time, so any other \
5952         extension (`.rs`, `.txt`, `.lisp.bak`) or no-extension shape is \
5953         structurally a parser error far from the source caixa.lisp, with \
5954         no field naming the offending `:bibliotecas` entry. Pin a relative \
5955         path under the caixa root whose terminating extension is \
5956         lowercase-`.lisp` (e.g. `\"lib/<name>.lisp\"`, \
5957         `\"lib/handlers.lisp\"`) — the same file-type contract the peer \
5958         `:behavior :on-*` (c97815a) and `:upgrade-from :state-change :script` \
5959         (33cc830) axes already carry through the same lifted \
5960         `is_lisp_extension` predicate",
5961        path.display()
5962    )]
5963    CodePathNonLispExtension { slot: &'static str, path: PathBuf },
5964    #[error(
5965        "{slot} entry {} does not terminate in the `.computeunit.yaml` \
5966         compound suffix — every `:servicos` entry is a typed `ComputeUnit` \
5967         CR YAML file the peer caixa-helm / caixa-flux renderers consume \
5968         through `serde_yaml::from_str` at chart / FluxCD bundle render \
5969         time, so any other extension (`.yaml`, `.yml`, `.json`, the \
5970         off-by-one-segment `.computeunit-yaml`, the editor-backup \
5971         `.computeunit.yaml.bak`) or no-extension shape is structurally a \
5972         YAML-parser error / `ComputeUnit` schema-mismatch far from the \
5973         source caixa.lisp, with no field naming the offending `:servicos` \
5974         entry. Pin a relative path under the caixa root whose terminating \
5975         compound suffix is lowercase-`.computeunit.yaml` (e.g. \
5976         `\"servicos/<name>.computeunit.yaml\"`, \
5977         `\"servicos/hello-rio.computeunit.yaml\"`) — the same file-type \
5978         contract the sibling `:bibliotecas` axis (64772a9) already carries \
5979         on the tatara-lisp-source axis through the peer lifted \
5980         `is_lisp_extension` predicate, here on the compound-suffix axis \
5981         `Path::extension` can't express on its own through the lifted \
5982         `is_computeunit_yaml_extension` predicate",
5983        path.display()
5984    )]
5985    CodePathNonComputeUnitYamlExtension { slot: &'static str, path: PathBuf },
5986    #[error(
5987        "{slot} entry {} appears more than once (the code-path list is \
5988         a set, not a multiset; every peer Vec-shaped author-supplied \
5989         list past validate is set-not-multiset — `:membros :caixa`, \
5990         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
5991         `:children :caixa`, `:deps` / `:deps-dev` `:nome`, \
5992         `:upgrade-from :from`, `:etiquetas`, `:autores` — and the three \
5993         code-path lists are the last Vec-shaped author-supplied slots on \
5994         the typed Caixa surface still admitting a duplicate entry. \
5995         `:bibliotecas` duplicates re-parse the same file at \
5996         `feira build` time and silently mask the author's intent to \
5997         declare a *second* biblioteca; `:exe` duplicates collide on the \
5998         flake `packages.<name>` derivation key at the future \
5999         `caixa-flake` materializer; `:servicos` duplicates surface as the \
6000         narrower [`caixa-helm`] / [`caixa-flux`] `UnsupportedServicoCount` \
6001         rejection far from the source `caixa.lisp`. Drop the duplicate \
6002         or rename it to the actual second file intended)",
6003        path.display()
6004    )]
6005    CodePathDuplicate { slot: &'static str, path: PathBuf },
6006    #[error(
6007        ":etiquetas entry is empty (every tag must carry a non-empty \
6008         registry-search identifier; the empty entry has no operational \
6009         meaning — it indexes nothing in the future caixa-registry search \
6010         axis and clutters the rendered Helm `Chart.yaml` `keywords:` array \
6011         with a no-op tag; omit the entry to express \"no tag on this \
6012         position\")"
6013    )]
6014    EtiquetaEmpty,
6015    #[error(
6016        ":etiquetas entry {etiqueta:?} appears more than once (the \
6017         registry-search tag set is a set, not a multiset; duplicate \
6018         entries are silently dedup'd by caixa-helm's `BTreeSet` collect \
6019         at chart render — a \"second wins / one silently disappears\" \
6020         shape divergent from every peer typed-graph set gate \
6021         (`:membros :caixa`, `:placement :clusters`, `:entrada :paths`, \
6022         `:contratos`, `:deps :nome`, `:upgrade-from :from`); drop the \
6023         duplicate or rename it to the actual tag intended)"
6024    )]
6025    EtiquetaDuplicate { etiqueta: String },
6026    #[error(
6027        ":etiquetas entry {etiqueta:?} is not a valid chart-keyword shape: \
6028         {reason} (the substrate consumes this string through the shared \
6029         `crate::render::is_chart_keyword_shape` predicate — the same \
6030         Cargo crates.io `[package] keywords` grammar entry shape: 1..=20 \
6031         bytes, starts with an ASCII letter, ASCII alphanumeric / `_` / `-` \
6032         continuation. The canonical authoring shapes are short kebab-case \
6033         identifiers like `\"mesh\"`, `\"wasm\"`, `\"tatara-lisp\"`, \
6034         `\"hello-world\"`, `\"caixa-servico\"`, `\"infrastructure\"`. \
6035         Without this gate a malformed `:etiquetas` entry (paste-from-doc \
6036         leading / trailing whitespace `\" mesh\"` / `\"mesh \"`; \
6037         paste-from-multiline-doc newline `\"mesh\\nhttp\"`; \
6038         paste-from-Windows-CRLF-doc CR; CSV-list-separator confusion \
6039         `\"mesh,http,grpc\"` — the author meant to author three separate \
6040         list entries; path-separator confusion `\"caixa/servico\"`; \
6041         namespace-suffix `\"http.1\"`; leading-digit `\"1foo\"`; \
6042         kebab-leak `\"-foo\"`; snake-leak `\"_foo\"`; non-ASCII \
6043         `\"café\"` — every legitimate search tag is strict ASCII; \
6044         paste-from-binary-blob NUL / BEL / ESC / DEL byte) silently \
6045         passed `from_lisp` + `validate_etiquetas` + \
6046         `StandardLayout::verify` and landed in the rendered \
6047         `lareira-<nome>` Helm chart's `Chart.yaml keywords:` array as a \
6048         malformed search tag — Artifact Hub's keyword index + the future \
6049         caixa-registry's keyword index would either silently drop the \
6050         tag or fail to index it far from the source caixa.lisp; the gate \
6051         moves the diagnostic to the manifest layer with the offending \
6052         value named verbatim)"
6053    )]
6054    EtiquetaInvalid { etiqueta: String, reason: String },
6055    #[error(
6056        ":autores entry is empty (every maintainer must carry a non-empty \
6057         identifier; the empty entry has no operational meaning — it \
6058         identifies no one in the substrate's authorship index and renders \
6059         as `maintainers: [{{name: \"\", email: null}}]` in the Helm chart's \
6060         `Chart.yaml`, a no-op maintainer the substrate cannot route to; \
6061         omit the entry to express \"no maintainer on this position\")"
6062    )]
6063    AutorEmpty,
6064    #[error(
6065        ":autores entry {autor:?} appears more than once (the maintainer \
6066         set is a set, not a multiset; unlike `:etiquetas`, caixa-helm's \
6067         `maintainers:` rendering does *no* dedup — duplicate entries \
6068         stack verbatim in `Chart.yaml` as two identical \
6069         `Maintainer {{ name, email: None }}` records, divergent from every \
6070         peer typed-graph set gate (`:etiquetas`, `:membros :caixa`, \
6071         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
6072         `:deps :nome`, `:upgrade-from :from`); drop the duplicate or \
6073         rename it to the actual author intended)"
6074    )]
6075    AutorDuplicate { autor: String },
6076    #[error(
6077        ":autores entry {autor:?} is not a valid chart-maintainer-name shape: \
6078         {reason} (the substrate consumes this string through the shared \
6079         `crate::render::is_chart_maintainer_name_shape` predicate — the same \
6080         single-line-UTF-8 floor every realistic chart maintainer name carries: \
6081         1..=128 bytes, no leading or trailing whitespace, no ASCII control \
6082         characters anywhere, Unicode bytes accepted. The canonical authoring \
6083         shapes are short single-line identifiers like `\"pleme-io\"`, \
6084         `\"Pleme Contributors\"`, `\"alice <alice@example.com>\"`, \
6085         `\"François Dupont\"`. Without this gate a malformed `:autores` entry \
6086         (paste-from-aligned-doc leading whitespace `\" pleme-io\"` / trailing \
6087         whitespace `\"pleme-io \"`; paste-from-multiline-doc newline \
6088         `\"alice\\nbob\"` — the author pasted a multi-line block of author \
6089         records into one entry instead of splitting into one entry per author; \
6090         paste-from-Windows-CRLF-doc carriage return `\"alice\\rbob\"`; \
6091         tab-from-aligned-doc `\"Pleme\\tContributors\"`; paste-from-binary-blob \
6092         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
6093         `validate_autores` + `StandardLayout::verify` and landed in the \
6094         rendered `lareira-<nome>` Helm chart's `Chart.yaml maintainers:` array \
6095         as a YAML-illegal multi-line scalar or a silently-trimmed whitespace \
6096         round-trip — every chart-aware UI (`helm list`, `helm search`, \
6097         Artifact Hub maintainer index) would render the maintainer name in a \
6098         single-line column far from the source caixa.lisp; the gate moves the \
6099         diagnostic to the manifest layer with the offending value named \
6100         verbatim)"
6101    )]
6102    AutorInvalid { autor: String, reason: String },
6103    #[error(
6104        ":repositorio is the empty string (every published caixa names its \
6105         git source via a non-empty `:repositorio` locator — the value \
6106         flows verbatim into the rendered `lareira-<nome>` Helm chart's \
6107         `Chart.yaml` `home:` field via `caixa-helm` and into the FluxCD \
6108         `GitRepository.spec.url` via `caixa-flux`'s \
6109         `ClusterBundleOpts::for_caixa`; both consumers' \
6110         `Option::unwrap_or_else` fallbacks only fire when the slot is \
6111         `None`, so an empty `Some(\"\")` silently lands as `home: \"\"` / \
6112         `url: \"\"` in the rendered artifacts and breaks at `helm \
6113         template` / FluxCD source-controller reconcile time far from the \
6114         source caixa.lisp; omit the slot entirely to defer to the \
6115         renderer's `https://github.com/pleme-io/<nome>` / \
6116         `caixa.nome`-derived fallback, or carry a canonical authoring \
6117         shape like `\"github:org/repo\"`, `\"https://host/path\"`, \
6118         `\"ssh://[user@]host/path\"`, `\"git@host:path\"`, or \
6119         `\"file:///path\"`)"
6120    )]
6121    RepositorioEmpty,
6122    #[error(
6123        ":repositorio {repositorio:?} is not a valid git repo URL: {reason} \
6124         (the substrate consumes this string through the shared \
6125         `crate::render::is_git_repo_url` predicate — the same parser the \
6126         peer `:deps :fonte (:tipo git :repo …)` axis routes its `:repo` \
6127         value through via `DepSource::validate`; the canonical authoring \
6128         shapes are `\"github:org/repo\"` shorthand, `\"https://host/path\"` \
6129         / `\"ssh://[user@]host/path\"` / `\"git://host/path\"` / \
6130         `\"file:///path\"` URL schemes, or the `\"git@host:path\"` \
6131         scp-style SSH form. Without this gate a malformed `:repositorio` \
6132         (whitespace from a paste-from-doc; control characters / CRLF \
6133         from a paste-from-multiline-doc; a leading `-` from a \
6134         CLI-argument-injection footgun; a missing `:` separator from a \
6135         bare `org/repo` shape git treats as a relative filesystem path) \
6136         silently landed in the rendered `Chart.yaml home:` and the \
6137         FluxCD `GitRepository.spec.url` and broke at `git clone` / \
6138         FluxCD reconcile time far from the source caixa.lisp; the gate \
6139         moves the diagnostic to the manifest layer with the offending \
6140         value named verbatim)"
6141    )]
6142    RepositorioInvalid { repositorio: String, reason: String },
6143    #[error(
6144        ":descricao is the empty string (every published caixa names \
6145         its purpose via a non-empty `:descricao` summary — the value \
6146         flows verbatim into the rendered `lareira-<nome>` Helm \
6147         chart's `Chart.yaml` `description:` field via `caixa-helm`'s \
6148         `build_chart_yaml` and into the chart `README.md` header via \
6149         `build_readme`; both consumers' `Option::unwrap_or_else` \
6150         `caixa.nome`-derived fallbacks only fire when the slot is \
6151         `None`, so an empty `Some(\"\")` silently lands as \
6152         `description: \"\"` / a blank `README.md` header in the \
6153         rendered artifacts and breaks at `helm lint` time \
6154         (`WARNING [chart.metadata.description]: description is \
6155         required` on `apiVersion: v2` charts) far from the source \
6156         caixa.lisp; omit the slot entirely to defer to the \
6157         renderer's `\"Generated chart for caixa Servico <nome>\"` / \
6158         `\"caixa Servico <nome>\"` fallbacks, or carry a non-empty \
6159         summary like `\"Canonical Rust→wasm32-wasip2 caixa \
6160         Servico.\"`)"
6161    )]
6162    DescricaoEmpty,
6163    #[error(
6164        ":descricao {descricao:?} is not a valid chart-description shape: \
6165         {reason} (the substrate consumes this string through the shared \
6166         `crate::render::is_chart_description_shape` predicate — the same \
6167         single-line-UTF-8 floor every realistic chart description carries: \
6168         1..=512 bytes, no leading or trailing whitespace, no ASCII control \
6169         characters anywhere, Unicode prose bytes accepted. The canonical \
6170         authoring shapes are short single-line summaries like `\"Canonical \
6171         Rust→wasm32-wasip2 caixa Servico.\"`, `\"Checkout flow.\"`, \
6172         `\"AWS provider caixa for tatara-lisp\"`. Without this gate a \
6173         malformed `:descricao` (paste-from-aligned-doc leading whitespace \
6174         `\" Checkout flow.\"` / trailing whitespace `\"Checkout flow. \"`; \
6175         paste-from-multiline-doc newline `\"Checkout\\nflow.\"`; \
6176         paste-from-Windows-CRLF-doc carriage return `\"Checkout\\rflow.\"`; \
6177         tab-from-aligned-doc `\"Checkout\\tflow.\"`; paste-from-binary-blob \
6178         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
6179         `validate_descricao` + `StandardLayout::verify` and landed in the \
6180         rendered `lareira-<nome>` Helm chart's `Chart.yaml description:` \
6181         field + `README.md` header paragraph as a YAML-illegal multi-line \
6182         scalar or a silently-trimmed whitespace round-trip — every \
6183         chart-aware UI (`helm list`, `helm search`, Artifact Hub) would \
6184         render the description in a single-line column far from the source \
6185         caixa.lisp; the gate moves the diagnostic to the manifest layer \
6186         with the offending value named verbatim)"
6187    )]
6188    DescricaoInvalid { descricao: String, reason: String },
6189    #[error(
6190        ":licenca is the empty string (every published caixa names \
6191         its license via a non-empty `:licenca` SPDX expression — the \
6192         value flows verbatim into the rendered `lareira-<nome>` Helm \
6193         chart's `README.md` `## License` section via `caixa-helm`'s \
6194         `build_readme` at `caixa-helm/src/lib.rs:361`; the consumer's \
6195         `Option::unwrap_or_else(|| \"MIT\".into())` `MIT` fallback \
6196         only fires when the slot is `None`, so an empty `Some(\"\")` \
6197         silently lands as a bare trailing period in the rendered \
6198         chart `README.md` `License` section far from the source \
6199         caixa.lisp; omit the slot entirely to defer to the \
6200         renderer's `MIT` fallback, or carry a canonical SPDX \
6201         expression like `\"MIT\"`, `\"Apache-2.0\"`, \
6202         `\"Apache-2.0 OR MIT\"`)"
6203    )]
6204    LicencaEmpty,
6205    #[error(
6206        ":licenca {licenca:?} is not a valid SPDX expression shape: {reason} \
6207         (the substrate consumes this string through the shared \
6208         `crate::render::is_spdx_expression_shape` predicate — the same \
6209         alphabet-floor parser every peer per-axis value-shape gate routes \
6210         its value through; the canonical authoring shapes are single \
6211         license identifiers like `\"MIT\"`, `\"Apache-2.0\"`, `\"BSD-3-Clause\"`, \
6212         compound expressions like `\"Apache-2.0 OR MIT\"`, \
6213         `\"MIT AND BSD-3-Clause\"`, `\"(MIT OR Apache-2.0) AND ISC\"`, \
6214         license-with-exception forms like `\"Apache-2.0 WITH LLVM-exception\"`, \
6215         `+`-suffix variants like `\"GPL-2.0+\"`, and user-defined references \
6216         like `\"LicenseRef-MyLicense\"` / \
6217         `\"DocumentRef-doc:LicenseRef-MyLicense\"`. Without this gate a \
6218         malformed `:licenca` (paste-from-doc whitespace `\"MIT \"` / \
6219         `\" MIT\"`; paste-from-multiline-doc CRLF `\"MIT\\n\"`; \
6220         tab-from-aligned-doc `\"MIT\\tOR Apache-2.0\"`; non-ASCII byte from \
6221         a smart-quote paste; underscore-instead-of-hyphen typo \
6222         `\"Apache_2.0\"`; comma-instead-of-`OR`-keyword colloquial idiom \
6223         `\"MIT, Apache-2.0\"`; slash-dual-license colloquial idiom \
6224         `\"MIT/Apache-2.0\"`; semicolon-list-separator confusion \
6225         `\"MIT; Apache-2.0\"`) silently landed in the rendered chart \
6226         `README.md` `## License` section + a future SPDX-aware \
6227         `Chart.yaml license:` emitter would refuse the value at \
6228         `helm lint` time far from the source caixa.lisp; the gate moves \
6229         the diagnostic to the manifest layer with the offending value \
6230         named verbatim)"
6231    )]
6232    LicencaInvalid { licenca: String, reason: String },
6233    #[error(
6234        ":edicao is the empty string (every published caixa names \
6235         its language edition via a non-empty `:edicao` value — the \
6236         edition determines the tatara-lisp macro surface + \
6237         compatibility flags the substrate applies when building \
6238         the caixa; the canonical `Caixa::template` scaffold every \
6239         `feira init` emits carries `:edicao \"2026\"` verbatim and \
6240         every renderer-side fixture (`caixa-helm`, `caixa-flux`, \
6241         `caixa-mesh`) carries `edicao: Some(\"2026\".into())` by \
6242         construction, so an empty `Some(\"\")` silently lands as a \
6243         bare `(:edicao \"\")` line in the rendered `caixa.lisp` and \
6244         a future renderer-side consumer that folds it through \
6245         `Option::unwrap_or_else` will skip the fallback and pass the \
6246         empty edition through to the substrate's build-time edition \
6247         selector far from the source caixa.lisp; omit the slot \
6248         entirely to defer to the substrate's default edition, or \
6249         carry a canonical edition like `\"2026\"`)"
6250    )]
6251    EdicaoEmpty,
6252    #[error(
6253        ":edicao {edicao:?} is not a valid edition: {reason} (every \
6254         documented tatara-lisp edition is a 4-digit ASCII decimal \
6255         year — `\"2026\"` is the only edition currently minted; \
6256         future-introduced siblings will follow the same shape, peer \
6257         with Cargo's `[package] edition` grammar which every value \
6258         Cargo has ever accepted matches: `\"2015\"`, `\"2018\"`, \
6259         `\"2021\"`, `\"2024\"`. Without this gate the canonical \
6260         paste-from-doc footguns silently passed: a trailing space \
6261         (`\"2026 \"`) from a paste-from-doc, a CRLF (`\"2026\\n\"`) \
6262         from a paste-from-multiline-doc, a fullwidth-keyboard \
6263         look-alike (`\"2026\"`), a free-form non-year value \
6264         (`\"x\"`, `\"latest\"`, `\"nightly\"`), a leading non-digit \
6265         version-tag prefix (`\"v2026\"`, `\"e2026\"`), a \
6266         decimal-shaped pseudo-version (`\"2026.1\"`), or a \
6267         wrong-length numeric value (`\"26\"`, `\"202\"`, \
6268         `\"20260\"`) all landed as `(:edicao \"<garbage>\")` in the \
6269         rendered caixa.lisp and broke at the substrate's \
6270         build-time edition selector far from the source caixa.lisp; \
6271         omit the slot entirely to defer to the substrate's default \
6272         edition, or carry a canonical 4-digit ASCII decimal year \
6273         like `\"2026\"`)"
6274    )]
6275    EdicaoInvalid { edicao: String, reason: String },
6276}
6277
6278#[cfg(test)]
6279mod tests {
6280    use super::*;
6281
6282    #[test]
6283    fn template_round_trips() {
6284        let src = Caixa::template("demo");
6285        let c = Caixa::from_lisp(&src).expect("template must parse");
6286        assert_eq!(c.nome, "demo");
6287        assert_eq!(c.versao, "0.1.0");
6288        assert_eq!(c.kind, CaixaKind::Biblioteca);
6289        assert_eq!(c.bibliotecas, vec!["lib/demo.lisp".to_string()]);
6290        assert!(c.deps.is_empty());
6291        assert!(c.deps_dev.is_empty());
6292    }
6293
6294    #[test]
6295    fn caixa_universal_axis_scalar_accessor_pair_is_const_fn() {
6296        // Fail-before-pass-after pin on [`Caixa::nome`] +
6297        // [`Caixa::versao`]'s `const`-eval-surface posture. Each
6298        // accessor projects the top-level manifest's per-`:nome` /
6299        // per-`:versao` [`String`] storage through the `pub const fn`
6300        // [`String::as_str`] (const-stable since Rust 1.87, well within
6301        // the workspace MSRV) — any future accidental downgrade to
6302        // non-`const` fails the corresponding `<name>_via_const_fn`
6303        // wrapper at caixa-core build time with E0015 (`cannot call
6304        // non-const method`), strictly stronger than a runtime
6305        // `assert!`. Sibling of the peer per-M2/M3-slot `String → &str`
6306        // scalar-accessor family pins on the sibling `const`-eval-
6307        // surface passes ([`crate::CaixaVersion::as_str`] at the
6308        // typed-newtype wrapper, [`crate::aplicacao::Membro::nome`] /
6309        // [`crate::aplicacao::Membro::versao_requirement`] at the M3
6310        // membership axis, [`crate::aplicacao::Entrada::hostname`] /
6311        // [`crate::aplicacao::Entrada::destination`] at the M3 ingress
6312        // axis, [`crate::supervisor::ChildSpec::nome`] /
6313        // [`crate::supervisor::ChildSpec::versao_requirement`] at the
6314        // M2 supervisor-tree axis,
6315        // [`crate::upgrade::UpgradeFromEntry::prior_versao`] at the M2
6316        // upgrade axis, [`crate::dep::Dep::nome`] /
6317        // [`crate::dep::Dep::versao_requirement`] at the dep-graph
6318        // axis, and the per-`:contratos`
6319        // [`crate::aplicacao::WitContract::source`] /
6320        // [`crate::aplicacao::WitContract::destination`] /
6321        // [`crate::aplicacao::WitContract::world_ref`] trio the
6322        // sibling pin at 279823b already anchors).
6323        const fn nome_via_const_fn(c: &Caixa) -> &str {
6324            c.nome()
6325        }
6326        const fn versao_via_const_fn(c: &Caixa) -> &str {
6327            c.versao()
6328        }
6329        let src = Caixa::template("demo");
6330        let c = Caixa::from_lisp(&src).expect("template must parse");
6331        assert_eq!(nome_via_const_fn(&c), c.nome());
6332        assert_eq!(versao_via_const_fn(&c), c.versao());
6333        assert_eq!(c.nome(), "demo");
6334        assert_eq!(c.versao(), "0.1.0");
6335    }
6336
6337    #[test]
6338    fn caixa_option_string_scalar_accessor_family_is_const_fn() {
6339        // Fail-before-pass-after pin on the five per-`Caixa`
6340        // `Option<String> → Option<&str>` scalar accessors
6341        // ([`Caixa::licenca`] / [`Caixa::repositorio`] /
6342        // [`Caixa::descricao`] / [`Caixa::edicao`] on the top-level
6343        // manifest's optional universal-axis surface, plus
6344        // [`Caixa::restart_window`] on the M2 supervisor-tree
6345        // per-`SupervisorSpec` peer raw-window-string projection axis).
6346        // Each accessor destructures the typed slot's `Option<String>`
6347        // storage through the `match &self.<field> { Some(s) =>
6348        // Some(s.as_str()), None => None }` shape — routing through
6349        // [`String::as_str`] (const-stable since Rust 1.87, well within
6350        // the workspace MSRV) rather than the non-const
6351        // [`Option::as_deref`] the pre-lift bodies carried — and any
6352        // future accidental downgrade to non-`const` fails the
6353        // corresponding `<name>_via_const_fn` wrapper at caixa-core
6354        // build time with E0015 (`cannot call non-const method`),
6355        // strictly stronger than a runtime `assert!` and strictly
6356        // stronger than a module-scope `const _: () = assert!(…)` pin
6357        // (which cannot be formed on a `&Caixa` fixture because the
6358        // type's `String` / `Option<String>` carriers rule out
6359        // `const`-context value construction; the `const fn` wrapper
6360        // is the load-bearing shape that side-steps the destructor-in-
6361        // const restriction on the value axis while still pinning the
6362        // `const`-fn posture on the callee — mirror of the sibling
6363        // [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
6364        // pin's discipline verbatim on the peer non-`Option`
6365        // `String → &str` axis at the same struct).
6366        //
6367        // Peer of the sibling per-M2/M3-slot `Option<String> →
6368        // Option<&str>` accessor family pin
6369        // [`m3_option_string_scalar_accessor_family_is_const_fn`] on
6370        // the M3 mesh-slot atom axes ([`WitContract::endpoint`] /
6371        // [`WitContract::subject`] / [`WitContract::slot`] on the
6372        // per-`:contratos` payload-carrier trio,
6373        // [`Placement::shard_key`] / [`Placement::affinity`] on the
6374        // per-`:placement` optional-scalar pair).
6375        const fn licenca_via_const_fn(c: &Caixa) -> Option<&str> {
6376            c.licenca()
6377        }
6378        const fn repositorio_via_const_fn(c: &Caixa) -> Option<&str> {
6379            c.repositorio()
6380        }
6381        const fn descricao_via_const_fn(c: &Caixa) -> Option<&str> {
6382            c.descricao()
6383        }
6384        const fn edicao_via_const_fn(c: &Caixa) -> Option<&str> {
6385            c.edicao()
6386        }
6387        const fn restart_window_via_const_fn(c: &Caixa) -> Option<&str> {
6388            c.restart_window()
6389        }
6390        // Sweep both the `Some`-carrying arm (author-declared slot,
6391        // the byte-string projection payload) and the `None`-carrying
6392        // arm (author-omitted slot, the default-path projection) on
6393        // every accessor so the `const fn` wrapper family pins each
6394        // axis's canonical two-arm partition through the same const
6395        // dispatch as the runtime path.
6396        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6397        c1.licenca = Some("MIT".to_string());
6398        c1.repositorio = Some("https://github.com/pleme-io/demo".to_string());
6399        c1.descricao = Some("demo caixa".to_string());
6400        c1.edicao = Some("2024".to_string());
6401        c1.restart_window = Some("60s".to_string());
6402        assert_eq!(licenca_via_const_fn(&c1), c1.licenca());
6403        assert_eq!(repositorio_via_const_fn(&c1), c1.repositorio());
6404        assert_eq!(descricao_via_const_fn(&c1), c1.descricao());
6405        assert_eq!(edicao_via_const_fn(&c1), c1.edicao());
6406        assert_eq!(restart_window_via_const_fn(&c1), c1.restart_window());
6407        assert_eq!(c1.licenca(), Some("MIT"));
6408        assert_eq!(c1.repositorio(), Some("https://github.com/pleme-io/demo"));
6409        assert_eq!(c1.descricao(), Some("demo caixa"));
6410        assert_eq!(c1.edicao(), Some("2024"));
6411        assert_eq!(c1.restart_window(), Some("60s"));
6412        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6413        c2.licenca = None;
6414        c2.repositorio = None;
6415        c2.descricao = None;
6416        c2.edicao = None;
6417        c2.restart_window = None;
6418        assert_eq!(licenca_via_const_fn(&c2), None);
6419        assert_eq!(repositorio_via_const_fn(&c2), None);
6420        assert_eq!(descricao_via_const_fn(&c2), None);
6421        assert_eq!(edicao_via_const_fn(&c2), None);
6422        assert_eq!(restart_window_via_const_fn(&c2), None);
6423    }
6424
6425    #[test]
6426    fn caixa_outer_copy_return_accessor_pair_is_const_fn() {
6427        // Fail-before-pass-after pin on the two outer-[`Caixa`]
6428        // `Copy`-return accessors — [`Caixa::kind`] on the required
6429        // [`CaixaKind`] enum-discriminant axis and [`Caixa::estrategia`]
6430        // on the M2 supervisor-tree flat-spread `Option<RestartStrategy>`
6431        // axis. Both accessors project a `Copy`-carrier field
6432        // (`CaixaKind: Copy` at caixa-core/src/kind.rs:17,
6433        // `RestartStrategy: Copy` at caixa-core/src/supervisor.rs:33 →
6434        // `Option<RestartStrategy>: Copy`) by value through a bare
6435        // `self.<field>` field-access — no dispatch, no destructor, no
6436        // heap. Any future accidental downgrade to non-`const` fails
6437        // the corresponding `<name>_via_const_fn` wrapper at caixa-core
6438        // build time with E0015 (`cannot call non-const method`),
6439        // strictly stronger than a runtime `assert!` and strictly
6440        // stronger than a module-scope `const _: () = assert!(…)` pin
6441        // (which cannot be formed on a `&Caixa` fixture because the
6442        // type's `String` / `Vec` / `Option<Composite>` carriers rule
6443        // out `const`-context value construction; the `const fn`
6444        // wrapper is the load-bearing shape that side-steps the
6445        // destructor-in-const restriction on the value axis while still
6446        // pinning the `const`-fn posture on the callee — mirror of the
6447        // sibling [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
6448        // + [`caixa_option_string_scalar_accessor_family_is_const_fn`]
6449        // pins' discipline verbatim on the peer outer-`Caixa`
6450        // `String → &str` + `Option<String> → Option<&str>` axes at the
6451        // same struct).
6452        //
6453        // Peer of the sibling per-M2/M3-slot `Copy`-return accessor pin
6454        // family on the inner-altitude nested-spec typed-slot
6455        // discriminator axes: [`crate::supervisor::SupervisorSpec::estrategia`]
6456        // + [`crate::supervisor::ChildSpec::restart`] on the M2
6457        // supervisor-tree axis (pinned at 152c868), and
6458        // [`crate::aplicacao::Placement::estrategia`] +
6459        // [`crate::aplicacao::Entrada::port`] on the M3 mesh-slot axis
6460        // (pinned at bafa004) — the outer-`Caixa` altitude is the last
6461        // unlifted altitude for the `Copy`-return-accessor family.
6462        const fn kind_via_const_fn(c: &Caixa) -> CaixaKind {
6463            c.kind()
6464        }
6465        const fn estrategia_via_const_fn(c: &Caixa) -> Option<crate::supervisor::RestartStrategy> {
6466            c.estrategia()
6467        }
6468        // Sweep every arm of both discriminant partitions the accessors
6469        // fan on — every [`CaixaKind`] variant the six-arm required
6470        // discriminant carries (Biblioteca / Binario / Servico /
6471        // Supervisor / Aplicacao / Acao) and both arms of the
6472        // [`Option<RestartStrategy>`] flat-spread supervisor-tree slot
6473        // (`Some(<strategy>)` on an author-declared supervisor and
6474        // `None` on the author-omitted default arm every non-Supervisor
6475        // caixa carries by `#[serde(default)]`) — so the `const fn`
6476        // wrapper family pins the closed-set partition through the
6477        // same const dispatch as the runtime path.
6478        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6479        c1.kind = CaixaKind::Servico;
6480        c1.estrategia = Some(crate::supervisor::RestartStrategy::OneForAll);
6481        assert_eq!(kind_via_const_fn(&c1), c1.kind());
6482        assert_eq!(estrategia_via_const_fn(&c1), c1.estrategia());
6483        assert_eq!(c1.kind(), CaixaKind::Servico);
6484        assert_eq!(
6485            c1.estrategia(),
6486            Some(crate::supervisor::RestartStrategy::OneForAll)
6487        );
6488        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6489        c2.kind = CaixaKind::Aplicacao;
6490        c2.estrategia = None;
6491        assert_eq!(kind_via_const_fn(&c2), CaixaKind::Aplicacao);
6492        assert_eq!(estrategia_via_const_fn(&c2), None);
6493        // Anchor the remaining discriminant arms so any future
6494        // reordering of [`CaixaKind`]'s six-variant enum surfaces
6495        // through the wrapper dispatch, not just through the direct
6496        // method call.
6497        for kind in [
6498            CaixaKind::Biblioteca,
6499            CaixaKind::Binario,
6500            CaixaKind::Servico,
6501            CaixaKind::Supervisor,
6502            CaixaKind::Aplicacao,
6503            CaixaKind::Acao,
6504        ] {
6505            let mut c = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6506            c.kind = kind;
6507            assert_eq!(kind_via_const_fn(&c), kind);
6508        }
6509    }
6510
6511    #[test]
6512    fn caixa_outer_string_slice_return_accessor_family_is_const_fn() {
6513        // Fail-before-pass-after pin on the five outer-[`Caixa`]
6514        // `Vec<String> → &[String]` slice-return accessors on the
6515        // universal-axis surface — [`Caixa::autores`] / [`Caixa::etiquetas`]
6516        // / [`Caixa::bibliotecas`] / [`Caixa::exe`] / [`Caixa::servicos`].
6517        // Each body is a bare `self.<field>.as_slice()` dispatch through
6518        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
6519        // the workspace MSRV). Any future accidental downgrade to
6520        // non-`const` fails the corresponding `<name>_via_const_fn`
6521        // wrapper at caixa-core build time with E0015 (`cannot call
6522        // non-const method`) — mirror of the sibling
6523        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] pin's
6524        // discipline on the peer outer-`Caixa` `Copy`-return accessor
6525        // axis, and peer of the sibling composite-carrier slice-return
6526        // pin below on the peer outer-`Caixa` composite-slice axis.
6527        const fn autores_via_const_fn(c: &Caixa) -> &[String] {
6528            c.autores()
6529        }
6530        const fn etiquetas_via_const_fn(c: &Caixa) -> &[String] {
6531            c.etiquetas()
6532        }
6533        const fn bibliotecas_via_const_fn(c: &Caixa) -> &[String] {
6534            c.bibliotecas()
6535        }
6536        const fn exe_via_const_fn(c: &Caixa) -> &[String] {
6537            c.exe()
6538        }
6539        const fn servicos_via_const_fn(c: &Caixa) -> &[String] {
6540            c.servicos()
6541        }
6542        // Sweep the empty arm (`autores` / `etiquetas` / `exe` /
6543        // `servicos` — the template's `Vec::new()` default) and the
6544        // populated arm (mutated below) on every accessor so the
6545        // `const fn` wrapper family pins each axis's two-arm partition
6546        // through the same const dispatch as the runtime path.
6547        // [`Caixa::template`] seeds `lib/demo.lisp` into `:bibliotecas`,
6548        // so that arm's "empty" fixture is the populated arm the
6549        // mutation sweep covers.
6550        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6551        assert!(autores_via_const_fn(&c_empty).is_empty());
6552        assert!(etiquetas_via_const_fn(&c_empty).is_empty());
6553        assert!(exe_via_const_fn(&c_empty).is_empty());
6554        assert!(servicos_via_const_fn(&c_empty).is_empty());
6555        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6556        c_full.autores = vec!["ada".to_string(), "erlang".to_string()];
6557        c_full.etiquetas = vec!["compounding".to_string()];
6558        c_full.bibliotecas = vec!["lib/one.lisp".to_string(), "lib/two.lisp".to_string()];
6559        c_full.exe = vec!["exe/cli.lisp".to_string()];
6560        c_full.servicos = vec!["servicos/one.computeunit.yaml".to_string()];
6561        assert_eq!(autores_via_const_fn(&c_full), c_full.autores());
6562        assert_eq!(autores_via_const_fn(&c_full), &["ada", "erlang"]);
6563        assert_eq!(etiquetas_via_const_fn(&c_full), c_full.etiquetas());
6564        assert_eq!(etiquetas_via_const_fn(&c_full), &["compounding"]);
6565        assert_eq!(bibliotecas_via_const_fn(&c_full), c_full.bibliotecas());
6566        assert_eq!(
6567            bibliotecas_via_const_fn(&c_full),
6568            &["lib/one.lisp", "lib/two.lisp"]
6569        );
6570        assert_eq!(exe_via_const_fn(&c_full), c_full.exe());
6571        assert_eq!(exe_via_const_fn(&c_full), &["exe/cli.lisp"]);
6572        assert_eq!(servicos_via_const_fn(&c_full), c_full.servicos());
6573        assert_eq!(
6574            servicos_via_const_fn(&c_full),
6575            &["servicos/one.computeunit.yaml"]
6576        );
6577    }
6578
6579    #[test]
6580    fn caixa_outer_composite_slice_return_accessor_family_is_const_fn() {
6581        // Fail-before-pass-after pin on the six outer-[`Caixa`] composite-
6582        // carrier `Vec<T> → &[T]` slice-return accessors — [`Caixa::deps`]
6583        // / [`Caixa::deps_dev`] on the dep-graph axis,
6584        // [`Caixa::upgrade_from`] on the M2 appup axis, [`Caixa::children`]
6585        // on the M2 supervisor-tree axis, and [`Caixa::membros`] /
6586        // [`Caixa::contratos`] on the M3 mesh-slot axis. Each body is a
6587        // bare `self.<field>.as_slice()` dispatch through
6588        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
6589        // the workspace MSRV) — peer of the sibling `String`-payload
6590        // slice-return pin above on the peer outer-`Caixa` universal-
6591        // axis surface, and peer of the sibling inner-composite-
6592        // altitude reference-return pin family
6593        // [`crate::aplicacao::tests::m3_aplicacao_spec_reference_return_accessor_family_is_const_fn`]
6594        // + [`crate::supervisor::tests::supervisor_children_slice_return_accessor_is_const_fn`]
6595        // + [`crate::upgrade::tests::upgrade_from_entry_instructions_slice_return_accessor_is_const_fn`]
6596        // (all pinned at 0b23e0f).
6597        const fn deps_via_const_fn(c: &Caixa) -> &[Dep] {
6598            c.deps()
6599        }
6600        const fn deps_dev_via_const_fn(c: &Caixa) -> &[Dep] {
6601            c.deps_dev()
6602        }
6603        const fn upgrade_from_via_const_fn(c: &Caixa) -> &[UpgradeFromEntry] {
6604            c.upgrade_from()
6605        }
6606        const fn children_via_const_fn(c: &Caixa) -> &[crate::supervisor::ChildSpec] {
6607            c.children()
6608        }
6609        const fn membros_via_const_fn(c: &Caixa) -> &[crate::aplicacao::Membro] {
6610            c.membros()
6611        }
6612        const fn contratos_via_const_fn(c: &Caixa) -> &[crate::aplicacao::WitContract] {
6613            c.contratos()
6614        }
6615        // Empty-arm sweep on all six composite-carrier axes — every
6616        // `Caixa::template` starts with `Vec::new()` on each.
6617        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6618        assert!(deps_via_const_fn(&c_empty).is_empty());
6619        assert!(deps_dev_via_const_fn(&c_empty).is_empty());
6620        assert!(upgrade_from_via_const_fn(&c_empty).is_empty());
6621        assert!(children_via_const_fn(&c_empty).is_empty());
6622        assert!(membros_via_const_fn(&c_empty).is_empty());
6623        assert!(contratos_via_const_fn(&c_empty).is_empty());
6624        // Populate `:membros` / `:contratos` directly via struct literals
6625        // — the parser-side validation path fans on `:kind`-gated cross-
6626        // slot invariants irrelevant to the accessor dispatch under test.
6627        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6628        c_full.membros = vec![
6629            crate::aplicacao::Membro {
6630                caixa: "demo-a".to_string(),
6631                versao: "^0.1.0".to_string(),
6632            },
6633            crate::aplicacao::Membro {
6634                caixa: "demo-b".to_string(),
6635                versao: "^0.2.0".to_string(),
6636            },
6637        ];
6638        c_full.contratos = vec![crate::aplicacao::WitContract {
6639            de: "demo-a".to_string(),
6640            para: "demo-b".to_string(),
6641            wit: "wasi:http/proxy".to_string(),
6642            endpoint: Some("/edge".to_string()),
6643            subject: None,
6644            slot: None,
6645        }];
6646        assert_eq!(membros_via_const_fn(&c_full), c_full.membros());
6647        assert_eq!(contratos_via_const_fn(&c_full), c_full.contratos());
6648        assert_eq!(membros_via_const_fn(&c_full).len(), 2);
6649        assert_eq!(contratos_via_const_fn(&c_full).len(), 1);
6650        // Alias-borrow check on the four remaining composite-carrier
6651        // slice-return arms — the wrapper's return borrow must alias the
6652        // caller's borrow so any future accessor re-routing that skips
6653        // the storage field surfaces through the assertion.
6654        assert!(std::ptr::eq(deps_via_const_fn(&c_full), c_full.deps()));
6655        assert!(std::ptr::eq(
6656            deps_dev_via_const_fn(&c_full),
6657            c_full.deps_dev()
6658        ));
6659        assert!(std::ptr::eq(
6660            upgrade_from_via_const_fn(&c_full),
6661            c_full.upgrade_from()
6662        ));
6663        assert!(std::ptr::eq(
6664            children_via_const_fn(&c_full),
6665            c_full.children()
6666        ));
6667    }
6668
6669    #[test]
6670    fn caixa_outer_option_composite_reference_return_accessor_family_is_const_fn() {
6671        // Fail-before-pass-after pin on the six outer-[`Caixa`]
6672        // `Option<Composite> → Option<&Composite>` reference-return
6673        // accessors — [`Caixa::limits`] / [`Caixa::behavior`] on the M2
6674        // Servico-runtime typed-slot axis, [`Caixa::politicas`] /
6675        // [`Caixa::placement`] / [`Caixa::entrada`] on the M3 mesh-slot
6676        // axis, and [`Caixa::ci`] on the Acao-kind typed-CI-run axis.
6677        // Each body is a bare `self.<field>.as_ref()` dispatch through
6678        // [`Option::as_ref`] (const-stable since Rust 1.83, well within
6679        // the workspace MSRV of 1.89). Any future accidental downgrade
6680        // to non-`const` fails the corresponding `<name>_via_const_fn`
6681        // wrapper at caixa-core build time with E0015 (`cannot call
6682        // non-const method`), strictly stronger than a runtime `assert!`
6683        // and strictly stronger than a module-scope `const _: () =
6684        // assert!(…)` pin (which cannot be formed on a `&Caixa` fixture
6685        // because the type's `String` / `Vec` / `Option<Composite>`
6686        // carriers rule out `const`-context value construction; the
6687        // `const fn` wrapper is the load-bearing shape that side-steps
6688        // the destructor-in-const restriction on the value axis while
6689        // still pinning the `const`-fn posture on the callee — mirror
6690        // of the sibling
6691        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] +
6692        // [`caixa_outer_string_slice_return_accessor_family_is_const_fn`] +
6693        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
6694        // pins' discipline verbatim on the peer outer-`Caixa` axes at
6695        // the same struct).
6696        //
6697        // Closes the outer-`Caixa` `Option<&Composite>` composite-
6698        // reference-return sub-family — the last unlifted altitude on
6699        // the outer-`Caixa` accessor-family const-eval surface after
6700        // the sibling `Copy`-return / universal-axis-`&str` /
6701        // `Option<&str>` / `&[String]` / composite-`&[T]` pins already
6702        // closed the sibling arms at 866d1d5 / 29c5d7e / 0650f64 /
6703        // 231a968 (the last of these pins the `Vec<T> → &[T]`
6704        // composite-slice arm the six accessors here close as their
6705        // `Option<Composite> → Option<&Composite>` peer). Peer of the
6706        // sibling inner-altitude nested-spec composite-reference-return
6707        // pin family — [`crate::AplicacaoSpec::politicas`] /
6708        // [`crate::AplicacaoSpec::placement`] /
6709        // [`crate::AplicacaoSpec::entrada`] on the inner
6710        // [`crate::AplicacaoSpec`] altitude (already `pub const fn`
6711        // per 0b23e0f), and the outer-`Caixa` altitude here now carries
6712        // the same shape so both altitudes of the reference-return
6713        // discipline (per-`Caixa` outer-slot presence + per-
6714        // `AplicacaoSpec` inner-slot presence) route through one typed
6715        // const dispatch on the substrate primitive.
6716        const fn limits_via_const_fn(c: &Caixa) -> Option<&LimitsSpec> {
6717            c.limits()
6718        }
6719        const fn behavior_via_const_fn(c: &Caixa) -> Option<&crate::BehaviorSpec> {
6720            c.behavior()
6721        }
6722        const fn politicas_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::MeshPolicy> {
6723            c.politicas()
6724        }
6725        const fn placement_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Placement> {
6726            c.placement()
6727        }
6728        const fn entrada_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Entrada> {
6729            c.entrada()
6730        }
6731        const fn ci_via_const_fn(c: &Caixa) -> Option<&canteiro_types::CiRun> {
6732            c.ci()
6733        }
6734        // Both-arm sweep on every accessor: the `None` author-omitted
6735        // arm (template default — no M2/M3/CI slot declared) and the
6736        // `Some(<composite>)` authored arm (mutated below via struct-
6737        // literal seeds, side-stepping the parser-side `:kind`-gated
6738        // cross-slot invariants irrelevant to the accessor dispatch
6739        // under test). Both arms route through the `const fn` wrapper
6740        // family so the two-arm `Option` partition is pinned through
6741        // the same const dispatch as the runtime path.
6742        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6743        assert!(limits_via_const_fn(&c_empty).is_none());
6744        assert!(behavior_via_const_fn(&c_empty).is_none());
6745        assert!(politicas_via_const_fn(&c_empty).is_none());
6746        assert!(placement_via_const_fn(&c_empty).is_none());
6747        assert!(entrada_via_const_fn(&c_empty).is_none());
6748        assert!(ci_via_const_fn(&c_empty).is_none());
6749        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
6750        c_full.limits = Some(LimitsSpec::default());
6751        c_full.behavior = Some(crate::BehaviorSpec::default());
6752        c_full.politicas = Some(crate::aplicacao::MeshPolicy::default());
6753        c_full.placement = Some(crate::aplicacao::Placement::default());
6754        c_full.entrada = Some(crate::aplicacao::Entrada {
6755            host: "demo.quero.cloud".to_string(),
6756            para: "demo".to_string(),
6757            paths: Vec::new(),
6758            port: crate::aplicacao::DEFAULT_SERVICO_PORT,
6759        });
6760        c_full.ci = Some(canteiro_types::CiRun {
6761            workspace: "pleme-io".into(),
6762            repo: "caixa".into(),
6763            nodes: vec![],
6764        });
6765        assert!(limits_via_const_fn(&c_full).is_some());
6766        assert!(behavior_via_const_fn(&c_full).is_some());
6767        assert!(politicas_via_const_fn(&c_full).is_some());
6768        assert!(placement_via_const_fn(&c_full).is_some());
6769        assert!(entrada_via_const_fn(&c_full).is_some());
6770        assert!(ci_via_const_fn(&c_full).is_some());
6771        // Alias-borrow check on every arm: the wrapper's inner-`Option`
6772        // reference must alias the caller's borrow so any future accessor
6773        // re-routing that skips the storage field surfaces through the
6774        // assertion.
6775        assert!(std::ptr::eq(
6776            limits_via_const_fn(&c_full).unwrap(),
6777            c_full.limits().unwrap()
6778        ));
6779        assert!(std::ptr::eq(
6780            behavior_via_const_fn(&c_full).unwrap(),
6781            c_full.behavior().unwrap()
6782        ));
6783        assert!(std::ptr::eq(
6784            politicas_via_const_fn(&c_full).unwrap(),
6785            c_full.politicas().unwrap()
6786        ));
6787        assert!(std::ptr::eq(
6788            placement_via_const_fn(&c_full).unwrap(),
6789            c_full.placement().unwrap()
6790        ));
6791        assert!(std::ptr::eq(
6792            entrada_via_const_fn(&c_full).unwrap(),
6793            c_full.entrada().unwrap()
6794        ));
6795        assert!(std::ptr::eq(
6796            ci_via_const_fn(&c_full).unwrap(),
6797            c_full.ci().unwrap()
6798        ));
6799    }
6800
6801    #[test]
6802    fn register_populates_registry() {
6803        Caixa::register().expect("first register call in this test process must succeed");
6804        let kws = tatara_lisp::domain::registered_keywords();
6805        assert!(kws.contains(&"defcaixa"));
6806    }
6807
6808    #[test]
6809    fn to_lisp_round_trips() {
6810        let src = Caixa::template("demo");
6811        let c1 = Caixa::from_lisp(&src).unwrap();
6812        let emitted = c1.to_lisp();
6813        let c2 = Caixa::from_lisp(&emitted).expect("emitted lisp parses back");
6814        assert_eq!(c1, c2);
6815    }
6816
6817    // ── DialetoEstrangeiro carries a single typed axis ────────────────────
6818    //
6819    // The compounding pin: the variant stores only the typed
6820    // [`crate::dialeto::CaixaDialeto`], and every user-facing byte-string
6821    // (canonical keyword, description, consumer) routes through the enum's
6822    // own accessors at Display time. Prior to that closure the variant
6823    // carried each accessor's return value as a stored `&'static str`
6824    // snapshot alongside `dialeto`; a caller could construct the variant
6825    // with a snapshot that drifted from what `dialeto`'s accessors would
6826    // return, and every downstream user-facing projection would silently
6827    // disagree with the classification. Storing only the axis makes the
6828    // drift structurally impossible.
6829
6830    #[test]
6831    fn dialeto_estrangeiro_variant_carries_only_the_typed_dialeto_axis() {
6832        // Single-field construction is the whole compounding shape — a
6833        // future re-introduction of a snapshot field (a `palavra_canonica:
6834        // &'static str`, a stored `descricao:`, a stored `consumidor:`)
6835        // would re-open the drift surface and this construction would fail
6836        // to compile with "missing field" until every snapshot was seeded
6837        // at the call site again. The compile-time guarantee is the
6838        // invariant; the assertion below only witnesses that the
6839        // construction is well-formed after the closure.
6840        let err = LeituraError::DialetoEstrangeiro {
6841            dialeto: crate::dialeto::CaixaDialeto::Molde,
6842        };
6843        assert!(matches!(
6844            err,
6845            LeituraError::DialetoEstrangeiro {
6846                dialeto: crate::dialeto::CaixaDialeto::Molde,
6847            }
6848        ));
6849    }
6850
6851    #[test]
6852    fn dialeto_estrangeiro_display_routes_through_typed_dialeto_accessors() {
6853        // For every foreign-dialect classification the variant surfaces —
6854        // [`crate::dialeto::CaixaDialeto::Molde`] and
6855        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two
6856        // variants [`Caixa::from_lisp`] raises this error for — the
6857        // rendered [`std::fmt::Display`] byte-string must interpolate each
6858        // typed accessor's return verbatim. A future re-introduction of a
6859        // stored `&'static str` snapshot alongside `dialeto` that Display
6860        // read instead of the accessor would fail this pin as soon as the
6861        // two disagreed; a future accessor rebrand (a per-dialect
6862        // consumer rename, a canonical-keyword shift once the substrate
6863        // migration named in [`crate::dialeto`] completes) reaches every
6864        // consumer through one typed dispatch and this pin verifies the
6865        // display path is one of them.
6866        for d in [
6867            crate::dialeto::CaixaDialeto::Molde,
6868            crate::dialeto::CaixaDialeto::MoldePosicional,
6869        ] {
6870            let rendered = LeituraError::DialetoEstrangeiro { dialeto: d }.to_string();
6871            assert!(
6872                rendered.contains(d.palavra_canonica()),
6873                "Display must interpolate `dialeto.palavra_canonica()` \
6874                 verbatim — a stored snapshot would silently drift from \
6875                 the typed accessor. dialect: {d}, rendered: {rendered:?}"
6876            );
6877            assert!(
6878                rendered.contains(d.descricao()),
6879                "Display must interpolate `dialeto.descricao()` verbatim. \
6880                 dialect: {d}, rendered: {rendered:?}"
6881            );
6882            assert!(
6883                rendered.contains(d.consumidor()),
6884                "Display must interpolate `dialeto.consumidor()` verbatim. \
6885                 dialect: {d}, rendered: {rendered:?}"
6886            );
6887        }
6888    }
6889
6890    #[test]
6891    fn from_lisp_rejects_molde_dialect_via_typed_variant() {
6892        // The end-to-end pin the compounding closure defends: a
6893        // Molde-dialect source lands as [`LeituraError::DialetoEstrangeiro`]
6894        // carrying [`crate::dialeto::CaixaDialeto::Molde`], and the
6895        // rendered Display byte-string names the Molde accessors'
6896        // returns verbatim. Any future path that constructed the variant
6897        // with a mismatched snapshot (a stored `palavra_canonica:
6898        // "defcaixa"` on a `Molde` classification) would land Display
6899        // pointing at `defcaixa` while the typed axis said `Molde` — the
6900        // exact drift the closure removes.
6901        let src = r#"
6902          (defcaixa
6903            :name "x"
6904            :kind :Biblioteca
6905            :ecosystem :rust-single-crate
6906            :package {:name "x" :version "0.1.0"})
6907        "#;
6908        let err = Caixa::from_lisp(src).expect_err("Molde dialect must not parse as Pacote");
6909        match err {
6910            LeituraError::DialetoEstrangeiro { dialeto } => {
6911                assert_eq!(dialeto, crate::dialeto::CaixaDialeto::Molde);
6912                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
6913                assert!(rendered.contains(dialeto.palavra_canonica()));
6914                assert!(rendered.contains(dialeto.consumidor()));
6915                assert!(rendered.contains(dialeto.descricao()));
6916            }
6917            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
6918        }
6919    }
6920
6921    #[test]
6922    fn from_lisp_rejects_molde_posicional_dialect_via_typed_variant() {
6923        // Coverage pin for the [`crate::dialeto::CaixaDialeto::MoldePosicional`]
6924        // arm of the [`Caixa::from_lisp`] foreign-dialect gate — the
6925        // positional-arity `defmolde` form written under a `(defcaixa …)`
6926        // head (`(defcaixa todoku-go :kind :Biblioteca :ecosystem :go
6927        // …)`). Pre-lift this arm rode the same `foreign =>` wildcard
6928        // the [`crate::dialeto::CaixaDialeto::Molde`] sibling arm rode,
6929        // so no test exercised the positional-arity path through
6930        // `Caixa::from_lisp` specifically; the sibling
6931        // [`from_lisp_rejects_molde_dialect_via_typed_variant`] only
6932        // covered [`crate::dialeto::CaixaDialeto::Molde`]. Post-lift the
6933        // two arms route through the lifted
6934        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
6935        // typed predicate — the same predicate the pre-lift `foreign =>`
6936        // wildcard resolved to today — and this pin makes the
6937        // positional-arity arm's byte-shape at the gate explicit rather
6938        // than implied by wildcard-absorption. A future regression that
6939        // silently reordered [`crate::dialeto::CaixaDialeto::is_molde_family`]'s
6940        // arm-set (dropped [`crate::dialeto::CaixaDialeto::MoldePosicional`]
6941        // from the two-arity closure) would fail this pin at caixa-core
6942        // test time rather than surfacing far from the change as a
6943        // `caixa.lisp` carrying a `(defcaixa todoku-go :ecosystem :go
6944        // …)` silently parsing past the derive.
6945        let src = r#"
6946          (defcaixa todoku-go
6947            :kind :Biblioteca
6948            :ecosystem :go
6949            :package {:name "todoku-go" :version "0.3.0"})
6950        "#;
6951        let err =
6952            Caixa::from_lisp(src).expect_err("MoldePosicional dialect must not parse as Pacote");
6953        match err {
6954            LeituraError::DialetoEstrangeiro { dialeto } => {
6955                assert_eq!(
6956                    dialeto,
6957                    crate::dialeto::CaixaDialeto::MoldePosicional,
6958                    "DialetoEstrangeiro must carry the MoldePosicional \
6959                     variant verbatim — the positional-arity `defmolde` \
6960                     form under a `(defcaixa …)` head is the \
6961                     `MoldePosicional` arm's canonical byte-shape"
6962                );
6963                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
6964                assert!(
6965                    rendered.contains(dialeto.palavra_canonica()),
6966                    "Display must interpolate `dialeto.palavra_canonica()` \
6967                     verbatim on the MoldePosicional arm; rendered: \
6968                     {rendered:?}"
6969                );
6970                assert!(
6971                    rendered.contains(dialeto.consumidor()),
6972                    "Display must interpolate `dialeto.consumidor()` \
6973                     verbatim on the MoldePosicional arm; rendered: \
6974                     {rendered:?}"
6975                );
6976                assert!(
6977                    rendered.contains(dialeto.descricao()),
6978                    "Display must interpolate `dialeto.descricao()` \
6979                     verbatim on the MoldePosicional arm; rendered: \
6980                     {rendered:?}"
6981                );
6982            }
6983            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
6984        }
6985    }
6986
6987    #[test]
6988    fn from_lisp_dialect_gate_dispatches_through_caixa_dialeto_is_molde_family_predicate() {
6989        // Load-bearing byte-parity pin: for every arm in
6990        // [`crate::dialeto::CaixaDialeto::ALL`], the
6991        // [`Caixa::from_lisp`] foreign-dialect gate's DialetoEstrangeiro
6992        // partition must agree with the lifted
6993        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
6994        // typed predicate — i.e. from_lisp raises
6995        // [`LeituraError::DialetoEstrangeiro`] carrying `d` iff
6996        // `d.is_molde_family()` returns `true`, and does NOT raise
6997        // [`LeituraError::DialetoEstrangeiro`] on any arm where the
6998        // predicate returns `false` (the arm's source falls through to
6999        // the derive — parses cleanly on
7000        // [`crate::dialeto::CaixaDialeto::Pacote`], surfaces a
7001        // [`LeituraError::Leitura`] on
7002        // [`crate::dialeto::CaixaDialeto::Desconhecido`]).
7003        //
7004        // Pre-lift the gate hand-rolled a three-arm match
7005        // (`Pacote => {}`, `Desconhecido => {}`, `foreign => Err(…)`)
7006        // whose `foreign =>` wildcard expressed no compile-time link
7007        // back to the substrate primitive's arm-family; a future fifth
7008        // dialect the [`crate::dialeto`] module doc's "third dialect"
7009        // hazard actualises would fall silently onto the wildcard
7010        // regardless of whether it belonged to the `defmolde` family or
7011        // to a distinct `defcaixa`-family. Post-lift the partition
7012        // resolves through
7013        // [`crate::dialeto::CaixaDialeto::is_molde_family`]'s single
7014        // typed dispatch, and this pin refuses any future regression
7015        // that silently split the from_lisp partition from the typed
7016        // predicate — the two paths now migrate as one on any future
7017        // arm addition.
7018        //
7019        // Sibling in shape to the peer
7020        // [`crate::dialeto::tests::caixa_dialeto_is_molde_family_agrees_with_palavra_canonica_defmolde_projection`]
7021        // (e9d2315) that pins the same byte-parity between
7022        // [`crate::dialeto::CaixaDialeto::is_molde_family`] and the
7023        // sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
7024        // `== "defmolde"` classifier — extends the discipline from the
7025        // two paths within the [`crate::dialeto`] primitive onto the
7026        // third external consumer of the `defmolde`-family partition
7027        // (the [`Caixa::from_lisp`] gate that raises
7028        // [`LeituraError::DialetoEstrangeiro`]).
7029        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
7030            (
7031                crate::dialeto::CaixaDialeto::Pacote,
7032                r#"
7033                  (defcaixa
7034                    :nome   "checkout"
7035                    :versao "0.1.0"
7036                    :kind   Biblioteca
7037                    :edicao "2026"
7038                    :descricao "canonical Pacote source"
7039                    :autores ()
7040                    :etiquetas ()
7041                    :deps ()
7042                    :deps-dev ()
7043                    :bibliotecas ("lib/checkout.lisp"))
7044                "#,
7045            ),
7046            (
7047                crate::dialeto::CaixaDialeto::Molde,
7048                r#"
7049                  (defcaixa
7050                    :name "base64"
7051                    :kind :Biblioteca
7052                    :ecosystem :rust-single-crate
7053                    :package {:name "base64" :version "0.22.1"}
7054                    :workflows [:auto-release])
7055                "#,
7056            ),
7057            (
7058                crate::dialeto::CaixaDialeto::MoldePosicional,
7059                r#"
7060                  (defcaixa todoku-go
7061                    :kind :Biblioteca
7062                    :ecosystem :go
7063                    :package {:name "todoku-go" :version "0.3.0"})
7064                "#,
7065            ),
7066            (
7067                crate::dialeto::CaixaDialeto::Desconhecido,
7068                r#"(defcaixa :licenca "MIT")"#,
7069            ),
7070        ];
7071
7072        // Coverage: every arm in [`crate::dialeto::CaixaDialeto::ALL`]
7073        // must appear in the fixture table so the pin's arm-set stays
7074        // synchronised with the enum's arm-set. Fails at test time if a
7075        // future fifth arm added to [`crate::dialeto::CaixaDialeto`]
7076        // (with a corresponding `is_molde_family` return) forgot to
7077        // extend this fixture table with a canonical source for the new
7078        // arm — the pin cannot cover an arm it has no source for.
7079        for &expected in crate::dialeto::CaixaDialeto::ALL {
7080            assert!(
7081                fixtures.iter().any(|(d, _)| *d == expected),
7082                "fixture table must carry a canonical source for every \
7083                 CaixaDialeto arm; missing: {expected:?}"
7084            );
7085        }
7086
7087        for &(expected_dialect, src) in fixtures {
7088            let classified = crate::dialeto::classify(src.trim()).unwrap_or_else(|err| {
7089                panic!(
7090                    "fixture source for {expected_dialect:?} must classify \
7091                     cleanly, got err: {err:?}"
7092                )
7093            });
7094            assert_eq!(
7095                classified, expected_dialect,
7096                "fixture source for {expected_dialect:?} must classify as \
7097                 {expected_dialect:?} (drift here defeats the byte-parity \
7098                 pin below — a source labelled for one arm but classifying \
7099                 as another would silently satisfy or violate the pin for \
7100                 the wrong reason)"
7101            );
7102
7103            let outcome = Caixa::from_lisp(src);
7104            match (expected_dialect.is_molde_family(), &outcome) {
7105                (true, Err(LeituraError::DialetoEstrangeiro { dialeto })) => {
7106                    assert_eq!(
7107                        *dialeto, expected_dialect,
7108                        "DialetoEstrangeiro must carry the same typed arm \
7109                         the classifier returned — a drift here would let \
7110                         from_lisp raise the error while pointing at the \
7111                         wrong dialect (e.g. rejecting a \
7112                         MoldePosicional source as Molde). arm: \
7113                         {expected_dialect:?}"
7114                    );
7115                }
7116                (true, other) => panic!(
7117                    "arm {expected_dialect:?} has is_molde_family() = true \
7118                     so from_lisp must raise DialetoEstrangeiro carrying \
7119                     {expected_dialect:?}; got: {other:?}"
7120                ),
7121                (false, Err(LeituraError::DialetoEstrangeiro { dialeto })) => panic!(
7122                    "arm {expected_dialect:?} has is_molde_family() = false \
7123                     so from_lisp must NOT raise DialetoEstrangeiro; got \
7124                     one carrying: {dialeto:?}. This means the typed \
7125                     predicate and the from_lisp partition disagree on \
7126                     this arm — exactly the drift this pin refuses."
7127                ),
7128                (false, _) => {
7129                    // A non-molde arm's source falls through to the
7130                    // derive: Pacote sources parse to Ok(_); Desconhecido
7131                    // sources surface as LeituraError::Leitura from the
7132                    // derive's own unknown-keyword rejection. Either
7133                    // shape is acceptable here — the pin's promise is
7134                    // narrower: "no DialetoEstrangeiro on
7135                    // is_molde_family() == false".
7136                }
7137            }
7138        }
7139    }
7140
7141    // ── M2 typed-substrate slot tests (limits, behavior, upgrade-from, supervisor) ──
7142
7143    #[test]
7144    fn limits_round_trip_via_json() {
7145        use crate::LimitsSpec;
7146        use std::time::Duration;
7147        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7148        c.limits = Some(LimitsSpec {
7149            memory: Some(64 * 1024 * 1024),
7150            fuel: Some(1_000_000),
7151            wall_clock: Some(Duration::from_secs(30)),
7152            cpu: Some(500),
7153        });
7154        let json = serde_json::to_string(&c).unwrap();
7155        assert!(json.contains("\"limits\""));
7156        assert!(json.contains("\"64MiB\""));
7157        assert!(json.contains("\"30s\""));
7158        assert!(json.contains("\"500m\""));
7159        let back: Caixa = serde_json::from_str(&json).unwrap();
7160        assert_eq!(c.limits, back.limits);
7161    }
7162
7163    #[test]
7164    fn behavior_round_trip_via_json() {
7165        use crate::BehaviorSpec;
7166        use std::path::PathBuf;
7167        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7168        c.behavior = Some(BehaviorSpec {
7169            on_init: Some(PathBuf::from("lib/init.lisp")),
7170            on_call: Some(PathBuf::from("lib/handlers.lisp")),
7171            ..Default::default()
7172        });
7173        let json = serde_json::to_string(&c).unwrap();
7174        let back: Caixa = serde_json::from_str(&json).unwrap();
7175        assert_eq!(c.behavior, back.behavior);
7176    }
7177
7178    #[test]
7179    fn upgrade_from_round_trip_via_json() {
7180        use crate::{UpgradeFromEntry, UpgradeInstruction};
7181        use std::path::PathBuf;
7182        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7183        c.upgrade_from = vec![UpgradeFromEntry {
7184            from: "0.1.0".into(),
7185            instructions: vec![
7186                UpgradeInstruction::LoadModule {
7187                    module: "demo".into(),
7188                },
7189                UpgradeInstruction::StateChange {
7190                    script: PathBuf::from("lib/migrations/v01-to-v02.lisp"),
7191                },
7192                UpgradeInstruction::SoftPurge {
7193                    module: "demo-old".into(),
7194                },
7195            ],
7196        }];
7197        let json = serde_json::to_string(&c).unwrap();
7198        let back: Caixa = serde_json::from_str(&json).unwrap();
7199        assert_eq!(c.upgrade_from, back.upgrade_from);
7200    }
7201
7202    #[test]
7203    fn supervisor_view_returns_typed_shape() {
7204        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
7205        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
7206        c.kind = CaixaKind::Supervisor;
7207        c.bibliotecas.clear();
7208        c.estrategia = Some(RestartStrategy::OneForOne);
7209        c.max_restarts = Some(5);
7210        c.restart_window = Some("60s".into());
7211        c.children = vec![ChildSpec {
7212            caixa: "worker".into(),
7213            versao: "^0.1".into(),
7214            restart: RestartPolicy::Permanent,
7215        }];
7216        let view = c.supervisor_view().expect("Supervisor kind has a view");
7217        assert_eq!(view.estrategia, RestartStrategy::OneForOne);
7218        assert_eq!(view.max_restarts, 5);
7219        assert_eq!(
7220            view.restart_window,
7221            Some(std::time::Duration::from_secs(60))
7222        );
7223        assert_eq!(view.children.len(), 1);
7224        view.validate().unwrap();
7225    }
7226
7227    #[test]
7228    fn supervisor_view_none_for_non_supervisor_kinds() {
7229        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7230        assert!(c.supervisor_view().is_none());
7231    }
7232
7233    #[test]
7234    fn declared_mesh_slots_empty_for_bare_caixa() {
7235        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7236        assert!(c.declared_mesh_slots().is_empty());
7237    }
7238
7239    #[test]
7240    fn declared_mesh_slots_reports_only_set_slots_in_canonical_order() {
7241        use crate::{Entrada, Membro};
7242        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7243        // Set a non-adjacent pair (:membros + :entrada) to pin that the
7244        // canonical declaration order is preserved regardless of which
7245        // subset is populated.
7246        c.membros = vec![Membro {
7247            caixa: "a".into(),
7248            versao: "^0.1".into(),
7249        }];
7250        c.entrada = Some(Entrada {
7251            host: "x.example.com".into(),
7252            para: "a".into(),
7253            paths: vec![],
7254            port: 8080,
7255        });
7256        assert_eq!(
7257            c.declared_mesh_slots(),
7258            vec![
7259                crate::render::M3_AUTHOR_KEY_MEMBROS,
7260                crate::render::M3_AUTHOR_KEY_ENTRADA,
7261            ]
7262        );
7263    }
7264
7265    #[test]
7266    fn m3_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
7267        // Scalar-value pin: the five author-facing kebab-case labels the
7268        // `(defcaixa … :<slot> (…))` surface admits on the M3 top-level
7269        // mesh slot axis, one arm per typed slot. Mirrors the peer
7270        // scalar-value pin the sibling
7271        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
7272        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
7273        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] M2 top-level slot consts
7274        // carry (f49c8b0), so both altitudes of the typed-slot algebra
7275        // (per-Servico M2 + per-Aplicacao M3) share the same
7276        // "one canonical byte-string per arm" discipline. A future
7277        // rebrand (`:membros` → `:members`, `:contratos` → `:contracts`,
7278        // `:politicas` → `:policies`, `:placement` → `:distribution`,
7279        // `:entrada` → `:ingress`) lands as an edit to exactly one const,
7280        // and every consumer that reaches for the label picks it up at
7281        // build time rather than at runtime as a downstream mismatch.
7282        assert_eq!(crate::render::M3_AUTHOR_KEY_MEMBROS, ":membros");
7283        assert_eq!(crate::render::M3_AUTHOR_KEY_CONTRATOS, ":contratos");
7284        assert_eq!(crate::render::M3_AUTHOR_KEY_POLITICAS, ":politicas");
7285        assert_eq!(crate::render::M3_AUTHOR_KEY_PLACEMENT, ":placement");
7286        assert_eq!(crate::render::M3_AUTHOR_KEY_ENTRADA, ":entrada");
7287    }
7288
7289    #[test]
7290    fn declared_mesh_slots_route_through_lifted_m3_author_key_consts() {
7291        // Production-through-const pin: the five per-arm labels the
7292        // [`Caixa::declared_mesh_slots`] tagger pushes onto its return
7293        // `Vec` route through the lifted
7294        // [`crate::M3_AUTHOR_KEY_MEMBROS`] /
7295        // [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
7296        // [`crate::M3_AUTHOR_KEY_POLITICAS`] /
7297        // [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
7298        // [`crate::M3_AUTHOR_KEY_ENTRADA`] consts, in canonical
7299        // declaration order. A future re-order or drift at the tagger
7300        // (a rename that reaches the tagger but not the const, or vice
7301        // versa) surfaces here at build time rather than at runtime as
7302        // a [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
7303        // `slots: <stale-kebab-case>` diagnostic far from the rename's
7304        // commit. Mirror of the peer
7305        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
7306        // pin (f49c8b0) on the sibling per-Servico M2 top-level slot
7307        // axis.
7308        use crate::{Entrada, Membro, MeshPolicy, Placement, PlacementStrategy, WitContract};
7309        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7310        c.membros = vec![Membro {
7311            caixa: "a".into(),
7312            versao: "^0.1".into(),
7313        }];
7314        c.contratos = vec![WitContract {
7315            de: "a".into(),
7316            para: "a".into(),
7317            wit: "wasi:http/proxy".into(),
7318            endpoint: Some("/x".into()),
7319            subject: None,
7320            slot: None,
7321        }];
7322        c.politicas = Some(MeshPolicy::default());
7323        c.placement = Some(Placement {
7324            estrategia: PlacementStrategy::Replicated,
7325            clusters: vec!["rio".into()],
7326            affinity: None,
7327            shard_key: None,
7328        });
7329        c.entrada = Some(Entrada {
7330            host: "x.example.com".into(),
7331            para: "a".into(),
7332            paths: vec![],
7333            port: 8080,
7334        });
7335        assert_eq!(
7336            c.declared_mesh_slots(),
7337            vec![
7338                crate::render::M3_AUTHOR_KEY_MEMBROS,
7339                crate::render::M3_AUTHOR_KEY_CONTRATOS,
7340                crate::render::M3_AUTHOR_KEY_POLITICAS,
7341                crate::render::M3_AUTHOR_KEY_PLACEMENT,
7342                crate::render::M3_AUTHOR_KEY_ENTRADA,
7343            ]
7344        );
7345    }
7346
7347    #[test]
7348    fn declared_supervisor_slots_empty_for_bare_caixa() {
7349        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7350        assert!(c.declared_supervisor_slots().is_empty());
7351    }
7352
7353    #[test]
7354    fn declared_supervisor_slots_reports_only_set_slots_in_canonical_order() {
7355        use crate::RestartStrategy;
7356        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7357        // Set a non-adjacent pair (:estrategia + :restart-window) to pin
7358        // that the canonical declaration order is preserved regardless
7359        // of which subset is populated.
7360        c.estrategia = Some(RestartStrategy::OneForOne);
7361        c.restart_window = Some("60s".into());
7362        assert_eq!(
7363            c.declared_supervisor_slots(),
7364            vec![
7365                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
7366                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
7367            ]
7368        );
7369    }
7370
7371    #[test]
7372    fn supervisor_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
7373        // Scalar-value pin: the four author-facing kebab-case labels the
7374        // `(defcaixa … :<slot> (…))` surface admits on the Supervisor
7375        // supervision-tree slot axis, one arm per typed slot. Mirrors the
7376        // peer scalar-value pins the sibling
7377        // [`crate::render::M2_AUTHOR_KEY_LIMITS`] /
7378        // [`crate::render::M2_AUTHOR_KEY_BEHAVIOR`] /
7379        // [`crate::render::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot
7380        // consts and [`crate::render::M3_AUTHOR_KEY_MEMBROS`] etc.
7381        // top-level M3 slot consts carry, so all three kind-scoped
7382        // typed-slot-family author-facing-label axes route through one
7383        // canonical per-arm declaration. A future rebrand
7384        // (`:estrategia` → `:strategy` for English uniformity,
7385        // `:max-restarts` → `:max-intensity` matching Erlang/OTP's
7386        // `MaxIntensity` name, `:restart-window` → `:period` matching
7387        // OTP's `Period` name, `:children` → `:workers` matching Elixir
7388        // idiom) lands as an edit to exactly one const, and every
7389        // consumer that reaches for the label picks it up at build time
7390        // rather than at runtime as a downstream mismatch.
7391        assert_eq!(
7392            crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
7393            ":estrategia"
7394        );
7395        assert_eq!(
7396            crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
7397            ":max-restarts"
7398        );
7399        assert_eq!(
7400            crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
7401            ":restart-window"
7402        );
7403        assert_eq!(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN, ":children");
7404    }
7405
7406    #[test]
7407    fn declared_supervisor_slots_route_through_lifted_supervisor_author_key_consts() {
7408        // Production-through-const pin: the four per-arm labels the
7409        // [`Caixa::declared_supervisor_slots`] tagger pushes onto its
7410        // return `Vec` route through the lifted
7411        // [`crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] /
7412        // [`crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`] /
7413        // [`crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW`] /
7414        // [`crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN`] consts, in
7415        // canonical declaration order. A future re-order or drift at the
7416        // tagger (a rename that reaches the tagger but not the const, or
7417        // vice versa) surfaces here at build time rather than at runtime
7418        // as a [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
7419        // `slots: <stale-kebab-case>` diagnostic far from the rename's
7420        // commit. Mirror of the peer
7421        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
7422        // (f49c8b0) and
7423        // [`declared_mesh_slots_route_through_lifted_m3_author_key_consts`]
7424        // (882f498) pins on the sibling M2 / M3 top-level slot axes.
7425        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
7426        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7427        c.estrategia = Some(RestartStrategy::OneForOne);
7428        c.max_restarts = Some(5);
7429        c.restart_window = Some("60s".into());
7430        c.children = vec![ChildSpec {
7431            caixa: "worker".into(),
7432            versao: "^0.1".into(),
7433            restart: RestartPolicy::Permanent,
7434        }];
7435        assert_eq!(
7436            c.declared_supervisor_slots(),
7437            vec![
7438                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
7439                crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
7440                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
7441                crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN,
7442            ]
7443        );
7444    }
7445
7446    #[test]
7447    fn declared_servico_slots_empty_for_bare_caixa() {
7448        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7449        assert!(c.declared_servico_slots().is_empty());
7450    }
7451
7452    #[test]
7453    fn declared_servico_slots_reports_only_set_slots_in_canonical_order() {
7454        use crate::{UpgradeFromEntry, UpgradeInstruction};
7455        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7456        // Set a non-adjacent pair (:limits + :upgrade-from) to pin that
7457        // the canonical declaration order is preserved regardless of
7458        // which subset is populated.
7459        c.limits = Some(crate::LimitsSpec {
7460            fuel: Some(1_000_000),
7461            ..Default::default()
7462        });
7463        c.upgrade_from = vec![UpgradeFromEntry {
7464            from: "0.1.0".into(),
7465            instructions: vec![UpgradeInstruction::Restart],
7466        }];
7467        assert_eq!(
7468            c.declared_servico_slots(),
7469            vec![
7470                crate::render::M2_AUTHOR_KEY_LIMITS,
7471                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
7472            ]
7473        );
7474    }
7475
7476    #[test]
7477    fn m2_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
7478        // Scalar-value pin: the three author-facing kebab-case labels
7479        // the `(defcaixa … :<slot> (…))` surface admits on the M2
7480        // top-level slot axis, one arm per typed slot. Mirrors the peer
7481        // scalar-value pin the sibling renderer-side
7482        // [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
7483        // [`crate::M2_KEY_UPGRADE_FROM`] camelCase overlay-container
7484        // consts carry, so both halves of the M2 top-level slot dual
7485        // axis (author-facing kebab-case label + renderer-side
7486        // camelCase overlay-container wire key) route through one
7487        // canonical per-arm declaration. A future rebrand
7488        // (`:limits` → `:sandbox` matching Lunatic per-process
7489        // terminology INSPIRATIONS §III.1, `:behavior` → `:gen-server`
7490        // matching Erlang's verbatim name, `:upgrade-from` → `:appup`
7491        // matching Erlang's verbatim appup name) lands as an edit to
7492        // exactly one const, and every consumer that reaches for the
7493        // label picks it up at build time rather than at runtime as a
7494        // downstream mismatch.
7495        assert_eq!(crate::render::M2_AUTHOR_KEY_LIMITS, ":limits");
7496        assert_eq!(crate::render::M2_AUTHOR_KEY_BEHAVIOR, ":behavior");
7497        assert_eq!(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM, ":upgrade-from");
7498    }
7499
7500    #[test]
7501    fn declared_servico_slots_route_through_lifted_m2_author_key_consts() {
7502        // Production-through-const pin: the three per-arm labels the
7503        // [`Caixa::declared_servico_slots`] tagger pushes onto its
7504        // return `Vec` route through the lifted
7505        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
7506        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
7507        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts, in canonical
7508        // declaration order. A future re-order or drift at the tagger
7509        // (a rename that reaches the tagger but not the const, or vice
7510        // versa) surfaces here at build time rather than at runtime as
7511        // a [`crate::LayoutError::ServicoSlotsOnNonServico`]
7512        // `slots: <stale-kebab-case>` diagnostic far from the rename's
7513        // commit. Mirror of the peer
7514        // [`crate::behavior::BehaviorSpec::declared_slots`] production
7515        // tagger pin (889dc18) on the sibling per-callback axis.
7516        use crate::{BehaviorSpec, UpgradeFromEntry, UpgradeInstruction};
7517        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7518        c.limits = Some(crate::LimitsSpec {
7519            fuel: Some(1_000_000),
7520            ..Default::default()
7521        });
7522        c.behavior = Some(BehaviorSpec {
7523            on_init: Some(PathBuf::from("lib/init.lisp")),
7524            ..Default::default()
7525        });
7526        c.upgrade_from = vec![UpgradeFromEntry {
7527            from: "0.1.0".into(),
7528            instructions: vec![UpgradeInstruction::Restart],
7529        }];
7530        assert_eq!(
7531            c.declared_servico_slots(),
7532            vec![
7533                crate::render::M2_AUTHOR_KEY_LIMITS,
7534                crate::render::M2_AUTHOR_KEY_BEHAVIOR,
7535                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
7536            ]
7537        );
7538    }
7539
7540    #[test]
7541    fn existing_manifests_unaffected_by_new_optional_slots() {
7542        // Regression test: a caixa.lisp authored before M2 typed slots
7543        // should still parse + serialize cleanly. The bare `defcaixa`
7544        // emitted by `Caixa::template` has none of the new fields.
7545        let src = Caixa::template("legacy");
7546        let c = Caixa::from_lisp(&src).unwrap();
7547        assert!(c.limits.is_none());
7548        assert!(c.behavior.is_none());
7549        assert!(c.upgrade_from.is_empty());
7550        assert!(c.estrategia.is_none());
7551        assert!(c.children.is_empty());
7552
7553        // And to_lisp emits a manifest with the new slots in the
7554        // empty/default state — round-trippable.
7555        let emitted = c.to_lisp();
7556        let back = Caixa::from_lisp(&emitted).unwrap();
7557        assert_eq!(c, back);
7558    }
7559
7560    #[test]
7561    fn validate_deps_accepts_canonical_caixa() {
7562        // Positive control: the bare template — zero deps, zero
7563        // deps_dev — passes the gate trivially. A future axis added to
7564        // `Dep::validate` mustn't regress an empty-deps caixa to a
7565        // build error.
7566        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7567        c.validate_deps().unwrap();
7568    }
7569
7570    #[test]
7571    fn validate_deps_rejects_invalid_versao_in_deps() {
7572        // Fail-before-pass-after pin: a malformed `:deps :versao`
7573        // surfaces at validate_deps() time, not at lacre-resolve time.
7574        // Mirrors `rejects_invalid_membro_versao_requirement` and
7575        // `validate_rejects_invalid_child_versao_requirement` on the
7576        // other two `:versao` axes.
7577        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7578        c.deps = vec![Dep::simple("caixa-teia", "^bad-version")];
7579        let err = c.validate_deps().unwrap_err();
7580        assert!(
7581            matches!(
7582                err,
7583                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
7584                    if nome == "caixa-teia" && versao == "^bad-version"
7585            ),
7586            "got {err:?}"
7587        );
7588    }
7589
7590    #[test]
7591    fn validate_deps_rejects_invalid_versao_in_deps_dev() {
7592        // Parity pin: `:deps-dev` must run through the same per-entry
7593        // validator as `:deps` — a typo in either axis surfaces the
7594        // same diagnostic. Without this leg, `:deps-dev` would be a
7595        // second-class citizen of the typed surface and an author
7596        // could land a build that passes validate_deps but fails at
7597        // `feira lock`-time when the dev-dep is resolved for a test
7598        // build.
7599        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7600        c.deps_dev = vec![Dep::simple("tatara-check", "^^0.1")];
7601        let err = c.validate_deps().unwrap_err();
7602        assert!(
7603            matches!(
7604                err,
7605                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
7606                    if nome == "tatara-check" && versao == "^^0.1"
7607            ),
7608            "got {err:?}"
7609        );
7610    }
7611
7612    #[test]
7613    fn validate_deps_runs_deps_before_deps_dev() {
7614        // Order pin: when both lists carry typos, the `:deps`
7615        // diagnostic surfaces first. The author's mental model is
7616        // "runtime deps are load-bearing; dev deps are scaffolding";
7617        // surfacing the runtime axis first matches that hierarchy.
7618        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7619        c.deps = vec![Dep::simple("runtime-dep", "^bad-runtime")];
7620        c.deps_dev = vec![Dep::simple("dev-dep", "^bad-dev")];
7621        let err = c.validate_deps().unwrap_err();
7622        assert!(
7623            matches!(
7624                err,
7625                crate::dep::DepError::VersaoInvalid { ref nome, .. }
7626                    if nome == "runtime-dep"
7627            ),
7628            "expected `:deps` typo to surface first, got {err:?}"
7629        );
7630    }
7631
7632    #[test]
7633    fn validate_deps_accepts_canonical_versao_forms_in_both_lists() {
7634        // Positive control sweep across both lists. Pin every
7635        // canonical Cargo-shaped form so a future tightening of the
7636        // accepted set surfaces here as a test failure (parity with
7637        // `accepts_canonical_membro_versao_forms` and
7638        // `validate_accepts_canonical_child_versao_forms`).
7639        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7640        c.deps = vec![
7641            Dep::simple("caret", "^0.1"),
7642            Dep::simple("tilde", "~0.1.2"),
7643            Dep::simple("exact", "0.1.0"),
7644            Dep::simple("wildcard", "*"),
7645            Dep::simple("multi-range", ">=0.1, <2"),
7646        ];
7647        c.deps_dev = vec![
7648            Dep::simple("dev-caret", "^0.1"),
7649            Dep::simple("dev-wildcard", "*"),
7650        ];
7651        c.validate_deps().unwrap();
7652    }
7653
7654    #[test]
7655    fn validate_deps_diagnostic_carries_offending_dep() {
7656        // Diagnostic-shape pin: the error names the offending entry's
7657        // `:nome` + `:versao` verbatim and carries a non-empty
7658        // `reason` from `semver::VersionReq::parse`, so a `feira lint`
7659        // run can render the diagnostic without re-parsing.
7660        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7661        c.deps = vec![Dep::simple("caixa-teia", "not-a-req")];
7662        let err = c.validate_deps().unwrap_err();
7663        let crate::dep::DepError::VersaoInvalid {
7664            nome,
7665            versao,
7666            reason,
7667        } = err
7668        else {
7669            panic!("expected VersaoInvalid, got other variant");
7670        };
7671        assert_eq!(nome, "caixa-teia");
7672        assert_eq!(versao, "not-a-req");
7673        assert!(
7674            !reason.is_empty(),
7675            "VersaoInvalid `reason` must carry the parser's wording verbatim"
7676        );
7677    }
7678
7679    #[test]
7680    fn validate_deps_rejects_ambiguous_fonte_in_deps_dev() {
7681        // Cross-axis pin: `validate_deps` walks both :deps and
7682        // :deps-dev through `Dep::validate`, and the new fonte gate
7683        // (`:tag` + `:branch` both set — the canonical "pin drift"
7684        // footgun) must surface from the :deps-dev arm with the
7685        // offending entry's :nome named. Pin the :deps-dev arm
7686        // explicitly so a future shortcut that only walks :deps
7687        // surfaces here as a regression.
7688        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7689        c.deps_dev = vec![Dep {
7690            nome: "dev-only".into(),
7691            versao: "^0.1".into(),
7692            fonte: Some(crate::DepSource::Git {
7693                repo: "github:p/x".into(),
7694                tag: Some("v1".into()),
7695                rev: None,
7696                branch: Some("main".into()),
7697            }),
7698            opcional: false,
7699            caracteristicas: vec![],
7700        }];
7701        let err = c.validate_deps().unwrap_err();
7702        let crate::dep::DepError::FontePinAmbiguous { nome, pins } = err else {
7703            panic!("expected FontePinAmbiguous from :deps-dev walk");
7704        };
7705        assert_eq!(nome, "dev-only");
7706        assert!(pins.contains(":tag") && pins.contains(":branch"));
7707    }
7708
7709    #[test]
7710    fn validate_deps_rejects_empty_repo_in_deps() {
7711        // Parity pin on the :deps arm: an empty :repo on the runtime
7712        // deps list surfaces the same FonteRepoEmpty diagnostic the
7713        // dep.rs per-entry tests pin, naming the offending entry.
7714        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7715        c.deps = vec![Dep {
7716            nome: "runtime".into(),
7717            versao: "^0.1".into(),
7718            fonte: Some(crate::DepSource::Git {
7719                repo: String::new(),
7720                tag: Some("v1".into()),
7721                rev: None,
7722                branch: None,
7723            }),
7724            opcional: false,
7725            caracteristicas: vec![],
7726        }];
7727        let err = c.validate_deps().unwrap_err();
7728        assert!(
7729            matches!(
7730                err,
7731                crate::dep::DepError::FonteRepoEmpty { ref nome }
7732                    if nome == "runtime"
7733            ),
7734            "got {err:?}"
7735        );
7736    }
7737
7738    // ── validate_deps: within-list :nome set-not-multiset gate ─────────
7739
7740    #[test]
7741    fn validate_deps_rejects_duplicate_nome_in_deps() {
7742        // Fail-before-pass-after pin: two `:deps` entries naming the same
7743        // caixa carry two `:versao` / `:fonte` / feature triples that the
7744        // caixa-resolver's lacre pipeline collapses (the second silently
7745        // overwrites the first at `concrete_versao`-resolve time). The
7746        // gate surfaces the duplicate at validate-time, naming the
7747        // offending caixa + the list, before the resolver-side silent
7748        // drop. Mirrors the peer typed-graph duplicate gates
7749        // (`DuplicateChildCaixa`, `MembroDuplicate`, `DuplicateFrom`, …).
7750        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7751        c.deps = vec![
7752            Dep::simple("caixa-teia", "^0.1"),
7753            Dep::simple("caixa-teia", "^0.2"),
7754        ];
7755        let err = c.validate_deps().unwrap_err();
7756        assert!(
7757            matches!(
7758                err,
7759                crate::dep::DepError::DuplicateNome { ref nome, list }
7760                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
7761            ),
7762            "got {err:?}"
7763        );
7764    }
7765
7766    #[test]
7767    fn validate_deps_rejects_duplicate_nome_in_deps_dev() {
7768        // Parity pin: `:deps-dev` runs through the same per-list
7769        // duplicate check as `:deps` — neither axis is a second-class
7770        // citizen of the set-not-multiset discipline.
7771        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7772        c.deps_dev = vec![
7773            Dep::simple("tatara-check", "*"),
7774            Dep::simple("tatara-check", "^0.1"),
7775        ];
7776        let err = c.validate_deps().unwrap_err();
7777        assert!(
7778            matches!(
7779                err,
7780                crate::dep::DepError::DuplicateNome { ref nome, list }
7781                    if nome == "tatara-check" && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
7782            ),
7783            "got {err:?}"
7784        );
7785    }
7786
7787    #[test]
7788    fn validate_deps_accepts_cross_list_same_nome() {
7789        // The Cargo `[dependencies]` + `[dev-dependencies]` override
7790        // convention is preserved: a name appearing in *both* lists is
7791        // valid (the dev-pin overrides at test/dev time). Only
7792        // within-list duplicates are structurally incoherent — pin the
7793        // permissive cross-list semantics so a future shortcut that
7794        // collapses the two seen-sets into one surfaces here as a test
7795        // failure.
7796        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7797        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
7798        c.deps_dev = vec![Dep::simple("caixa-teia", "^0.2")];
7799        c.validate_deps().unwrap();
7800    }
7801
7802    #[test]
7803    fn validate_deps_accepts_distinct_nome_in_both_lists() {
7804        // Positive control: distinct names within each list pass — the
7805        // gate's identity element on the canonical authoring shape.
7806        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7807        c.deps = vec![
7808            Dep::simple("caixa-teia", "^0.1"),
7809            Dep::simple("pleme-mesh", "*"),
7810        ];
7811        c.deps_dev = vec![
7812            Dep::simple("tatara-check", "*"),
7813            Dep::simple("dev-shim", "^0.1"),
7814        ];
7815        c.validate_deps().unwrap();
7816    }
7817
7818    #[test]
7819    fn validate_deps_per_entry_validate_fires_before_duplicate_in_deps() {
7820        // Diagnostic-precedence pin: a malformed `:versao` on the
7821        // duplicating entry surfaces its narrower `VersaoInvalid`
7822        // diagnostic first, before the cross-entry duplicate gate fires
7823        // — the canonical "per-entry shape before cross-entry uniqueness"
7824        // precedence every peer set-not-multiset gate establishes
7825        // (`*_invalid_fires_before_duplicate_check` pins on
7826        // `SupervisorSpec::validate`, `AplicacaoSpec::validate_membros`,
7827        // `validate_upgrade_from`).
7828        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7829        c.deps = vec![
7830            Dep::simple("caixa-teia", "^0.1"),
7831            Dep::simple("caixa-teia", "^bad-version"),
7832        ];
7833        let err = c.validate_deps().unwrap_err();
7834        assert!(
7835            matches!(
7836                err,
7837                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
7838                    if nome == "caixa-teia" && versao == "^bad-version"
7839            ),
7840            "expected VersaoInvalid to surface before DuplicateNome, got {err:?}"
7841        );
7842    }
7843
7844    #[test]
7845    fn validate_deps_duplicate_diagnostic_names_first_collision() {
7846        // First-collision determinism pin: with three entries naming the
7847        // same caixa, the first colliding pair surfaces — not the last.
7848        // Mirrors the peer first-collision posture on every
7849        // duplicate-target gate
7850        // (`validate_upgrade_from_duplicate_diagnostic_names_second_collision`
7851        // — the second entry is the first collision; this gate uses the
7852        // same shape: the second entry's `:nome` lands in the diagnostic
7853        // because `seen.insert(first.nome)` already populated the set).
7854        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7855        c.deps = vec![
7856            Dep::simple("caixa-teia", "^0.1"),
7857            Dep::simple("caixa-teia", "^0.2"),
7858            Dep::simple("caixa-teia", "^0.3"),
7859        ];
7860        let err = c.validate_deps().unwrap_err();
7861        // The diagnostic carries the offending caixa name; the
7862        // implementation surfaces on the *second* entry (the first
7863        // collision), so the test pins the `:nome` value.
7864        assert!(
7865            matches!(
7866                err,
7867                crate::dep::DepError::DuplicateNome { ref nome, list }
7868                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
7869            ),
7870            "got {err:?}"
7871        );
7872    }
7873
7874    #[test]
7875    fn validate_deps_duplicate_in_deps_fires_before_duplicate_in_deps_dev() {
7876        // Cross-list precedence pin: when both lists carry duplicates,
7877        // the `:deps` diagnostic surfaces first — same author-mental-
7878        // model ordering the `validate_deps_runs_deps_before_deps_dev`
7879        // pin establishes for malformed `:versao` (runtime axis before
7880        // dev axis).
7881        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7882        c.deps = vec![
7883            Dep::simple("runtime-dep", "^0.1"),
7884            Dep::simple("runtime-dep", "^0.2"),
7885        ];
7886        c.deps_dev = vec![Dep::simple("dev-dep", "*"), Dep::simple("dev-dep", "^0.1")];
7887        let err = c.validate_deps().unwrap_err();
7888        assert!(
7889            matches!(
7890                err,
7891                crate::dep::DepError::DuplicateNome { ref nome, list }
7892                    if nome == "runtime-dep" && list == crate::render::DEP_AUTHOR_KEY_DEPS
7893            ),
7894            "expected :deps duplicate to surface before :deps-dev duplicate, got {err:?}"
7895        );
7896    }
7897
7898    #[test]
7899    fn validate_deps_empty_lists_pass_duplicate_gate() {
7900        // Empty-set identity pin: the bare template (zero deps, zero
7901        // deps_dev) passes the duplicate gate as the gate's identity
7902        // element. A future tighten that conflates "empty" with
7903        // "missing" would regress this baseline.
7904        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7905        c.validate_deps().unwrap();
7906    }
7907
7908    #[test]
7909    fn validate_deps_duplicate_diagnostic_carries_list_tag() {
7910        // Diagnostic-shape pin: the `list:` field tags which list the
7911        // duplicate landed in (`:deps` vs `:deps-dev`) verbatim, so a
7912        // `feira lint` run can route the author to the right block in
7913        // their caixa.lisp without re-deriving the list from context.
7914        // Same self-locating shape every peer per-axis diagnostic
7915        // already exposes.
7916        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7917        c.deps_dev = vec![
7918            Dep::simple("dev-thing", "*"),
7919            Dep::simple("dev-thing", "^0.1"),
7920        ];
7921        let err = c.validate_deps().unwrap_err();
7922        let crate::dep::DepError::DuplicateNome { nome, list } = err else {
7923            panic!("expected DuplicateNome from :deps-dev walk");
7924        };
7925        assert_eq!(nome, "dev-thing");
7926        assert_eq!(list, crate::render::DEP_AUTHOR_KEY_DEPS_DEV);
7927    }
7928
7929    // ── validate_deps: per-entry :caracteristicas set-discipline gate ──
7930
7931    #[test]
7932    fn validate_deps_surfaces_caracteristicas_duplicate_in_deps_list() {
7933        // Thread-through pin on `:deps`: the per-entry
7934        // `Dep::validate_caracteristicas` gate fires inside
7935        // `Caixa::validate_deps`'s linear walk, so a malformed feature
7936        // list on any `:deps` entry surfaces as a `DepError` from
7937        // `validate_deps` — the same reachability shape every per-entry
7938        // `Dep::validate` arm threads through. Without this pin a future
7939        // shortcut that skips the per-entry `Dep::validate` call on the
7940        // cross-entry-uniqueness path would mask the within-entry
7941        // `:caracteristicas` gates.
7942        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7943        c.deps = vec![Dep {
7944            nome: "caixa-teia".into(),
7945            versao: "^0.1".into(),
7946            fonte: None,
7947            opcional: false,
7948            caracteristicas: vec!["http".into(), "http".into()],
7949        }];
7950        let err = c.validate_deps().unwrap_err();
7951        let crate::dep::DepError::CaracteristicaDuplicate {
7952            nome,
7953            caracteristica,
7954        } = err
7955        else {
7956            panic!("expected CaracteristicaDuplicate from :deps walk, got {err:?}");
7957        };
7958        assert_eq!(nome, "caixa-teia");
7959        assert_eq!(caracteristica, "http");
7960    }
7961
7962    #[test]
7963    fn validate_deps_surfaces_caracteristicas_empty_in_deps_dev_list() {
7964        // Peer thread-through pin on `:deps-dev`: same reachability as
7965        // the `:deps` arm above, on the dev-only authoring axis. Pins
7966        // that the `validate_deps` walk visits both lists' per-entry
7967        // gates uniformly. The empty-feature arm carries here so both
7968        // new `:caracteristicas` arms are surfaced via at least one
7969        // `validate_deps` thread-through.
7970        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7971        c.deps_dev = vec![Dep {
7972            nome: "caixa-teia".into(),
7973            versao: "^0.1".into(),
7974            fonte: None,
7975            opcional: false,
7976            caracteristicas: vec![String::new()],
7977        }];
7978        let err = c.validate_deps().unwrap_err();
7979        let crate::dep::DepError::CaracteristicaEmpty { nome } = err else {
7980            panic!("expected CaracteristicaEmpty from :deps-dev walk, got {err:?}");
7981        };
7982        assert_eq!(nome, "caixa-teia");
7983    }
7984
7985    #[test]
7986    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_list() {
7987        // Thread-through pin on `:deps`: the per-entry
7988        // `Dep::validate_caracteristicas` value-shape gate (lifted via
7989        // `crate::render::is_cargo_feature_name`) fires inside
7990        // `Caixa::validate_deps`'s linear walk on the `:deps` list, so
7991        // a structurally invalid feature name on any `:deps` entry
7992        // surfaces as `DepError::CaracteristicaInvalid` from
7993        // `validate_deps` — the same reachability shape every per-entry
7994        // `Dep::validate` arm threads through. Without this pin a
7995        // future shortcut that skips the per-entry `Dep::validate` call
7996        // on the cross-entry-uniqueness path would mask the within-
7997        // entry `:caracteristicas` value-shape gate.
7998        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7999        c.deps = vec![Dep {
8000            nome: "caixa-teia".into(),
8001            versao: "^0.1".into(),
8002            fonte: None,
8003            opcional: false,
8004            caracteristicas: vec!["+http".into()],
8005        }];
8006        let err = c.validate_deps().unwrap_err();
8007        let crate::dep::DepError::CaracteristicaInvalid {
8008            nome,
8009            caracteristica,
8010            ..
8011        } = err
8012        else {
8013            panic!("expected CaracteristicaInvalid from :deps walk, got {err:?}");
8014        };
8015        assert_eq!(nome, "caixa-teia");
8016        assert_eq!(caracteristica, "+http");
8017    }
8018
8019    #[test]
8020    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_dev_list() {
8021        // Peer thread-through pin on `:deps-dev`: same reachability as
8022        // the `:deps` arm above, on the dev-only authoring axis. The
8023        // `http/json` shape carries here so the segment-separator
8024        // diagnostic (the canonical Cargo `dep/feat` namespaced-dep
8025        // confusion footgun) is surfaced via the cross-entry walk too —
8026        // pinning that the `:deps-dev` list visits the same per-entry
8027        // value-shape gate as the `:deps` list.
8028        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8029        c.deps_dev = vec![Dep {
8030            nome: "caixa-teia".into(),
8031            versao: "^0.1".into(),
8032            fonte: None,
8033            opcional: false,
8034            caracteristicas: vec!["http/json".into()],
8035        }];
8036        let err = c.validate_deps().unwrap_err();
8037        let crate::dep::DepError::CaracteristicaInvalid {
8038            nome,
8039            caracteristica,
8040            ..
8041        } = err
8042        else {
8043            panic!("expected CaracteristicaInvalid from :deps-dev walk, got {err:?}");
8044        };
8045        assert_eq!(nome, "caixa-teia");
8046        assert_eq!(caracteristica, "http/json");
8047    }
8048
8049    #[test]
8050    fn to_lisp_preserves_deps() {
8051        let src = r#"
8052(defcaixa
8053  :nome "x"
8054  :versao "0.1.0"
8055  :kind Biblioteca
8056  :deps ((:nome "a" :versao "^0.1")
8057         (:nome "b" :versao "*" :fonte (:tipo git :repo "github:o/b" :tag "v1"))))
8058"#;
8059        let c1 = Caixa::from_lisp(src).unwrap();
8060        let emitted = c1.to_lisp();
8061        let c2 = Caixa::from_lisp(&emitted).expect("round trip");
8062        assert_eq!(c1.deps, c2.deps);
8063    }
8064
8065    // ── Caixa::validate_nome — top-level :nome value-shape gate ─────────
8066
8067    fn caixa_with_nome(nome: &str) -> Caixa {
8068        let mut c = Caixa::from_lisp(&Caixa::template("placeholder")).unwrap();
8069        c.nome = nome.to_string();
8070        c
8071    }
8072
8073    #[test]
8074    fn validate_nome_accepts_canonical_template() {
8075        // Positive control: the bare `feira init`-style template's
8076        // `:nome` ("demo") is a canonical DNS-1123 label; the gate must
8077        // not regress this baseline shape. A future tightening of the
8078        // accepted set surfaces here as a test failure first.
8079        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8080        c.validate_nome().unwrap();
8081    }
8082
8083    #[test]
8084    fn validate_nome_accepts_canonical_forms() {
8085        // Positive-set sweep: each realistic caixa-name shape the K8s
8086        // apiserver accepts as a `metadata.name` label must pass —
8087        // single-word, hyphen-joined, version-suffixed, single-char,
8088        // two-char, digit-start (DNS-1123 allows this; the stricter
8089        // DNS-1035 Service-name rule doesn't), version-suffix-bearing.
8090        // Mirrors `accepts_canonical_membro_caixa_forms` (3f9d7a0) on
8091        // the peer member-name axis.
8092        for nome in [
8093            "checkout",
8094            "cart-v2",
8095            "a",
8096            "db",
8097            "3rd-party-shim",
8098            "payment-retry",
8099            "0",
8100        ] {
8101            caixa_with_nome(nome)
8102                .validate_nome()
8103                .unwrap_or_else(|e| panic!("canonical :nome {nome:?} must validate, got {e:?}"));
8104        }
8105    }
8106
8107    #[test]
8108    fn validate_nome_rejects_empty() {
8109        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
8110        // an empty `:nome` (the derive macro stores the raw String);
8111        // the gate's empty arm names the offending axis with a narrower
8112        // diagnostic than the `NomeInvalid` parse arm would emit.
8113        let c = caixa_with_nome("");
8114        let err = c.validate_nome().unwrap_err();
8115        assert_eq!(err, ManifestError::NomeEmpty);
8116    }
8117
8118    #[test]
8119    fn validate_nome_rejects_uppercase() {
8120        // The canonical "I copied the TitleCase display name verbatim"
8121        // footgun. The K8s apiserver rejects `metadata.name: MyApp` at
8122        // admission on every derived artifact (Helm chart, ComputeUnit,
8123        // CNP, HTTPRoute, label values); the gate moves the diagnostic
8124        // to the source `caixa.lisp` and the reason suggests the
8125        // lowercased fix verbatim.
8126        let c = caixa_with_nome("MyApp");
8127        let err = c.validate_nome().unwrap_err();
8128        let ManifestError::NomeInvalid { nome, reason } = err else {
8129            panic!("expected NomeInvalid for uppercase :nome");
8130        };
8131        assert_eq!(nome, "MyApp");
8132        assert!(
8133            reason.contains("uppercase") && reason.contains("myapp"),
8134            "diagnostic must name the violation + the lowercased fix, got {reason:?}"
8135        );
8136    }
8137
8138    #[test]
8139    fn validate_nome_rejects_underscore() {
8140        // The Python-/Postgres-style `snake_case` leak. DNS-1123 forbids
8141        // `_`; the apiserver rejects on admission across every derived
8142        // artifact. Same fixture pinned for `:membros :caixa` (3f9d7a0)
8143        // and `:children :caixa` (31bfa43).
8144        let c = caixa_with_nome("my_app");
8145        let err = c.validate_nome().unwrap_err();
8146        assert!(
8147            matches!(
8148                err,
8149                ManifestError::NomeInvalid { ref nome, ref reason }
8150                    if nome == "my_app" && reason.contains('_')
8151            ),
8152            "got {err:?}"
8153        );
8154    }
8155
8156    #[test]
8157    fn validate_nome_rejects_dot() {
8158        // A `:nome` is a single DNS-1123 label, not a subdomain. The
8159        // "I want to namespace with `.`" footgun the gate redirects to
8160        // `-` via the shared predicate's reason wording.
8161        let c = caixa_with_nome("team.app");
8162        let err = c.validate_nome().unwrap_err();
8163        assert!(
8164            matches!(
8165                err,
8166                ManifestError::NomeInvalid { ref nome, ref reason }
8167                    if nome == "team.app" && reason.contains('.')
8168            ),
8169            "got {err:?}"
8170        );
8171    }
8172
8173    #[test]
8174    fn validate_nome_rejects_leading_hyphen() {
8175        // DNS-1123 boundary rule: the label must start with an ASCII
8176        // alphanumeric. Pin the leading-`-` arm explicitly.
8177        let c = caixa_with_nome("-app");
8178        let err = c.validate_nome().unwrap_err();
8179        assert!(
8180            matches!(
8181                err,
8182                ManifestError::NomeInvalid { ref nome, .. } if nome == "-app"
8183            ),
8184            "got {err:?}"
8185        );
8186    }
8187
8188    #[test]
8189    fn validate_nome_rejects_trailing_hyphen() {
8190        // Symmetric arm of the boundary rule, pinned separately so a
8191        // future relaxation that only checks the leading position
8192        // surfaces here. Mirrors `rejects_membro_caixa_with_trailing_hyphen`
8193        // and `_with_trailing_hyphen` on the supervisor / aplicacao
8194        // axes.
8195        let c = caixa_with_nome("app-");
8196        let err = c.validate_nome().unwrap_err();
8197        assert!(
8198            matches!(
8199                err,
8200                ManifestError::NomeInvalid { ref nome, .. } if nome == "app-"
8201            ),
8202            "got {err:?}"
8203        );
8204    }
8205
8206    #[test]
8207    fn validate_nome_rejects_unicode() {
8208        // IDN must be pre-encoded as Punycode (`xn--…`); raw Unicode
8209        // bytes are rejected by the K8s apiserver on every name axis.
8210        let c = caixa_with_nome("café");
8211        let err = c.validate_nome().unwrap_err();
8212        assert!(
8213            matches!(
8214                err,
8215                ManifestError::NomeInvalid { ref nome, .. } if nome == "café"
8216            ),
8217            "got {err:?}"
8218        );
8219    }
8220
8221    #[test]
8222    fn validate_nome_rejects_whitespace() {
8223        // The paste-from-sketch / paste-from-spec footgun. Internal
8224        // whitespace is rejected by every K8s name axis.
8225        let c = caixa_with_nome("my app");
8226        let err = c.validate_nome().unwrap_err();
8227        assert!(
8228            matches!(
8229                err,
8230                ManifestError::NomeInvalid { ref nome, .. } if nome == "my app"
8231            ),
8232            "got {err:?}"
8233        );
8234    }
8235
8236    #[test]
8237    fn validate_nome_rejects_too_long() {
8238        // 64-byte boundary pin: the K8s apiserver rejects any
8239        // `metadata.name` over 63 bytes at admission; the diagnostic
8240        // names both the 63-byte cap and the actual length so the
8241        // author can shorten in one edit. Mirrors `_too_long` on the
8242        // peer member-/cluster-/child-name axes.
8243        let over = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN + 1);
8244        let c = caixa_with_nome(&over);
8245        let err = c.validate_nome().unwrap_err();
8246        let ManifestError::NomeInvalid { nome, reason } = err else {
8247            panic!("expected NomeInvalid for over-cap :nome");
8248        };
8249        assert_eq!(nome.len(), crate::DNS_1123_LABEL_MAX_LEN + 1);
8250        assert!(
8251            reason.contains("63") && reason.contains("64"),
8252            "diagnostic must name the cap + actual length, got {reason:?}"
8253        );
8254    }
8255
8256    #[test]
8257    fn nome_max_length_validates() {
8258        // The 63-byte cap exactly — the boundary-accepting case pinned
8259        // alongside `validate_nome_rejects_too_long` so a future cap
8260        // shift surfaces both arms simultaneously. Mirrors
8261        // `membro_caixa_max_length_validates`,
8262        // `placement_cluster_max_length_validates`,
8263        // `child_caixa_max_length_validates`.
8264        let at_cap = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
8265        caixa_with_nome(&at_cap).validate_nome().unwrap();
8266    }
8267
8268    #[test]
8269    fn nome_empty_takes_precedence_over_invalid() {
8270        // Order pin: the empty arm fires before the predicate is
8271        // consulted. Empty < invalid in self-locating-ness — the
8272        // narrower `NomeEmpty` diagnostic doesn't carry a useless
8273        // `nome: ""` reference into the parser-shaped reason. Mirrors
8274        // `membro_caixa_empty_takes_precedence_over_invalid` on the
8275        // peer axis (3f9d7a0).
8276        let c = caixa_with_nome("");
8277        assert_eq!(c.validate_nome().unwrap_err(), ManifestError::NomeEmpty);
8278    }
8279
8280    #[test]
8281    fn nome_invalid_diagnostic_carries_offending_nome() {
8282        // Diagnostic-shape pin: the error names the offending `:nome`
8283        // verbatim with a non-empty parser-shaped reason, so a `feira
8284        // lint` run can render the diagnostic without re-parsing.
8285        // Mirrors `membro_caixa_invalid_diagnostic_carries_offending_caixa`.
8286        let c = caixa_with_nome("MyApp");
8287        let err = c.validate_nome().unwrap_err();
8288        let ManifestError::NomeInvalid { nome, reason } = err else {
8289            panic!("expected NomeInvalid variant");
8290        };
8291        assert_eq!(nome, "MyApp");
8292        assert!(
8293            !reason.is_empty(),
8294            "NomeInvalid `reason` must carry the predicate's wording verbatim"
8295        );
8296    }
8297
8298    // ── Caixa::validate_nome_chart_name_budget — joint-length on `:nome` ──
8299    //
8300    // The bare-`:nome` axis [`Caixa::validate_nome`] caps at 63 bytes
8301    // via DNS-1123; this second-axis gate caps the joint
8302    // `lareira-<nome>` chart name at the same 63-byte ceiling. The
8303    // canonical [`crate::lareira_chart_name`] helper's doc comment
8304    // (f7320d7, caixa-core/src/render.rs:3198) explicitly deferred:
8305    // "the M4 admission webhook will pin the joint-length invariant
8306    // when it lands". These tests pin it at the manifest-validate
8307    // layer instead, fail-before-pass-after on the 56-byte boundary.
8308
8309    #[test]
8310    fn validate_nome_chart_name_budget_accepts_canonical_template() {
8311        // Positive control: the bare `feira init`-style template's
8312        // `:nome` ("demo") sits far below the cap; the gate must not
8313        // regress this baseline. Same shape every peer
8314        // value-shape-gate baseline pin uses.
8315        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8316        c.validate_nome_chart_name_budget().unwrap();
8317    }
8318
8319    #[test]
8320    fn validate_nome_chart_name_budget_accepts_canonical_fixtures() {
8321        // Positive-set sweep across the canonical author surface every
8322        // in-tree fixture uses (`hello-rio`, `cart`, `checkout`,
8323        // `worker`, the `checkout-aplicacao` example members, the
8324        // `example-attest` caixa-tatara fixture). Every value sits
8325        // far below the 55-byte per-`:nome` budget. Same shape every
8326        // peer per-axis baseline pin uses.
8327        for nome in [
8328            "hello-rio",
8329            "cart",
8330            "checkout",
8331            "worker",
8332            "example-attest",
8333            "demo",
8334            "a",
8335        ] {
8336            caixa_with_nome(nome)
8337                .validate_nome_chart_name_budget()
8338                .unwrap_or_else(|e| {
8339                    panic!("canonical :nome {nome:?} must pass chart-name budget, got {e:?}")
8340                });
8341        }
8342    }
8343
8344    #[test]
8345    fn validate_nome_chart_name_budget_accepts_nome_at_cap() {
8346        // Boundary-accepting case at the 55-byte per-`:nome` budget —
8347        // the joint chart name is exactly 63 bytes, the DNS-1123 label
8348        // cap. Pinned alongside the rejecting-arm test so a future cap
8349        // shift surfaces both arms simultaneously. Mirrors
8350        // `nome_max_length_validates` on the peer bare-`:nome` axis.
8351        let at_cap = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN);
8352        caixa_with_nome(&at_cap)
8353            .validate_nome_chart_name_budget()
8354            .unwrap();
8355    }
8356
8357    #[test]
8358    fn validate_nome_chart_name_budget_rejects_nome_one_over_cap() {
8359        // Fail-before-pass-after pin on the 56-byte boundary: the
8360        // smallest `:nome` length that overflows the joint chart-name
8361        // cap. The inner [`is_dns_1123_label`] gate
8362        // (`Caixa::validate_nome`) accepts it (56 ≤ 63), so prior to
8363        // this gate it silently passed the manifest-validate cascade
8364        // and surfaced as a `helm lint` / apiserver rejection on the
8365        // rendered chart name far from the source `caixa.lisp`, with
8366        // no field naming the overflow. With this gate the diagnostic
8367        // names the offending `:nome` verbatim alongside the rendered
8368        // chart name and the budget, so the author can shorten in one
8369        // edit. Mirrors `validate_nome_rejects_too_long` on the peer
8370        // bare-`:nome` axis.
8371        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
8372        let c = caixa_with_nome(&over);
8373        let err = c.validate_nome_chart_name_budget().unwrap_err();
8374        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
8375            panic!("expected NomeChartNameBudgetExceeded for over-budget :nome");
8376        };
8377        assert_eq!(nome.len(), crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
8378        assert_eq!(nome, over);
8379        assert!(
8380            reason.contains("63") && reason.contains("64") && reason.contains("55"),
8381            "diagnostic must name the DNS-1123 cap (63), the actual chart-name length (64), \
8382             and the per-`:nome` budget (55), got {reason:?}"
8383        );
8384    }
8385
8386    #[test]
8387    fn validate_nome_chart_name_budget_rejects_nome_at_bare_dns_cap() {
8388        // The 63-byte `:nome` boundary — passes the bare-`:nome`
8389        // [`is_dns_1123_label`] cap exactly, but produces a 71-byte
8390        // joint chart name that overflows the DNS-1123 label cap
8391        // structurally. The most stringent fail-before-pass-after
8392        // surface: every `:nome` in the 56..=63-byte range passed the
8393        // prior cascade and broke at admission.
8394        let bare_max = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
8395        let c = caixa_with_nome(&bare_max);
8396        // The bare-`:nome` gate accepts the 63-byte length.
8397        c.validate_nome().unwrap();
8398        // The new joint-length gate rejects it.
8399        let err = c.validate_nome_chart_name_budget().unwrap_err();
8400        assert!(
8401            matches!(
8402                err,
8403                ManifestError::NomeChartNameBudgetExceeded { ref nome, .. }
8404                    if nome.len() == crate::DNS_1123_LABEL_MAX_LEN
8405            ),
8406            "got {err:?}"
8407        );
8408    }
8409
8410    #[test]
8411    fn validate_nome_chart_name_budget_diagnostic_carries_offending_chart_name() {
8412        // Diagnostic-shape pin: the rendered `lareira-<nome>` chart
8413        // name appears verbatim in the diagnostic so the author sees
8414        // exactly the string the apiserver / `helm lint` would have
8415        // rejected — no re-derivation required to grep the source.
8416        // Peer with `nome_invalid_diagnostic_carries_offending_nome`
8417        // on the bare-`:nome` axis.
8418        let over = "x".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 5);
8419        let c = caixa_with_nome(&over);
8420        let err = c.validate_nome_chart_name_budget().unwrap_err();
8421        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
8422            panic!("expected NomeChartNameBudgetExceeded variant");
8423        };
8424        assert_eq!(nome, over);
8425        let expected_chart = crate::lareira_chart_name(&over);
8426        assert!(
8427            reason.contains(&expected_chart),
8428            "diagnostic must carry the rendered chart name {expected_chart:?} verbatim, \
8429             got {reason:?}"
8430        );
8431        assert!(
8432            reason.contains("lareira-"),
8433            "diagnostic must name the canonical chart-name prefix verbatim, got {reason:?}"
8434        );
8435    }
8436
8437    #[test]
8438    fn validate_nome_chart_name_budget_runs_after_nome_shape_via_layout_verify() {
8439        // Order pin on the layout cascade: the narrower
8440        // `NomeInvalid` (bare-DNS-1123 shape) fires before the
8441        // joint-length budget. A structurally-malformed `:nome` (here:
8442        // uppercase) surfaces its specific shape error rather than
8443        // the chart-name-budget error, even when the joint length
8444        // would also overflow — the narrower diagnostic is more
8445        // self-locating. Mirrors the cascade-precedence pins peer
8446        // gates already use (e.g. `EntradaParaEmpty` before
8447        // `EntradaParaInvalid`).
8448        let over = "A".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
8449        let c = caixa_with_nome(&over);
8450        // The bare-shape gate fires first.
8451        let err = c.validate_nome().unwrap_err();
8452        assert!(
8453            matches!(err, ManifestError::NomeInvalid { .. }),
8454            "bare-shape gate must fire before chart-name-budget gate; got {err:?}"
8455        );
8456        // And the layout verify cascade surfaces that diagnostic, not
8457        // the budget arm. Inject a path-exists oracle so the cascade
8458        // gets past the manifest-presence check and into the
8459        // value-shape gates.
8460        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
8461        let err = crate::LayoutInvariants::verify(
8462            &layout,
8463            &c,
8464            std::path::Path::new("/tmp/caixa-test-fake-root"),
8465        )
8466        .unwrap_err();
8467        let issue = err.to_string();
8468        assert!(
8469            issue.contains("DNS-1123") || issue.contains("uppercase"),
8470            "layout cascade must surface the bare-DNS-1123 diagnostic on a \
8471             structurally-malformed :nome, not the chart-name-budget diagnostic; got {issue:?}"
8472        );
8473    }
8474
8475    #[test]
8476    fn layout_verify_routes_chart_name_budget_through_nome_violation() {
8477        // Cross-axis envelope pin: the layout cascade wraps both
8478        // bare-`:nome` and joint-length-`:nome` failures through the
8479        // same [`LayoutError::NomeViolation`] envelope, since both
8480        // arms are on the `:nome` axis. The user's diagnostic stays
8481        // self-locating ("which axis"), and a future consumer that
8482        // dispatches on the layout-error variant (e.g. a `feira lint`
8483        // exit-code mapping) sees a single per-axis envelope. The
8484        // wrapped `issue:` carries the full inner diagnostic.
8485        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
8486        let c = caixa_with_nome(&over);
8487        // The bare-shape gate accepts.
8488        c.validate_nome().unwrap();
8489        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
8490        let err = crate::LayoutInvariants::verify(
8491            &layout,
8492            &c,
8493            std::path::Path::new("/tmp/caixa-test-fake-root"),
8494        )
8495        .unwrap_err();
8496        let crate::LayoutError::NomeViolation { caixa, issue } = err else {
8497            panic!("expected LayoutError::NomeViolation, got {err:?}");
8498        };
8499        assert_eq!(caixa, over);
8500        assert!(
8501            issue.contains("lareira-") && issue.contains("63") && issue.contains("55"),
8502            "wrapped issue must carry the joint-length diagnostic verbatim, got {issue:?}"
8503        );
8504    }
8505
8506    // ── Caixa::validate_versao — top-level :versao value-shape gate ─────
8507
8508    fn caixa_with_versao(versao: &str) -> Caixa {
8509        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8510        c.versao = versao.to_string();
8511        c
8512    }
8513
8514    #[test]
8515    fn validate_versao_accepts_canonical_template() {
8516        // Positive control: the bare `feira init`-style template's
8517        // `:versao` ("0.1.0") is a canonical SemVer-2 literal; the gate
8518        // must not regress this baseline shape. A future tightening of
8519        // the accepted set surfaces here as a test failure first.
8520        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8521        c.validate_versao().unwrap();
8522    }
8523
8524    #[test]
8525    fn validate_versao_accepts_canonical_forms() {
8526        // Positive-set sweep: each realistic SemVer-2 shape the
8527        // substrate's downstream consumers accept must pass — bare
8528        // MAJOR.MINOR.PATCH, pre-release tags (`-rc.1`, `-alpha.0`),
8529        // build metadata (`+build.42`), the combined form, and the
8530        // `0.0.0` boundary case. Mirrors `accepts_canonical_forms` on
8531        // the peer `:nome` axis (6c992f8).
8532        for versao in [
8533            "0.1.0",
8534            "0.0.0",
8535            "1.0.0",
8536            "0.2.0-rc.1",
8537            "1.0.0-alpha.0",
8538            "1.0.0+build.42",
8539            "1.0.0-rc.1+build.42",
8540            "10.20.30",
8541        ] {
8542            caixa_with_versao(versao)
8543                .validate_versao()
8544                .unwrap_or_else(|e| {
8545                    panic!("canonical :versao {versao:?} must validate, got {e:?}")
8546                });
8547        }
8548    }
8549
8550    #[test]
8551    fn validate_versao_rejects_empty() {
8552        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
8553        // an empty `:versao` (the derive macro stores the raw String);
8554        // the gate's empty arm names the offending axis with a narrower
8555        // diagnostic than the `VersaoInvalid` parse arm would emit.
8556        // Mirrors `validate_nome_rejects_empty` (6c992f8).
8557        let c = caixa_with_versao("");
8558        let err = c.validate_versao().unwrap_err();
8559        assert_eq!(err, ManifestError::VersaoEmpty);
8560    }
8561
8562    #[test]
8563    fn validate_versao_rejects_git_tag_shape() {
8564        // The canonical "I copied the git tag verbatim" footgun —
8565        // `feira publish` *emits* `v<versao>` git tags, so a leaked
8566        // `v0.1.0` in `:versao` would render as `vv0.1.0` and silently
8567        // shift every downstream consumer's version axis. `semver`
8568        // rejects the leading `v` at parse time; the gate moves the
8569        // diagnostic to the source `caixa.lisp`.
8570        let c = caixa_with_versao("v0.1.0");
8571        let err = c.validate_versao().unwrap_err();
8572        let ManifestError::VersaoInvalid { versao, reason } = err else {
8573            panic!("expected VersaoInvalid for git-tag-shape :versao");
8574        };
8575        assert_eq!(versao, "v0.1.0");
8576        assert!(
8577            !reason.is_empty(),
8578            "VersaoInvalid `reason` must carry the parser's wording, got {reason:?}"
8579        );
8580    }
8581
8582    #[test]
8583    fn validate_versao_rejects_missing_patch() {
8584        // The canonical "I shortened it" footgun — SemVer-2 requires
8585        // three parts. Cargo's `version =` field accepts the shortened
8586        // form as a requirement, conflating the two leaks across the
8587        // typed `:deps :versao` vs top-level `:versao` axes; the gate
8588        // pins the top-level axis to the strict three-part shape.
8589        let c = caixa_with_versao("0.1");
8590        let err = c.validate_versao().unwrap_err();
8591        assert!(
8592            matches!(
8593                err,
8594                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1"
8595            ),
8596            "got {err:?}"
8597        );
8598    }
8599
8600    #[test]
8601    fn validate_versao_rejects_requirement_shape() {
8602        // The canonical "I leaked a requirement into a version" footgun —
8603        // the typed `:deps :versao` / `:membros :versao` axes accept
8604        // `^0.1` (a `VersionReq`); the top-level `:versao` requires a
8605        // concrete `Version`. Without this gate the two typed surfaces
8606        // would silently overlap, and a top-level `^0.1` would surface
8607        // at `helm install` time as a Chart.yaml version rejection far
8608        // from the source `caixa.lisp`.
8609        let c = caixa_with_versao("^0.1");
8610        let err = c.validate_versao().unwrap_err();
8611        assert!(
8612            matches!(
8613                err,
8614                ManifestError::VersaoInvalid { ref versao, .. } if versao == "^0.1"
8615            ),
8616            "got {err:?}"
8617        );
8618    }
8619
8620    #[test]
8621    fn validate_versao_rejects_docker_tag_shape() {
8622        // The "I confused it with a docker tag" footgun — `latest`,
8623        // `main`, `stable` parse as identifiers, not SemVer-2 versions.
8624        // SemVer rejects at parse time; the gate moves the diagnostic
8625        // to the source `caixa.lisp`.
8626        for bad in ["latest", "main", "stable"] {
8627            let c = caixa_with_versao(bad);
8628            let err = c.validate_versao().unwrap_err();
8629            assert!(
8630                matches!(
8631                    err,
8632                    ManifestError::VersaoInvalid { ref versao, .. } if versao == bad
8633                ),
8634                "got {err:?} for {bad:?}"
8635            );
8636        }
8637    }
8638
8639    #[test]
8640    fn validate_versao_rejects_four_part_form() {
8641        // The Java/Microsoft "MAJOR.MINOR.PATCH.BUILD" convention
8642        // SemVer-2 forbids. A leak from a non-SemVer ecosystem; the
8643        // semver crate rejects the extra `.0` at parse time.
8644        let c = caixa_with_versao("0.1.0.0");
8645        let err = c.validate_versao().unwrap_err();
8646        assert!(
8647            matches!(
8648                err,
8649                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1.0.0"
8650            ),
8651            "got {err:?}"
8652        );
8653    }
8654
8655    #[test]
8656    fn versao_empty_takes_precedence_over_invalid() {
8657        // Order pin: the empty arm fires before the parser is consulted.
8658        // Empty < invalid in self-locating-ness — the narrower
8659        // `VersaoEmpty` diagnostic doesn't carry a useless `versao: ""`
8660        // reference into the parser-shaped reason. Mirrors
8661        // `nome_empty_takes_precedence_over_invalid` (6c992f8) on the
8662        // peer axis.
8663        let c = caixa_with_versao("");
8664        assert_eq!(c.validate_versao().unwrap_err(), ManifestError::VersaoEmpty);
8665    }
8666
8667    #[test]
8668    fn versao_invalid_diagnostic_carries_offending_versao() {
8669        // Diagnostic-shape pin: the error names the offending `:versao`
8670        // verbatim with a non-empty parser-shaped reason, so a `feira
8671        // lint` run can render the diagnostic without re-parsing.
8672        // Mirrors `nome_invalid_diagnostic_carries_offending_nome`.
8673        let c = caixa_with_versao("v0.1.0");
8674        let err = c.validate_versao().unwrap_err();
8675        let ManifestError::VersaoInvalid { versao, reason } = err else {
8676            panic!("expected VersaoInvalid variant");
8677        };
8678        assert_eq!(versao, "v0.1.0");
8679        assert!(
8680            !reason.is_empty(),
8681            "VersaoInvalid `reason` must carry the parser's wording verbatim"
8682        );
8683    }
8684
8685    #[test]
8686    fn validate_versao_accepts_what_upgrade_from_from_accepts() {
8687        // Parity pin: every shape `UpgradeFromEntry::validate` accepts
8688        // for `:upgrade-from :from` must also pass `validate_versao` —
8689        // the two `:versao`-typed surfaces (top-level `:versao`,
8690        // `:upgrade-from :from`) consume the *same* `semver::Version`
8691        // parser, so they must agree on the accepted set. Without this
8692        // pin, a future tightening of one axis could silently diverge
8693        // from the other. Mirrors the `:versao` requirement-axis
8694        // parity (`:deps`/`:deps-dev`/`:membros`/`:children`) the prior
8695        // commits established.
8696        for versao in ["0.1.0", "0.2.0-rc.1", "1.0.0+build.42"] {
8697            // From the canonical UpgradeFromEntry round-trip fixture
8698            // (`upgrade::tests::round_trip_load_module` peers).
8699            let entry = crate::UpgradeFromEntry {
8700                from: versao.to_string(),
8701                instructions: Vec::new(),
8702            };
8703            entry
8704                .validate()
8705                .unwrap_or_else(|e| panic!(":from {versao:?} must validate, got {e:?}"));
8706            caixa_with_versao(versao)
8707                .validate_versao()
8708                .unwrap_or_else(|e| {
8709                    panic!(":versao {versao:?} must validate, got {e:?} — peer axis diverges")
8710                });
8711        }
8712    }
8713
8714    // ── Caixa::validate_restart_window — supervisor restart-window
8715    //    folds through the shared `supervisor::duration_codec` ────────
8716
8717    fn caixa_with_restart_window(window: Option<&str>) -> Caixa {
8718        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
8719        c.kind = CaixaKind::Supervisor;
8720        c.restart_window = window.map(str::to_string);
8721        c
8722    }
8723
8724    #[test]
8725    fn validate_restart_window_accepts_none() {
8726        // The canonical "omit the slot to express no reset" shape — a
8727        // `None` raw string is the absence of the typed
8728        // `:restart-window` slot, which is exactly the SupervisorSpec
8729        // "never reset" semantics. The gate must be a no-op here; a
8730        // future tightening that rejected `None` would force every
8731        // supervisor caixa to authoring-time pin a window even when
8732        // the OTP semantics call for none.
8733        caixa_with_restart_window(None)
8734            .validate_restart_window()
8735            .unwrap();
8736    }
8737
8738    #[test]
8739    fn validate_restart_window_accepts_canonical_forms() {
8740        // Positive-set sweep across the canonical authoring units the
8741        // shared `supervisor::duration_codec::parse` accepts —
8742        // matches the codec-side `parse_accepts_integer_canonical_units`
8743        // pin in supervisor::tests so a future codec-side tightening
8744        // surfaces simultaneously on both axes.
8745        for window in ["60s", "5m", "1h", "500ms", "30", "0s"] {
8746            caixa_with_restart_window(Some(window))
8747                .validate_restart_window()
8748                .unwrap_or_else(|e| {
8749                    panic!("canonical :restart-window {window:?} must validate, got {e:?}")
8750                });
8751        }
8752    }
8753
8754    #[test]
8755    fn validate_restart_window_rejects_fractional_seconds() {
8756        // Fail-before-pass-after pin: the `"1.5s"` drift class (parses
8757        // as f64 to 1.5 → renders back as `"1500ms"` on first
8758        // serialize). Prior to the fold + this gate, the inline
8759        // `parse_window_inline` accepted f64 magnitudes and silently
8760        // produced a `Duration::from_secs_f64(1.5)`, divergent from
8761        // the shared codec's integer-magnitude discipline on the
8762        // serde-routed siblings. The gate now surfaces a self-locating
8763        // diagnostic at the manifest layer.
8764        let err = caixa_with_restart_window(Some("1.5s"))
8765            .validate_restart_window()
8766            .unwrap_err();
8767        let ManifestError::RestartWindowMalformed {
8768            restart_window,
8769            reason,
8770        } = err
8771        else {
8772            panic!("expected RestartWindowMalformed for fractional seconds");
8773        };
8774        assert_eq!(restart_window, "1.5s");
8775        assert!(
8776            reason.contains("\"1.5\"") && reason.contains("not a non-negative integer"),
8777            "diagnostic must carry shared-codec wording, got {reason:?}"
8778        );
8779    }
8780
8781    #[test]
8782    fn validate_restart_window_rejects_decimal_shaped_integer() {
8783        // The `"1.0s"` class — numerically `1s` exactly, but the
8784        // canonical form is `"1s"` not `"1.0s"`. Decimal-shape leak
8785        // gets the same canonical-form diagnostic.
8786        let err = caixa_with_restart_window(Some("1.0s"))
8787            .validate_restart_window()
8788            .unwrap_err();
8789        assert!(
8790            matches!(
8791                err,
8792                ManifestError::RestartWindowMalformed { ref restart_window, .. }
8793                    if restart_window == "1.0s"
8794            ),
8795            "got {err:?}"
8796        );
8797    }
8798
8799    #[test]
8800    fn validate_restart_window_rejects_half_unit_minute() {
8801        // `"0.5m"` is the unit-fraction footgun — author writes a
8802        // human-readable half-minute, the prior inline parser silently
8803        // produced `Duration::from_secs_f64(30.0)` and serde
8804        // re-emitted as `"30s"`, rewriting author intent. The gate
8805        // closes the loop at the manifest layer.
8806        let err = caixa_with_restart_window(Some("0.5m"))
8807            .validate_restart_window()
8808            .unwrap_err();
8809        let ManifestError::RestartWindowMalformed {
8810            restart_window,
8811            reason,
8812        } = err
8813        else {
8814            panic!("expected RestartWindowMalformed");
8815        };
8816        assert_eq!(restart_window, "0.5m");
8817        assert!(
8818            reason.contains("\"30s\""),
8819            "diagnostic must point at the canonical-form remediation, got {reason:?}"
8820        );
8821    }
8822
8823    #[test]
8824    fn validate_restart_window_rejects_leading_sign() {
8825        // `"+30s"` and `"-30s"` both round-tripped through f64 cleanly
8826        // on the prior parser (`+30` parses as `30.0`; `-30` parsed
8827        // and was caught by the `num < 0.0` arm which silently
8828        // returned `None`, dropping the author-supplied window). The
8829        // shared codec's digit-only gate rejects both with a unified
8830        // canonical-form diagnostic; the manifest-layer wrapper names
8831        // the offending value.
8832        for bad in ["+30s", "-30s"] {
8833            let err = caixa_with_restart_window(Some(bad))
8834                .validate_restart_window()
8835                .unwrap_err();
8836            assert!(
8837                matches!(
8838                    err,
8839                    ManifestError::RestartWindowMalformed { ref restart_window, .. }
8840                        if restart_window == bad
8841                ),
8842                "got {err:?} for {bad:?}"
8843            );
8844        }
8845    }
8846
8847    #[test]
8848    fn validate_restart_window_rejects_unknown_unit() {
8849        // `"30x"` — the typo / wrong-unit footgun. The shared codec's
8850        // unit dispatch surfaces an `unknown duration unit` reason;
8851        // the manifest-layer wrapper names the offending value.
8852        let err = caixa_with_restart_window(Some("30x"))
8853            .validate_restart_window()
8854            .unwrap_err();
8855        let ManifestError::RestartWindowMalformed {
8856            restart_window,
8857            reason,
8858        } = err
8859        else {
8860            panic!("expected RestartWindowMalformed for unknown unit");
8861        };
8862        assert_eq!(restart_window, "30x");
8863        assert!(
8864            reason.contains("unknown duration unit"),
8865            "diagnostic must carry shared-codec unit-rejection wording, got {reason:?}"
8866        );
8867    }
8868
8869    #[test]
8870    fn validate_restart_window_rejects_garbage() {
8871        // Pure non-numeric magnitude (`"abc"`) falls through to the
8872        // shared codec's narrower `"bad duration magnitude"` arm. Same
8873        // diagnostic shape as the codec-side
8874        // `parse_garbage_still_falls_through_to_bad_magnitude` pin.
8875        let err = caixa_with_restart_window(Some("abc"))
8876            .validate_restart_window()
8877            .unwrap_err();
8878        let ManifestError::RestartWindowMalformed {
8879            restart_window,
8880            reason,
8881        } = err
8882        else {
8883            panic!("expected RestartWindowMalformed for garbage");
8884        };
8885        assert_eq!(restart_window, "abc");
8886        assert!(
8887            reason.contains("bad duration magnitude"),
8888            "diagnostic must carry shared-codec garbage-rejection wording, got {reason:?}"
8889        );
8890    }
8891
8892    #[test]
8893    fn validate_restart_window_rejects_empty_string() {
8894        // The empty-after-trim edge case — distinct from the `None`
8895        // canonical "omit the slot" shape. The shared codec's
8896        // digit-only gate refuses an empty magnitude; the manifest
8897        // layer names the offending `""` so the author can grep for
8898        // the literal empty value in their `caixa.lisp` and either
8899        // remove the slot (the canonical "no reset" shape) or pin a
8900        // positive duration.
8901        let err = caixa_with_restart_window(Some(""))
8902            .validate_restart_window()
8903            .unwrap_err();
8904        assert!(
8905            matches!(
8906                err,
8907                ManifestError::RestartWindowMalformed { ref restart_window, .. }
8908                    if restart_window.is_empty()
8909            ),
8910            "got {err:?}"
8911        );
8912    }
8913
8914    #[test]
8915    fn validate_restart_window_diagnostic_carries_offending_value() {
8916        // Diagnostic-shape pin (peer with
8917        // `nome_invalid_diagnostic_carries_offending_nome` /
8918        // `versao_invalid_diagnostic_carries_offending_versao`): the
8919        // error names the offending raw `:restart-window` verbatim
8920        // with a non-empty shared-codec-shaped reason, so a `feira
8921        // lint` run can render the diagnostic without re-parsing.
8922        let err = caixa_with_restart_window(Some("1.5s"))
8923            .validate_restart_window()
8924            .unwrap_err();
8925        let ManifestError::RestartWindowMalformed {
8926            restart_window,
8927            reason,
8928        } = err
8929        else {
8930            panic!("expected RestartWindowMalformed variant");
8931        };
8932        assert_eq!(restart_window, "1.5s");
8933        assert!(
8934            !reason.is_empty(),
8935            "RestartWindowMalformed `reason` must carry the codec's wording verbatim"
8936        );
8937    }
8938
8939    #[test]
8940    fn supervisor_view_folds_through_shared_codec_on_canonical_form() {
8941        // Behavioral parity pin after the fold (`parse_window_inline`
8942        // deletion): the canonical `"60s"` still produces
8943        // `Duration::from_secs(60)` on the typed view — the fold is
8944        // semantically equivalent to the prior inline parser on the
8945        // accepted set. Mirrors the pre-fold `supervisor_view_returns_typed_shape`
8946        // pin, narrowed to the parser-side contract.
8947        let c = caixa_with_restart_window(Some("60s"));
8948        let view = c.supervisor_view().expect("Supervisor kind has a view");
8949        assert_eq!(
8950            view.restart_window,
8951            Some(std::time::Duration::from_secs(60))
8952        );
8953    }
8954
8955    #[test]
8956    fn supervisor_view_soft_swallows_what_validate_rejects() {
8957        // Parity pin between the view-construction path and the
8958        // manifest-level validator: the same `"1.5s"` that surfaces
8959        // `RestartWindowMalformed` at `validate_restart_window` time
8960        // becomes `restart_window: None` on the typed view (the fold
8961        // preserves the existing best-effort shape of `supervisor_view`).
8962        // The contract is: a layout-verifier / `feira lint` flow that
8963        // cares about the malformed-window axis MUST consult
8964        // `validate_restart_window` — relying solely on the view's
8965        // `None` swallows the diagnostic silently. This pin makes the
8966        // expectation a typed invariant.
8967        let c = caixa_with_restart_window(Some("1.5s"));
8968        let view = c.supervisor_view().expect("Supervisor kind has a view");
8969        assert_eq!(
8970            view.restart_window, None,
8971            "view-construction path soft-swallows the parse error to None"
8972        );
8973        // And the manifest-level validator does NOT soft-swallow:
8974        assert!(
8975            matches!(
8976                c.validate_restart_window().unwrap_err(),
8977                ManifestError::RestartWindowMalformed { ref restart_window, .. }
8978                    if restart_window == "1.5s"
8979            ),
8980            "validator must surface the offending value",
8981        );
8982    }
8983
8984    // ── validate_code_paths — per-entry shape on :bibliotecas / :exe / :servicos ──
8985
8986    fn caixa_with_code_paths(bibliotecas: Vec<&str>, exe: Vec<&str>, servicos: Vec<&str>) -> Caixa {
8987        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8988        c.bibliotecas = bibliotecas.into_iter().map(String::from).collect();
8989        c.exe = exe.into_iter().map(String::from).collect();
8990        c.servicos = servicos.into_iter().map(String::from).collect();
8991        c
8992    }
8993
8994    #[test]
8995    fn validate_code_paths_accepts_canonical_template() {
8996        // The bare `Caixa::template` shape is the gate's identity element
8997        // on the canonical authoring shape — `:bibliotecas
8998        // ("lib/demo.lisp")` + empty `:exe` + empty `:servicos`. Pins
8999        // that the gate is non-disruptive against every existing caixa.
9000        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9001        c.validate_code_paths().unwrap();
9002    }
9003
9004    #[test]
9005    fn validate_code_paths_accepts_explicit_relative_paths_on_every_slot() {
9006        // Positive control sweep: a canonical-shaped path on every slot
9007        // passes. Mirrors the peer
9008        // `behavior::validate_every_slot_relative_is_ok` pin.
9009        let c = caixa_with_code_paths(
9010            vec!["lib/demo.lisp", "lib/helpers.lisp"],
9011            vec!["exe/demo", "exe/tool"],
9012            vec!["servicos/demo.computeunit.yaml"],
9013        );
9014        c.validate_code_paths().unwrap();
9015    }
9016
9017    #[test]
9018    fn validate_code_paths_accepts_all_empty_lists() {
9019        // The empty-list identity element: every Caixa with no declared
9020        // code paths trivially passes (Supervisor / Aplicacao kinds rely
9021        // on this — the OwnCode gate already rejected them before the
9022        // path-shape gate runs in the layout, but the validator itself
9023        // must accept the empty shape).
9024        let c = caixa_with_code_paths(vec![], vec![], vec![]);
9025        c.validate_code_paths().unwrap();
9026    }
9027
9028    #[test]
9029    fn validate_code_paths_rejects_empty_bibliotecas_entry() {
9030        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
9031        let err = c.validate_code_paths().unwrap_err();
9032        assert!(
9033            matches!(
9034                err,
9035                ManifestError::CodePathEmpty {
9036                    slot: ":bibliotecas"
9037                }
9038            ),
9039            "got {err:?}",
9040        );
9041    }
9042
9043    #[test]
9044    fn validate_code_paths_rejects_empty_exe_entry() {
9045        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
9046        let err = c.validate_code_paths().unwrap_err();
9047        assert!(
9048            matches!(err, ManifestError::CodePathEmpty { slot: ":exe" }),
9049            "got {err:?}",
9050        );
9051    }
9052
9053    #[test]
9054    fn validate_code_paths_rejects_empty_servicos_entry() {
9055        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
9056        let err = c.validate_code_paths().unwrap_err();
9057        assert!(
9058            matches!(err, ManifestError::CodePathEmpty { slot: ":servicos" }),
9059            "got {err:?}",
9060        );
9061    }
9062
9063    #[test]
9064    fn validate_code_paths_rejects_absolute_bibliotecas_entry() {
9065        // `:bibliotecas` has no `starts_with(<dir>)` fence downstream,
9066        // so an absolute path that resolves on disk silently passes the
9067        // layout's existence check — the canonical sandbox-escape on
9068        // the biblioteca axis.
9069        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
9070        let err = c.validate_code_paths().unwrap_err();
9071        let ManifestError::CodePathAbsolute { slot, path } = err else {
9072            panic!("expected CodePathAbsolute, got {err:?}");
9073        };
9074        assert_eq!(slot, ":bibliotecas");
9075        assert_eq!(path, PathBuf::from("/etc/passwd"));
9076    }
9077
9078    #[test]
9079    fn validate_code_paths_rejects_absolute_exe_entry() {
9080        let c = caixa_with_code_paths(vec![], vec!["/usr/bin/env"], vec![]);
9081        let err = c.validate_code_paths().unwrap_err();
9082        let ManifestError::CodePathAbsolute { slot, path } = err else {
9083            panic!("expected CodePathAbsolute, got {err:?}");
9084        };
9085        assert_eq!(slot, ":exe");
9086        assert_eq!(path, PathBuf::from("/usr/bin/env"));
9087    }
9088
9089    #[test]
9090    fn validate_code_paths_rejects_absolute_servicos_entry() {
9091        let c = caixa_with_code_paths(vec![], vec![], vec!["/var/servicos/x.yaml"]);
9092        let err = c.validate_code_paths().unwrap_err();
9093        let ManifestError::CodePathAbsolute { slot, path } = err else {
9094            panic!("expected CodePathAbsolute, got {err:?}");
9095        };
9096        assert_eq!(slot, ":servicos");
9097        assert_eq!(path, PathBuf::from("/var/servicos/x.yaml"));
9098    }
9099
9100    #[test]
9101    fn validate_code_paths_rejects_parent_escape_bibliotecas_leading() {
9102        // Canonical "I want a lib from a sibling caixa" footgun on the
9103        // biblioteca axis. `:bibliotecas` has no `starts_with` fence
9104        // downstream, so a leading `..` traverses to the parent of the
9105        // caixa root with no diagnostic at layout time if the resolved
9106        // target exists.
9107        let c = caixa_with_code_paths(vec!["../sibling/x.lisp"], vec![], vec![]);
9108        let err = c.validate_code_paths().unwrap_err();
9109        let ManifestError::CodePathParentEscape { slot, path } = err else {
9110            panic!("expected CodePathParentEscape, got {err:?}");
9111        };
9112        assert_eq!(slot, ":bibliotecas");
9113        assert_eq!(path, PathBuf::from("../sibling/x.lisp"));
9114    }
9115
9116    #[test]
9117    fn validate_code_paths_rejects_parent_escape_exe_mid_path() {
9118        // Mid-path `..` defeats the layout's component-aware
9119        // `starts_with(exe_dir)` fence — `root.join("exe/../../escape")`
9120        // `starts_with(<root>/exe)` is true, but the canonical resolution
9121        // lives outside the caixa root. Caught regardless of where the
9122        // `..` sits — mirrors the peer
9123        // `behavior::validate_rejects_parent_escape_mid_path` pin.
9124        let c = caixa_with_code_paths(vec![], vec!["exe/../../escape"], vec![]);
9125        let err = c.validate_code_paths().unwrap_err();
9126        let ManifestError::CodePathParentEscape { slot, path } = err else {
9127            panic!("expected CodePathParentEscape, got {err:?}");
9128        };
9129        assert_eq!(slot, ":exe");
9130        assert_eq!(path, PathBuf::from("exe/../../escape"));
9131    }
9132
9133    #[test]
9134    fn validate_code_paths_rejects_parent_escape_servicos_trailing() {
9135        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/foo/../../escape.yaml"]);
9136        let err = c.validate_code_paths().unwrap_err();
9137        let ManifestError::CodePathParentEscape { slot, path } = err else {
9138            panic!("expected CodePathParentEscape, got {err:?}");
9139        };
9140        assert_eq!(slot, ":servicos");
9141        assert_eq!(path, PathBuf::from("servicos/foo/../../escape.yaml"));
9142    }
9143
9144    #[test]
9145    fn validate_code_paths_cross_slot_precedence_bibliotecas_before_exe_before_servicos() {
9146        // Cross-slot precedence pin: `:bibliotecas` → `:exe` →
9147        // `:servicos`. A manifest with malformed entries on all three
9148        // surfaces surfaces the `:bibliotecas` defect first, mirroring
9149        // the canonical declaration order
9150        // `Caixa::declared_foreign_code_slots` already establishes for
9151        // the foreign-code-slot diagnostic.
9152        let c = caixa_with_code_paths(vec![""], vec![""], vec![""]);
9153        let err = c.validate_code_paths().unwrap_err();
9154        assert!(
9155            matches!(
9156                err,
9157                ManifestError::CodePathEmpty {
9158                    slot: ":bibliotecas"
9159                }
9160            ),
9161            "got {err:?}",
9162        );
9163    }
9164
9165    #[test]
9166    fn validate_code_paths_within_slot_precedence_empty_before_absolute_before_parent_escape() {
9167        // Within-slot precedence pin: empty → absolute → parent-escape,
9168        // matching the [`PathShapeViolation`] arm-ordering every peer
9169        // `is_sandboxed_relative_path` caller follows (b0c8389
9170        // BehaviorSpec, 26da2c7 UpgradeInstruction::StateChange). A
9171        // `:bibliotecas` list whose first entry is empty *and* whose
9172        // later entries are absolute/parent-escape surfaces the empty
9173        // arm first, on the lexicographically-earliest offending entry.
9174        let c = caixa_with_code_paths(vec!["", "/etc/passwd", "../escape.lisp"], vec![], vec![]);
9175        let err = c.validate_code_paths().unwrap_err();
9176        assert!(
9177            matches!(
9178                err,
9179                ManifestError::CodePathEmpty {
9180                    slot: ":bibliotecas"
9181                }
9182            ),
9183            "got {err:?}",
9184        );
9185    }
9186
9187    #[test]
9188    fn validate_code_paths_first_offender_per_slot_wins() {
9189        // Within a single slot, the first declaration-order offender
9190        // surfaces — pins that the gate is left-to-right deterministic
9191        // (peer of every `*_first_collision_*` pin on duplicate gates).
9192        let c = caixa_with_code_paths(
9193            vec!["lib/ok.lisp", "/etc/escape", "../also-escape"],
9194            vec![],
9195            vec![],
9196        );
9197        let err = c.validate_code_paths().unwrap_err();
9198        let ManifestError::CodePathAbsolute { slot, path } = err else {
9199            panic!("expected CodePathAbsolute, got {err:?}");
9200        };
9201        assert_eq!(slot, ":bibliotecas");
9202        assert_eq!(path, PathBuf::from("/etc/escape"));
9203    }
9204
9205    #[test]
9206    fn validate_code_paths_diagnostic_carries_offending_slot_and_path() {
9207        // Diagnostic-shape pin (peer with
9208        // `nome_invalid_diagnostic_carries_offending_nome` /
9209        // `versao_invalid_diagnostic_carries_offending_versao`): the
9210        // error's Display surfaces both the offending `:slot` tag and
9211        // the offending path verbatim, so a `feira lint` run can render
9212        // the diagnostic without re-parsing.
9213        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
9214        let rendered = c.validate_code_paths().unwrap_err().to_string();
9215        assert!(
9216            rendered.contains(":bibliotecas"),
9217            "diagnostic must name the offending slot: {rendered}",
9218        );
9219        assert!(
9220            rendered.contains("/etc/passwd"),
9221            "diagnostic must quote the offending path: {rendered}",
9222        );
9223    }
9224
9225    #[test]
9226    fn validate_code_paths_rejects_duplicate_bibliotecas_entry() {
9227        // Canonical copy-paste-the-wrong-file footgun on the biblioteca
9228        // axis. Without the gate `feira build` re-parses the same lib
9229        // twice, wasting work and silently masking the author's intent
9230        // to declare a *second* biblioteca.
9231        let c = caixa_with_code_paths(vec!["lib/demo.lisp", "lib/demo.lisp"], vec![], vec![]);
9232        let err = c.validate_code_paths().unwrap_err();
9233        let ManifestError::CodePathDuplicate { slot, path } = err else {
9234            panic!("expected CodePathDuplicate, got {err:?}");
9235        };
9236        assert_eq!(slot, ":bibliotecas");
9237        assert_eq!(path, PathBuf::from("lib/demo.lisp"));
9238    }
9239
9240    #[test]
9241    fn validate_code_paths_rejects_duplicate_exe_entry() {
9242        // Same footgun on the Binario surface. The future `caixa-flake`
9243        // emitter that materializes each `:exe` entry as a flake
9244        // `packages.<name>` derivation would collide on the duplicate
9245        // package key — surfaced here at the typed-validate layer with a
9246        // self-locating diagnostic instead.
9247        let c = caixa_with_code_paths(vec![], vec!["exe/cli", "exe/cli"], vec![]);
9248        let err = c.validate_code_paths().unwrap_err();
9249        let ManifestError::CodePathDuplicate { slot, path } = err else {
9250            panic!("expected CodePathDuplicate, got {err:?}");
9251        };
9252        assert_eq!(slot, ":exe");
9253        assert_eq!(path, PathBuf::from("exe/cli"));
9254    }
9255
9256    #[test]
9257    fn validate_code_paths_rejects_duplicate_servicos_entry() {
9258        // Same footgun on the Servico surface. The peer caixa-helm /
9259        // caixa-flux renderers refuse `:servicos.len() != 1` with the
9260        // narrower `UnsupportedServicoCount` diagnostic, but that
9261        // diagnostic surfaces "too many servicos" without naming
9262        // "duplicate entry" — the typed self-locating framing only lands
9263        // at this gate.
9264        let c = caixa_with_code_paths(
9265            vec![],
9266            vec![],
9267            vec![
9268                "servicos/demo.computeunit.yaml",
9269                "servicos/demo.computeunit.yaml",
9270            ],
9271        );
9272        let err = c.validate_code_paths().unwrap_err();
9273        let ManifestError::CodePathDuplicate { slot, path } = err else {
9274            panic!("expected CodePathDuplicate, got {err:?}");
9275        };
9276        assert_eq!(slot, ":servicos");
9277        assert_eq!(path, PathBuf::from("servicos/demo.computeunit.yaml"));
9278    }
9279
9280    #[test]
9281    fn validate_code_paths_accepts_same_path_across_slots() {
9282        // Per-list scope pin: a `:bibliotecas` entry that happens to
9283        // collide with an `:exe` or `:servicos` entry as a *string* is
9284        // not a duplicate by this gate (each list gets its own HashSet),
9285        // mirroring the peer `:deps` ↔ `:deps-dev` per-list scope
9286        // (a `:nome` present in both lists is a legitimate dev-vs-runtime
9287        // shape on the dep axis). The structural `starts_with(<exe |
9288        // servicos>_dir)` fence at layout time prevents the realistic
9289        // cross-slot collision case from existing on disk, but the gate's
9290        // per-list scope is correct independent of that downstream fence.
9291        let c = caixa_with_code_paths(
9292            vec!["lib/x.lisp"],
9293            vec!["exe/x"],
9294            vec!["servicos/x.computeunit.yaml"],
9295        );
9296        c.validate_code_paths().unwrap();
9297    }
9298
9299    #[test]
9300    fn validate_code_paths_duplicate_fires_after_structural_checks_on_same_slot() {
9301        // Within-slot ordering pin: structural defects (empty / absolute
9302        // / parent-escape) fire before the duplicate gate on the same
9303        // slot. A `:bibliotecas ("" "lib/x.lisp" "lib/x.lisp")` shape
9304        // surfaces the narrower `CodePathEmpty` for the empty entry
9305        // first, not the duplicate on the later pair — same arm-ordering
9306        // every peer per-list duplicate gate uses (`:etiquetas` 360a499,
9307        // `:autores` 86c769b, `:deps` 359fba5).
9308        let c = caixa_with_code_paths(vec!["", "lib/x.lisp", "lib/x.lisp"], vec![], vec![]);
9309        let err = c.validate_code_paths().unwrap_err();
9310        assert!(
9311            matches!(
9312                err,
9313                ManifestError::CodePathEmpty {
9314                    slot: ":bibliotecas"
9315                }
9316            ),
9317            "got {err:?}",
9318        );
9319    }
9320
9321    #[test]
9322    fn validate_code_paths_duplicate_in_bibliotecas_fires_before_duplicate_in_exe() {
9323        // Cross-slot ordering pin on the duplicate arm: `:bibliotecas`
9324        // duplicates surface before `:exe` duplicates, matching the
9325        // canonical `:bibliotecas` → `:exe` → `:servicos` declaration
9326        // order every peer per-slot diagnostic on this surface follows.
9327        let c = caixa_with_code_paths(
9328            vec!["lib/x.lisp", "lib/x.lisp"],
9329            vec!["exe/y", "exe/y"],
9330            vec![],
9331        );
9332        let err = c.validate_code_paths().unwrap_err();
9333        let ManifestError::CodePathDuplicate { slot, path } = err else {
9334            panic!("expected CodePathDuplicate, got {err:?}");
9335        };
9336        assert_eq!(slot, ":bibliotecas");
9337        assert_eq!(path, PathBuf::from("lib/x.lisp"));
9338    }
9339
9340    #[test]
9341    fn validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path() {
9342        // Diagnostic-shape pin (peer with
9343        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
9344        // on the structural arm): the duplicate-arm Display surfaces both
9345        // the offending `:slot` tag and the offending path verbatim, so a
9346        // `feira lint` run can render the diagnostic without re-parsing.
9347        let c = caixa_with_code_paths(
9348            vec![],
9349            vec![],
9350            vec![
9351                "servicos/demo.computeunit.yaml",
9352                "servicos/demo.computeunit.yaml",
9353            ],
9354        );
9355        let rendered = c.validate_code_paths().unwrap_err().to_string();
9356        assert!(
9357            rendered.contains(":servicos"),
9358            "diagnostic must name the offending slot: {rendered}",
9359        );
9360        assert!(
9361            rendered.contains("servicos/demo.computeunit.yaml"),
9362            "diagnostic must quote the offending path: {rendered}",
9363        );
9364    }
9365
9366    // ── validate_code_paths — `.lisp` extension gate on :bibliotecas ──
9367    //
9368    // The lifted [`crate::render::is_lisp_extension`] predicate (33cc830)
9369    // now gates `:bibliotecas` entries on the tatara-lisp-source file-type
9370    // contract. The `feira build` loop (`caixa-feira/src/cmd/build.rs:33`)
9371    // reads every declared `:bibliotecas` entry through `tatara_lisp::read`
9372    // at parse time — the same downstream consumer the peer `:behavior
9373    // :on-*` (c97815a, [`crate::BehaviorError::NonLispExtension`]) and
9374    // `:upgrade-from :state-change :script` (33cc830,
9375    // [`crate::UpgradeError::NonLispExtensionScript`]) axes route through.
9376    // `:exe` and `:servicos` are deliberately excluded — `:exe` is the
9377    // nix-built executable surface (`"exe/<name>"` shape per the canonical
9378    // [`crate::LayoutError::ExeOutsideDir`] error message and every
9379    // in-tree `caixa_with_code_paths` positive control), and `:servicos`
9380    // is the `.computeunit.yaml` ComputeUnit-CR axis.
9381
9382    #[test]
9383    fn validate_code_paths_rejects_no_extension_bibliotecas_entry() {
9384        // Canonical "I dragged the wrong file from the workspace tree"
9385        // footgun on the biblioteca axis. Without the gate `feira build`
9386        // hands the extensionless path to `tatara_lisp::read` and fails
9387        // with a parser-shaped diagnostic far from the source caixa.lisp,
9388        // with no field naming the offending `:bibliotecas` entry.
9389        for relpath in ["lib/demo", "demo", "lib/handlers/inner"] {
9390            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
9391            let err = c.validate_code_paths().unwrap_err();
9392            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
9393                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
9394            };
9395            assert_eq!(slot, ":bibliotecas");
9396            assert_eq!(path, PathBuf::from(relpath));
9397        }
9398    }
9399
9400    #[test]
9401    fn validate_code_paths_rejects_wrong_extension_bibliotecas_entry() {
9402        // Wrong-extension sweep across common authoring footguns. Same
9403        // sweep posture as the peer
9404        // `behavior::validate_rejects_wrong_extension` (c97815a) and
9405        // `upgrade::tests::state_change_rejects_wrong_extension_script`
9406        // (33cc830) cases.
9407        for relpath in [
9408            "lib/demo.rs",
9409            "lib/demo.txt",
9410            "lib/demo.md",
9411            "lib/demo.json",
9412            "lib/demo.yaml",
9413            "lib/demo.toml",
9414            "lib/demo.lisp.bak",
9415            "lib/demo.lispx",
9416            "lib/demo.lis",
9417        ] {
9418            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
9419            let err = c.validate_code_paths().unwrap_err();
9420            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
9421                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
9422            };
9423            assert_eq!(slot, ":bibliotecas");
9424            assert_eq!(path, PathBuf::from(relpath));
9425        }
9426    }
9427
9428    #[test]
9429    fn validate_code_paths_rejects_case_folded_extension_bibliotecas_entry() {
9430        // Case-sensitivity sweep — pins the strict lowercase `.lisp`
9431        // contract. An uppercase `.LISP` shape that the layout's existence
9432        // check would (case-insensitively, on case-insensitive volumes)
9433        // match the on-disk file still mismatches the canonical form the
9434        // codec emits, breaking the THEORY.md §V.2.7 render-determinism
9435        // contract. Mirrors the peer
9436        // `behavior::validate_rejects_case_folded_extension` (c97815a) and
9437        // `upgrade::tests::state_change_rejects_case_folded_extension_script`
9438        // (33cc830) sweeps.
9439        for relpath in [
9440            "lib/demo.LISP",
9441            "lib/demo.Lisp",
9442            "lib/demo.LiSp",
9443            "lib/demo.lISP",
9444        ] {
9445            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
9446            let err = c.validate_code_paths().unwrap_err();
9447            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
9448                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
9449            };
9450            assert_eq!(slot, ":bibliotecas");
9451            assert_eq!(path, PathBuf::from(relpath));
9452        }
9453    }
9454
9455    #[test]
9456    fn validate_code_paths_accepts_canonical_lisp_shapes() {
9457        // Positive-control sweep through every canonical authoring shape
9458        // every in-tree fixture and the `Caixa::template` scaffold use.
9459        // Mirrors the peer `behavior::validate_accepts_canonical_lisp_paths`
9460        // (c97815a) and the lifted predicate's own
9461        // `is_lisp_extension_accepts_canonical_shapes` sweep in render.rs
9462        // (33cc830).
9463        for relpath in [
9464            "lib/demo.lisp",
9465            "lib/handlers.lisp",
9466            "lib/migrations/v01-to-v02.lisp",
9467            "demo.lisp",
9468            "a.lisp",
9469            "./lib/demo.lisp",
9470            "lib/./handlers.lisp",
9471            "lib/migrations/v.0.1.lisp",
9472        ] {
9473            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
9474            c.validate_code_paths()
9475                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
9476        }
9477    }
9478
9479    #[test]
9480    fn validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos() {
9481        // The file-type gate is per-slot — only `:bibliotecas` carries the
9482        // tatara-lisp-source contract. An extensionless `:exe` entry
9483        // (`exe/demo`) and a `.computeunit.yaml` `:servicos` entry are the
9484        // canonical shapes every in-tree fixture uses, and must continue
9485        // to pass validate. Pins that a future tightening that broadens
9486        // the `.lisp` gate to either axis surfaces as a test failure
9487        // rather than as a silent breaking change to existing valid
9488        // manifests.
9489        let c = caixa_with_code_paths(
9490            vec![],
9491            vec!["exe/demo", "exe/tool"],
9492            vec!["servicos/demo.computeunit.yaml"],
9493        );
9494        c.validate_code_paths().unwrap();
9495    }
9496
9497    #[test]
9498    fn validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension() {
9499        // Cross-arm precedence pin: a `:bibliotecas` entry that is *both*
9500        // sandbox-escaping and non-`.lisp` surfaces the more fundamental
9501        // sandbox-shape diagnostic first (the `.lisp` remediation would
9502        // be misleading when the offending path can never resolve under
9503        // the caixa root anyway). Mirrors the peer
9504        // `EmptyPath` → `AbsolutePath` → `ParentEscape` → `NonLispExtension`
9505        // ordering on `:behavior :on-*` (c97815a) and `EmptyScript` →
9506        // `AbsoluteScript` → `ParentEscapeScript` → `NonLispExtensionScript`
9507        // on `:upgrade-from :state-change :script` (33cc830).
9508        //
9509        // Empty wins (the strictly-smaller-scope structural arm).
9510        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
9511        assert!(
9512            matches!(
9513                c.validate_code_paths().unwrap_err(),
9514                ManifestError::CodePathEmpty {
9515                    slot: ":bibliotecas"
9516                }
9517            ),
9518            "empty must win over non-lisp-extension",
9519        );
9520        // Absolute wins (the path can't resolve under the caixa root).
9521        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
9522        let err = c.validate_code_paths().unwrap_err();
9523        let ManifestError::CodePathAbsolute { slot, .. } = err else {
9524            panic!("absolute must win over non-lisp-extension, got {err:?}");
9525        };
9526        assert_eq!(slot, ":bibliotecas");
9527        // ParentEscape wins (the path escapes the caixa root).
9528        let c = caixa_with_code_paths(vec!["../sibling/x.txt"], vec![], vec![]);
9529        let err = c.validate_code_paths().unwrap_err();
9530        let ManifestError::CodePathParentEscape { slot, .. } = err else {
9531            panic!("parent-escape must win over non-lisp-extension, got {err:?}");
9532        };
9533        assert_eq!(slot, ":bibliotecas");
9534    }
9535
9536    #[test]
9537    fn validate_code_paths_non_lisp_extension_precedes_duplicate() {
9538        // Within-slot precedence pin: the per-entry file-type shape gate
9539        // fires before the cross-entry duplicate gate, so the narrower
9540        // structural defect dominates the uniqueness diagnostic. A
9541        // `("lib/x.txt" "lib/x.txt")` shape surfaces
9542        // `CodePathNonLispExtension` on the first entry rather than
9543        // `CodePathDuplicate` on the pair — same posture every per-entry
9544        // shape-gate-precedes-duplicate cascade follows on this surface
9545        // (the empty / absolute / parent-escape arms already precede the
9546        // duplicate arm; the lifted file-type arm joins that set).
9547        let c = caixa_with_code_paths(vec!["lib/x.txt", "lib/x.txt"], vec![], vec![]);
9548        let err = c.validate_code_paths().unwrap_err();
9549        let ManifestError::CodePathNonLispExtension { slot, path } = err else {
9550            panic!("expected CodePathNonLispExtension, got {err:?}");
9551        };
9552        assert_eq!(slot, ":bibliotecas");
9553        assert_eq!(path, PathBuf::from("lib/x.txt"));
9554    }
9555
9556    #[test]
9557    fn validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path() {
9558        // Diagnostic-shape pin (peer with
9559        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
9560        // on the sandbox-shape arms and
9561        // `validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path`
9562        // on the duplicate arm): the file-type-arm Display surfaces both
9563        // the offending `:slot` tag, the offending path verbatim, and the
9564        // expected `.lisp` extension named in the remediation text, so a
9565        // `feira lint` run can render the diagnostic without re-parsing.
9566        let c = caixa_with_code_paths(vec!["lib/demo.rs"], vec![], vec![]);
9567        let rendered = c.validate_code_paths().unwrap_err().to_string();
9568        assert!(
9569            rendered.contains(":bibliotecas"),
9570            "diagnostic must name the offending slot: {rendered}",
9571        );
9572        assert!(
9573            rendered.contains("lib/demo.rs"),
9574            "diagnostic must quote the offending path: {rendered}",
9575        );
9576        assert!(
9577            rendered.contains(".lisp"),
9578            "diagnostic must name the expected extension: {rendered}",
9579        );
9580    }
9581
9582    // ── validate_code_paths — `.computeunit.yaml` compound-suffix gate on :servicos ──
9583    //
9584    // The lifted [`crate::render::is_computeunit_yaml_extension`] predicate
9585    // now gates `:servicos` entries on the ComputeUnit-CR YAML file-type
9586    // contract. The peer caixa-helm / caixa-flux renderers consume each
9587    // `:servicos` entry through `serde_yaml::from_str` as a typed
9588    // `ComputeUnit` CR — same downstream-consumer-shape lift as the peer
9589    // `:bibliotecas` `.lisp` gate (64772a9), here on the compound-suffix
9590    // axis `Path::extension` can't express on its own.
9591
9592    #[test]
9593    fn validate_code_paths_rejects_no_extension_servicos_entry() {
9594        // Canonical "I dragged the wrong file from the workspace tree"
9595        // footgun on the Servico axis. Without the gate the peer
9596        // caixa-helm / caixa-flux renderers hand the extensionless path
9597        // to `serde_yaml::from_str` and fail with a parser-shaped
9598        // diagnostic far from the source caixa.lisp, with no field
9599        // naming the offending `:servicos` entry.
9600        for relpath in ["servicos/demo", "demo", "servicos/sub/nested"] {
9601            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
9602            let err = c.validate_code_paths().unwrap_err();
9603            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
9604                panic!(
9605                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
9606                     got {err:?}"
9607                );
9608            };
9609            assert_eq!(slot, ":servicos");
9610            assert_eq!(path, PathBuf::from(relpath));
9611        }
9612    }
9613
9614    #[test]
9615    fn validate_code_paths_rejects_wrong_extension_servicos_entry() {
9616        // Wrong-extension sweep across common authoring footguns on the
9617        // Servico axis. Bare `.yaml` is the canonical "I forgot the
9618        // `.computeunit` segment" typo; the off-by-one-segment shapes
9619        // (`.computeunit-yaml` / `.computeunit_yaml`) silently pass the
9620        // bare `Path::extension` view but mismatch the typed compound
9621        // suffix the renderers' `serde_yaml::from_str` consumer demands.
9622        // Same sweep-posture as the peer
9623        // `validate_code_paths_rejects_wrong_extension_bibliotecas_entry`
9624        // (64772a9) on the sibling tatara-lisp-source axis.
9625        for relpath in [
9626            "servicos/demo.yaml",
9627            "servicos/demo.yml",
9628            "servicos/demo.json",
9629            "servicos/demo.toml",
9630            "servicos/demo.txt",
9631            "servicos/demo.computeunit.yaml.bak",
9632            "servicos/demo.computeunit.yam",
9633            "servicos/demo.computeunit",
9634            "servicos/demo-computeunit.yaml",
9635            "servicos/demo_computeunit.yaml",
9636        ] {
9637            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
9638            let err = c.validate_code_paths().unwrap_err();
9639            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
9640                panic!(
9641                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
9642                     got {err:?}"
9643                );
9644            };
9645            assert_eq!(slot, ":servicos");
9646            assert_eq!(path, PathBuf::from(relpath));
9647        }
9648    }
9649
9650    #[test]
9651    fn validate_code_paths_rejects_case_folded_extension_servicos_entry() {
9652        // Case-sensitivity sweep — pins the strict lowercase
9653        // `.computeunit.yaml` contract. A case-folded shape that the
9654        // layout's existence check would (case-insensitively, on
9655        // case-insensitive volumes) match the on-disk file still
9656        // mismatches the canonical form the codec emits, breaking the
9657        // THEORY.md §V.2.7 render-determinism contract. Mirrors the peer
9658        // `validate_code_paths_rejects_case_folded_extension_bibliotecas_entry`
9659        // (64772a9) sweep on the sibling tatara-lisp-source axis.
9660        for relpath in [
9661            "servicos/demo.ComputeUnit.yaml",
9662            "servicos/demo.COMPUTEUNIT.yaml",
9663            "servicos/demo.computeunit.YAML",
9664            "servicos/demo.computeunit.Yaml",
9665            "servicos/demo.COMPUTEUNIT.YAML",
9666        ] {
9667            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
9668            let err = c.validate_code_paths().unwrap_err();
9669            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
9670                panic!(
9671                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
9672                     got {err:?}"
9673                );
9674            };
9675            assert_eq!(slot, ":servicos");
9676            assert_eq!(path, PathBuf::from(relpath));
9677        }
9678    }
9679
9680    #[test]
9681    fn validate_code_paths_rejects_empty_stem_servicos_entry() {
9682        // Degenerate hidden-file shape: a file name exactly equal to the
9683        // suffix (`.computeunit.yaml` — no stem preceding the suffix) is
9684        // the structural "Servico declared with no identity" footgun.
9685        // The substrate identifies each ComputeUnit by the file-stem
9686        // segment that precedes `.computeunit.yaml` (the rendered
9687        // `lareira-<stem>` Helm chart, the per-Servico `metadata.name`,
9688        // the M3 `:contratos` membership lookup), so an empty stem
9689        // leaves the Servico unidentifiable. Pinned at the typed-axis
9690        // level so a future regression that drops the `name.len() >
9691        // SUFFIX.len()` bound at the predicate surfaces here, not
9692        // piecemeal as a `lareira-` chart-name collision at render time.
9693        for relpath in ["servicos/.computeunit.yaml"] {
9694            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
9695            let err = c.validate_code_paths().unwrap_err();
9696            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
9697                panic!(
9698                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
9699                     got {err:?}"
9700                );
9701            };
9702            assert_eq!(slot, ":servicos");
9703            assert_eq!(path, PathBuf::from(relpath));
9704        }
9705    }
9706
9707    #[test]
9708    fn validate_code_paths_accepts_canonical_computeunit_yaml_shapes() {
9709        // Positive-control sweep through every canonical authoring shape
9710        // every in-tree fixture and the `Caixa::template` scaffold use.
9711        // Mirrors the peer
9712        // `validate_code_paths_accepts_canonical_lisp_shapes` (64772a9)
9713        // and the lifted predicate's own
9714        // `computeunit_yaml_extension_accepts_canonical_shapes` sweep in
9715        // render.rs.
9716        for relpath in [
9717            "servicos/demo.computeunit.yaml",
9718            "servicos/hello-rio.computeunit.yaml",
9719            "servicos/my-service.computeunit.yaml",
9720            "servicos/a.computeunit.yaml",
9721            "./servicos/demo.computeunit.yaml",
9722            "servicos/./demo.computeunit.yaml",
9723            "servicos/sub/nested.computeunit.yaml",
9724            "servicos/v0.1.computeunit.yaml",
9725        ] {
9726            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
9727            c.validate_code_paths()
9728                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
9729        }
9730    }
9731
9732    #[test]
9733    fn validate_code_paths_non_computeunit_yaml_extension_does_not_fire_on_bibliotecas_or_exe() {
9734        // The file-type gate is per-slot — only `:servicos` carries the
9735        // ComputeUnit-CR YAML contract. A canonical `.lisp` `:bibliotecas`
9736        // entry and an extensionless `:exe` entry are the canonical
9737        // shapes every in-tree fixture uses, and must continue to pass
9738        // validate. Peer of
9739        // `validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos`
9740        // (64772a9) — together pin that the typed
9741        // [`CodePathFileType`] dispatch is exhaustively per-slot, with no
9742        // cross-axis leakage in either direction.
9743        let c = caixa_with_code_paths(
9744            vec!["lib/demo.lisp"],
9745            vec!["exe/demo", "exe/tool"],
9746            vec!["servicos/demo.computeunit.yaml"],
9747        );
9748        c.validate_code_paths().unwrap();
9749    }
9750
9751    #[test]
9752    fn validate_code_paths_sandbox_shape_arms_precede_non_computeunit_yaml_extension() {
9753        // Cross-arm precedence pin: a `:servicos` entry that is *both*
9754        // sandbox-escaping and wrong-extension surfaces the more
9755        // fundamental sandbox-shape diagnostic first (the
9756        // `.computeunit.yaml` remediation would be misleading when the
9757        // offending path can never resolve under the caixa root
9758        // anyway). Mirrors the peer
9759        // `validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension`
9760        // (64772a9) ordering on the sibling `:bibliotecas` axis and the
9761        // peer `EmptyPath` → `AbsolutePath` → `ParentEscape` →
9762        // `NonComputeUnitYamlExtension` arm-ordering the dispatch
9763        // table establishes.
9764        //
9765        // Empty wins (the strictly-smaller-scope structural arm).
9766        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
9767        assert!(
9768            matches!(
9769                c.validate_code_paths().unwrap_err(),
9770                ManifestError::CodePathEmpty { slot: ":servicos" }
9771            ),
9772            "empty must win over non-computeunit-yaml-extension",
9773        );
9774        // Absolute wins (the path can't resolve under the caixa root).
9775        let c = caixa_with_code_paths(vec![], vec![], vec!["/etc/foo.yaml"]);
9776        let err = c.validate_code_paths().unwrap_err();
9777        let ManifestError::CodePathAbsolute { slot, .. } = err else {
9778            panic!("absolute must win over non-computeunit-yaml-extension, got {err:?}");
9779        };
9780        assert_eq!(slot, ":servicos");
9781        // ParentEscape wins (the path escapes the caixa root).
9782        let c = caixa_with_code_paths(vec![], vec![], vec!["../sibling/x.yaml"]);
9783        let err = c.validate_code_paths().unwrap_err();
9784        let ManifestError::CodePathParentEscape { slot, .. } = err else {
9785            panic!("parent-escape must win over non-computeunit-yaml-extension, got {err:?}");
9786        };
9787        assert_eq!(slot, ":servicos");
9788    }
9789
9790    #[test]
9791    fn validate_code_paths_non_computeunit_yaml_extension_precedes_duplicate() {
9792        // Within-slot precedence pin: the per-entry file-type shape gate
9793        // fires before the cross-entry duplicate gate, so the narrower
9794        // structural defect dominates the uniqueness diagnostic. A
9795        // `("servicos/x.yaml" "servicos/x.yaml")` shape surfaces
9796        // `CodePathNonComputeUnitYamlExtension` on the first entry
9797        // rather than `CodePathDuplicate` on the pair — same posture
9798        // every per-entry shape-gate-precedes-duplicate cascade follows
9799        // on this surface, peer of the 64772a9 `:bibliotecas`
9800        // `("lib/x.txt" "lib/x.txt")` ordering.
9801        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/x.yaml", "servicos/x.yaml"]);
9802        let err = c.validate_code_paths().unwrap_err();
9803        let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
9804            panic!("expected CodePathNonComputeUnitYamlExtension, got {err:?}");
9805        };
9806        assert_eq!(slot, ":servicos");
9807        assert_eq!(path, PathBuf::from("servicos/x.yaml"));
9808    }
9809
9810    #[test]
9811    fn validate_code_paths_non_computeunit_yaml_extension_diagnostic_carries_offending_slot_and_path()
9812     {
9813        // Diagnostic-shape pin (peer with
9814        // `validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path`
9815        // on the sibling tatara-lisp-source axis): the file-type-arm
9816        // Display surfaces both the offending `:slot` tag, the
9817        // offending path verbatim, and the expected
9818        // `.computeunit.yaml` compound suffix named in the remediation
9819        // text, so a `feira lint` run can render the diagnostic without
9820        // re-parsing.
9821        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.yaml"]);
9822        let rendered = c.validate_code_paths().unwrap_err().to_string();
9823        assert!(
9824            rendered.contains(":servicos"),
9825            "diagnostic must name the offending slot: {rendered}",
9826        );
9827        assert!(
9828            rendered.contains("servicos/demo.yaml"),
9829            "diagnostic must quote the offending path: {rendered}",
9830        );
9831        assert!(
9832            rendered.contains(".computeunit.yaml"),
9833            "diagnostic must name the expected compound suffix: {rendered}",
9834        );
9835    }
9836
9837    // ── validate_etiquetas — universal-axis registry-search-tag shape ──
9838
9839    fn caixa_with_etiquetas(etiquetas: Vec<&str>) -> Caixa {
9840        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9841        c.etiquetas = etiquetas.into_iter().map(String::from).collect();
9842        c
9843    }
9844
9845    #[test]
9846    fn validate_etiquetas_accepts_empty_list() {
9847        // The empty-list identity: every caixa with no declared tags
9848        // trivially passes — `Caixa::template` emits `:etiquetas ()`,
9849        // so the gate is non-disruptive against every existing manifest.
9850        let c = caixa_with_etiquetas(vec![]);
9851        c.validate_etiquetas().unwrap();
9852    }
9853
9854    #[test]
9855    fn validate_etiquetas_accepts_canonical_forms() {
9856        // Positive control sweep: a canonical-shaped non-empty distinct
9857        // tag list passes, mirroring the example checkout-aplicacao
9858        // (`:etiquetas ("example" "aplicacao" "mesh" "ecommerce" "demo")`)
9859        // and the hello-rio fixture (`("hello-world" "wasm" "rust")`).
9860        let c = caixa_with_etiquetas(vec!["example", "aplicacao", "mesh", "ecommerce", "demo"]);
9861        c.validate_etiquetas().unwrap();
9862    }
9863
9864    #[test]
9865    fn validate_etiquetas_rejects_empty_entry() {
9866        // Canonical paste-from-blank-doc footgun. Without the gate the
9867        // empty entry rendered as `keywords: [""]` in `Chart.yaml`, a
9868        // no-op tag indexing nothing in the future caixa-registry.
9869        let c = caixa_with_etiquetas(vec![""]);
9870        let err = c.validate_etiquetas().unwrap_err();
9871        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
9872    }
9873
9874    #[test]
9875    fn validate_etiquetas_rejects_duplicate_entry() {
9876        // Canonical copy-paste-the-wrong-tag footgun. Without the gate
9877        // the duplicate was silently dedup'd by caixa-helm's BTreeSet
9878        // collect at chart render — a "second wins / one silently
9879        // disappears" shape divergent from every peer typed-graph set
9880        // gate. The duplicate-arm names the offending tag verbatim.
9881        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
9882        let err = c.validate_etiquetas().unwrap_err();
9883        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
9884            panic!("expected EtiquetaDuplicate, got {err:?}");
9885        };
9886        assert_eq!(etiqueta, "demo");
9887    }
9888
9889    #[test]
9890    fn validate_etiquetas_empty_takes_precedence_over_duplicate() {
9891        // Empty-first cascade pin: `("" "demo" "demo")` surfaces
9892        // `EtiquetaEmpty` not `EtiquetaDuplicate` — the narrower
9893        // structural "this entry has no value" defect dominates the
9894        // cross-entry uniqueness diagnostic. Mirrors the peer
9895        // empty-before-duplicate cascades on `:caracteristicas`
9896        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
9897        // fc3b4d5) and `:membros :caixa` (`MembroCaixaEmpty` before
9898        // `MembroDuplicate`).
9899        let c = caixa_with_etiquetas(vec!["", "demo", "demo"]);
9900        let err = c.validate_etiquetas().unwrap_err();
9901        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
9902    }
9903
9904    #[test]
9905    fn validate_etiquetas_duplicate_reports_first_collision() {
9906        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
9907        // duplicate (the lexicographically-earliest offending position
9908        // — the second `"a"` at index 2 collides with the first `"a"`
9909        // at index 0), not the later `"b"` collision at index 3,
9910        // peer with every other first-collision diagnostic posture on
9911        // this surface (`validate_load_singularity_reports_first_collision`,
9912        // `validate_cleanup_singularity_reports_first_collision`).
9913        let c = caixa_with_etiquetas(vec!["a", "b", "a", "b"]);
9914        let err = c.validate_etiquetas().unwrap_err();
9915        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
9916            panic!("expected EtiquetaDuplicate, got {err:?}");
9917        };
9918        assert_eq!(etiqueta, "a");
9919    }
9920
9921    #[test]
9922    fn validate_etiquetas_case_sensitive() {
9923        // Case-sensitivity pin: `("Foo" "foo")` is two distinct entries,
9924        // mirroring the peer `:membros :caixa` / `:children :caixa`
9925        // exact-string-match discipline. The shape gate this routine
9926        // landed (`is_chart_keyword_shape`, Cargo crates.io keyword
9927        // grammar) accepts mixed case — crates.io's keyword rule is
9928        // "case-insensitive" at the index layer but admits mixed case
9929        // at the entry layer (the canonical Helm chart `keywords:`
9930        // shape is lowercase by convention, but the grammar admits
9931        // uppercase). Case-sensitivity at the duplicate-set layer
9932        // remains structural — two distinct strings are two distinct
9933        // entries.
9934        let c = caixa_with_etiquetas(vec!["Foo", "foo"]);
9935        c.validate_etiquetas().unwrap();
9936    }
9937
9938    #[test]
9939    fn validate_etiquetas_diagnostic_carries_offending_tag() {
9940        // Diagnostic-shape pin (peer with
9941        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`):
9942        // the error's Display surfaces the offending tag verbatim, so a
9943        // `feira lint` run can render the diagnostic without re-parsing
9944        // and the author can grep their caixa.lisp for the offending
9945        // value.
9946        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
9947        let rendered = c.validate_etiquetas().unwrap_err().to_string();
9948        assert!(
9949            rendered.contains(":etiquetas"),
9950            "diagnostic must name the offending slot: {rendered}",
9951        );
9952        assert!(
9953            rendered.contains("demo"),
9954            "diagnostic must quote the offending tag: {rendered}",
9955        );
9956    }
9957
9958    #[test]
9959    fn validate_etiquetas_rejects_leading_whitespace_entry() {
9960        // Canonical paste-from-aligned-doc footgun. Without the shape
9961        // gate `" mesh"` silently passed validate and landed as a
9962        // YAML plain-style scalar with leading whitespace in the
9963        // rendered Chart.yaml `keywords:` array — every YAML 1.2
9964        // dumper trims leading whitespace from plain-style scalars,
9965        // so the authored space round-tripped inconsistently back
9966        // through `caixa.lisp`. Mirrors the peer
9967        // `validate_autores_rejects_leading_whitespace_entry`.
9968        let c = caixa_with_etiquetas(vec![" mesh"]);
9969        let err = c.validate_etiquetas().unwrap_err();
9970        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9971            panic!("expected EtiquetaInvalid, got {err:?}");
9972        };
9973        assert_eq!(etiqueta, " mesh");
9974        assert!(reason.contains("whitespace"), "got: {reason}");
9975    }
9976
9977    #[test]
9978    fn validate_etiquetas_rejects_embedded_newline_entry() {
9979        // Canonical paste-from-multiline-doc footgun — the author
9980        // pasted a multi-tag block into one `:etiquetas` entry
9981        // instead of splitting into one entry per tag. Without the
9982        // shape gate `"mesh\nhttp"` silently passed validate and
9983        // landed as a YAML-illegal multi-line scalar in the rendered
9984        // Chart.yaml `keywords:` array.
9985        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
9986        let err = c.validate_etiquetas().unwrap_err();
9987        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9988            panic!("expected EtiquetaInvalid, got {err:?}");
9989        };
9990        assert_eq!(etiqueta, "mesh\nhttp");
9991        assert!(reason.contains("newline"), "got: {reason}");
9992    }
9993
9994    #[test]
9995    fn validate_etiquetas_rejects_embedded_comma_entry() {
9996        // Canonical CSV-list-separator-confusion footgun: the author
9997        // confused the CSV-style separator convention with the
9998        // `:etiquetas` list grammar. Without the shape gate
9999        // `"mesh,http,grpc"` silently passed validate and landed as a
10000        // single malformed search tag in the rendered Chart.yaml
10001        // `keywords:` array — Artifact Hub's keyword index would
10002        // either silently drop the tag or index it as
10003        // `mesh,http,grpc` instead of three separate tags.
10004        let c = caixa_with_etiquetas(vec!["mesh,http,grpc"]);
10005        let err = c.validate_etiquetas().unwrap_err();
10006        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
10007            panic!("expected EtiquetaInvalid, got {err:?}");
10008        };
10009        assert_eq!(etiqueta, "mesh,http,grpc");
10010        assert!(reason.contains('`'), "got: {reason}");
10011        assert!(reason.contains(','), "got: {reason}");
10012    }
10013
10014    #[test]
10015    fn validate_etiquetas_rejects_embedded_slash_entry() {
10016        // Canonical path-separator-confusion footgun: the author
10017        // confused namespace-path notation with the keyword grammar.
10018        let c = caixa_with_etiquetas(vec!["caixa/servico"]);
10019        let err = c.validate_etiquetas().unwrap_err();
10020        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
10021            panic!("expected EtiquetaInvalid, got {err:?}");
10022        };
10023        assert_eq!(etiqueta, "caixa/servico");
10024        assert!(reason.contains('/'), "got: {reason}");
10025    }
10026
10027    #[test]
10028    fn validate_etiquetas_rejects_leading_digit_entry() {
10029        // Canonical paste-from-numbered-list footgun: the author
10030        // copied `1. mesh` from a numbered doc and the `1` leaked
10031        // into the tag.
10032        let c = caixa_with_etiquetas(vec!["1mesh"]);
10033        let err = c.validate_etiquetas().unwrap_err();
10034        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
10035            panic!("expected EtiquetaInvalid, got {err:?}");
10036        };
10037        assert_eq!(etiqueta, "1mesh");
10038        assert!(reason.contains("digit"), "got: {reason}");
10039    }
10040
10041    #[test]
10042    fn validate_etiquetas_rejects_leading_hyphen_entry() {
10043        // Canonical kebab-leak footgun.
10044        let c = caixa_with_etiquetas(vec!["-foo"]);
10045        let err = c.validate_etiquetas().unwrap_err();
10046        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
10047            panic!("expected EtiquetaInvalid, got {err:?}");
10048        };
10049        assert_eq!(etiqueta, "-foo");
10050        assert!(reason.contains('-'), "got: {reason}");
10051    }
10052
10053    #[test]
10054    fn validate_etiquetas_rejects_non_ascii_entry() {
10055        // Canonical paste-from-Unicode-doc footgun. Every legitimate
10056        // search tag is strict ASCII; raw non-ASCII silently
10057        // round-trips inconsistently across NFC/NFD normalization on
10058        // APFS / case-folding filesystems and breaks the Artifact Hub
10059        // keyword search index lookup.
10060        let c = caixa_with_etiquetas(vec!["café"]);
10061        let err = c.validate_etiquetas().unwrap_err();
10062        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
10063            panic!("expected EtiquetaInvalid, got {err:?}");
10064        };
10065        assert_eq!(etiqueta, "café");
10066        assert!(reason.contains("non-ASCII"), "got: {reason}");
10067    }
10068
10069    #[test]
10070    fn validate_etiquetas_rejects_period_entry() {
10071        // Canonical namespace-confusion / version-suffix footgun
10072        // (`"http.1"` / `"v1.0"`): Cargo's crates.io keyword grammar
10073        // excludes `.` from the continuation set even though the
10074        // sibling `:caracteristicas` axis (Cargo's feature-name
10075        // grammar) admits it. Tighter than the sibling axis, peer
10076        // with Cargo's own crates.io keyword shape.
10077        let c = caixa_with_etiquetas(vec!["http.1"]);
10078        let err = c.validate_etiquetas().unwrap_err();
10079        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
10080            panic!("expected EtiquetaInvalid, got {err:?}");
10081        };
10082        assert_eq!(etiqueta, "http.1");
10083        assert!(reason.contains('.'), "got: {reason}");
10084    }
10085
10086    #[test]
10087    fn validate_etiquetas_empty_takes_precedence_over_shape() {
10088        // Per-entry empty-first cascade pin: an entry that is both
10089        // empty *and* shape-invalid surfaces `EtiquetaEmpty` (the
10090        // narrower "this entry has no value" structural defect
10091        // dominates the broader shape-predicate diagnostic). The
10092        // empty arm fires before the shape predicate is consulted,
10093        // mirroring the peer `validate_autores_empty_takes_precedence_over_shape`
10094        // cascade established on the sibling universal-axis Vec<String>
10095        // surface.
10096        let c = caixa_with_etiquetas(vec![""]);
10097        let err = c.validate_etiquetas().unwrap_err();
10098        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
10099    }
10100
10101    #[test]
10102    fn validate_etiquetas_shape_takes_precedence_over_duplicate() {
10103        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
10104        // entry that is malformed surfaces `EtiquetaInvalid` even when
10105        // a later entry would have collided on duplicate. The
10106        // per-entry shape arm fires inside the same loop iteration as
10107        // the empty arm, before the seen-set insert at end-of-iteration
10108        // — structural per-entry defects dominate the cross-entry
10109        // uniqueness diagnostic. Mirrors the peer
10110        // `validate_autores_shape_takes_precedence_over_duplicate`.
10111        let c = caixa_with_etiquetas(vec!["mesh\nhttp", "mesh\nhttp"]);
10112        let err = c.validate_etiquetas().unwrap_err();
10113        assert!(
10114            matches!(err, ManifestError::EtiquetaInvalid { .. }),
10115            "got {err:?}",
10116        );
10117    }
10118
10119    #[test]
10120    fn validate_etiquetas_invalid_diagnostic_names_offending_slot_and_value() {
10121        // Diagnostic-shape pin on the new shape arm (peer with
10122        // `validate_autores_invalid_diagnostic_names_offending_slot_and_value`):
10123        // the rendered Display surfaces both the offending slot name
10124        // and the offending value verbatim, so a `feira lint` run
10125        // points the author at the exact `:etiquetas` entry to fix.
10126        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
10127        let rendered = c.validate_etiquetas().unwrap_err().to_string();
10128        assert!(
10129            rendered.contains(":etiquetas"),
10130            "diagnostic must name the offending slot: {rendered}",
10131        );
10132        assert!(
10133            rendered.contains("mesh\\nhttp"),
10134            "diagnostic must quote the offending value (debug-escaped): {rendered}",
10135        );
10136    }
10137
10138    #[test]
10139    fn validate_etiquetas_rejects_at_21_byte_boundary() {
10140        // The 20-byte cap pin — boundary-exceeding case rejected,
10141        // boundary-accepting case passes. Mirrors the peer
10142        // `chart_keyword_shape_rejects_at_21_byte_boundary` substrate-
10143        // side pin, surfaced at the per-axis caller so the cap
10144        // propagates through validate end-to-end. Constructed as a
10145        // single all-`a` token so only the cap arm fires.
10146        let max_ok = "a".repeat(20);
10147        let c = caixa_with_etiquetas(vec![max_ok.as_str()]);
10148        c.validate_etiquetas().unwrap();
10149        let too_long = "a".repeat(21);
10150        let c = caixa_with_etiquetas(vec![too_long.as_str()]);
10151        let err = c.validate_etiquetas().unwrap_err();
10152        let ManifestError::EtiquetaInvalid { reason, .. } = err else {
10153            panic!("expected EtiquetaInvalid, got {err:?}");
10154        };
10155        assert!(reason.contains("20"), "got: {reason}");
10156        assert!(reason.contains("21"), "got: {reason}");
10157    }
10158
10159    #[test]
10160    fn validate_etiquetas_accepts_canonical_shaped_forms() {
10161        // Positive control sweep: every canonical-shaped tag from the
10162        // hello-rio / checkout-aplicacao / pangea-tatara-akeyless
10163        // example fixtures plus the substrate-fixed tags caixa-helm
10164        // unions in at chart render. Drift between this list and the
10165        // substrate-side `chart_keyword_shape_accepts_canonical_forms`
10166        // sweep surfaces here — one source of truth for the rule.
10167        let c = caixa_with_etiquetas(vec![
10168            "example",
10169            "aplicacao",
10170            "mesh",
10171            "ecommerce",
10172            "demo",
10173            "infrastructure",
10174            "aws",
10175            "akeyless",
10176            "pangea-native",
10177            "hello-world",
10178            "wasm",
10179            "rust",
10180            "tatara-lisp",
10181            "caixa-servico",
10182            "lareira",
10183        ]);
10184        c.validate_etiquetas().unwrap();
10185    }
10186
10187    // ── validate_autores — universal-axis maintainer shape ────────────
10188
10189    fn caixa_with_autores(autores: Vec<&str>) -> Caixa {
10190        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10191        c.autores = autores.into_iter().map(String::from).collect();
10192        c
10193    }
10194
10195    #[test]
10196    fn validate_autores_accepts_empty_list() {
10197        // The empty-list identity: `Caixa::template` emits `:autores ()`,
10198        // so the gate is non-disruptive against every existing manifest.
10199        let c = caixa_with_autores(vec![]);
10200        c.validate_autores().unwrap();
10201    }
10202
10203    #[test]
10204    fn validate_autores_accepts_canonical_forms() {
10205        // Positive control sweep: every canonical-shaped non-empty
10206        // distinct maintainer list passes — the hello-rio / checkout-
10207        // aplicacao fixtures' `:autores ("pleme-io")` shape, plus the
10208        // multi-author shape downstream packaging surfaces emit.
10209        let c = caixa_with_autores(vec!["pleme-io"]);
10210        c.validate_autores().unwrap();
10211        let c = caixa_with_autores(vec!["alice <alice@example.com>", "bob <bob@example.com>"]);
10212        c.validate_autores().unwrap();
10213    }
10214
10215    #[test]
10216    fn validate_autores_rejects_empty_entry() {
10217        // Canonical paste-from-blank-doc footgun. Without the gate the
10218        // empty entry rendered as `maintainers: [{name: "", email: null}]`
10219        // in `Chart.yaml`, a no-op maintainer the substrate cannot route
10220        // to.
10221        let c = caixa_with_autores(vec![""]);
10222        let err = c.validate_autores().unwrap_err();
10223        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
10224    }
10225
10226    #[test]
10227    fn validate_autores_rejects_duplicate_entry() {
10228        // Canonical copy-paste-the-wrong-author footgun. Unlike the
10229        // `:etiquetas` peer (caixa-helm's `BTreeSet` collect silently
10230        // dedups the rendered `keywords:` array), the `maintainers:`
10231        // rendering has *no* dedup — duplicates stack verbatim. The
10232        // duplicate-arm names the offending author verbatim.
10233        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
10234        let err = c.validate_autores().unwrap_err();
10235        let ManifestError::AutorDuplicate { autor } = err else {
10236            panic!("expected AutorDuplicate, got {err:?}");
10237        };
10238        assert_eq!(autor, "pleme-io");
10239    }
10240
10241    #[test]
10242    fn validate_autores_empty_takes_precedence_over_duplicate() {
10243        // Empty-first cascade pin: `("" "pleme-io" "pleme-io")` surfaces
10244        // `AutorEmpty` not `AutorDuplicate` — the narrower structural
10245        // "this entry has no value" defect dominates the cross-entry
10246        // uniqueness diagnostic. Mirrors the peer empty-before-duplicate
10247        // cascades on `:etiquetas` (`EtiquetaEmpty` before
10248        // `EtiquetaDuplicate`, 360a499), `:caracteristicas`
10249        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
10250        // fc3b4d5), and `:membros :caixa` (`MembroCaixaEmpty` before
10251        // `MembroDuplicate`).
10252        let c = caixa_with_autores(vec!["", "pleme-io", "pleme-io"]);
10253        let err = c.validate_autores().unwrap_err();
10254        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
10255    }
10256
10257    #[test]
10258    fn validate_autores_duplicate_reports_first_collision() {
10259        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
10260        // duplicate (the lexicographically-earliest offending position
10261        // — the second `"a"` at index 2 collides with the first `"a"`
10262        // at index 0), not the later `"b"` collision at index 3,
10263        // peer with every other first-collision diagnostic posture on
10264        // this surface.
10265        let c = caixa_with_autores(vec!["a", "b", "a", "b"]);
10266        let err = c.validate_autores().unwrap_err();
10267        let ManifestError::AutorDuplicate { autor } = err else {
10268            panic!("expected AutorDuplicate, got {err:?}");
10269        };
10270        assert_eq!(autor, "a");
10271    }
10272
10273    #[test]
10274    fn validate_autores_case_sensitive() {
10275        // Case-sensitivity pin: `("Pleme-io" "pleme-io")` is two distinct
10276        // entries, mirroring the peer `:etiquetas` / `:membros :caixa`
10277        // / `:children :caixa` exact-string-match discipline.
10278        let c = caixa_with_autores(vec!["Pleme-io", "pleme-io"]);
10279        c.validate_autores().unwrap();
10280    }
10281
10282    #[test]
10283    fn validate_autores_diagnostic_carries_offending_author() {
10284        // Diagnostic-shape pin (peer with
10285        // `validate_etiquetas_diagnostic_carries_offending_tag`): the
10286        // error's Display surfaces the offending author verbatim, so a
10287        // `feira lint` run can render the diagnostic without re-parsing
10288        // and the author can grep their caixa.lisp for the offending
10289        // value.
10290        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
10291        let rendered = c.validate_autores().unwrap_err().to_string();
10292        assert!(
10293            rendered.contains(":autores"),
10294            "diagnostic must name the offending slot: {rendered}",
10295        );
10296        assert!(
10297            rendered.contains("pleme-io"),
10298            "diagnostic must quote the offending author: {rendered}",
10299        );
10300    }
10301
10302    #[test]
10303    fn validate_autores_rejects_leading_whitespace_entry() {
10304        // Canonical paste-from-aligned-doc footgun. Without the shape
10305        // gate `" pleme-io"` silently passed validate and landed as a
10306        // YAML plain-style scalar with leading whitespace in the
10307        // rendered Chart.yaml `maintainers:` array — every YAML 1.2
10308        // dumper trims leading whitespace from plain-style scalars, so
10309        // the authored space round-tripped inconsistently back through
10310        // `caixa.lisp`. Mirrors the peer
10311        // `validate_descricao_rejects_leading_whitespace`.
10312        let c = caixa_with_autores(vec![" pleme-io"]);
10313        let err = c.validate_autores().unwrap_err();
10314        let ManifestError::AutorInvalid { autor, reason } = err else {
10315            panic!("expected AutorInvalid, got {err:?}");
10316        };
10317        assert_eq!(autor, " pleme-io");
10318        assert!(reason.contains("whitespace"), "got: {reason}");
10319    }
10320
10321    #[test]
10322    fn validate_autores_rejects_trailing_whitespace_entry() {
10323        // Canonical paste-from-doc footgun.
10324        let c = caixa_with_autores(vec!["pleme-io "]);
10325        let err = c.validate_autores().unwrap_err();
10326        let ManifestError::AutorInvalid { autor, reason } = err else {
10327            panic!("expected AutorInvalid, got {err:?}");
10328        };
10329        assert_eq!(autor, "pleme-io ");
10330        assert!(reason.contains("whitespace"), "got: {reason}");
10331    }
10332
10333    #[test]
10334    fn validate_autores_rejects_embedded_newline_entry() {
10335        // Canonical paste-from-multiline-doc footgun — the author
10336        // pasted a multi-line block of author records into one
10337        // `:autores` entry instead of splitting into one entry per
10338        // author. Without the shape gate `"alice\nbob"` silently
10339        // passed validate and landed as a YAML-illegal multi-line
10340        // scalar in the rendered Chart.yaml `maintainers:` array.
10341        let c = caixa_with_autores(vec!["alice\nbob"]);
10342        let err = c.validate_autores().unwrap_err();
10343        let ManifestError::AutorInvalid { autor, reason } = err else {
10344            panic!("expected AutorInvalid, got {err:?}");
10345        };
10346        assert_eq!(autor, "alice\nbob");
10347        assert!(reason.contains("newline"), "got: {reason}");
10348    }
10349
10350    #[test]
10351    fn validate_autores_rejects_embedded_carriage_return_entry() {
10352        // Canonical paste-from-Windows-CRLF-doc footgun.
10353        let c = caixa_with_autores(vec!["alice\rbob"]);
10354        let err = c.validate_autores().unwrap_err();
10355        let ManifestError::AutorInvalid { autor, reason } = err else {
10356            panic!("expected AutorInvalid, got {err:?}");
10357        };
10358        assert_eq!(autor, "alice\rbob");
10359        assert!(reason.contains("carriage return"), "got: {reason}");
10360    }
10361
10362    #[test]
10363    fn validate_autores_rejects_embedded_tab_entry() {
10364        // Canonical tab-from-aligned-doc footgun.
10365        let c = caixa_with_autores(vec!["Pleme\tContributors"]);
10366        let err = c.validate_autores().unwrap_err();
10367        let ManifestError::AutorInvalid { autor, reason } = err else {
10368            panic!("expected AutorInvalid, got {err:?}");
10369        };
10370        assert_eq!(autor, "Pleme\tContributors");
10371        assert!(reason.contains("tab"), "got: {reason}");
10372    }
10373
10374    #[test]
10375    fn validate_autores_rejects_embedded_control_bytes_entry() {
10376        // Paste-from-binary-blob footguns: NUL, BEL, ESC, DEL all
10377        // surface the same control-byte arm.
10378        for entry in [
10379            "alice\x00bob",
10380            "alice\x07bob",
10381            "alice\x1bbob",
10382            "alice\x7fbob",
10383        ] {
10384            let c = caixa_with_autores(vec![entry]);
10385            let err = c.validate_autores().unwrap_err();
10386            let ManifestError::AutorInvalid { autor, reason } = err else {
10387                panic!("expected AutorInvalid for {entry:?}, got {err:?}");
10388            };
10389            assert_eq!(autor, entry);
10390            assert!(
10391                reason.contains("control character"),
10392                "{entry:?} reason: {reason}",
10393            );
10394        }
10395    }
10396
10397    #[test]
10398    fn validate_autores_accepts_unicode_entry() {
10399        // Unicode positive control: realistic maintainer names carry
10400        // Unicode (`François`, `日本語`, `naïve`). The predicate must
10401        // round-trip Unicode losslessly, peer with the
10402        // `chart_maintainer_name_shape_accepts_unicode` substrate-side
10403        // sweep.
10404        let c = caixa_with_autores(vec![
10405            "François Dupont",
10406            "日本語の名前",
10407            "naïve <naive@example.com>",
10408        ]);
10409        c.validate_autores().unwrap();
10410    }
10411
10412    #[test]
10413    fn validate_autores_empty_takes_precedence_over_shape() {
10414        // Per-entry empty-first cascade pin: an entry that is both
10415        // empty *and* shape-invalid surfaces `AutorEmpty` (the narrower
10416        // "this entry has no value" structural defect dominates the
10417        // broader shape-predicate diagnostic). The empty arm fires
10418        // before the shape predicate is consulted, mirroring the peer
10419        // `validate_repositorio_empty_takes_precedence_over_shape`
10420        // cascade on the universal `Option<String>` siblings — and now
10421        // established on the Vec<String> per-entry surface.
10422        let c = caixa_with_autores(vec![""]);
10423        let err = c.validate_autores().unwrap_err();
10424        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
10425    }
10426
10427    #[test]
10428    fn validate_autores_shape_takes_precedence_over_duplicate() {
10429        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
10430        // entry that is malformed surfaces `AutorInvalid` even when a
10431        // later entry would have collided on duplicate. The per-entry
10432        // shape arm fires inside the same loop iteration as the empty
10433        // arm, before the seen-set insert at end-of-iteration —
10434        // structural per-entry defects dominate the cross-entry
10435        // uniqueness diagnostic.
10436        let c = caixa_with_autores(vec!["alice\nbob", "alice\nbob"]);
10437        let err = c.validate_autores().unwrap_err();
10438        assert!(
10439            matches!(err, ManifestError::AutorInvalid { .. }),
10440            "got {err:?}",
10441        );
10442    }
10443
10444    #[test]
10445    fn validate_autores_invalid_diagnostic_names_offending_slot_and_value() {
10446        // Diagnostic-shape pin on the new shape arm (peer with
10447        // `validate_descricao_invalid_diagnostic_carries_offending_value`):
10448        // the rendered Display surfaces both the offending slot name
10449        // and the offending value verbatim, so a `feira lint` run
10450        // points the author at the exact `:autores` entry to fix.
10451        let c = caixa_with_autores(vec!["alice\nbob"]);
10452        let rendered = c.validate_autores().unwrap_err().to_string();
10453        assert!(
10454            rendered.contains(":autores"),
10455            "diagnostic must name the offending slot: {rendered}",
10456        );
10457        assert!(
10458            rendered.contains("alice\\nbob"),
10459            "diagnostic must quote the offending value (debug-escaped): {rendered}",
10460        );
10461    }
10462
10463    #[test]
10464    fn validate_autores_rejects_at_129_byte_boundary() {
10465        // The 128-byte cap pin — boundary-exceeding case rejected,
10466        // boundary-accepting case passes. Mirrors the peer
10467        // `chart_maintainer_name_shape_rejects_at_129_byte_boundary`
10468        // substrate-side pin, surfaced at the per-axis caller so the
10469        // cap propagates through validate end-to-end. Constructed as
10470        // a single all-`a` token so only the cap arm fires.
10471        let max_ok = "a".repeat(128);
10472        let c = caixa_with_autores(vec![max_ok.as_str()]);
10473        c.validate_autores().unwrap();
10474        let too_long = "a".repeat(129);
10475        let c = caixa_with_autores(vec![too_long.as_str()]);
10476        let err = c.validate_autores().unwrap_err();
10477        let ManifestError::AutorInvalid { reason, .. } = err else {
10478            panic!("expected AutorInvalid, got {err:?}");
10479        };
10480        assert!(reason.contains("128"), "got: {reason}");
10481        assert!(reason.contains("129"), "got: {reason}");
10482    }
10483
10484    // ── validate_repositorio — universal-axis git-repo-URL shape ──────
10485
10486    fn caixa_with_repositorio(repositorio: Option<&str>) -> Caixa {
10487        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10488        c.repositorio = repositorio.map(String::from);
10489        c
10490    }
10491
10492    #[test]
10493    fn validate_repositorio_accepts_none() {
10494        // The omit-the-slot identity: `:repositorio` is optional. The
10495        // gate is a no-op when the author didn't declare a value —
10496        // every caixa without a `:repositorio` line trivially passes,
10497        // and the substrate-side renderers fall back to their
10498        // documented placeholder (`caixa-helm`'s `home: None`,
10499        // `caixa-flux`'s `https://github.com/pleme-io/<nome>` derived
10500        // URL). Mirrors the peer `validate_restart_window_accepts_none`
10501        // posture on the other `Option<String>` Caixa slot.
10502        let c = caixa_with_repositorio(None);
10503        c.validate_repositorio().unwrap();
10504    }
10505
10506    #[test]
10507    fn validate_repositorio_accepts_canonical_forms() {
10508        // Positive control sweep across every documented `:repositorio`
10509        // authoring shape — the same union the shared
10510        // `crate::render::is_git_repo_url` predicate accepts and the
10511        // peer `:deps :fonte :repo` axis already routes through.
10512        // Covers the `github:` shorthand (the canonical pleme-io
10513        // convention used in the `:repositorio` field of every
10514        // manifest fixture across `caixa-helm` / `caixa-mesh` and the
10515        // `examples/`), the `https://…` URL the README quickstart uses,
10516        // the `ssh://`, `git://`, `git@host:path` scp-style SSH, and
10517        // `file://` URL schemes the shared predicate documents.
10518        for repo in [
10519            "github:pleme-io/hello-rio",
10520            "github:pleme-io/checkout",
10521            "https://github.com/pleme-io/hello-rio",
10522            "ssh://git@github.com/pleme-io/hello-rio.git",
10523            "git://github.com/pleme-io/hello-rio.git",
10524            "git@github.com:pleme-io/hello-rio.git",
10525            "file:///srv/pleme/hello-rio",
10526        ] {
10527            let c = caixa_with_repositorio(Some(repo));
10528            c.validate_repositorio()
10529                .unwrap_or_else(|err| panic!("canonical {repo:?} must pass: {err:?}"));
10530        }
10531    }
10532
10533    #[test]
10534    fn validate_repositorio_rejects_empty_some() {
10535        // Canonical paste-from-blank-doc footgun. The narrower
10536        // [`ManifestError::RepositorioEmpty`] arm fires before the
10537        // shape predicate is consulted, mirroring the empty-first
10538        // cascade every peer per-axis identity gate uses
10539        // (`NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
10540        // `FonteRepoEmpty` → `FonteRepoInvalid`). Without this gate
10541        // the empty `Some("")` silently passed the renderer's
10542        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
10543        // on `None`) and landed as `home: ""` in `Chart.yaml` /
10544        // `url: ""` in the FluxCD `GitRepository`.
10545        let c = caixa_with_repositorio(Some(""));
10546        let err = c.validate_repositorio().unwrap_err();
10547        assert!(
10548            matches!(err, ManifestError::RepositorioEmpty),
10549            "got {err:?}",
10550        );
10551    }
10552
10553    #[test]
10554    fn validate_repositorio_rejects_whitespace() {
10555        // Paste-from-doc whitespace footgun. The shared
10556        // `is_git_repo_url` predicate refuses any whitespace byte; a
10557        // trailing space in a `:repositorio` value silently broke
10558        // `git clone '<value> '` at clone time. The diagnostic names
10559        // the offending value verbatim.
10560        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio "));
10561        let err = c.validate_repositorio().unwrap_err();
10562        let ManifestError::RepositorioInvalid { repositorio, .. } = err else {
10563            panic!("expected RepositorioInvalid, got {err:?}");
10564        };
10565        assert_eq!(repositorio, "github:pleme-io/hello-rio ");
10566    }
10567
10568    #[test]
10569    fn validate_repositorio_rejects_control_char() {
10570        // Paste-from-multiline-doc CRLF footgun — control characters
10571        // at the URL boundary are a class of subprocess-arg injection
10572        // and break git's URL parser at every porcelain entry point.
10573        let c = caixa_with_repositorio(Some("https://example.com/repo\n"));
10574        let err = c.validate_repositorio().unwrap_err();
10575        assert!(
10576            matches!(err, ManifestError::RepositorioInvalid { .. }),
10577            "got {err:?}",
10578        );
10579    }
10580
10581    #[test]
10582    fn validate_repositorio_rejects_leading_dash() {
10583        // Canonical CLI-argument-injection footgun: `git clone <repo>`
10584        // interprets a leading `-` as a CLI flag, so a
10585        // `-upload-pack=…` value escapes the subprocess argument
10586        // boundary. The shared predicate refuses every leading-`-`
10587        // shape at validate time.
10588        let c = caixa_with_repositorio(Some("-upload-pack=evil"));
10589        let err = c.validate_repositorio().unwrap_err();
10590        assert!(
10591            matches!(err, ManifestError::RepositorioInvalid { .. }),
10592            "got {err:?}",
10593        );
10594    }
10595
10596    #[test]
10597    fn validate_repositorio_rejects_missing_colon_separator() {
10598        // The bare `org/repo` ambiguity footgun — `git clone` reads
10599        // a no-`:` form as a relative filesystem path rather than the
10600        // GitHub-shorthand expansion the author probably intended.
10601        // The shared predicate refuses every shape without a `:`
10602        // separator.
10603        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
10604        let err = c.validate_repositorio().unwrap_err();
10605        assert!(
10606            matches!(err, ManifestError::RepositorioInvalid { .. }),
10607            "got {err:?}",
10608        );
10609    }
10610
10611    #[test]
10612    fn validate_repositorio_rejects_fragment_anchor() {
10613        // Paste-from-browser-address-bar footgun on the
10614        // `:repositorio` axis — an author copies a GitHub permalink
10615        // to a README section / line-permalink and forgets to trim
10616        // the `#fragment` tail. The shared `is_git_repo_url`
10617        // predicate refuses the byte at the URL-grammar layer
10618        // (libcurl strips the fragment before opening the
10619        // transport, so the byte rides verbatim into the rendered
10620        // `Chart.yaml` `home:` and FluxCD `GitRepository` `url:`
10621        // fields but is silently dropped on the wire — two
10622        // manifest variants whose values differ only in their
10623        // fragment anchor lock to two distinct rendered artifacts
10624        // for the byte-identical clone, defeating the THEORY.md
10625        // §V.2 render-determinism contract on the `:repositorio`
10626        // axis the peer `:fonte :repo` axis already closes).
10627        let c = caixa_with_repositorio(Some("https://github.com/pleme-io/hello-rio#readme"));
10628        let err = c.validate_repositorio().unwrap_err();
10629        let ManifestError::RepositorioInvalid {
10630            repositorio,
10631            reason,
10632        } = err
10633        else {
10634            panic!("expected RepositorioInvalid, got {err:?}");
10635        };
10636        assert_eq!(repositorio, "https://github.com/pleme-io/hello-rio#readme");
10637        assert!(
10638            reason.contains("must not contain `#`"),
10639            "reason must surface the fragment-`#` arm, got {reason:?}"
10640        );
10641    }
10642
10643    #[test]
10644    fn validate_repositorio_rejects_query_string() {
10645        // Paste-from-browser-address-bar footgun on the
10646        // `:repositorio` axis (peer with the a68f818 fragment-`#`
10647        // arm on the same axis). An author copies a GitHub tab
10648        // deep-link out of the address bar and forgets to trim
10649        // the `?tab=…` query tail. The shared `is_git_repo_url`
10650        // predicate refuses the byte at the URL-grammar layer
10651        // (GitHub / GitLab / Bitbucket silently ignore the
10652        // `?query` tail and serve the same repo regardless, so
10653        // the byte rides verbatim into the rendered `Chart.yaml`
10654        // `home:` and FluxCD `GitRepository` `url:` fields but
10655        // is silently masked at the wire — two manifest variants
10656        // whose values differ only in their query tail lock to
10657        // two distinct rendered artifacts for the byte-identical
10658        // clone, defeating the THEORY.md §V.2 render-determinism
10659        // contract on the `:repositorio` axis the peer `:fonte
10660        // :repo` axis already closes).
10661        let c = caixa_with_repositorio(Some(
10662            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file",
10663        ));
10664        let err = c.validate_repositorio().unwrap_err();
10665        let ManifestError::RepositorioInvalid {
10666            repositorio,
10667            reason,
10668        } = err
10669        else {
10670            panic!("expected RepositorioInvalid, got {err:?}");
10671        };
10672        assert_eq!(
10673            repositorio,
10674            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file"
10675        );
10676        assert!(
10677            reason.contains("must not contain `?`"),
10678            "reason must surface the query-`?` arm, got {reason:?}"
10679        );
10680    }
10681
10682    #[test]
10683    fn validate_repositorio_rejects_embedded_backslash() {
10684        // Windows-file-path-confusion footgun on the `:repositorio`
10685        // axis (peer with the prior fragment-`#` / query-`?` arms on
10686        // the same axis, and peer with the new dep-level `:fonte :repo`
10687        // backslash arm on the URL-grammar trajectory). An author
10688        // pastes a Windows Explorer address-bar `file:///C:\Users\me\
10689        // hello-rio` into the `:repositorio` slot, expecting the
10690        // `lareira-<nome>` chart's `home:` field and the FluxCD
10691        // `GitRepository` `url:` field to render the canonical local
10692        // file-URI. The shared `is_git_repo_url` predicate refuses
10693        // the byte at the URL-grammar layer (libcurl silently
10694        // translates `\` → `/` on some platforms and refuses it on
10695        // others, so the byte rides verbatim into the rendered
10696        // artifacts but is silently rewritten or rejected at the wire
10697        // — two manifest variants whose values differ only in
10698        // backslash-vs-forward-slash lock to two distinct rendered
10699        // artifacts for the byte-identical clone, defeating the
10700        // THEORY.md §V.2 render-determinism contract on the
10701        // `:repositorio` axis the peer `:fonte :repo` axis already
10702        // closes).
10703        let c = caixa_with_repositorio(Some("file:///C:\\Users\\me\\hello-rio"));
10704        let err = c.validate_repositorio().unwrap_err();
10705        let ManifestError::RepositorioInvalid {
10706            repositorio,
10707            reason,
10708        } = err
10709        else {
10710            panic!("expected RepositorioInvalid, got {err:?}");
10711        };
10712        assert_eq!(repositorio, "file:///C:\\Users\\me\\hello-rio");
10713        assert!(
10714            reason.contains("must not contain `\\`"),
10715            "reason must surface the backslash-`\\` arm, got {reason:?}"
10716        );
10717    }
10718
10719    #[test]
10720    fn validate_repositorio_rejects_uri_template_placeholder() {
10721        // URI Template (RFC 6570) placeholder footgun on the
10722        // `:repositorio` axis (peer with the prior fragment-`#` /
10723        // query-`?` / backslash-`\` arms on the same axis, and peer
10724        // with the new dep-level `:fonte :repo` `{` / `}` arm on the
10725        // URL-grammar trajectory). An author pastes a quick-start
10726        // README snippet / OpenAPI `servers:` URL / Helm chart
10727        // `home:` template carrying unresolved `{org}` / `{repo}`
10728        // placeholders into the `:repositorio` slot, expecting the
10729        // substrate to resolve the placeholder downstream. The
10730        // shared `is_git_repo_url` predicate refuses the byte at the
10731        // URL-grammar layer (libcurl percent-encodes `{` / `}` to
10732        // `%7B` / `%7D` on the wire, so the byte round-trips
10733        // inconsistently between the rendered `Chart.yaml home:` /
10734        // FluxCD `GitRepository url:` and the resolver's `git clone`
10735        // invocation, defeating the THEORY.md §V.2 render-
10736        // determinism contract on the `:repositorio` axis the peer
10737        // `:fonte :repo` axis already closes; every git porcelain
10738        // entry-point additionally fetches a nonexistent literal-
10739        // `{placeholder}`-named path far from the source caixa.lisp).
10740        let c = caixa_with_repositorio(Some("https://github.com/{org}/hello-rio"));
10741        let err = c.validate_repositorio().unwrap_err();
10742        let ManifestError::RepositorioInvalid {
10743            repositorio,
10744            reason,
10745        } = err
10746        else {
10747            panic!("expected RepositorioInvalid, got {err:?}");
10748        };
10749        assert_eq!(repositorio, "https://github.com/{org}/hello-rio");
10750        assert!(
10751            reason.contains("must not contain `{`"),
10752            "reason must surface the open-brace `{{` arm, got {reason:?}"
10753        );
10754        assert!(
10755            reason.contains("URI Template") || reason.contains("RFC 6570"),
10756            "reason must name the RFC 6570 URI Template grammar, got {reason:?}"
10757        );
10758    }
10759
10760    #[test]
10761    fn validate_repositorio_empty_takes_precedence_over_shape() {
10762        // Empty-first cascade pin: the empty `Some("")` surfaces the
10763        // narrower `RepositorioEmpty` not the shape-predicate-wrapped
10764        // `RepositorioInvalid`, mirroring the peer
10765        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
10766        // `FonteRepoEmpty` → `FonteRepoInvalid` cascades. The shared
10767        // `is_git_repo_url` predicate also rejects the empty input
10768        // (defensively, with its own `"must not be empty"` reason),
10769        // but the manifest-layer empty arm runs first to surface the
10770        // narrower diagnostic verbatim.
10771        let c = caixa_with_repositorio(Some(""));
10772        let err = c.validate_repositorio().unwrap_err();
10773        assert!(
10774            matches!(err, ManifestError::RepositorioEmpty),
10775            "got {err:?}",
10776        );
10777    }
10778
10779    #[test]
10780    fn validate_repositorio_diagnostic_carries_offending_value() {
10781        // Diagnostic-shape pin (peer with
10782        // `validate_autores_diagnostic_carries_offending_author`): the
10783        // error's Display surfaces the offending value + slot name
10784        // verbatim, so a `feira lint` run can render the diagnostic
10785        // without re-parsing and the author can grep their caixa.lisp
10786        // for the offending `:repositorio` value.
10787        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
10788        let rendered = c.validate_repositorio().unwrap_err().to_string();
10789        assert!(
10790            rendered.contains(":repositorio"),
10791            "diagnostic must name the offending slot: {rendered}",
10792        );
10793        assert!(
10794            rendered.contains("pleme-io/hello-rio"),
10795            "diagnostic must quote the offending value: {rendered}",
10796        );
10797    }
10798
10799    // ── validate_descricao — universal-axis Chart.yaml description shape ──
10800
10801    fn caixa_with_descricao(descricao: Option<&str>) -> Caixa {
10802        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10803        c.descricao = descricao.map(String::from);
10804        c
10805    }
10806
10807    #[test]
10808    fn validate_descricao_accepts_none() {
10809        // The omit-the-slot identity: `:descricao` is optional. The
10810        // gate is a no-op when the author didn't declare a value —
10811        // every caixa without a `:descricao` line trivially passes,
10812        // and the substrate-side renderers fall back to their
10813        // documented `caixa.nome`-derived placeholder. Mirrors the
10814        // peer `validate_repositorio_accepts_none` posture on the
10815        // sibling `Option<String>` Caixa slot.
10816        let c = caixa_with_descricao(None);
10817        c.validate_descricao().unwrap();
10818    }
10819
10820    #[test]
10821    fn validate_descricao_accepts_canonical_summary() {
10822        // Positive control: the canonical pleme-io descricao shape —
10823        // a short free-form prose summary — passes the gate. Covers
10824        // the fixture shapes the `caixa-helm` / `caixa-flux` /
10825        // `caixa-mesh` test fixtures use (`"Canonical Rust→wasm32-
10826        // wasip2 caixa Servico."`, `"Checkout flow."`).
10827        for desc in [
10828            "Canonical Rust→wasm32-wasip2 caixa Servico.",
10829            "Checkout flow.",
10830            "AWS provider caixa for tatara-lisp",
10831            "FIXME — describe this caixa",
10832            "x",
10833        ] {
10834            let c = caixa_with_descricao(Some(desc));
10835            c.validate_descricao()
10836                .unwrap_or_else(|err| panic!("canonical {desc:?} must pass: {err:?}"));
10837        }
10838    }
10839
10840    #[test]
10841    fn validate_descricao_rejects_empty_some() {
10842        // Canonical paste-from-blank-doc footgun. Without this gate
10843        // the empty `Some("")` silently passed the renderer's
10844        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
10845        // on `None`) and landed as `description: ""` in `Chart.yaml`
10846        // and a blank `README.md` header. Mirrors the peer
10847        // [`ManifestError::RepositorioEmpty`] empty-arm on the
10848        // sibling `Option<String>` Caixa slot.
10849        let c = caixa_with_descricao(Some(""));
10850        let err = c.validate_descricao().unwrap_err();
10851        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
10852    }
10853
10854    #[test]
10855    fn validate_descricao_rejects_leading_whitespace() {
10856        // Paste-from-aligned-doc footgun: a leading ASCII space the
10857        // bare empty-arm gate accepted, the shape predicate now
10858        // refuses. The diagnostic carries the offending value
10859        // verbatim (with the leading space preserved) so the author
10860        // can grep their caixa.lisp for the exact `:descricao` line
10861        // and fix the round-trip-inconsistent leading whitespace.
10862        // Mirrors the peer
10863        // `validate_licenca_rejects_leading_whitespace` arm on the
10864        // sibling `:licenca` axis.
10865        let c = caixa_with_descricao(Some(" Checkout flow."));
10866        let err = c.validate_descricao().unwrap_err();
10867        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
10868            panic!("expected DescricaoInvalid, got {err:?}");
10869        };
10870        assert_eq!(descricao, " Checkout flow.");
10871        assert!(reason.contains("whitespace"), "got: {reason:?}");
10872    }
10873
10874    #[test]
10875    fn validate_descricao_rejects_trailing_whitespace() {
10876        // Paste-from-doc footgun: a trailing ASCII space the bare
10877        // empty-arm gate accepted, the shape predicate now refuses.
10878        let c = caixa_with_descricao(Some("Checkout flow. "));
10879        let err = c.validate_descricao().unwrap_err();
10880        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
10881            panic!("expected DescricaoInvalid, got {err:?}");
10882        };
10883        assert_eq!(descricao, "Checkout flow. ");
10884        assert!(reason.contains("whitespace"), "got: {reason:?}");
10885    }
10886
10887    #[test]
10888    fn validate_descricao_rejects_embedded_newline() {
10889        // Paste-from-multiline-doc footgun: an embedded LF the bare
10890        // empty-arm gate accepted, the shape predicate now refuses.
10891        // Without this gate the embedded newline silently landed in
10892        // the rendered Chart.yaml as a multi-line YAML block scalar,
10893        // and every chart-aware UI (`helm list`, `helm search`,
10894        // Artifact Hub) renders the description in a single-line
10895        // column so the embedded newline is silently dropped at
10896        // every downstream consumer.
10897        let c = caixa_with_descricao(Some("Checkout\nflow."));
10898        let err = c.validate_descricao().unwrap_err();
10899        assert!(
10900            matches!(err, ManifestError::DescricaoInvalid { .. }),
10901            "got {err:?}",
10902        );
10903        assert!(err.to_string().contains("newline"), "got {err}");
10904    }
10905
10906    #[test]
10907    fn validate_descricao_rejects_embedded_carriage_return() {
10908        // Paste-from-Windows-CRLF-doc footgun.
10909        let c = caixa_with_descricao(Some("Checkout\rflow."));
10910        let err = c.validate_descricao().unwrap_err();
10911        assert!(
10912            matches!(err, ManifestError::DescricaoInvalid { .. }),
10913            "got {err:?}",
10914        );
10915        assert!(err.to_string().contains("carriage return"), "got {err}");
10916    }
10917
10918    #[test]
10919    fn validate_descricao_rejects_embedded_tab() {
10920        // Tab-from-aligned-doc footgun.
10921        let c = caixa_with_descricao(Some("Checkout\tflow."));
10922        let err = c.validate_descricao().unwrap_err();
10923        assert!(
10924            matches!(err, ManifestError::DescricaoInvalid { .. }),
10925            "got {err:?}",
10926        );
10927        assert!(err.to_string().contains("tab"), "got {err}");
10928    }
10929
10930    #[test]
10931    fn validate_descricao_rejects_embedded_control_bytes() {
10932        // Paste-from-binary-blob footgun: every other control byte
10933        // (NUL, BEL, ESC, DEL) is refused at validate time. Mirrors
10934        // the peer SPDX-expression control-byte arm.
10935        for s in [
10936            "Checkout\x00flow.",
10937            "Checkout\x07flow.",
10938            "Checkout\x1bflow.",
10939            "Checkout\x7fflow.",
10940        ] {
10941            let c = caixa_with_descricao(Some(s));
10942            let err = c.validate_descricao().unwrap_err();
10943            assert!(
10944                matches!(err, ManifestError::DescricaoInvalid { .. }),
10945                "{s:?} got {err:?}",
10946            );
10947            assert!(
10948                err.to_string().contains("control character"),
10949                "{s:?} got {err}",
10950            );
10951        }
10952    }
10953
10954    #[test]
10955    fn validate_descricao_accepts_unicode_prose() {
10956        // Positive control: Unicode prose is accepted — the
10957        // canonical fixtures carry `→` (U+2192) and `—` (U+2014),
10958        // and `Caixa::template`'s `"FIXME — describe this caixa"`
10959        // scaffold every `feira init` emits must continue to pass.
10960        for s in [
10961            "Canonical Rust→wasm32-wasip2 caixa Servico.",
10962            "FIXME — describe this caixa",
10963            "Caixa pour le projet tâche",
10964            "日本語の説明",
10965        ] {
10966            let c = caixa_with_descricao(Some(s));
10967            c.validate_descricao()
10968                .unwrap_or_else(|err| panic!("Unicode {s:?} must pass: {err:?}"));
10969        }
10970    }
10971
10972    #[test]
10973    fn validate_descricao_empty_takes_precedence_over_shape() {
10974        // Cascade pin: a `Some("")` surfaces the narrower
10975        // `DescricaoEmpty` arm, not the broader `DescricaoInvalid`
10976        // shape-predicate arm. Mirrors the peer
10977        // `validate_licenca_empty_takes_precedence_over_shape` pin
10978        // on the sibling `:licenca` axis.
10979        let c = caixa_with_descricao(Some(""));
10980        let err = c.validate_descricao().unwrap_err();
10981        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
10982    }
10983
10984    #[test]
10985    fn validate_descricao_invalid_diagnostic_carries_offending_value_and_slot() {
10986        // Diagnostic-shape pin: the error's Display surfaces both
10987        // the `:descricao` slot name and the offending value
10988        // verbatim, so a `feira lint` run can render the diagnostic
10989        // without re-parsing and the author can grep their caixa.lisp
10990        // for the offending `:descricao` line. Mirrors the peer
10991        // `validate_licenca_invalid_diagnostic_carries_offending_value_and_slot`
10992        // pin (ee2e888) on the sibling `:licenca` axis.
10993        // The `{descricao:?}` Debug format escapes embedded control
10994        // bytes; the quoted offending value surfaces as
10995        // `"Checkout\nflow."` (literal backslash-n) in the rendered
10996        // diagnostic. The author can grep their caixa.lisp for the
10997        // literal `Checkout` summary prefix.
10998        let c = caixa_with_descricao(Some("Checkout\nflow."));
10999        let rendered = c.validate_descricao().unwrap_err().to_string();
11000        assert!(
11001            rendered.contains(":descricao"),
11002            "diagnostic must name the offending slot: {rendered}",
11003        );
11004        assert!(
11005            rendered.contains("Checkout\\nflow."),
11006            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11007        );
11008    }
11009
11010    #[test]
11011    fn validate_descricao_template_passes() {
11012        // Round-trip pin: the bare `Caixa::template` shape carries
11013        // `:descricao "FIXME — describe this caixa"` (a non-empty
11014        // sentinel), so the template-derived Caixa passes the gate by
11015        // construction. A future template-shape change that omits or
11016        // empties `:descricao` would surface here as a regression.
11017        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11018        c.validate_descricao().unwrap();
11019    }
11020
11021    #[test]
11022    fn validate_descricao_diagnostic_names_offending_slot() {
11023        // Diagnostic-shape pin (peer with
11024        // `validate_repositorio_diagnostic_carries_offending_value`):
11025        // the error's Display surfaces the `:descricao` slot name
11026        // verbatim, so a `feira lint` run can render the diagnostic
11027        // without re-parsing and the author can grep their caixa.lisp
11028        // for the offending `:descricao` line.
11029        let c = caixa_with_descricao(Some(""));
11030        let rendered = c.validate_descricao().unwrap_err().to_string();
11031        assert!(
11032            rendered.contains(":descricao"),
11033            "diagnostic must name the offending slot: {rendered}",
11034        );
11035    }
11036
11037    // ── validate_licenca — universal-axis chart README license shape ──
11038
11039    fn caixa_with_licenca(licenca: Option<&str>) -> Caixa {
11040        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11041        c.licenca = licenca.map(String::from);
11042        c
11043    }
11044
11045    #[test]
11046    fn validate_licenca_accepts_none() {
11047        // The omit-the-slot identity: `:licenca` is optional. The
11048        // gate is a no-op when the author didn't declare a value —
11049        // every caixa without a `:licenca` line trivially passes,
11050        // and the substrate-side `caixa-helm` renderer falls back to
11051        // the documented `"MIT"` placeholder. Mirrors the peer
11052        // `validate_descricao_accepts_none` posture on the sibling
11053        // `Option<String>` Caixa slot.
11054        let c = caixa_with_licenca(None);
11055        c.validate_licenca().unwrap();
11056    }
11057
11058    #[test]
11059    fn validate_licenca_accepts_canonical_expressions() {
11060        // Positive control: every canonical SPDX expression shape
11061        // pleme-io carries in its existing fixtures + the canonical
11062        // SPDX dual-license / with-exception / `+`-suffix / grouped /
11063        // user-defined-reference shapes all pass the gate. Covers
11064        // the single-license, `OR`-compound, `AND`-compound,
11065        // `WITH`-exception, parenthesis-grouped, `+`-suffix, and
11066        // `LicenseRef-` / `DocumentRef-:LicenseRef-` shapes — every
11067        // production the SPDX 2.1 expression grammar admits that
11068        // sits within the alphabet floor the
11069        // `is_spdx_expression_shape` predicate enforces.
11070        for lic in [
11071            "MIT",
11072            "Apache-2.0",
11073            "Apache-2.0 OR MIT",
11074            "Apache-2.0 AND MIT",
11075            "BSD-3-Clause",
11076            "MPL-2.0",
11077            "GPL-3.0-or-later",
11078            "GPL-2.0+",
11079            "Apache-2.0 WITH LLVM-exception",
11080            "(MIT OR Apache-2.0) AND BSD-3-Clause",
11081            "(MIT OR Apache-2.0) AND BSD-3-Clause AND ISC",
11082            "LicenseRef-MyLicense",
11083            "DocumentRef-spdx-tool:LicenseRef-MIT-Style",
11084            "x",
11085        ] {
11086            let c = caixa_with_licenca(Some(lic));
11087            c.validate_licenca()
11088                .unwrap_or_else(|err| panic!("canonical {lic:?} must pass: {err:?}"));
11089        }
11090    }
11091
11092    #[test]
11093    fn validate_licenca_rejects_trailing_whitespace() {
11094        // Paste-from-doc whitespace footgun. A trailing space in the
11095        // `:licenca` value would silently break a downstream SPDX
11096        // parser that splits on exact `AND` / `OR` / `WITH` keyword
11097        // boundaries. The shape predicate refuses every trailing
11098        // whitespace byte by construction. Peer with
11099        // `validate_repositorio_rejects_whitespace` and
11100        // `validate_edicao_rejects_trailing_whitespace`.
11101        let c = caixa_with_licenca(Some("MIT "));
11102        let err = c.validate_licenca().unwrap_err();
11103        let ManifestError::LicencaInvalid { licenca, .. } = err else {
11104            panic!("expected LicencaInvalid, got {err:?}");
11105        };
11106        assert_eq!(licenca, "MIT ");
11107    }
11108
11109    #[test]
11110    fn validate_licenca_rejects_leading_whitespace() {
11111        // Symmetric paste-from-doc whitespace footgun on the leading
11112        // boundary — the gate refuses every shape that starts with a
11113        // space byte by construction. Peer with
11114        // `validate_edicao_rejects_leading_whitespace`.
11115        let c = caixa_with_licenca(Some(" MIT"));
11116        let err = c.validate_licenca().unwrap_err();
11117        assert!(
11118            matches!(err, ManifestError::LicencaInvalid { .. }),
11119            "got {err:?}",
11120        );
11121    }
11122
11123    #[test]
11124    fn validate_licenca_rejects_control_char() {
11125        // Paste-from-multiline-doc CRLF footgun — control characters
11126        // at the value boundary land as a malformed line in the
11127        // rendered chart `README.md` `## License` section. Peer with
11128        // `validate_repositorio_rejects_control_char` and
11129        // `validate_edicao_rejects_control_char`.
11130        for lic in ["MIT\n", "MIT\r\n", "MIT\rApache-2.0"] {
11131            let c = caixa_with_licenca(Some(lic));
11132            let err = c.validate_licenca().unwrap_err();
11133            assert!(
11134                matches!(err, ManifestError::LicencaInvalid { .. }),
11135                "expected LicencaInvalid on {lic:?}, got {err:?}",
11136            );
11137        }
11138    }
11139
11140    #[test]
11141    fn validate_licenca_rejects_tab() {
11142        // Tab-from-aligned-doc footgun — SPDX expressions use a
11143        // single ASCII space between tokens; a tab breaks every
11144        // downstream SPDX parser that splits on exact `" "`
11145        // boundaries.
11146        let c = caixa_with_licenca(Some("MIT\tOR Apache-2.0"));
11147        let err = c.validate_licenca().unwrap_err();
11148        assert!(
11149            matches!(err, ManifestError::LicencaInvalid { .. }),
11150            "got {err:?}",
11151        );
11152    }
11153
11154    #[test]
11155    fn validate_licenca_rejects_non_ascii() {
11156        // Smart-quote / non-ASCII paste footgun — SPDX identifiers
11157        // are ASCII per the `idstring = 1*(ALPHA / DIGIT / "-" /
11158        // ".")` production. The shape predicate refuses every
11159        // non-ASCII byte by construction; peer with
11160        // `validate_edicao_rejects_non_ascii_lookalike`.
11161        for lic in ["MIT\u{a0}OR Apache-2.0", "MIT\u{2013}1.0", "Café-1.0"] {
11162            let c = caixa_with_licenca(Some(lic));
11163            let err = c.validate_licenca().unwrap_err();
11164            assert!(
11165                matches!(err, ManifestError::LicencaInvalid { .. }),
11166                "expected LicencaInvalid on {lic:?}, got {err:?}",
11167            );
11168        }
11169    }
11170
11171    #[test]
11172    fn validate_licenca_rejects_underscore() {
11173        // Underscore-instead-of-hyphen typo footgun — `Apache_2.0` /
11174        // `MIT_Style` / `BSD_3_Clause` are familiar shapes from
11175        // snake-case identifier conventions that don't apply to the
11176        // SPDX `idstring` grammar (which admits only `ALPHA / DIGIT /
11177        // "-" / "."`). The shape predicate refuses every underscore
11178        // byte by construction.
11179        for lic in ["Apache_2.0", "MIT_Style", "BSD_3_Clause"] {
11180            let c = caixa_with_licenca(Some(lic));
11181            let err = c.validate_licenca().unwrap_err();
11182            assert!(
11183                matches!(err, ManifestError::LicencaInvalid { .. }),
11184                "expected LicencaInvalid on {lic:?}, got {err:?}",
11185            );
11186        }
11187    }
11188
11189    #[test]
11190    fn validate_licenca_rejects_comma_separator() {
11191        // Comma-instead-of-`OR`-keyword colloquial idiom footgun —
11192        // SPDX expressions compose multiple licenses via `AND` / `OR`
11193        // keywords, not the comma separator. The shape predicate
11194        // refuses every comma byte by construction.
11195        for lic in ["MIT, Apache-2.0", "MIT,Apache-2.0"] {
11196            let c = caixa_with_licenca(Some(lic));
11197            let err = c.validate_licenca().unwrap_err();
11198            assert!(
11199                matches!(err, ManifestError::LicencaInvalid { .. }),
11200                "expected LicencaInvalid on {lic:?}, got {err:?}",
11201            );
11202        }
11203    }
11204
11205    #[test]
11206    fn validate_licenca_rejects_slash_dual_license() {
11207        // Slash-dual-license colloquial idiom footgun — the
11208        // `MIT/Apache-2.0` shape is common in Cargo's pre-SPDX
11209        // `package.license` field but non-SPDX; the SPDX equivalent
11210        // is `MIT OR Apache-2.0`. The shape predicate refuses every
11211        // forward-slash byte by construction.
11212        for lic in ["MIT/Apache-2.0", "MIT/BSD-3-Clause"] {
11213            let c = caixa_with_licenca(Some(lic));
11214            let err = c.validate_licenca().unwrap_err();
11215            assert!(
11216                matches!(err, ManifestError::LicencaInvalid { .. }),
11217                "expected LicencaInvalid on {lic:?}, got {err:?}",
11218            );
11219        }
11220    }
11221
11222    #[test]
11223    fn validate_licenca_rejects_semicolon_separator() {
11224        // Semicolon-list-separator confusion footgun — adjacent to
11225        // the comma-separator idiom, every list-separator-belongs-
11226        // to-list-grammar confusion lands here.
11227        let c = caixa_with_licenca(Some("MIT; Apache-2.0"));
11228        let err = c.validate_licenca().unwrap_err();
11229        assert!(
11230            matches!(err, ManifestError::LicencaInvalid { .. }),
11231            "got {err:?}",
11232        );
11233    }
11234
11235    #[test]
11236    fn validate_licenca_empty_takes_precedence_over_shape() {
11237        // Empty-first cascade pin: the empty `Some("")` surfaces the
11238        // narrower `LicencaEmpty` not the shape-predicate-wrapped
11239        // `LicencaInvalid`, mirroring the peer
11240        // `validate_edicao_empty_takes_precedence_over_shape` and
11241        // `validate_repositorio_empty_takes_precedence_over_shape`
11242        // (`RepositorioEmpty` → `RepositorioInvalid`), `NomeEmpty` →
11243        // `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid` cascades.
11244        // The shape predicate also refuses the empty input
11245        // (defensively — `"must not be empty"`), but the manifest-
11246        // layer empty arm runs first to surface the narrower
11247        // diagnostic verbatim.
11248        let c = caixa_with_licenca(Some(""));
11249        let err = c.validate_licenca().unwrap_err();
11250        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
11251    }
11252
11253    #[test]
11254    fn validate_licenca_invalid_diagnostic_carries_offending_value() {
11255        // Diagnostic-shape pin on the shape-predicate arm (peer with
11256        // `validate_edicao_invalid_diagnostic_carries_offending_value`
11257        // and `validate_repositorio_diagnostic_carries_offending_value`):
11258        // the error's Display surfaces the offending value + slot
11259        // name verbatim, so a `feira lint` run can render the
11260        // diagnostic without re-parsing and the author can grep
11261        // their caixa.lisp for the offending `:licenca` value.
11262        let c = caixa_with_licenca(Some("Apache_2.0"));
11263        let rendered = c.validate_licenca().unwrap_err().to_string();
11264        assert!(
11265            rendered.contains(":licenca"),
11266            "diagnostic must name the offending slot: {rendered}",
11267        );
11268        assert!(
11269            rendered.contains("Apache_2.0"),
11270            "diagnostic must quote the offending value: {rendered}",
11271        );
11272    }
11273
11274    #[test]
11275    fn validate_licenca_rejects_empty_some() {
11276        // Canonical paste-from-blank-doc footgun. Without this gate
11277        // the empty `Some("")` silently passed the renderer's
11278        // `Option::unwrap_or_else(|| "MIT".into())` (which only
11279        // fires on `None`) and landed as a bare trailing period in
11280        // the rendered chart `README.md` `## License` section.
11281        // Mirrors the peer [`ManifestError::DescricaoEmpty`] empty-
11282        // arm on the sibling `Option<String>` Caixa slot.
11283        let c = caixa_with_licenca(Some(""));
11284        let err = c.validate_licenca().unwrap_err();
11285        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
11286    }
11287
11288    #[test]
11289    fn validate_licenca_template_passes() {
11290        // Round-trip pin: the bare `Caixa::template` shape (whether
11291        // it carries `:licenca` or omits it) passes the gate by
11292        // construction. A future template-shape change that
11293        // introduced `(:licenca "")` would surface here as a
11294        // regression. Mirrors the peer
11295        // `validate_descricao_template_passes` pin.
11296        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11297        c.validate_licenca().unwrap();
11298    }
11299
11300    #[test]
11301    fn validate_licenca_diagnostic_names_offending_slot() {
11302        // Diagnostic-shape pin (peer with
11303        // `validate_descricao_diagnostic_names_offending_slot`):
11304        // the error's Display surfaces the `:licenca` slot name
11305        // verbatim, so a `feira lint` run can render the diagnostic
11306        // without re-parsing and the author can grep their caixa.lisp
11307        // for the offending `:licenca` line.
11308        let c = caixa_with_licenca(Some(""));
11309        let rendered = c.validate_licenca().unwrap_err().to_string();
11310        assert!(
11311            rendered.contains(":licenca"),
11312            "diagnostic must name the offending slot: {rendered}",
11313        );
11314    }
11315
11316    // ── Caixa::licenca — outer top-level Option<&str> scalar accessor ──
11317
11318    #[test]
11319    fn licenca_returns_licenca_byte_string_verbatim_across_permutations() {
11320        // The canonical per-`Caixa` `:licenca` SPDX-expression scalar
11321        // pin: [`Caixa::licenca`] must return the `:licenca` typed
11322        // byte-string verbatim as an `Option<&str>`, byte-equal to the
11323        // raw `self.licenca.as_deref()` access across every
11324        // representative value in the accept-set — `None` (the "omit
11325        // the slot to defer to the caixa-helm renderer's `MIT`
11326        // fallback" arm every existing fixture without a `:licenca`
11327        // line carries), `Some("")` (a past-the-guard sentinel that
11328        // pins the accessor doesn't perform a silent
11329        // `Some("") → None` collapse on the empty arm — validate
11330        // rejects `Some("")` through `LicencaEmpty` but the accessor
11331        // must ship the raw slot verbatim so a validate-time gate
11332        // regression surfaces at the caixa-helm emit boundary rather
11333        // than being silently absorbed into the fallback), `Some("MIT")`
11334        // (the canonical single-license shape every `feira init`
11335        // template scaffolds), `Some("Apache-2.0 OR MIT")` (the
11336        // canonical `OR`-compound shape the peer
11337        // `validate_licenca_accepts_canonical_expressions` positive
11338        // sweep exercises), `Some("(MIT OR Apache-2.0) AND
11339        // BSD-3-Clause")` (the canonical parenthesis-grouped shape),
11340        // `Some("MIT ")` / `Some(" MIT")` / `Some("MIT\n")` /
11341        // `Some("Apache_2.0")` / `Some("MIT,Apache-2.0")` (past-the-
11342        // guard sentinels — validate rejects each through
11343        // `LicencaInvalid` but the accessor must ship the raw slot
11344        // verbatim).
11345        //
11346        // First outer top-level [`Caixa`] `Option<&str>`-return scalar
11347        // accessor pin on the substrate primitive — opens the "outer
11348        // [`Caixa`] `Option<&str>` scalar" projection pattern the
11349        // sibling per-`Caixa` `:descricao` / `:repositorio` / `:edicao`
11350        // future lifts fold on. Sibling in shape to the peer per-`:placement`
11351        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
11352        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
11353        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
11354        // axes, extended onto the outer top-level [`Caixa`] universal-
11355        // axis surface. Pins against a future silent detour that
11356        // returned an owned `Option<String>` (which would type-check
11357        // but silently allocate on every accessor call, breaking the
11358        // zero-cost projection every peer sibling accessor carries), a
11359        // `Some("") → None` collapse (which would silently absorb the
11360        // `LicencaEmpty` refusal case at the accessor boundary and the
11361        // caixa-helm emit path would silently fall back to `"MIT"` on
11362        // a struct-literal `Caixa { licenca: Some(""), .. }`), or a
11363        // `None → Some("MIT")` collapse (which would silently reify
11364        // the caixa-helm renderer's `"MIT"` fallback at the accessor
11365        // boundary and every downstream consumer keying off the
11366        // `Option::is_none()` discriminator would lose the "author
11367        // omitted the slot" signal).
11368        for licenca in [
11369            None,
11370            Some(""),
11371            Some("MIT"),
11372            Some("Apache-2.0 OR MIT"),
11373            Some("(MIT OR Apache-2.0) AND BSD-3-Clause"),
11374            Some("MIT "),
11375            Some(" MIT"),
11376            Some("MIT\n"),
11377            Some("Apache_2.0"),
11378            Some("MIT,Apache-2.0"),
11379        ] {
11380            let c = caixa_with_licenca(licenca);
11381            assert_eq!(
11382                c.licenca(),
11383                licenca,
11384                "Caixa::licenca must return :licenca verbatim (got {:?}, \
11385                 expected {licenca:?})",
11386                c.licenca(),
11387            );
11388            assert_eq!(
11389                c.licenca(),
11390                c.licenca.as_deref(),
11391                "Caixa::licenca must byte-equal the raw \
11392                 `self.licenca.as_deref()` field access across every \
11393                 value in the Option<&str> accept-set",
11394            );
11395        }
11396    }
11397
11398    #[test]
11399    fn validate_licenca_empty_arm_routes_through_accessor() {
11400        // Composition pin: [`Caixa::validate_licenca`]'s empty-arm gate
11401        // must key off [`Caixa::licenca`], not the raw
11402        // `self.licenca.as_deref()` field access. Structurally: a
11403        // `Caixa { licenca: Some(""), .. }` must surface the
11404        // `LicencaEmpty` refusal exactly, and a
11405        // `Caixa { licenca: Some("MIT"), .. }` (the canonical
11406        // single-license form) must pass validate. The pair jointly
11407        // pins the accessor + validate-gate composition: any future
11408        // silent detour that had the accessor return `None` on the
11409        // empty arm (a `.filter(|s| !s.is_empty())` collapse) would
11410        // silently absorb the `LicencaEmpty` refusal at the accessor
11411        // boundary and the validate gate would accept a struct-literal
11412        // `Caixa { licenca: Some(""), .. }` — the composition pin
11413        // catches that at caixa-core build time.
11414        //
11415        // Peer of the per-`:politicas :circuit-breaker`
11416        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
11417        // accessor-composition pin
11418        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
11419        // on the sibling per-M3-mesh-slot required-`u32` axis — same
11420        // "the validate / shape-gate predicate must route through the
11421        // substrate-primitive typed dispatch" discipline extended onto
11422        // the outer top-level [`Caixa`] universal-axis
11423        // `Option<&str>`-composition surface.
11424        let c = caixa_with_licenca(Some(""));
11425        assert!(
11426            matches!(c.validate_licenca(), Err(ManifestError::LicencaEmpty)),
11427            "validate_licenca must reject licenca == Some(\"\") with \
11428             LicencaEmpty — the accessor and the validate gate must \
11429             route through the same substrate-primitive typed dispatch \
11430             on the :licenca empty arm",
11431        );
11432        let c = caixa_with_licenca(Some("MIT"));
11433        assert!(
11434            c.validate_licenca().is_ok(),
11435            "validate_licenca must accept licenca == Some(\"MIT\") \
11436             (the canonical single-license SPDX shape)",
11437        );
11438    }
11439
11440    #[test]
11441    fn licenca_projects_option_str_by_borrow() {
11442        // The by-borrow pin: [`Caixa::licenca`] returns
11443        // `Option<&str>` by borrow — the `&str` borrows the underlying
11444        // `String` storage of the `Option<String>` slot and the
11445        // accessor must not allocate a fresh `String` on every call.
11446        // Peer of the per-`:placement`
11447        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
11448        // borrow pin on the peer per-M3-mesh-slot
11449        // `Option<&str>`-return axis, extended onto the outer top-
11450        // level [`Caixa`] universal-axis `Option<&str>` shape — the
11451        // accessor's returned `&str` must borrow from `&self` (the
11452        // returned reference's lifetime is tied to `&self`), and
11453        // calling the accessor twice on the same [`Caixa`] must yield
11454        // the same `Option<&str>` verbatim (idempotent, no side
11455        // effects on `&self`).
11456        //
11457        // Pins against a future silent detour that returned an owned
11458        // `Option<String>` (which would type-check but silently
11459        // allocate on every call, breaking the zero-cost projection
11460        // every peer sibling accessor carries), or a one-arm-only
11461        // accessor that returned a saturating value on some sentinel
11462        // input (breaking the pass-through invariant the sibling
11463        // required-scalar accessors carry).
11464        for licenca in [None, Some(""), Some("MIT"), Some("Apache-2.0 OR MIT")] {
11465            let c = caixa_with_licenca(licenca);
11466            let first = c.licenca();
11467            let second = c.licenca();
11468            assert_eq!(
11469                first, second,
11470                "Caixa::licenca must be idempotent — two successive \
11471                 calls on the same &self must return the same \
11472                 Option<&str>",
11473            );
11474            assert_eq!(
11475                first, licenca,
11476                "Caixa::licenca must return :licenca verbatim by \
11477                 borrow — got {first:?}, expected {licenca:?}",
11478            );
11479        }
11480    }
11481
11482    // ── Caixa::repositorio — outer top-level Option<&str> scalar accessor ──
11483
11484    #[test]
11485    fn repositorio_returns_repositorio_byte_string_verbatim_across_permutations() {
11486        // The canonical per-`Caixa` `:repositorio` git-repo-URL scalar
11487        // pin: [`Caixa::repositorio`] must return the `:repositorio`
11488        // typed byte-string verbatim as an `Option<&str>`, byte-equal
11489        // to the raw `self.repositorio.as_deref()` access across every
11490        // representative value in the accept-set — `None` (the "omit
11491        // the slot to defer to the per-renderer placeholder" arm every
11492        // existing fixture without a `:repositorio` line carries),
11493        // `Some("")` (a past-the-guard sentinel that pins the accessor
11494        // doesn't perform a silent `Some("") → None` collapse on the
11495        // empty arm — validate rejects `Some("")` through
11496        // `RepositorioEmpty` but the accessor must ship the raw slot
11497        // verbatim so a validate-time gate regression surfaces at the
11498        // caixa-helm / caixa-flux emit boundary rather than being
11499        // silently absorbed into the per-renderer fallback),
11500        // `Some("github:pleme-io/hello-rio")` (the canonical `github:`
11501        // shorthand every existing manifest fixture across
11502        // `caixa-helm` / `caixa-mesh` and the `examples/` uses),
11503        // `Some("https://github.com/pleme-io/checkout")` (the canonical
11504        // `https://` URL the README quickstart uses),
11505        // `Some("ssh://git@github.com/pleme-io/checkout.git")` /
11506        // `Some("git://github.com/pleme-io/checkout.git")` /
11507        // `Some("git@github.com:pleme-io/checkout.git")` /
11508        // `Some("file:///opt/mirrors/pleme-io/checkout")` (every non-
11509        // github scheme the shared `is_git_repo_url` predicate
11510        // documents), and five past-the-guard sentinels for the
11511        // `RepositorioInvalid` refusal cases (`Some("pleme-io/checkout")`
11512        // missing-colon, `Some("-upload-pack=evil")` leading-dash, /
11513        // `Some("github:pleme-io/checkout?ref=main")` query-string, /
11514        // `Some("github:pleme-io/checkout#main")` fragment-anchor, /
11515        // `Some("github:pleme-io/{tpl}")` URI-template-placeholder — the
11516        // sentinels pin the accessor doesn't silently absorb the
11517        // refusal cases into a fallback).
11518        //
11519        // Second outer top-level [`Caixa`] `Option<&str>`-return scalar
11520        // accessor pin on the substrate primitive — sibling of the peer
11521        // [`Caixa::licenca`] (6d5bc28) pin
11522        // (`licenca_returns_licenca_byte_string_verbatim_across_permutations`)
11523        // that opened the "outer [`Caixa`] `Option<&str>` scalar"
11524        // projection pin pattern this pin folds on. Sibling in shape to
11525        // the peer per-`:placement`
11526        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
11527        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
11528        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
11529        // axes, extended onto the outer top-level [`Caixa`] universal-
11530        // axis surface. Pins against a future silent detour that
11531        // returned an owned `Option<String>` (which would type-check
11532        // but silently allocate on every accessor call, breaking the
11533        // zero-cost projection every peer sibling accessor carries), a
11534        // `Some("") → None` collapse (which would silently absorb the
11535        // `RepositorioEmpty` refusal case at the accessor boundary and
11536        // the caixa-helm `Chart.yaml` `home:` fold would silently
11537        // render a `home: null` / omitted field on a struct-literal
11538        // `Caixa { repositorio: Some(""), .. }`), or a
11539        // `None → Some(<default>)` collapse (which would silently reify
11540        // the per-renderer fallback at the accessor boundary and every
11541        // downstream consumer keying off the `Option::is_none()`
11542        // discriminator would lose the "author omitted the slot"
11543        // signal).
11544        for repositorio in [
11545            None,
11546            Some(""),
11547            Some("github:pleme-io/hello-rio"),
11548            Some("https://github.com/pleme-io/checkout"),
11549            Some("ssh://git@github.com/pleme-io/checkout.git"),
11550            Some("git://github.com/pleme-io/checkout.git"),
11551            Some("git@github.com:pleme-io/checkout.git"),
11552            Some("file:///opt/mirrors/pleme-io/checkout"),
11553            Some("pleme-io/checkout"),
11554            Some("-upload-pack=evil"),
11555            Some("github:pleme-io/checkout?ref=main"),
11556            Some("github:pleme-io/checkout#main"),
11557            Some("github:pleme-io/{tpl}"),
11558        ] {
11559            let c = caixa_with_repositorio(repositorio);
11560            assert_eq!(
11561                c.repositorio(),
11562                repositorio,
11563                "Caixa::repositorio must return :repositorio verbatim \
11564                 (got {:?}, expected {repositorio:?})",
11565                c.repositorio(),
11566            );
11567            assert_eq!(
11568                c.repositorio(),
11569                c.repositorio.as_deref(),
11570                "Caixa::repositorio must byte-equal the raw \
11571                 `self.repositorio.as_deref()` field access across every \
11572                 value in the Option<&str> accept-set",
11573            );
11574        }
11575    }
11576
11577    #[test]
11578    fn validate_repositorio_empty_arm_routes_through_accessor() {
11579        // Composition pin: [`Caixa::validate_repositorio`]'s empty-arm
11580        // gate must key off [`Caixa::repositorio`], not the raw
11581        // `self.repositorio.as_deref()` field access. Structurally: a
11582        // `Caixa { repositorio: Some(""), .. }` must surface the
11583        // `RepositorioEmpty` refusal exactly, and a
11584        // `Caixa { repositorio: Some("github:pleme-io/hello-rio"), .. }`
11585        // (the canonical `github:` shorthand form) must pass validate.
11586        // The pair jointly pins the accessor + validate-gate
11587        // composition: any future silent detour that had the accessor
11588        // return `None` on the empty arm (a `.filter(|s| !s.is_empty())`
11589        // collapse) would silently absorb the `RepositorioEmpty` refusal
11590        // at the accessor boundary and the validate gate would accept a
11591        // struct-literal `Caixa { repositorio: Some(""), .. }` — the
11592        // composition pin catches that at caixa-core build time.
11593        //
11594        // Peer of the [`Caixa::licenca`] (6d5bc28)
11595        // `validate_licenca_empty_arm_routes_through_accessor`
11596        // composition pin on the sibling outer top-level [`Caixa`]
11597        // `Option<&str>` universal-axis surface — same "the validate /
11598        // shape-gate predicate must route through the substrate-
11599        // primitive typed dispatch" discipline extended onto the second
11600        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
11601        // composition surface.
11602        let c = caixa_with_repositorio(Some(""));
11603        assert!(
11604            matches!(
11605                c.validate_repositorio(),
11606                Err(ManifestError::RepositorioEmpty),
11607            ),
11608            "validate_repositorio must reject repositorio == Some(\"\") \
11609             with RepositorioEmpty — the accessor and the validate gate \
11610             must route through the same substrate-primitive typed \
11611             dispatch on the :repositorio empty arm",
11612        );
11613        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio"));
11614        assert!(
11615            c.validate_repositorio().is_ok(),
11616            "validate_repositorio must accept repositorio == \
11617             Some(\"github:pleme-io/hello-rio\") (the canonical \
11618             `github:` shorthand git-repo-URL shape)",
11619        );
11620    }
11621
11622    #[test]
11623    fn repositorio_projects_option_str_by_borrow() {
11624        // The by-borrow pin: [`Caixa::repositorio`] returns
11625        // `Option<&str>` by borrow — the `&str` borrows the underlying
11626        // `String` storage of the `Option<String>` slot and the
11627        // accessor must not allocate a fresh `String` on every call.
11628        // Peer of the per-`:placement`
11629        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) and the
11630        // [`Caixa::licenca`] (6d5bc28) by-borrow pins on the peer
11631        // `Option<&str>`-return axes, extended onto the second outer
11632        // top-level [`Caixa`] universal-axis `Option<&str>` shape —
11633        // the accessor's returned `&str` must borrow from `&self` (the
11634        // returned reference's lifetime is tied to `&self`), and
11635        // calling the accessor twice on the same [`Caixa`] must yield
11636        // the same `Option<&str>` verbatim (idempotent, no side effects
11637        // on `&self`).
11638        //
11639        // Pins against a future silent detour that returned an owned
11640        // `Option<String>` (which would type-check but silently
11641        // allocate on every call, breaking the zero-cost projection
11642        // every peer sibling accessor carries), or a one-arm-only
11643        // accessor that returned a saturating value on some sentinel
11644        // input (breaking the pass-through invariant the sibling
11645        // required-scalar accessors carry).
11646        for repositorio in [
11647            None,
11648            Some(""),
11649            Some("github:pleme-io/hello-rio"),
11650            Some("https://github.com/pleme-io/checkout"),
11651        ] {
11652            let c = caixa_with_repositorio(repositorio);
11653            let first = c.repositorio();
11654            let second = c.repositorio();
11655            assert_eq!(
11656                first, second,
11657                "Caixa::repositorio must be idempotent — two successive \
11658                 calls on the same &self must return the same \
11659                 Option<&str>",
11660            );
11661            assert_eq!(
11662                first, repositorio,
11663                "Caixa::repositorio must return :repositorio verbatim by \
11664                 borrow — got {first:?}, expected {repositorio:?}",
11665            );
11666        }
11667    }
11668
11669    // ── Caixa::canonical_git_url — resolved-git-URL composer ──────────
11670
11671    #[test]
11672    fn canonical_git_url_returns_repositorio_verbatim_on_some_arm() {
11673        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] must
11674        // return the author-declared `:repositorio` byte-string verbatim
11675        // on the `Some` arm — no scheme rewrite, no trailing-slash
11676        // canonicalization, no `github:` → `https://github.com/`
11677        // desugaring. The resolved-URL composer is the projection of
11678        // the raw [`Caixa::repositorio`] `Option<&str>` accessor onto
11679        // the `String`-return arity every substrate-side field-fill
11680        // consumer keys off; on the `Some` arm the projection is
11681        // `str::to_owned` verbatim, so every accept-set value the
11682        // sibling `repositorio_returns_repositorio_byte_string_verbatim_
11683        // across_permutations` pin covers (`https://…`, `github:…`,
11684        // `ssh://…`, `git://…`, `git@…`, `file://…`, and the past-the-
11685        // guard sentinel `pleme-io/…`) must survive the accessor
11686        // byte-equal. Pins against a future silent detour that rewrote
11687        // the `github:` shorthand to the `https://github.com/` full URL
11688        // at the accessor boundary (which would silently split the
11689        // resolved-URL surface from the raw [`Caixa::repositorio`]
11690        // accessor's documented pass-through invariant), or a trailing-
11691        // slash normalization (which would silently break the
11692        // FluxCD `GitRepository` `spec.url` byte-exact match every
11693        // downstream consumer keys the source-controller reconcile off).
11694        for repositorio in [
11695            "github:pleme-io/hello-rio",
11696            "https://github.com/pleme-io/checkout",
11697            "ssh://git@github.com/pleme-io/checkout.git",
11698            "git://github.com/pleme-io/checkout.git",
11699            "git@github.com:pleme-io/checkout.git",
11700            "file:///opt/mirrors/pleme-io/checkout",
11701        ] {
11702            let c = caixa_with_repositorio(Some(repositorio));
11703            assert_eq!(
11704                c.canonical_git_url(),
11705                repositorio,
11706                "Caixa::canonical_git_url on the Some arm must return \
11707                 :repositorio verbatim (got {:?}, expected {repositorio:?})",
11708                c.canonical_git_url(),
11709            );
11710        }
11711    }
11712
11713    #[test]
11714    fn canonical_git_url_falls_back_to_pleme_org_url_on_none_arm() {
11715        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] on the
11716        // `None` arm must emit the substrate's canonical pleme-org github
11717        // URL derived from `caixa.nome()` — `https://github.com/<org>/
11718        // <nome>` with `<org>` bound to [`crate::DEFAULT_PLEME_GIT_ORG`]
11719        // and `<nome>` bound to the typed [`Caixa::nome`] accessor. This
11720        // is the exact byte-image of the prior inline
11721        // [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url`
11722        // composer at caixa-flux/src/lib.rs:2080 that every prior caller
11723        // re-derived open-coded. Pins against a future silent detour
11724        // that migrated the `<org>` segment to a different constant (a
11725        // fork rebranding that split off a new
11726        // `DEFAULT_PLEME_GIT_ORG_MIRROR` const the accessor would need
11727        // to migrate onto), a scheme change (`https://` → `git://` or
11728        // `ssh://`), or a per-`Caixa` `.canonical_git_url_prefix`
11729        // override (which would break the substrate-wide single-source-
11730        // of-truth guarantee this method encodes).
11731        let c = caixa_with_repositorio(None);
11732        let expected = format!(
11733            "https://github.com/{org}/{nome}",
11734            org = crate::DEFAULT_PLEME_GIT_ORG,
11735            nome = c.nome(),
11736        );
11737        assert_eq!(
11738            c.canonical_git_url(),
11739            expected,
11740            "Caixa::canonical_git_url on the None arm must fold through \
11741             the substrate's canonical pleme-org github URL fallback \
11742             `https://github.com/<DEFAULT_PLEME_GIT_ORG>/<nome>` — got \
11743             {:?}, expected {expected:?}",
11744            c.canonical_git_url(),
11745        );
11746    }
11747
11748    #[test]
11749    fn canonical_git_url_byte_matches_manual_composition() {
11750        // Byte-parity pin: [`Caixa::canonical_git_url`] must render
11751        // byte-identically to the manual open-coded
11752        // `caixa.repositorio().map(str::to_owned).unwrap_or_else(||
11753        //  format!("https://github.com/{org}/{nome}", ...))` composition
11754        // every prior substrate-side caller re-derived. Guards the
11755        // paired-site convergence just applied at caixa-flux's
11756        // [`ClusterBundleOpts::for_caixa`] `git_url` composer (which
11757        // now routes through this accessor): a future implementation of
11758        // this method that reordered the format arguments, swapped the
11759        // `<org>` constant for a different one, or interposed a
11760        // canonicalization pass on the `Some` arm surfaces here as a
11761        // caixa-core build-time test failure rather than as a downstream
11762        // FluxCD `GitRepository` reconcile mismatch far from this
11763        // method's source.
11764        for repositorio in [
11765            None,
11766            Some("github:pleme-io/hello-rio"),
11767            Some("https://github.com/pleme-io/checkout"),
11768            Some("ssh://git@github.com/pleme-io/checkout.git"),
11769        ] {
11770            let c = caixa_with_repositorio(repositorio);
11771            let manual = c.repositorio().map_or_else(
11772                || {
11773                    format!(
11774                        "https://github.com/{org}/{nome}",
11775                        org = crate::DEFAULT_PLEME_GIT_ORG,
11776                        nome = c.nome(),
11777                    )
11778                },
11779                str::to_owned,
11780            );
11781            assert_eq!(
11782                c.canonical_git_url(),
11783                manual,
11784                "Caixa::canonical_git_url must byte-equal the manual \
11785                 open-coded `repositorio().map(str::to_owned)\
11786                 .unwrap_or_else(|| format!(...))` composition across \
11787                 every representative :repositorio input — got {:?}, \
11788                 expected {manual:?}",
11789                c.canonical_git_url(),
11790            );
11791        }
11792    }
11793
11794    // ── Caixa::publish_tag — resolved-publish-tag composer ───────────
11795
11796    #[test]
11797    fn publish_tag_composes_prefix_and_versao_on_all_shapes() {
11798        // Fail-before-pass-after pin: [`Caixa::publish_tag`] must compose
11799        // [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] against the caixa's typed
11800        // [`Caixa::versao`] byte-string across every SemVer-2 shape the
11801        // sibling [`validate_versao_accepts_canonical_forms`] positive-set
11802        // sweep documents — bare MAJOR.MINOR.PATCH, pre-release tags
11803        // (`-rc.1`), build metadata (`+build.42`), the combined form, and
11804        // the `0.0.0` boundary case. Every accept-set value the peer
11805        // validate gate lets through must survive the resolved-tag
11806        // projection byte-equal.
11807        for versao in [
11808            "0.1.0",
11809            "0.0.0",
11810            "1.0.0",
11811            "1.2.3-rc.1",
11812            "1.2.3+build.42",
11813            "1.2.3-rc.1+build.42",
11814        ] {
11815            let c = caixa_with_versao(versao);
11816            let expected = format!(
11817                "{prefix}{versao}",
11818                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
11819            );
11820            assert_eq!(
11821                c.publish_tag(),
11822                expected,
11823                "Caixa::publish_tag must compose \
11824                 DEFAULT_PUBLISH_TAG_PREFIX ({prefix:?}) against \
11825                 :versao ({versao:?}) verbatim — got {got:?}, \
11826                 expected {expected:?}",
11827                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
11828                got = c.publish_tag(),
11829            );
11830        }
11831    }
11832
11833    #[test]
11834    fn publish_tag_starts_with_default_publish_tag_prefix() {
11835        // Prefix-shape pin: every [`Caixa::publish_tag`] emission must
11836        // begin with the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
11837        // byte-string on every input, guarding a hypothetical future
11838        // implementation that migrated the prefix segment to an inline
11839        // literal (`"v"`) that would silently drift from any rebrand of
11840        // the lifted constant. Peer to the sibling caixa-flux
11841        // `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`
11842        // test which pins the same prefix invariant at the reader-side
11843        // `GitRefSpec::Tag` emit site.
11844        for versao in ["0.0.0", "0.1.0", "1.2.3-rc.1", "9.9.9+build.1"] {
11845            let c = caixa_with_versao(versao);
11846            let tag = c.publish_tag();
11847            assert!(
11848                tag.starts_with(crate::DEFAULT_PUBLISH_TAG_PREFIX),
11849                "Caixa::publish_tag emission {tag:?} must start with \
11850                 the lifted crate::DEFAULT_PUBLISH_TAG_PREFIX \
11851                 ({prefix:?})",
11852                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
11853            );
11854        }
11855    }
11856
11857    #[test]
11858    fn publish_tag_byte_matches_manual_composition() {
11859        // Byte-parity pin: [`Caixa::publish_tag`] must render byte-
11860        // identically to the manual open-coded
11861        // `format!("{prefix}{versao}", prefix =
11862        //  caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao =
11863        //  caixa.versao())` composition every prior substrate-side
11864        // caller re-derived. Guards the paired-site convergence just
11865        // applied at caixa-flux's [`ClusterBundleOpts::for_caixa`]
11866        // `git_ref` composer (which now routes through this accessor):
11867        // a future implementation of this method that reordered the
11868        // format arguments, swapped the `<prefix>` constant for a
11869        // different one, or interposed a canonicalization pass on the
11870        // `:versao` axis surfaces here as a caixa-core build-time test
11871        // failure rather than as a downstream FluxCD `GitRepository`
11872        // reconcile mismatch far from this method's source.
11873        for versao in [
11874            "0.1.0",
11875            "0.0.0",
11876            "1.2.3-rc.1",
11877            "1.2.3+build.42",
11878            "1.2.3-rc.1+build.42",
11879        ] {
11880            let c = caixa_with_versao(versao);
11881            let manual = format!(
11882                "{prefix}{versao}",
11883                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
11884                versao = c.versao(),
11885            );
11886            assert_eq!(
11887                c.publish_tag(),
11888                manual,
11889                "Caixa::publish_tag must byte-equal the manual \
11890                 open-coded `format!(\"{{prefix}}{{versao}}\", ...)` \
11891                 composition across every representative :versao input \
11892                 — got {got:?}, expected {manual:?}",
11893                got = c.publish_tag(),
11894            );
11895        }
11896    }
11897
11898    // ── Caixa::lareira_chart_name — resolved-chart-name composer ─────
11899
11900    #[test]
11901    fn lareira_chart_name_composes_prefix_and_nome_on_all_shapes() {
11902        // Fail-before-pass-after pin: [`Caixa::lareira_chart_name`] must
11903        // compose [`crate::LAREIRA_CHART_NAME_PREFIX`] against the caixa's
11904        // typed [`Caixa::nome`] byte-string across every DNS-1123 shape
11905        // the sibling [`validate_nome_accepts_canonical_forms`] positive-
11906        // set sweep documents — single-word, hyphen-joined, version-
11907        // suffixed, single-char, two-char, digit-start, retry-suffixed.
11908        // Every accept-set value the peer validate gate lets through must
11909        // survive the resolved-chart-name projection byte-equal.
11910        for nome in [
11911            "checkout",
11912            "cart-v2",
11913            "a",
11914            "db",
11915            "3rd-party-shim",
11916            "payment-retry",
11917            "0",
11918        ] {
11919            let c = caixa_with_nome(nome);
11920            let expected = format!("{prefix}{nome}", prefix = crate::LAREIRA_CHART_NAME_PREFIX);
11921            assert_eq!(
11922                c.lareira_chart_name(),
11923                expected,
11924                "Caixa::lareira_chart_name must compose \
11925                 LAREIRA_CHART_NAME_PREFIX ({prefix:?}) against \
11926                 :nome ({nome:?}) verbatim — got {got:?}, \
11927                 expected {expected:?}",
11928                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
11929                got = c.lareira_chart_name(),
11930            );
11931        }
11932    }
11933
11934    #[test]
11935    fn lareira_chart_name_starts_with_lifted_prefix() {
11936        // Prefix-shape pin: every [`Caixa::lareira_chart_name`] emission
11937        // must begin with the canonical
11938        // [`crate::LAREIRA_CHART_NAME_PREFIX`] byte-string on every
11939        // input, guarding a hypothetical future implementation that
11940        // migrated the prefix segment to an inline literal (`"lareira-"`)
11941        // that would silently drift from any rebrand of the lifted
11942        // constant. Peer to the sibling
11943        // [`publish_tag_starts_with_default_publish_tag_prefix`] pin on
11944        // the co-resident resolved-publish-tag composer's prefix axis.
11945        for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
11946            let c = caixa_with_nome(nome);
11947            let chart = c.lareira_chart_name();
11948            assert!(
11949                chart.starts_with(crate::LAREIRA_CHART_NAME_PREFIX),
11950                "Caixa::lareira_chart_name emission {chart:?} must start \
11951                 with the lifted crate::LAREIRA_CHART_NAME_PREFIX \
11952                 ({prefix:?})",
11953                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
11954            );
11955        }
11956    }
11957
11958    #[test]
11959    fn lareira_chart_name_byte_matches_canonical_helper_composition() {
11960        // Byte-parity pin: [`Caixa::lareira_chart_name`] must render
11961        // byte-identically to the manual open-coded
11962        // `caixa_core::lareira_chart_name(caixa.nome())` two-step
11963        // composition every prior substrate-side caller re-derived.
11964        // Guards the paired-site convergence just applied at caixa-helm's
11965        // [`render_chart_for_servico_with`] `ChartDir.name` composer,
11966        // caixa-flux's [`cluster_bundle`] per-CR `chart_name` binding,
11967        // and caixa-tatara's [`process_for_aplicacao`] `release_name`
11968        // composer (all of which now route through this accessor): a
11969        // future implementation of this method that reordered the
11970        // composition arguments, swapped the `<prefix>` constant for a
11971        // different one, or interposed a canonicalization pass on the
11972        // `:nome` axis surfaces here as a caixa-core build-time test
11973        // failure rather than as a downstream Helm chart-render / FluxCD
11974        // reconcile / tatara Process-CR mismatch far from this method's
11975        // source.
11976        for nome in [
11977            "checkout",
11978            "cart-v2",
11979            "a",
11980            "db",
11981            "3rd-party-shim",
11982            "payment-retry",
11983        ] {
11984            let c = caixa_with_nome(nome);
11985            let manual = crate::lareira_chart_name(c.nome());
11986            assert_eq!(
11987                c.lareira_chart_name(),
11988                manual,
11989                "Caixa::lareira_chart_name must byte-equal the manual \
11990                 open-coded `caixa_core::lareira_chart_name(caixa.nome())` \
11991                 composition across every representative :nome input — \
11992                 got {got:?}, expected {manual:?}",
11993                got = c.lareira_chart_name(),
11994            );
11995        }
11996    }
11997
11998    // ── Caixa::oci_chart_ref — resolved-OCI-chart-ref composer ────────
11999
12000    #[test]
12001    fn oci_chart_ref_composes_scheme_and_lareira_chart_name_on_all_shapes() {
12002        // Fail-before-pass-after pin: [`Caixa::oci_chart_ref`] must
12003        // compose [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied
12004        // `registry` + [`crate::lareira_chart_name`]-of-[`Caixa::nome`]
12005        // across the full paired `(registry, :nome)` accept-set — every
12006        // representative registry the substrate-side emitters carry
12007        // (`ghcr.io/pleme-io/charts`, the canonical CAIXA-SDLC §II
12008        // ArtifactHub-tier registry; `ghcr.io/pleme-io`, the bare-org
12009        // arm the sibling `oci_chart_ref_pins_byte_shape_against_prior_
12010        // inline_format` render-side pin exercises; `registry.example.
12011        // com`, an off-org shape; `localhost:5000`, the local-dev shape
12012        // every `feira chart` iteration path lands under) × every DNS-
12013        // 1123 `:nome` shape the peer `validate_nome_accepts_canonical_
12014        // forms` positive-set sweep documents (single-word, hyphen-
12015        // joined, single-char, two-char, digit-start, retry-suffixed).
12016        // Every accept-set pair the peer validate gates let through must
12017        // survive the resolved-OCI-ref projection byte-equal.
12018        for registry in [
12019            "ghcr.io/pleme-io/charts",
12020            "ghcr.io/pleme-io",
12021            "registry.example.com",
12022            "localhost:5000",
12023        ] {
12024            for nome in [
12025                "checkout",
12026                "cart-v2",
12027                "a",
12028                "db",
12029                "3rd-party-shim",
12030                "payment-retry",
12031                "0",
12032            ] {
12033                let c = caixa_with_nome(nome);
12034                let expected = format!(
12035                    "{scheme}{registry}/{chart}",
12036                    scheme = crate::OCI_SCHEME_PREFIX,
12037                    chart = crate::lareira_chart_name(nome),
12038                );
12039                assert_eq!(
12040                    c.oci_chart_ref(registry),
12041                    expected,
12042                    "Caixa::oci_chart_ref must compose \
12043                     OCI_SCHEME_PREFIX ({scheme:?}) + registry ({registry:?}) + \
12044                     lareira_chart_name(:nome ({nome:?})) verbatim — got {got:?}, \
12045                     expected {expected:?}",
12046                    scheme = crate::OCI_SCHEME_PREFIX,
12047                    got = c.oci_chart_ref(registry),
12048                );
12049            }
12050        }
12051    }
12052
12053    #[test]
12054    fn oci_chart_ref_starts_with_lifted_scheme_prefix() {
12055        // Scheme-prefix-shape pin: every [`Caixa::oci_chart_ref`]
12056        // emission must begin with the canonical
12057        // [`crate::OCI_SCHEME_PREFIX`] byte-string on every input, guarding
12058        // a hypothetical future implementation that migrated the scheme
12059        // segment to an inline literal (`"oci://"`) that would silently
12060        // drift from any rebrand of the lifted constant. Peer to the
12061        // sibling [`publish_tag_starts_with_default_publish_tag_prefix`]
12062        // + [`lareira_chart_name_starts_with_lifted_prefix`] pins on the
12063        // co-resident resolved-publish-tag / resolved-chart-name
12064        // composers' prefix axes.
12065        for registry in [
12066            "ghcr.io/pleme-io/charts",
12067            "ghcr.io/pleme-io",
12068            "localhost:5000",
12069        ] {
12070            for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
12071                let c = caixa_with_nome(nome);
12072                let ref_ = c.oci_chart_ref(registry);
12073                assert!(
12074                    ref_.starts_with(crate::OCI_SCHEME_PREFIX),
12075                    "Caixa::oci_chart_ref emission {ref_:?} must start \
12076                     with the lifted crate::OCI_SCHEME_PREFIX ({scheme:?}) \
12077                     — registry ({registry:?}), :nome ({nome:?})",
12078                    scheme = crate::OCI_SCHEME_PREFIX,
12079                );
12080            }
12081        }
12082    }
12083
12084    #[test]
12085    fn oci_chart_ref_byte_matches_canonical_helper_composition() {
12086        // Byte-parity pin: [`Caixa::oci_chart_ref`] must render byte-
12087        // identically to the manual open-coded
12088        // `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step
12089        // composition every prior substrate-side caller re-derived.
12090        // Guards the paired-site convergence just applied at caixa-
12091        // tatara's [`derive_chart_ref`] helper (which now routes through
12092        // this accessor): a future implementation of this method that
12093        // reordered the composition arguments, swapped the `<scheme>`
12094        // constant for a different one, migrated the `<chart>` segment
12095        // off the paired [`crate::lareira_chart_name`] composer, or
12096        // interposed a canonicalization pass on either input axis
12097        // surfaces here as a caixa-core build-time test failure rather
12098        // than as a downstream `helm install` / FluxCD OCI-source
12099        // reconcile / tatara `Process`-CR mismatch far from this
12100        // method's source. Sibling to the peer
12101        // [`lareira_chart_name_byte_matches_canonical_helper_composition`]
12102        // / [`publish_tag_byte_matches_manual_composition`] /
12103        // [`canonical_git_url_byte_matches_manual_composition`] byte-
12104        // parity pins that carry the same discipline on the co-resident
12105        // resolved-chart-name / resolved-publish-tag / resolved-git-URL
12106        // composers.
12107        for registry in [
12108            "ghcr.io/pleme-io/charts",
12109            "ghcr.io/pleme-io",
12110            "registry.example.com",
12111            "localhost:5000",
12112        ] {
12113            for nome in [
12114                "checkout",
12115                "cart-v2",
12116                "a",
12117                "db",
12118                "3rd-party-shim",
12119                "payment-retry",
12120            ] {
12121                let c = caixa_with_nome(nome);
12122                let manual = crate::oci_chart_ref(registry, c.nome());
12123                assert_eq!(
12124                    c.oci_chart_ref(registry),
12125                    manual,
12126                    "Caixa::oci_chart_ref must byte-equal the manual \
12127                     open-coded `caixa_core::oci_chart_ref(registry, \
12128                     caixa.nome())` composition across every representative \
12129                     (registry, :nome) pair — registry ({registry:?}), \
12130                     :nome ({nome:?}), got {got:?}, expected {manual:?}",
12131                    got = c.oci_chart_ref(registry),
12132                );
12133            }
12134        }
12135    }
12136
12137    // ── Caixa::descricao — outer top-level Option<&str> scalar accessor ──
12138
12139    #[test]
12140    fn descricao_returns_descricao_byte_string_verbatim_across_permutations() {
12141        // The canonical per-`Caixa` `:descricao` free-form-prose scalar
12142        // pin: [`Caixa::descricao`] must return the `:descricao` typed
12143        // byte-string verbatim as an `Option<&str>`, byte-equal to the
12144        // raw `self.descricao.as_deref()` access across every
12145        // representative value in the accept-set — `None` (the "omit
12146        // the slot to defer to the per-renderer `caixa.nome`-derived
12147        // fallback" arm every existing fixture without a `:descricao`
12148        // line carries), `Some("")` (a past-the-guard sentinel that
12149        // pins the accessor doesn't perform a silent `Some("") → None`
12150        // collapse on the empty arm — validate rejects `Some("")`
12151        // through `DescricaoEmpty` but the accessor must ship the raw
12152        // slot verbatim so a validate-time gate regression surfaces at
12153        // the caixa-helm / caixa-feira emit boundary rather than being
12154        // silently absorbed into the per-renderer `caixa.nome`-derived
12155        // fallback), `Some("Checkout flow.")` (the canonical one-line
12156        // prose descriptor the peer
12157        // `validate_descricao_accepts_canonical_value` positive sweep
12158        // exercises), `Some("Canonical Rust→wasm32-wasip2 caixa
12159        // Servico.")` (the multi-byte Unicode continuation-byte shape
12160        // the `hello-rio` fixture carries), `Some("→ — · ✓")` (a
12161        // multi-glyph Unicode shape the peer
12162        // `is_chart_description_shape` predicate accepts), and five
12163        // past-the-guard sentinels for the `DescricaoInvalid` refusal
12164        // cases (`Some(" Checkout flow.")` leading-whitespace,
12165        // `Some("Checkout flow. ")` trailing-whitespace,
12166        // `Some("Checkout\nflow.")` embedded-LF,
12167        // `Some("Checkout\tflow.")` embedded-TAB, and
12168        // `Some("Checkout\x00flow.")` embedded-NUL — the sentinels pin
12169        // the accessor doesn't silently absorb the refusal cases into
12170        // a fallback).
12171        //
12172        // Third outer top-level [`Caixa`] `Option<&str>`-return scalar
12173        // accessor pin on the substrate primitive — sibling of the peer
12174        // [`Caixa::licenca`] (6d5bc28) and [`Caixa::repositorio`]
12175        // (cc7332d) pins that opened the "outer [`Caixa`]
12176        // `Option<&str>` scalar" projection pin pattern this pin folds
12177        // on. Sibling in shape to the peer per-`:placement`
12178        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12179        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12180        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12181        // axes, extended onto the outer top-level [`Caixa`] universal-
12182        // axis surface. Pins against a future silent detour that
12183        // returned an owned `Option<String>` (which would type-check
12184        // but silently allocate on every accessor call, breaking the
12185        // zero-cost projection every peer sibling accessor carries), a
12186        // `Some("") → None` collapse (which would silently absorb the
12187        // `DescricaoEmpty` refusal case at the accessor boundary and
12188        // the caixa-helm `Chart.yaml` `description:` fold would
12189        // silently render a `caixa.nome`-derived fallback on a
12190        // struct-literal `Caixa { descricao: Some(""), .. }`), or a
12191        // `None → Some(<default>)` collapse (which would silently
12192        // reify the per-renderer `caixa.nome`-derived fallback at the
12193        // accessor boundary and every downstream consumer keying off
12194        // the `Option::is_none()` discriminator would lose the "author
12195        // omitted the slot" signal).
12196        for descricao in [
12197            None,
12198            Some(""),
12199            Some("Checkout flow."),
12200            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
12201            Some("→ — · ✓"),
12202            Some(" Checkout flow."),
12203            Some("Checkout flow. "),
12204            Some("Checkout\nflow."),
12205            Some("Checkout\tflow."),
12206            Some("Checkout\x00flow."),
12207        ] {
12208            let c = caixa_with_descricao(descricao);
12209            assert_eq!(
12210                c.descricao(),
12211                descricao,
12212                "Caixa::descricao must return :descricao verbatim (got \
12213                 {:?}, expected {descricao:?})",
12214                c.descricao(),
12215            );
12216            assert_eq!(
12217                c.descricao(),
12218                c.descricao.as_deref(),
12219                "Caixa::descricao must byte-equal the raw \
12220                 `self.descricao.as_deref()` field access across every \
12221                 value in the Option<&str> accept-set",
12222            );
12223        }
12224    }
12225
12226    #[test]
12227    fn validate_descricao_empty_arm_routes_through_accessor() {
12228        // Composition pin: [`Caixa::validate_descricao`]'s empty-arm
12229        // gate must key off [`Caixa::descricao`], not the raw
12230        // `self.descricao.as_deref()` field access. Structurally: a
12231        // `Caixa { descricao: Some(""), .. }` must surface the
12232        // `DescricaoEmpty` refusal exactly, and a
12233        // `Caixa { descricao: Some("Checkout flow."), .. }` (the
12234        // canonical one-line-prose form) must pass validate. The pair
12235        // jointly pins the accessor + validate-gate composition: any
12236        // future silent detour that had the accessor return `None` on
12237        // the empty arm (a `.filter(|s| !s.is_empty())` collapse) would
12238        // silently absorb the `DescricaoEmpty` refusal at the accessor
12239        // boundary and the validate gate would accept a struct-literal
12240        // `Caixa { descricao: Some(""), .. }` — the composition pin
12241        // catches that at caixa-core build time.
12242        //
12243        // Peer of the [`Caixa::licenca`] (6d5bc28)
12244        // `validate_licenca_empty_arm_routes_through_accessor` and
12245        // [`Caixa::repositorio`] (cc7332d)
12246        // `validate_repositorio_empty_arm_routes_through_accessor`
12247        // composition pins on the sibling outer top-level [`Caixa`]
12248        // `Option<&str>` universal-axis surface — same "the validate /
12249        // shape-gate predicate must route through the substrate-
12250        // primitive typed dispatch" discipline extended onto the third
12251        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
12252        // composition surface.
12253        let c = caixa_with_descricao(Some(""));
12254        assert!(
12255            matches!(c.validate_descricao(), Err(ManifestError::DescricaoEmpty),),
12256            "validate_descricao must reject descricao == Some(\"\") \
12257             with DescricaoEmpty — the accessor and the validate gate \
12258             must route through the same substrate-primitive typed \
12259             dispatch on the :descricao empty arm",
12260        );
12261        let c = caixa_with_descricao(Some("Checkout flow."));
12262        assert!(
12263            c.validate_descricao().is_ok(),
12264            "validate_descricao must accept descricao == \
12265             Some(\"Checkout flow.\") (the canonical one-line-prose \
12266             chart-description shape)",
12267        );
12268    }
12269
12270    #[test]
12271    fn descricao_projects_option_str_by_borrow() {
12272        // The by-borrow pin: [`Caixa::descricao`] returns
12273        // `Option<&str>` by borrow — the `&str` borrows the underlying
12274        // `String` storage of the `Option<String>` slot and the
12275        // accessor must not allocate a fresh `String` on every call.
12276        // Peer of the [`Caixa::licenca`] (6d5bc28) and
12277        // [`Caixa::repositorio`] (cc7332d) by-borrow pins on the peer
12278        // outer top-level [`Caixa`] `Option<&str>`-return axes, and of
12279        // the per-`:placement`
12280        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
12281        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
12282        // return axis, extended onto the third outer top-level
12283        // [`Caixa`] universal-axis `Option<&str>` shape — the
12284        // accessor's returned `&str` must borrow from `&self` (the
12285        // returned reference's lifetime is tied to `&self`), and
12286        // calling the accessor twice on the same [`Caixa`] must yield
12287        // the same `Option<&str>` verbatim (idempotent, no side
12288        // effects on `&self`).
12289        //
12290        // Pins against a future silent detour that returned an owned
12291        // `Option<String>` (which would type-check but silently
12292        // allocate on every call, breaking the zero-cost projection
12293        // every peer sibling accessor carries), or a one-arm-only
12294        // accessor that returned a saturating value on some sentinel
12295        // input (breaking the pass-through invariant the sibling
12296        // required-scalar accessors carry).
12297        for descricao in [
12298            None,
12299            Some(""),
12300            Some("Checkout flow."),
12301            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
12302        ] {
12303            let c = caixa_with_descricao(descricao);
12304            let first = c.descricao();
12305            let second = c.descricao();
12306            assert_eq!(
12307                first, second,
12308                "Caixa::descricao must be idempotent — two successive \
12309                 calls on the same &self must return the same \
12310                 Option<&str>",
12311            );
12312            assert_eq!(
12313                first, descricao,
12314                "Caixa::descricao must return :descricao verbatim by \
12315                 borrow — got {first:?}, expected {descricao:?}",
12316            );
12317        }
12318    }
12319
12320    // ── validate_edicao — universal-axis language-edition shape ──
12321
12322    fn caixa_with_edicao(edicao: Option<&str>) -> Caixa {
12323        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12324        c.edicao = edicao.map(String::from);
12325        c
12326    }
12327
12328    #[test]
12329    fn validate_edicao_accepts_none() {
12330        // The omit-the-slot identity: `:edicao` is optional. The
12331        // gate is a no-op when the author didn't declare a value —
12332        // every caixa without an `:edicao` line trivially passes,
12333        // and the substrate-side build pipeline falls back to the
12334        // documented default edition. Mirrors the peer
12335        // `validate_licenca_accepts_none` posture on the sibling
12336        // `Option<String>` Caixa slot.
12337        let c = caixa_with_edicao(None);
12338        c.validate_edicao().unwrap();
12339    }
12340
12341    #[test]
12342    fn validate_edicao_accepts_canonical_value() {
12343        // Positive control: the canonical `"2026"` edition every
12344        // existing renderer-side fixture (`caixa-helm`, `caixa-flux`,
12345        // `caixa-mesh`) carries by construction passes the gate.
12346        // Future-introduced sibling editions (`"2027"`, `"2030"`,
12347        // `"2049"`) that match the same 4-digit ASCII decimal year
12348        // shape must also trivially pass — the structural shape
12349        // predicate accepts every well-formed year regardless of
12350        // whether the substrate yet understands the specific value
12351        // (a future known-edition allowlist tightens that).
12352        for ed in ["2026", "2027", "2030", "2049"] {
12353            let c = caixa_with_edicao(Some(ed));
12354            c.validate_edicao()
12355                .unwrap_or_else(|err| panic!("canonical {ed:?} must pass: {err:?}"));
12356        }
12357    }
12358
12359    #[test]
12360    fn validate_edicao_rejects_empty_some() {
12361        // Canonical paste-from-blank-doc footgun. Without this gate
12362        // the empty `Some("")` silently lands as `(:edicao "")` in
12363        // the rendered caixa.lisp and a future renderer-side
12364        // consumer's `Option::unwrap_or_else` (which only fires on
12365        // `None`) skips its fallback. Mirrors the peer
12366        // [`ManifestError::LicencaEmpty`] empty-arm on the sibling
12367        // `Option<String>` Caixa slot.
12368        let c = caixa_with_edicao(Some(""));
12369        let err = c.validate_edicao().unwrap_err();
12370        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
12371    }
12372
12373    #[test]
12374    fn validate_edicao_rejects_free_form_non_year() {
12375        // Free-form non-year footgun: the bare `"x"` / `"latest"` /
12376        // `"nightly"` shapes carry no operational meaning on the
12377        // substrate's build-time edition selector. Until this gate
12378        // landed the bare empty-arm check let every such value
12379        // through and broke far from the source caixa.lisp. Peer
12380        // with the shape-predicate cascade
12381        // `validate_repositorio_rejects_missing_colon_separator`
12382        // establishes past its own empty arm.
12383        for ed in ["x", "latest", "nightly", "stable"] {
12384            let c = caixa_with_edicao(Some(ed));
12385            let err = c.validate_edicao().unwrap_err();
12386            assert!(
12387                matches!(err, ManifestError::EdicaoInvalid { .. }),
12388                "expected EdicaoInvalid on {ed:?}, got {err:?}",
12389            );
12390        }
12391    }
12392
12393    #[test]
12394    fn validate_edicao_rejects_trailing_whitespace() {
12395        // Paste-from-doc whitespace footgun. A trailing space in
12396        // the `:edicao` value would silently break the substrate's
12397        // build-time edition match-table lookup at the rendered
12398        // artifact's edition-selector consumer. The shape predicate
12399        // refuses every whitespace byte by construction (any byte
12400        // outside `0-9` fails `is_ascii_digit`). Peer with
12401        // `validate_repositorio_rejects_whitespace`.
12402        let c = caixa_with_edicao(Some("2026 "));
12403        let err = c.validate_edicao().unwrap_err();
12404        let ManifestError::EdicaoInvalid { edicao, .. } = err else {
12405            panic!("expected EdicaoInvalid, got {err:?}");
12406        };
12407        assert_eq!(edicao, "2026 ");
12408    }
12409
12410    #[test]
12411    fn validate_edicao_rejects_leading_whitespace() {
12412        // Symmetric paste-from-doc whitespace footgun on the leading
12413        // boundary — the gate refuses every shape with a non-digit
12414        // byte by construction.
12415        let c = caixa_with_edicao(Some(" 2026"));
12416        let err = c.validate_edicao().unwrap_err();
12417        assert!(
12418            matches!(err, ManifestError::EdicaoInvalid { .. }),
12419            "got {err:?}",
12420        );
12421    }
12422
12423    #[test]
12424    fn validate_edicao_rejects_control_char() {
12425        // Paste-from-multiline-doc CRLF footgun — control characters
12426        // at the value boundary break the substrate's build-time
12427        // edition-selector parser. Peer with
12428        // `validate_repositorio_rejects_control_char`.
12429        let c = caixa_with_edicao(Some("2026\n"));
12430        let err = c.validate_edicao().unwrap_err();
12431        assert!(
12432            matches!(err, ManifestError::EdicaoInvalid { .. }),
12433            "got {err:?}",
12434        );
12435    }
12436
12437    #[test]
12438    fn validate_edicao_rejects_non_ascii_lookalike() {
12439        // Fullwidth-keyboard look-alike footgun — `"2026"` is
12440        // the U+FF12 U+FF10 U+FF12 U+FF16 sequence (CJK fullwidth
12441        // digits), 4 codepoints but 12 UTF-8 bytes; the substrate's
12442        // edition selector wants an ASCII year, and the gate
12443        // refuses every non-ASCII shape by construction (length in
12444        // bytes is 12 ≠ 4, *and* every byte falls outside
12445        // `is_ascii_digit`'s `0-9` range).
12446        let c = caixa_with_edicao(Some("2026"));
12447        let err = c.validate_edicao().unwrap_err();
12448        assert!(
12449            matches!(err, ManifestError::EdicaoInvalid { .. }),
12450            "got {err:?}",
12451        );
12452    }
12453
12454    #[test]
12455    fn validate_edicao_rejects_version_tag_prefix() {
12456        // Common version-tag idiom footgun — `"v2026"` / `"e2026"`
12457        // / `"r2026"` are familiar shapes from git-tag / Rust
12458        // edition / release-tag conventions that don't apply to
12459        // the year-shaped edition axis. The shape predicate refuses
12460        // every leading non-digit prefix.
12461        for ed in ["v2026", "e2026", "r2026"] {
12462            let c = caixa_with_edicao(Some(ed));
12463            let err = c.validate_edicao().unwrap_err();
12464            assert!(
12465                matches!(err, ManifestError::EdicaoInvalid { .. }),
12466                "expected EdicaoInvalid on {ed:?}, got {err:?}",
12467            );
12468        }
12469    }
12470
12471    #[test]
12472    fn validate_edicao_rejects_decimal_shape() {
12473        // Decimal-shaped pseudo-version footgun — `"2026.1"` /
12474        // `"2026.0"` are familiar shapes from semver / float
12475        // conventions that don't apply to the year-shaped edition
12476        // axis. The shape predicate refuses every non-digit byte
12477        // (`.` falls outside `is_ascii_digit`).
12478        for ed in ["2026.1", "2026.0", "2026.0.1"] {
12479            let c = caixa_with_edicao(Some(ed));
12480            let err = c.validate_edicao().unwrap_err();
12481            assert!(
12482                matches!(err, ManifestError::EdicaoInvalid { .. }),
12483                "expected EdicaoInvalid on {ed:?}, got {err:?}",
12484            );
12485        }
12486    }
12487
12488    #[test]
12489    fn validate_edicao_rejects_wrong_length_numeric() {
12490        // Wrong-length numeric footgun — `"26"` (truncated) /
12491        // `"202"` (truncated) / `"20260"` (extra digit) / `"00026"`
12492        // (zero-padded too wide) all parse as integers but don't
12493        // name a 4-digit year. The shape predicate refuses every
12494        // value whose length isn't exactly 4 bytes.
12495        for ed in ["26", "202", "20260", "00026", "9"] {
12496            let c = caixa_with_edicao(Some(ed));
12497            let err = c.validate_edicao().unwrap_err();
12498            assert!(
12499                matches!(err, ManifestError::EdicaoInvalid { .. }),
12500                "expected EdicaoInvalid on {ed:?}, got {err:?}",
12501            );
12502        }
12503    }
12504
12505    #[test]
12506    fn validate_edicao_empty_takes_precedence_over_shape() {
12507        // Empty-first cascade pin: the empty `Some("")` surfaces
12508        // the narrower `EdicaoEmpty` not the shape-predicate-
12509        // wrapped `EdicaoInvalid`, mirroring the peer
12510        // `validate_repositorio_empty_takes_precedence_over_shape`
12511        // (`RepositorioEmpty` → `RepositorioInvalid`),
12512        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` →
12513        // `VersaoInvalid`, `FonteRepoEmpty` → `FonteRepoInvalid`
12514        // cascades. The shape predicate also refuses the empty
12515        // input (defensively — `s.len() != 4`), but the
12516        // manifest-layer empty arm runs first to surface the
12517        // narrower diagnostic verbatim.
12518        let c = caixa_with_edicao(Some(""));
12519        let err = c.validate_edicao().unwrap_err();
12520        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
12521    }
12522
12523    #[test]
12524    fn validate_edicao_template_passes() {
12525        // Round-trip pin: the bare `Caixa::template` shape (which
12526        // carries `:edicao "2026"` verbatim) passes the gate by
12527        // construction. A future template-shape change that
12528        // introduced `(:edicao "")` or a non-year value would
12529        // surface here as a regression. Mirrors the peer
12530        // `validate_licenca_template_passes` pin.
12531        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12532        c.validate_edicao().unwrap();
12533    }
12534
12535    #[test]
12536    fn validate_edicao_diagnostic_names_offending_slot() {
12537        // Diagnostic-shape pin (peer with
12538        // `validate_licenca_diagnostic_names_offending_slot`): the
12539        // error's Display surfaces the `:edicao` slot name verbatim,
12540        // so a `feira lint` run can render the diagnostic without
12541        // re-parsing and the author can grep their caixa.lisp for
12542        // the offending `:edicao` line.
12543        let c = caixa_with_edicao(Some(""));
12544        let rendered = c.validate_edicao().unwrap_err().to_string();
12545        assert!(
12546            rendered.contains(":edicao"),
12547            "diagnostic must name the offending slot: {rendered}",
12548        );
12549    }
12550
12551    #[test]
12552    fn validate_edicao_invalid_diagnostic_carries_offending_value() {
12553        // Diagnostic-shape pin on the shape-predicate arm (peer
12554        // with `validate_repositorio_diagnostic_carries_offending_value`):
12555        // the error's Display surfaces the offending value + slot
12556        // name verbatim, so a `feira lint` run can render the
12557        // diagnostic without re-parsing and the author can grep
12558        // their caixa.lisp for the offending `:edicao` value.
12559        let c = caixa_with_edicao(Some("v2026"));
12560        let rendered = c.validate_edicao().unwrap_err().to_string();
12561        assert!(
12562            rendered.contains(":edicao"),
12563            "diagnostic must name the offending slot: {rendered}",
12564        );
12565        assert!(
12566            rendered.contains("v2026"),
12567            "diagnostic must quote the offending value: {rendered}",
12568        );
12569    }
12570
12571    // ── Caixa::edicao — outer top-level Option<&str> scalar accessor ──
12572
12573    #[test]
12574    fn edicao_returns_edicao_byte_string_verbatim_across_permutations() {
12575        // The canonical per-`Caixa` `:edicao` language-edition scalar
12576        // pin: [`Caixa::edicao`] must return the `:edicao` typed
12577        // byte-string verbatim as an `Option<&str>`, byte-equal to the
12578        // raw `self.edicao.as_deref()` access across every representative
12579        // value in the accept-set — `None` (the "omit the slot to defer
12580        // to the substrate's default edition" arm every existing
12581        // [`caixa-resolver`] fixture without an `:edicao` line carries),
12582        // `Some("")` (a past-the-guard sentinel that pins the accessor
12583        // doesn't perform a silent `Some("") → None` collapse on the
12584        // empty arm — validate rejects `Some("")` through `EdicaoEmpty`
12585        // but the accessor must ship the raw slot verbatim so a
12586        // validate-time gate regression surfaces at any future edition-
12587        // aware consumer's boundary rather than being silently absorbed
12588        // into the substrate's default edition), `Some("2026")` (the
12589        // canonical 4-digit-ASCII-decimal-year shape every `feira init`
12590        // template scaffolds via [`Caixa::template`] and every
12591        // renderer-side fixture at `caixa-helm/src/lib.rs:978` /
12592        // `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208`
12593        // carries by construction), `Some("2018")` / `Some("2021")` /
12594        // `Some("2024")` (canonical 4-digit-ASCII-decimal-year shapes
12595        // peer with Cargo's `[package] edition` grammar every future-
12596        // introduced sibling to `"2026"` will follow), and eight
12597        // past-the-guard sentinels for the `EdicaoInvalid` refusal cases
12598        // (`Some("2026 ")` trailing-whitespace, `Some(" 2026")` leading-
12599        // whitespace, `Some("2026\n")` embedded-LF, `Some("2026")`
12600        // fullwidth-non-ASCII-lookalike, `Some("v2026")` version-tag-
12601        // prefix, `Some("2026.1")` decimal-shape, `Some("26")` wrong-
12602        // length-numeric, `Some("latest")` free-form-non-year — the
12603        // sentinels pin the accessor doesn't silently absorb the
12604        // refusal cases into a substrate-default-edition fallback).
12605        //
12606        // Fourth and final outer top-level [`Caixa`] `Option<&str>`-
12607        // return scalar accessor pin on the substrate primitive —
12608        // sibling of the peer [`Caixa::licenca`] (6d5bc28),
12609        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
12610        // (3f16e2f) pins that opened the "outer [`Caixa`]
12611        // `Option<&str>` scalar" projection pin pattern this pin folds
12612        // on. Sibling in shape to the peer per-`:placement`
12613        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12614        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12615        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12616        // axes, extended onto the outer top-level [`Caixa`] universal-
12617        // axis surface's last unlifted `Option<String>` slot. Pins
12618        // against a future silent detour that returned an owned
12619        // `Option<String>` (which would type-check but silently
12620        // allocate on every accessor call, breaking the zero-cost
12621        // projection every peer sibling accessor carries), a
12622        // `Some("") → None` collapse (which would silently absorb the
12623        // `EdicaoEmpty` refusal case at the accessor boundary and any
12624        // future edition-aware consumer would silently fall back to
12625        // the substrate's default edition on a struct-literal
12626        // `Caixa { edicao: Some(""), .. }`), or a
12627        // `None → Some("2026")` collapse (which would silently reify
12628        // the substrate's default edition at the accessor boundary
12629        // and every downstream consumer keying off the
12630        // `Option::is_none()` discriminator would lose the "author
12631        // omitted the slot" signal).
12632        for edicao in [
12633            None,
12634            Some(""),
12635            Some("2026"),
12636            Some("2018"),
12637            Some("2021"),
12638            Some("2024"),
12639            Some("2026 "),
12640            Some(" 2026"),
12641            Some("2026\n"),
12642            Some("2026"),
12643            Some("v2026"),
12644            Some("2026.1"),
12645            Some("26"),
12646            Some("latest"),
12647        ] {
12648            let c = caixa_with_edicao(edicao);
12649            assert_eq!(
12650                c.edicao(),
12651                edicao,
12652                "Caixa::edicao must return :edicao verbatim (got {:?}, \
12653                 expected {edicao:?})",
12654                c.edicao(),
12655            );
12656            assert_eq!(
12657                c.edicao(),
12658                c.edicao.as_deref(),
12659                "Caixa::edicao must byte-equal the raw \
12660                 `self.edicao.as_deref()` field access across every \
12661                 value in the Option<&str> accept-set",
12662            );
12663        }
12664    }
12665
12666    #[test]
12667    fn validate_edicao_empty_arm_routes_through_accessor() {
12668        // Composition pin: [`Caixa::validate_edicao`]'s empty-arm gate
12669        // must key off [`Caixa::edicao`], not the raw
12670        // `self.edicao.as_deref()` field access. Structurally: a
12671        // `Caixa { edicao: Some(""), .. }` must surface the
12672        // `EdicaoEmpty` refusal exactly, and a
12673        // `Caixa { edicao: Some("2026"), .. }` (the canonical
12674        // 4-digit-ASCII-decimal-year form) must pass validate. The
12675        // pair jointly pins the accessor + validate-gate composition:
12676        // any future silent detour that had the accessor return `None`
12677        // on the empty arm (a `.filter(|s| !s.is_empty())` collapse)
12678        // would silently absorb the `EdicaoEmpty` refusal at the
12679        // accessor boundary and the validate gate would accept a
12680        // struct-literal `Caixa { edicao: Some(""), .. }` — the
12681        // composition pin catches that at caixa-core build time.
12682        //
12683        // Peer of the [`Caixa::licenca`] (6d5bc28)
12684        // `validate_licenca_empty_arm_routes_through_accessor`,
12685        // [`Caixa::repositorio`] (cc7332d)
12686        // `validate_repositorio_empty_arm_routes_through_accessor`,
12687        // and [`Caixa::descricao`] (3f16e2f)
12688        // `validate_descricao_empty_arm_routes_through_accessor`
12689        // composition pins on the sibling outer top-level [`Caixa`]
12690        // `Option<&str>` universal-axis surface — same "the validate /
12691        // shape-gate predicate must route through the substrate-
12692        // primitive typed dispatch" discipline extended onto the
12693        // fourth and final outer top-level [`Caixa`] universal-axis
12694        // `Option<&str>`-composition surface, closing the accessor-
12695        // composition family.
12696        let c = caixa_with_edicao(Some(""));
12697        assert!(
12698            matches!(c.validate_edicao(), Err(ManifestError::EdicaoEmpty)),
12699            "validate_edicao must reject edicao == Some(\"\") with \
12700             EdicaoEmpty — the accessor and the validate gate must \
12701             route through the same substrate-primitive typed dispatch \
12702             on the :edicao empty arm",
12703        );
12704        let c = caixa_with_edicao(Some("2026"));
12705        assert!(
12706            c.validate_edicao().is_ok(),
12707            "validate_edicao must accept edicao == Some(\"2026\") \
12708             (the canonical 4-digit-ASCII-decimal-year shape)",
12709        );
12710    }
12711
12712    #[test]
12713    fn edicao_projects_option_str_by_borrow() {
12714        // The by-borrow pin: [`Caixa::edicao`] returns
12715        // `Option<&str>` by borrow — the `&str` borrows the underlying
12716        // `String` storage of the `Option<String>` slot and the
12717        // accessor must not allocate a fresh `String` on every call.
12718        // Peer of the [`Caixa::licenca`] (6d5bc28),
12719        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
12720        // (3f16e2f) by-borrow pins on the peer outer top-level
12721        // [`Caixa`] `Option<&str>`-return axes, and of the
12722        // per-`:placement`
12723        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
12724        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
12725        // return axis, extended onto the fourth and final outer top-
12726        // level [`Caixa`] universal-axis `Option<&str>` shape — the
12727        // accessor's returned `&str` must borrow from `&self` (the
12728        // returned reference's lifetime is tied to `&self`), and
12729        // calling the accessor twice on the same [`Caixa`] must yield
12730        // the same `Option<&str>` verbatim (idempotent, no side
12731        // effects on `&self`).
12732        //
12733        // Pins against a future silent detour that returned an owned
12734        // `Option<String>` (which would type-check but silently
12735        // allocate on every call, breaking the zero-cost projection
12736        // every peer sibling accessor carries), or a one-arm-only
12737        // accessor that returned a saturating value on some sentinel
12738        // input (breaking the pass-through invariant the sibling
12739        // required-scalar accessors carry).
12740        for edicao in [None, Some(""), Some("2026"), Some("2018")] {
12741            let c = caixa_with_edicao(edicao);
12742            let first = c.edicao();
12743            let second = c.edicao();
12744            assert_eq!(
12745                first, second,
12746                "Caixa::edicao must be idempotent — two successive \
12747                 calls on the same &self must return the same \
12748                 Option<&str>",
12749            );
12750            assert_eq!(
12751                first, edicao,
12752                "Caixa::edicao must return :edicao verbatim by \
12753                 borrow — got {first:?}, expected {edicao:?}",
12754            );
12755        }
12756    }
12757
12758    #[test]
12759    fn nome_returns_nome_byte_string_verbatim_across_permutations() {
12760        // The canonical per-`Caixa` `:nome` universal-axis DNS-1123-
12761        // label caixa-identity scalar pin: [`Caixa::nome`] must return
12762        // the `:nome` typed `String` verbatim as `&str`, byte-equal to
12763        // the raw field access across every representative value in
12764        // the accept-set — the canonical `"demo"` template baseline
12765        // (the same `feira init`-scaffolded default the sibling
12766        // `validate_nome_accepts_canonical_template` positive-control
12767        // gate pins), plus every sibling per-typed-slot atom accessor's
12768        // canonical positive-arm byte-string (`"catalog"` per
12769        // [`crate::aplicacao::Membro::nome`], `"cart"` per the peer
12770        // per-`:contratos` `:de`, `"hello-rio"` per the canonical
12771        // `caixa-helm`/`caixa-flux` cross-crate integration-test
12772        // fixture, `"checkout"` per the M3 mesh-slot Aplicacao
12773        // canonical example), plus every past-the-guard sentinel for
12774        // the `NomeEmpty` / `NomeInvalid` / `NomeChartNameBudgetExceeded`
12775        // refusal cases (`""`, `"Bad_Name"`, `"a"` × 56 — 56 bytes fits
12776        // the bare DNS-1123 63-byte cap but overflows the joint
12777        // `lareira-<nome>` chart-name budget the sibling
12778        // [`Caixa::validate_nome_chart_name_budget`] gate closes on).
12779        //
12780        // The past-the-guard sentinels pin the accessor doesn't
12781        // silently absorb the refusal cases into a template-derived
12782        // fallback (a future `.nome().is_empty().then(|| "demo")`
12783        // collapse would silently absorb the `NomeEmpty` refusal at
12784        // the accessor boundary and the validate gate would accept a
12785        // struct-literal `Caixa { nome: "".into(), .. }` — the pin
12786        // catches that at caixa-core build time).
12787        //
12788        // First outer top-level [`Caixa`] `&str`-return required-
12789        // scalar accessor pin — opens the "outer [`Caixa`] `&str`
12790        // required-scalar" projection pattern the sibling per-`Caixa`
12791        // `:versao` future lift folds on. Sibling in shape to the peer
12792        // per-`:membros` [`crate::aplicacao::Membro::nome`] (4a32abf)
12793        // required-`String`-carry accessor pin on the sibling per-
12794        // sub-struct required-axis, extended onto the outer top-level
12795        // [`Caixa`] universal-axis required-`String`-carry axis.
12796        for nome in [
12797            "demo",
12798            "catalog",
12799            "cart",
12800            "hello-rio",
12801            "checkout",
12802            "",
12803            "Bad_Name",
12804            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
12805        ] {
12806            let c = caixa_with_nome(nome);
12807            assert_eq!(
12808                c.nome(),
12809                nome,
12810                "Caixa::nome must return :nome verbatim (got {}, \
12811                 expected {nome})",
12812                c.nome(),
12813            );
12814            assert_eq!(
12815                c.nome(),
12816                c.nome.as_str(),
12817                "Caixa::nome must byte-equal the raw .nome field \
12818                 access across every value in the String accept-set",
12819            );
12820        }
12821    }
12822
12823    #[test]
12824    fn validate_nome_empty_arm_routes_through_accessor() {
12825        // Composition pin: [`Caixa::validate_nome`]'s empty-arm must
12826        // key off [`Caixa::nome`], not the raw `.nome` field access.
12827        // Structurally: a `Caixa { nome: "".into(), .. }` must surface
12828        // the `NomeEmpty` refusal exactly, and the canonical `"demo"`
12829        // template baseline (the peer positive-arm the sibling
12830        // `validate_nome_accepts_canonical_template` gate carves out)
12831        // must pass validate. The pair jointly pins the accessor +
12832        // validate-gate composition: any future silent detour that
12833        // had the accessor return a fresh `"demo"` on the empty arm
12834        // (a `.nome().is_empty().then(|| "demo")` fallback collapse)
12835        // would silently absorb the `NomeEmpty` refusal at the
12836        // accessor boundary and the validate gate would accept a
12837        // struct-literal `Caixa { nome: "".into(), .. }` — the
12838        // composition pin catches that at caixa-core build time.
12839        //
12840        // Peer of the sibling per-`Caixa`
12841        // `validate_licenca_empty_arm_routes_through_accessor` (6d5bc28)
12842        // / `validate_repositorio_empty_arm_routes_through_accessor`
12843        // (cc7332d) / `validate_descricao_empty_arm_routes_through_accessor`
12844        // (3f16e2f) / `validate_edicao_empty_arm_routes_through_accessor`
12845        // (2641cbd) composition pins on the sibling outer top-level
12846        // [`Caixa`] `Option<&str>` axes — same "the validate /
12847        // shape-gate predicate must route through the substrate-
12848        // primitive typed dispatch" discipline extended onto the peer
12849        // outer top-level [`Caixa`] required-`&str` composition axis.
12850        let c = caixa_with_nome("");
12851        assert!(
12852            matches!(c.validate_nome(), Err(ManifestError::NomeEmpty)),
12853            "validate_nome must reject nome == \"\" with NomeEmpty — \
12854             the accessor and the validate gate must route through the \
12855             same substrate-primitive typed dispatch on the :nome \
12856             empty-arm",
12857        );
12858        let c = caixa_with_nome("demo");
12859        assert!(
12860            c.validate_nome().is_ok(),
12861            "validate_nome must accept nome == \"demo\" (the canonical \
12862             DNS-1123-label template baseline)",
12863        );
12864    }
12865
12866    #[test]
12867    fn nome_projects_str_by_borrow() {
12868        // The by-borrow pin: [`Caixa::nome`] returns `&str` by borrow
12869        // — the `&str` borrows the underlying `String` storage of the
12870        // required `nome` slot and the accessor must not allocate a
12871        // fresh `String` on every call. Peer of the [`Caixa::licenca`]
12872        // (6d5bc28) / [`Caixa::repositorio`] (cc7332d) /
12873        // [`Caixa::descricao`] (3f16e2f) / [`Caixa::edicao`] (2641cbd)
12874        // by-borrow pins on the peer outer top-level [`Caixa`]
12875        // `Option<&str>`-return axes, extended onto the first outer
12876        // top-level [`Caixa`] required-`&str`-return axis — the
12877        // accessor's returned `&str` must borrow from `&self` (the
12878        // returned reference's lifetime is tied to `&self`), and
12879        // calling the accessor twice on the same [`Caixa`] must yield
12880        // the same `&str` verbatim (idempotent, no side effects on
12881        // `&self`).
12882        //
12883        // Pins against a future silent detour that returned an owned
12884        // `String` (which would type-check but silently allocate on
12885        // every call, breaking the zero-cost projection every peer
12886        // sibling accessor carries), an accidental
12887        // `.nome.to_lowercase()` detour that returned a fresh
12888        // allocation through an already-DNS-1123-lowercase-only
12889        // string (breaking a future `const fn` regression), or a
12890        // one-arm-only accessor that returned a canonicalized value
12891        // on some sentinel input (breaking the pass-through invariant
12892        // the sibling required-scalar accessors carry).
12893        for nome in ["demo", "catalog", "hello-rio", "checkout"] {
12894            let c = caixa_with_nome(nome);
12895            let first = c.nome();
12896            let second = c.nome();
12897            assert_eq!(
12898                first, second,
12899                "Caixa::nome must be idempotent — two successive calls \
12900                 on the same &self must return the same &str",
12901            );
12902            assert_eq!(
12903                first, nome,
12904                "Caixa::nome must return :nome verbatim by borrow — \
12905                 got {first}, expected {nome}",
12906            );
12907        }
12908    }
12909
12910    #[test]
12911    fn versao_returns_versao_byte_string_verbatim_across_permutations() {
12912        // The canonical per-`Caixa` `:versao` universal-axis SemVer-2
12913        // pinned-version scalar pin: [`Caixa::versao`] must return the
12914        // `:versao` typed `String` verbatim as `&str`, byte-equal to the
12915        // raw `.versao` field access across every representative value
12916        // in the accept-set — the canonical `"0.1.0"` template baseline
12917        // (the same `feira init`-scaffolded default the sibling
12918        // `validate_versao_accepts_canonical_template` positive-control
12919        // gate pins), plus every canonical SemVer-2 shape the sibling
12920        // `validate_versao_accepts_canonical_forms` positive-arm sweep
12921        // covers (`"0.0.0"`, `"1.0.0"`, `"0.2.0-rc.1"`,
12922        // `"1.0.0-alpha.0"`, `"1.0.0+build.42"`, `"1.0.0-rc.1+build.42"`,
12923        // `"10.20.30"`), plus every past-the-guard sentinel for the
12924        // `VersaoEmpty` / `VersaoInvalid` refusal cases (`""` the empty
12925        // arm, `"v0.1.0"` the git-tag-shape-leak footgun, `"0.1"` the
12926        // missing-patch footgun, `"^0.1"` the requirement-shape-leak
12927        // footgun, `"0.1.0.0"` the four-part-Java-convention footgun,
12928        // `"latest"` the docker-tag-shape footgun — the sentinels pin
12929        // the accessor doesn't silently absorb the refusal cases into a
12930        // template-derived fallback like `"0.1.0"`).
12931        //
12932        // The past-the-guard sentinels pin the accessor doesn't silently
12933        // absorb the refusal cases into a template-derived fallback (a
12934        // future `.versao().is_empty().then(|| "0.1.0")` collapse would
12935        // silently absorb the `VersaoEmpty` refusal at the accessor
12936        // boundary and the validate gate would accept a struct-literal
12937        // `Caixa { versao: "".into(), .. }` — the pin catches that at
12938        // caixa-core build time).
12939        //
12940        // Second outer top-level [`Caixa`] `&str`-return required-scalar
12941        // accessor pin — folds on the "outer [`Caixa`] `&str` required-
12942        // scalar" projection pattern the sibling per-`Caixa`
12943        // [`Caixa::nome`] (e6b7d97) opened. Sibling in shape to the peer
12944        // per-`:membros` [`crate::aplicacao::Membro::versao_requirement`]
12945        // (4127bb6) / per-`:children`
12946        // [`crate::supervisor::ChildSpec::versao_requirement`] (2c053c8)
12947        // / per-`:upgrade-from`
12948        // [`crate::UpgradeFromEntry::prior_versao`] (75d27a8) per-sub-
12949        // struct `:versao`-shaped `&str`-return accessor pins on the
12950        // sibling per-typed-slot version-carrier axes, extended onto the
12951        // second outer top-level [`Caixa`] universal-axis required-
12952        // `String`-carry axis so the two universal-axis identity-
12953        // carrying scalars every `defcaixa` form supplies (`:nome` +
12954        // `:versao`) share the same "one typed dispatch per axis" pin
12955        // discipline.
12956        for versao in [
12957            "0.1.0",
12958            "0.0.0",
12959            "1.0.0",
12960            "0.2.0-rc.1",
12961            "1.0.0-alpha.0",
12962            "1.0.0+build.42",
12963            "1.0.0-rc.1+build.42",
12964            "10.20.30",
12965            "",
12966            "v0.1.0",
12967            "0.1",
12968            "^0.1",
12969            "0.1.0.0",
12970            "latest",
12971        ] {
12972            let c = caixa_with_versao(versao);
12973            assert_eq!(
12974                c.versao(),
12975                versao,
12976                "Caixa::versao must return :versao verbatim (got {}, \
12977                 expected {versao})",
12978                c.versao(),
12979            );
12980            assert_eq!(
12981                c.versao(),
12982                c.versao.as_str(),
12983                "Caixa::versao must byte-equal the raw .versao field \
12984                 access across every value in the String accept-set",
12985            );
12986        }
12987    }
12988
12989    #[test]
12990    fn validate_versao_empty_arm_routes_through_accessor() {
12991        // Composition pin: [`Caixa::validate_versao`]'s empty-arm gate
12992        // must key off [`Caixa::versao`], not the raw `.versao` field
12993        // access. Structurally: a `Caixa { versao: "".into(), .. }` must
12994        // surface the `VersaoEmpty` refusal exactly, and the canonical
12995        // `"0.1.0"` template baseline (the peer positive-arm the sibling
12996        // `validate_versao_accepts_canonical_template` gate carves out)
12997        // must pass validate. The pair jointly pins the accessor +
12998        // validate-gate composition: any future silent detour that had
12999        // the accessor return a fresh `"0.1.0"` on the empty arm
13000        // (a `.versao().is_empty().then(|| "0.1.0")` fallback collapse)
13001        // would silently absorb the `VersaoEmpty` refusal at the
13002        // accessor boundary and the validate gate would accept a
13003        // struct-literal `Caixa { versao: "".into(), .. }` — the
13004        // composition pin catches that at caixa-core build time.
13005        //
13006        // Peer of the sibling per-`Caixa`
13007        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97)
13008        // composition pin on the sibling outer top-level [`Caixa`]
13009        // required-`&str` universal-axis surface — same "the validate /
13010        // shape-gate predicate must route through the substrate-
13011        // primitive typed dispatch" discipline extended onto the peer
13012        // outer top-level [`Caixa`] required-`&str` universal-axis
13013        // pinned-version composition axis, closing the second
13014        // coordinate of the "one canonical typed dispatch per per-Caixa
13015        // required-`&str` universal-axis" discipline.
13016        let c = caixa_with_versao("");
13017        assert!(
13018            matches!(c.validate_versao(), Err(ManifestError::VersaoEmpty)),
13019            "validate_versao must reject versao == \"\" with VersaoEmpty — \
13020             the accessor and the validate gate must route through the \
13021             same substrate-primitive typed dispatch on the :versao \
13022             empty-arm",
13023        );
13024        let c = caixa_with_versao("0.1.0");
13025        assert!(
13026            c.validate_versao().is_ok(),
13027            "validate_versao must accept versao == \"0.1.0\" (the \
13028             canonical SemVer-2 template baseline)",
13029        );
13030    }
13031
13032    #[test]
13033    fn versao_projects_str_by_borrow() {
13034        // The by-borrow pin: [`Caixa::versao`] returns `&str` by borrow
13035        // — the `&str` borrows the underlying `String` storage of the
13036        // required `versao` slot and the accessor must not allocate a
13037        // fresh `String` on every call. Peer of the [`Caixa::nome`]
13038        // (e6b7d97) by-borrow pin on the sibling outer top-level
13039        // [`Caixa`] required-`&str`-return axis, extended onto the
13040        // second outer top-level [`Caixa`] required-`&str`-return
13041        // universal-axis pinned-version surface — the accessor's
13042        // returned `&str` must borrow from `&self` (the returned
13043        // reference's lifetime is tied to `&self`), and calling the
13044        // accessor twice on the same [`Caixa`] must yield the same
13045        // `&str` verbatim (idempotent, no side effects on `&self`).
13046        //
13047        // Pins against a future silent detour that returned an owned
13048        // `String` (which would type-check but silently allocate on
13049        // every call, breaking the zero-cost projection every peer
13050        // sibling accessor carries), an accidental
13051        // `semver::Version::parse(&self.versao).unwrap().to_string()`
13052        // detour that returned a canonicalized fresh allocation through
13053        // an already-canonical byte-string (breaking a future `const fn`
13054        // regression and silently absorbing the `VersaoInvalid` refusal
13055        // at the accessor boundary), or a one-arm-only accessor that
13056        // returned a canonicalized value on some sentinel input
13057        // (breaking the pass-through invariant the sibling required-
13058        // scalar accessors carry).
13059        for versao in ["0.1.0", "1.0.0", "0.2.0-rc.1", "1.0.0+build.42"] {
13060            let c = caixa_with_versao(versao);
13061            let first = c.versao();
13062            let second = c.versao();
13063            assert_eq!(
13064                first, second,
13065                "Caixa::versao must be idempotent — two successive \
13066                 calls on the same &self must return the same &str",
13067            );
13068            assert_eq!(
13069                first, versao,
13070                "Caixa::versao must return :versao verbatim by borrow \
13071                 — got {first}, expected {versao}",
13072            );
13073        }
13074    }
13075
13076    fn caixa_with_kind(kind: CaixaKind) -> Caixa {
13077        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13078        c.kind = kind;
13079        c
13080    }
13081
13082    #[test]
13083    fn kind_returns_kind_variant_verbatim_across_permutations() {
13084        // The canonical per-`Caixa` `:kind` universal-axis closed-set-
13085        // enum discriminant pin: [`Caixa::kind`] must return the `:kind`
13086        // typed [`CaixaKind`] variant verbatim by `Copy`, byte-equal to
13087        // the raw `.kind` field access across every variant in the
13088        // closed accept-set (`Biblioteca` — the library kind that
13089        // exports lisp forms; `Binario` — the nix-built executable kind
13090        // under `exe/`; `Servico` — the wasm-component daemon kind
13091        // under `servicos/`; `Supervisor` — the OTP-shaped hierarchical
13092        // reconciliation kind; `Aplicacao` — the M3 typed-mesh
13093        // composition kind).
13094        //
13095        // Pins against a future silent detour that re-derived the kind
13096        // from a peer axis (an accidental fallback to
13097        // `if !servicos.is_empty() { Servico } else if
13098        // !membros.is_empty() { Aplicacao } else { Biblioteca }`
13099        // collapse that read the code-surface / mesh-slot columns into
13100        // the kind discriminator), a variant remap the operator
13101        // authors on one consumer without the other, or a stale-derive
13102        // detour that substituted [`CaixaKind::Biblioteca`] as the
13103        // default when the field held any other variant (which would
13104        // silently collapse the distinction between "author explicitly
13105        // declared `:kind Servico`" and "author declared any other
13106        // kind" every downstream renderer-dispatch site depends on).
13107        //
13108        // First outer top-level [`Caixa`] `Copy`-return required-enum-
13109        // discriminant accessor pin — opens the "outer [`Caixa`]
13110        // `Copy`-return required-discriminant" projection pattern.
13111        // Sibling in shape to the peer per-`:supervisor`
13112        // [`crate::supervisor::SupervisorSpec::estrategia`] (eafb619),
13113        // per-`:placement` [`crate::aplicacao::Placement::estrategia`]
13114        // (921fe1b), and per-`:children`
13115        // [`crate::supervisor::ChildSpec::restart`] (dfb4a81)
13116        // `Copy`-return closed-set-enum discriminant accessor pins on
13117        // the sibling nested-spec typed-slot discriminator axes,
13118        // extended here to the outer top-level [`Caixa`] universal-
13119        // axis surface.
13120        for kind in [
13121            CaixaKind::Biblioteca,
13122            CaixaKind::Binario,
13123            CaixaKind::Servico,
13124            CaixaKind::Supervisor,
13125            CaixaKind::Aplicacao,
13126        ] {
13127            let c = caixa_with_kind(kind);
13128            assert_eq!(
13129                c.kind(),
13130                kind,
13131                "Caixa::kind must return :kind verbatim (got {:?}, \
13132                 expected {kind:?})",
13133                c.kind(),
13134            );
13135            assert_eq!(
13136                c.kind(),
13137                c.kind,
13138                "Caixa::kind accessor and .kind field access must \
13139                 byte-equal — the accessor is the substrate-primitive \
13140                 typed dispatch every downstream kind-gate consumer \
13141                 must route through",
13142            );
13143        }
13144    }
13145
13146    #[test]
13147    fn require_kind_reads_through_lifted_kind_accessor() {
13148        // Two-consumer coherence pin: the [`crate::render::require_kind`]
13149        // entry-gate predicate (the canonical two-line
13150        // `require_kind(caixa, Servico)?` prelude every per-Servico /
13151        // per-Aplicacao renderer runs at its entry-point) and the
13152        // sibling [`crate::render::KindMismatch`] error carrier's
13153        // `actual:` field (which names the offending caixa's variant
13154        // in the diagnostic) must both key off the lifted accessor, so
13155        // any future rebrand on the typed slot's reader shape lands at
13156        // exactly one place. Pins the two-site coherence by exercising
13157        // every off-diagonal `(actual, expected)` pair across the
13158        // closed accept-set — the `KindMismatch { actual, expected }`
13159        // surfaced on the mismatch arm must byte-equal the pair the
13160        // accessor returns for each side.
13161        //
13162        // Peer of the sibling per-`:placement`
13163        // `validate_placement_reads_through_lifted_estrategia_accessor`
13164        // (921fe1b) two-arm consumer-coherence pin on the M3 mesh-slot
13165        // `Copy`-return discriminant axis — same "the entry-gate
13166        // predicate and the error carrier's `actual:` field must route
13167        // through the substrate-primitive typed dispatch" discipline
13168        // extended onto the outer top-level [`Caixa`] universal-axis
13169        // discriminant surface.
13170        for expected in [
13171            CaixaKind::Biblioteca,
13172            CaixaKind::Binario,
13173            CaixaKind::Servico,
13174            CaixaKind::Supervisor,
13175            CaixaKind::Aplicacao,
13176        ] {
13177            for actual in [
13178                CaixaKind::Biblioteca,
13179                CaixaKind::Binario,
13180                CaixaKind::Servico,
13181                CaixaKind::Supervisor,
13182                CaixaKind::Aplicacao,
13183            ] {
13184                let c = caixa_with_kind(actual);
13185                let result = crate::render::require_kind(&c, expected);
13186                if expected == actual {
13187                    assert!(
13188                        result.is_ok(),
13189                        "require_kind must accept when actual == expected \
13190                         (actual={actual:?}, expected={expected:?})",
13191                    );
13192                } else {
13193                    let err = result.expect_err("require_kind must reject when actual != expected");
13194                    assert_eq!(
13195                        err.actual,
13196                        c.kind(),
13197                        "KindMismatch.actual must byte-equal Caixa::kind() \
13198                         — the error carrier's `actual:` field reads \
13199                         through the lifted accessor",
13200                    );
13201                    assert_eq!(
13202                        err.expected, expected,
13203                        "KindMismatch.expected must byte-equal the \
13204                         expected variant passed to require_kind",
13205                    );
13206                }
13207            }
13208        }
13209    }
13210
13211    #[test]
13212    fn aplicacao_view_kind_gate_routes_through_accessor() {
13213        // Composition pin: [`Caixa::aplicacao_view`]'s kind-gate arm
13214        // must key off [`Caixa::kind`], not the raw `.kind` field
13215        // access. Structurally: a `Caixa { kind: X, .. }` for any
13216        // non-`Aplicacao` variant must fold to `None` on the
13217        // `aplicacao_view` composer (the "kind mismatch → no typed
13218        // view" contract every downstream Aplicacao consumer keys off
13219        // via `?`), and a `Caixa { kind: Aplicacao, .. }` must fold to
13220        // `Some(_)`. The pair jointly pins the accessor + view-gate
13221        // composition: any future silent detour that had the accessor
13222        // return a fresh [`CaixaKind::Aplicacao`] on some sentinel
13223        // input would silently absorb the kind-mismatch case at the
13224        // accessor boundary and every per-Aplicacao renderer would
13225        // silently render a non-Aplicacao caixa's mesh slots — the
13226        // composition pin catches that at caixa-core build time.
13227        //
13228        // Peer of the sibling per-`Caixa`
13229        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97) /
13230        // `validate_versao_empty_arm_routes_through_accessor` (20c0539)
13231        // composition pins on the sibling outer top-level [`Caixa`]
13232        // required-`&str` universal-axis surfaces — same "the
13233        // composer / validate gate must route through the substrate-
13234        // primitive typed dispatch" discipline extended onto the
13235        // outer top-level [`Caixa`] `Copy`-return required-
13236        // discriminant composition axis.
13237        for kind in [
13238            CaixaKind::Biblioteca,
13239            CaixaKind::Binario,
13240            CaixaKind::Servico,
13241            CaixaKind::Supervisor,
13242        ] {
13243            let c = caixa_with_kind(kind);
13244            assert!(
13245                c.aplicacao_view().is_none(),
13246                "aplicacao_view must return None on non-Aplicacao \
13247                 kind {kind:?} — the composer's kind-gate must route \
13248                 through Caixa::kind()",
13249            );
13250        }
13251        let c = caixa_with_kind(CaixaKind::Aplicacao);
13252        assert!(
13253            c.aplicacao_view().is_some(),
13254            "aplicacao_view must return Some on kind Aplicacao — \
13255             the composer's kind-gate must accept the matching arm \
13256             through Caixa::kind()",
13257        );
13258    }
13259
13260    #[test]
13261    fn supervisor_view_kind_gate_routes_through_accessor() {
13262        // Composition pin (mirror of the sibling
13263        // `aplicacao_view_kind_gate_routes_through_accessor` on the
13264        // second `_view` composer): [`Caixa::supervisor_view`]'s kind-
13265        // gate arm must key off [`Caixa::kind`], not the raw `.kind`
13266        // field access. A `Caixa { kind: X, .. }` for any non-
13267        // `Supervisor` variant must fold to `None` on the
13268        // `supervisor_view` composer, and a `Caixa { kind:
13269        // Supervisor, .. }` must fold to `Some(_)`. Same peer
13270        // composition pin discipline on the second `_view` composer
13271        // axis.
13272        for kind in [
13273            CaixaKind::Biblioteca,
13274            CaixaKind::Binario,
13275            CaixaKind::Servico,
13276            CaixaKind::Aplicacao,
13277        ] {
13278            let c = caixa_with_kind(kind);
13279            assert!(
13280                c.supervisor_view().is_none(),
13281                "supervisor_view must return None on non-Supervisor \
13282                 kind {kind:?} — the composer's kind-gate must route \
13283                 through Caixa::kind()",
13284            );
13285        }
13286        let mut c = caixa_with_kind(CaixaKind::Supervisor);
13287        // A Supervisor caixa needs a strategy + at least one child to
13288        // fold to a Some(_) that also validates; the composer itself
13289        // requires only the kind arm, so bare kind flip is enough to
13290        // pin the `Some(_)` return, but we populate the minimum
13291        // supervisor shape so a future strengthening of the composer
13292        // to reject an empty spec doesn't false-positive this pin.
13293        c.estrategia = Some(crate::supervisor::RestartStrategy::OneForOne);
13294        c.children = vec![crate::supervisor::ChildSpec {
13295            caixa: "child".into(),
13296            versao: "^0.1".into(),
13297            restart: crate::supervisor::RestartPolicy::Permanent,
13298        }];
13299        assert!(
13300            c.supervisor_view().is_some(),
13301            "supervisor_view must return Some on kind Supervisor — \
13302             the composer's kind-gate must accept the matching arm \
13303             through Caixa::kind()",
13304        );
13305    }
13306
13307    #[test]
13308    fn kind_projects_by_copy() {
13309        // The by-`Copy` pin: [`Caixa::kind`] returns a fresh
13310        // [`CaixaKind`] by `Copy` — the accessor must not borrow from
13311        // `&self` (the returned value is owned, `Copy`-projected from
13312        // the underlying [`CaixaKind`] storage; two calls on the same
13313        // [`Caixa`] must yield byte-equal values). Peer of the peer
13314        // per-`:placement` `Placement::estrategia` / per-`:supervisor`
13315        // `SupervisorSpec::estrategia` / per-`:children`
13316        // `ChildSpec::restart` `Copy`-return discriminant accessor
13317        // pins on the sibling nested-spec typed-slot discriminator
13318        // axes, extended onto the first outer top-level [`Caixa`]
13319        // required-`Copy`-return axis — pins against a future silent
13320        // detour that returned `&CaixaKind` (which would type-check
13321        // but silently constrain every consumer's callsite to a
13322        // borrow-shaped dispatch, breaking the zero-cost `Copy`
13323        // projection every peer sibling accessor carries).
13324        for kind in [
13325            CaixaKind::Biblioteca,
13326            CaixaKind::Binario,
13327            CaixaKind::Servico,
13328            CaixaKind::Supervisor,
13329            CaixaKind::Aplicacao,
13330        ] {
13331            let c = caixa_with_kind(kind);
13332            let first: CaixaKind = c.kind();
13333            let second: CaixaKind = c.kind();
13334            assert_eq!(
13335                first, second,
13336                "Caixa::kind must be idempotent — two successive \
13337                 calls on the same &self must return the same \
13338                 CaixaKind variant",
13339            );
13340            assert_eq!(
13341                first, kind,
13342                "Caixa::kind must return :kind verbatim by Copy — \
13343                 got {first:?}, expected {kind:?}",
13344            );
13345        }
13346    }
13347
13348    // ── Caixa::autores — outer top-level &[T] slice accessor ──────────
13349
13350    #[test]
13351    fn autores_returns_autores_slice_verbatim_across_permutations() {
13352        // The canonical per-`Caixa` `:autores` universal-axis maintainer-
13353        // name-list slice pin: [`Caixa::autores`] must return the
13354        // `:autores` typed [`Vec<String>`] list verbatim as a
13355        // `&[String]`, byte-equal to the raw `self.autores.as_slice()`
13356        // access across every representative value in the accept-set —
13357        // `[]` (the "no maintainers declared" arm every existing
13358        // fixture without an `:autores` line carries), `[""]` (a past-
13359        // the-guard sentinel that pins the accessor doesn't perform a
13360        // silent `[""] → []` collapse on the empty-entry arm — validate
13361        // rejects `[""]` through `AutorEmpty` but the accessor must
13362        // ship the raw slot verbatim so a validate-time gate regression
13363        // surfaces at the caixa-helm emit boundary rather than being
13364        // silently absorbed into a maintainer-drop), `["pleme-io"]` (the
13365        // canonical single-maintainer form every `feira init` template
13366        // scaffolds), `["alice", "bob"]` (a canonical multi-maintainer
13367        // form), `["alice <alice@example.com>", "bob <bob@example.com>"]`
13368        // (the canonical RFC-5322 `<name> <email>` form the
13369        // `is_chart_maintainer_name_shape` predicate accepts), and
13370        // `["pleme-io", "pleme-io"]` (a past-the-guard duplicate
13371        // sentinel — validate rejects through `AutorDuplicate` but the
13372        // accessor must ship the raw slot verbatim).
13373        //
13374        // First outer top-level [`Caixa`] `&[T]`-return slice accessor
13375        // pin on the substrate primitive — opens the "outer [`Caixa`]
13376        // `&[T]` slice" projection pattern the sibling per-`Caixa`
13377        // `:etiquetas` / `:deps` / `:deps-dev` / `:exe` / `:bibliotecas`
13378        // / `:servicos` / `:upgrade-from` / `:children` future lifts
13379        // fold on. Sibling in shape to the peer per-`:supervisor`
13380        // [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
13381        // per-`:placement` [`crate::aplicacao::Placement::clusters`]
13382        // (a6e18d7), per-`:membros`
13383        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
13384        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
13385        // (0dcc926), and per-`:upgrade-from :instructions`
13386        // [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
13387        // `&[T]`-return slice accessor pins on the sibling per-M2 /
13388        // per-M3 typed-slot list axes, extended onto the outer top-
13389        // level [`Caixa`] universal-axis surface. Pins against a future
13390        // silent detour that returned an owned `Vec<String>` (which
13391        // would type-check but silently clone on every accessor call,
13392        // breaking the zero-cost projection every peer sibling slice
13393        // accessor carries), a `[""] → []` collapse (which would
13394        // silently absorb the `AutorEmpty` refusal case at the accessor
13395        // boundary), or a `["a", "a"] → ["a"]` dedup collapse (which
13396        // would silently absorb the `AutorDuplicate` refusal case at
13397        // the accessor boundary and the caixa-helm `maintainers:` fold
13398        // would silently render a dedupped list on a struct-literal
13399        // `Caixa { autores: vec!["a".into(), "a".into()], .. }`).
13400        for autores in [
13401            vec![],
13402            vec![""],
13403            vec!["pleme-io"],
13404            vec!["alice", "bob"],
13405            vec!["alice <alice@example.com>", "bob <bob@example.com>"],
13406            vec!["pleme-io", "pleme-io"],
13407        ] {
13408            let c = caixa_with_autores(autores.clone());
13409            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
13410            assert_eq!(
13411                c.autores(),
13412                expected.as_slice(),
13413                "Caixa::autores must return :autores verbatim (got {:?}, \
13414                 expected {expected:?})",
13415                c.autores(),
13416            );
13417            assert_eq!(
13418                c.autores(),
13419                c.autores.as_slice(),
13420                "Caixa::autores must byte-equal the raw \
13421                 `self.autores.as_slice()` field access across every \
13422                 value in the Vec<String> accept-set",
13423            );
13424        }
13425    }
13426
13427    #[test]
13428    fn validate_autores_empty_entry_arm_routes_through_accessor() {
13429        // Composition pin: [`Caixa::validate_autores`]'s per-entry
13430        // empty-arm gate must key off [`Caixa::autores`], not the raw
13431        // `&self.autores` field-borrow walk. Structurally: a
13432        // `Caixa { autores: vec!["".into()], .. }` must surface the
13433        // `AutorEmpty` refusal exactly, and a
13434        // `Caixa { autores: vec!["pleme-io".into()], .. }` (the
13435        // canonical single-maintainer form) must pass validate. The
13436        // pair jointly pins the accessor + validate-gate composition:
13437        // any future silent detour that had the accessor return an
13438        // empty slice on the `[""]` arm (a
13439        // `.iter().filter(|s| !s.is_empty()).collect()` collapse)
13440        // would silently absorb the `AutorEmpty` refusal at the
13441        // accessor boundary and the validate gate would accept a
13442        // struct-literal `Caixa { autores: vec!["".into()], .. }` —
13443        // the composition pin catches that at caixa-core build time.
13444        //
13445        // Peer of the per-`Caixa` [`Caixa::validate_licenca`] (6d5bc28)
13446        // accessor-composition pin
13447        // (`validate_licenca_empty_arm_routes_through_accessor`) on the
13448        // sibling `Option<&str>`-composition axis and the
13449        // per-`:politicas :circuit-breaker`
13450        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
13451        // accessor-composition pin
13452        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
13453        // on the sibling required-`u32`-composition axis — same "the
13454        // validate / shape-gate predicate must route through the
13455        // substrate-primitive typed dispatch" discipline extended onto
13456        // the outer top-level [`Caixa`] universal-axis `&[T]`-
13457        // composition surface.
13458        let c = caixa_with_autores(vec![""]);
13459        assert!(
13460            matches!(c.validate_autores(), Err(ManifestError::AutorEmpty)),
13461            "validate_autores must reject autores == vec![\"\"] with \
13462             AutorEmpty — the accessor and the validate gate must \
13463             route through the same substrate-primitive typed dispatch \
13464             on the :autores per-entry empty arm",
13465        );
13466        let c = caixa_with_autores(vec!["pleme-io"]);
13467        assert!(
13468            c.validate_autores().is_ok(),
13469            "validate_autores must accept autores == vec![\"pleme-io\"] \
13470             (the canonical single-maintainer shape every `feira init` \
13471             template scaffolds)",
13472        );
13473    }
13474
13475    #[test]
13476    fn autores_projects_slice_by_borrow() {
13477        // The by-borrow pin: [`Caixa::autores`] returns `&[String]` by
13478        // borrow — the returned slice borrows the underlying
13479        // `Vec<String>` storage of the `:autores` slot and the
13480        // accessor must not clone the backing `Vec` on every call.
13481        // Peer of the per-`:membros`
13482        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36) /
13483        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
13484        // (0dcc926) / per-`:placement`
13485        // [`crate::aplicacao::Placement::clusters`] (a6e18d7) /
13486        // per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
13487        // (bc92bce) by-borrow pins on the sibling per-M2 / per-M3
13488        // typed-slot `&[T]`-return axes, extended onto the outer top-
13489        // level [`Caixa`] universal-axis `&[String]` shape — the
13490        // accessor's returned slice must borrow from `&self` (the
13491        // returned reference's lifetime is tied to `&self`), and
13492        // calling the accessor twice on the same [`Caixa`] must yield
13493        // slices that are pointer-equal (the underlying byte-buffer is
13494        // the storage `Vec`'s allocation, not a fresh copy) as well as
13495        // value-equal (idempotent, no side effects on `&self`).
13496        //
13497        // Pins against a future silent detour that returned an owned
13498        // `Vec<String>` (which would type-check but silently clone on
13499        // every call, breaking the zero-cost projection every peer
13500        // sibling slice accessor carries), a `&Vec<String>` return
13501        // (which would leak the backing `Vec`'s grow/push/reserve
13502        // surface no downstream consumer reaches for), or a one-arm-
13503        // only accessor that returned a saturating value on some
13504        // sentinel input (breaking the pass-through invariant the
13505        // sibling slice accessors carry).
13506        for autores in [
13507            vec![],
13508            vec!["pleme-io"],
13509            vec!["alice", "bob"],
13510            vec!["pleme-io", "pleme-io"],
13511        ] {
13512            let c = caixa_with_autores(autores.clone());
13513            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
13514            let first = c.autores();
13515            let second = c.autores();
13516            assert_eq!(
13517                first, second,
13518                "Caixa::autores must be idempotent — two successive \
13519                 calls on the same &self must return the same \
13520                 &[String]",
13521            );
13522            assert_eq!(
13523                first.as_ptr(),
13524                second.as_ptr(),
13525                "Caixa::autores must borrow the underlying Vec<String> \
13526                 storage — two successive calls must return slices \
13527                 with the same backing pointer (a fresh Vec<String> \
13528                 clone would change the pointer on every call)",
13529            );
13530            assert_eq!(
13531                first,
13532                expected.as_slice(),
13533                "Caixa::autores must return :autores verbatim by \
13534                 borrow — got {first:?}, expected {expected:?}",
13535            );
13536        }
13537    }
13538
13539    // ── Caixa::etiquetas — outer top-level &[T] slice accessor ────────
13540
13541    #[test]
13542    fn etiquetas_returns_etiquetas_slice_verbatim_across_permutations() {
13543        // The canonical per-`Caixa` `:etiquetas` universal-axis
13544        // registry-search-tag-list slice pin: [`Caixa::etiquetas`] must
13545        // return the `:etiquetas` typed [`Vec<String>`] list verbatim
13546        // as a `&[String]`, byte-equal to the raw
13547        // `self.etiquetas.as_slice()` access across every representative
13548        // value in the accept-set — `[]` (the "no tags declared" arm
13549        // every existing fixture without an `:etiquetas` line carries),
13550        // `[""]` (a past-the-guard sentinel that pins the accessor
13551        // doesn't perform a silent `[""] → []` collapse on the empty-
13552        // entry arm — validate rejects `[""]` through `EtiquetaEmpty`
13553        // but the accessor must ship the raw slot verbatim so a
13554        // validate-time gate regression surfaces at the caixa-helm emit
13555        // boundary rather than being silently absorbed into a keyword-
13556        // drop), `["demo"]` (the canonical single-tag form every
13557        // `feira init` template scaffolds), `["example", "aplicacao",
13558        // "mesh", "ecommerce", "demo"]` (the canonical multi-tag form
13559        // the checkout-aplicacao fixture emits), and `["demo", "demo"]`
13560        // (a past-the-guard duplicate sentinel — validate rejects
13561        // through `EtiquetaDuplicate` but the accessor must ship the
13562        // raw slot verbatim so the caixa-helm `BTreeSet::collect` dedup
13563        // at chart-render time isn't silently promoted into the
13564        // accessor boundary and struct-literal
13565        // `Caixa { etiquetas: vec!["demo".into(), "demo".into()], .. }`
13566        // fixtures continue to expose the duplicate at the accessor).
13567        //
13568        // Second outer top-level [`Caixa`] `&[T]`-return slice accessor
13569        // pin on the substrate primitive — folds on the "outer
13570        // [`Caixa`] `&[T]` slice" projection pattern
13571        // `autores_returns_autores_slice_verbatim_across_permutations`
13572        // (b5d813f) opened, sibling in shape and idiom. Pins against a
13573        // future silent detour that returned an owned `Vec<String>`
13574        // (which would type-check but silently clone on every accessor
13575        // call, breaking the zero-cost projection every peer sibling
13576        // slice accessor carries), a `[""] → []` collapse (which would
13577        // silently absorb the `EtiquetaEmpty` refusal case at the
13578        // accessor boundary), or a `["a", "a"] → ["a"]` dedup collapse
13579        // (which would silently absorb the `EtiquetaDuplicate` refusal
13580        // case at the accessor boundary — the caixa-helm chart-render
13581        // `BTreeSet::collect` dedup is downstream of the accessor and
13582        // must not be silently promoted into it).
13583        for etiquetas in [
13584            vec![],
13585            vec![""],
13586            vec!["demo"],
13587            vec!["example", "aplicacao", "mesh", "ecommerce", "demo"],
13588            vec!["demo", "demo"],
13589        ] {
13590            let c = caixa_with_etiquetas(etiquetas.clone());
13591            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
13592            assert_eq!(
13593                c.etiquetas(),
13594                expected.as_slice(),
13595                "Caixa::etiquetas must return :etiquetas verbatim (got \
13596                 {:?}, expected {expected:?})",
13597                c.etiquetas(),
13598            );
13599            assert_eq!(
13600                c.etiquetas(),
13601                c.etiquetas.as_slice(),
13602                "Caixa::etiquetas must byte-equal the raw \
13603                 `self.etiquetas.as_slice()` field access across every \
13604                 value in the Vec<String> accept-set",
13605            );
13606        }
13607    }
13608
13609    #[test]
13610    fn validate_etiquetas_empty_entry_arm_routes_through_accessor() {
13611        // Composition pin: [`Caixa::validate_etiquetas`]'s per-entry
13612        // empty-arm gate must key off [`Caixa::etiquetas`], not the raw
13613        // `&self.etiquetas` field-borrow walk. Structurally: a
13614        // `Caixa { etiquetas: vec!["".into()], .. }` must surface the
13615        // `EtiquetaEmpty` refusal exactly, and a
13616        // `Caixa { etiquetas: vec!["demo".into()], .. }` (the canonical
13617        // single-tag form) must pass validate. The pair jointly pins
13618        // the accessor + validate-gate composition: any future silent
13619        // detour that had the accessor return an empty slice on the
13620        // `[""]` arm (a
13621        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
13622        // silently absorb the `EtiquetaEmpty` refusal at the accessor
13623        // boundary and the validate gate would accept a struct-literal
13624        // `Caixa { etiquetas: vec!["".into()], .. }` — the composition
13625        // pin catches that at caixa-core build time.
13626        //
13627        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
13628        // through_accessor` (b5d813f) accessor-composition pin on the
13629        // sibling `&[T]`-composition axis — same "the validate / shape-
13630        // gate predicate must route through the substrate-primitive
13631        // typed dispatch" discipline extended onto the sibling outer
13632        // top-level [`Caixa`] `&[T]`-composition surface.
13633        let c = caixa_with_etiquetas(vec![""]);
13634        assert!(
13635            matches!(c.validate_etiquetas(), Err(ManifestError::EtiquetaEmpty)),
13636            "validate_etiquetas must reject etiquetas == vec![\"\"] \
13637             with EtiquetaEmpty — the accessor and the validate gate \
13638             must route through the same substrate-primitive typed \
13639             dispatch on the :etiquetas per-entry empty arm",
13640        );
13641        let c = caixa_with_etiquetas(vec!["demo"]);
13642        assert!(
13643            c.validate_etiquetas().is_ok(),
13644            "validate_etiquetas must accept etiquetas == vec![\"demo\"] \
13645             (the canonical single-tag shape every `feira init` \
13646             template scaffolds)",
13647        );
13648    }
13649
13650    #[test]
13651    fn etiquetas_projects_slice_by_borrow() {
13652        // The by-borrow pin: [`Caixa::etiquetas`] returns `&[String]`
13653        // by borrow — the returned slice borrows the underlying
13654        // `Vec<String>` storage of the `:etiquetas` slot and the
13655        // accessor must not clone the backing `Vec` on every call.
13656        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
13657        // (b5d813f) by-borrow pin on the sibling outer top-level
13658        // [`Caixa`] `&[String]`-return axis — the accessor's returned
13659        // slice must borrow from `&self` (the returned reference's
13660        // lifetime is tied to `&self`), and calling the accessor twice
13661        // on the same [`Caixa`] must yield slices that are pointer-
13662        // equal (the underlying byte-buffer is the storage `Vec`'s
13663        // allocation, not a fresh copy) as well as value-equal
13664        // (idempotent, no side effects on `&self`).
13665        //
13666        // Pins against a future silent detour that returned an owned
13667        // `Vec<String>` (which would type-check but silently clone on
13668        // every call, breaking the zero-cost projection every peer
13669        // sibling slice accessor carries), a `&Vec<String>` return
13670        // (which would leak the backing `Vec`'s grow/push/reserve
13671        // surface no downstream consumer reaches for), or a one-arm-
13672        // only accessor that returned a saturating value on some
13673        // sentinel input (breaking the pass-through invariant the
13674        // sibling slice accessors carry).
13675        for etiquetas in [
13676            vec![],
13677            vec!["demo"],
13678            vec!["example", "aplicacao", "mesh"],
13679            vec!["demo", "demo"],
13680        ] {
13681            let c = caixa_with_etiquetas(etiquetas.clone());
13682            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
13683            let first = c.etiquetas();
13684            let second = c.etiquetas();
13685            assert_eq!(
13686                first, second,
13687                "Caixa::etiquetas must be idempotent — two successive \
13688                 calls on the same &self must return the same \
13689                 &[String]",
13690            );
13691            assert_eq!(
13692                first.as_ptr(),
13693                second.as_ptr(),
13694                "Caixa::etiquetas must borrow the underlying \
13695                 Vec<String> storage — two successive calls must \
13696                 return slices with the same backing pointer (a fresh \
13697                 Vec<String> clone would change the pointer on every \
13698                 call)",
13699            );
13700            assert_eq!(
13701                first,
13702                expected.as_slice(),
13703                "Caixa::etiquetas must return :etiquetas verbatim by \
13704                 borrow — got {first:?}, expected {expected:?}",
13705            );
13706        }
13707    }
13708
13709    // ── Caixa::bibliotecas — outer top-level &[T] slice accessor ──────
13710
13711    #[test]
13712    fn bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations() {
13713        // The canonical per-`Caixa` `:bibliotecas` universal-axis
13714        // library-source-path-list slice pin: [`Caixa::bibliotecas`]
13715        // must return the `:bibliotecas` typed [`Vec<String>`] list
13716        // verbatim as a `&[String]`, byte-equal to the raw
13717        // `self.bibliotecas.as_slice()` access across every
13718        // representative value in the accept-set — `[]` (the "no
13719        // libraries declared" arm every `:kind` other than `Biblioteca`
13720        // + every `Biblioteca` relying on the canonical
13721        // `lib/<nome>.lisp` implicit-default path carries; the
13722        // layout's [`crate::LayoutInvariants`] `MissingLib` arm-gate
13723        // fires exactly on this empty-slot + `Biblioteca`-kind
13724        // combination), `[""]` (a past-the-guard sentinel that pins
13725        // the accessor doesn't perform a silent `[""] → []` collapse
13726        // on the empty-entry arm — validate rejects `[""]` through
13727        // `CodePathEmpty { slot: ":bibliotecas" }` but the accessor
13728        // must ship the raw slot verbatim so a validate-time gate
13729        // regression surfaces at the `feira build` phase-1 parse
13730        // boundary rather than being silently absorbed into a
13731        // library-drop), `["lib/demo.lisp"]` (the canonical single-
13732        // entry form `Caixa::template` scaffolds and every `feira init`
13733        // template emits), `["lib/demo.lisp", "lib/helpers.lisp"]`
13734        // (the canonical multi-library form the
13735        // `validate_code_paths_accepts_explicit_relative_paths_on_
13736        // every_slot` fixture emits), and `["lib/foo.lisp",
13737        // "lib/foo.lisp"]` (a past-the-guard duplicate sentinel —
13738        // validate rejects through `CodePathDuplicate { slot:
13739        // ":bibliotecas" }` per the per-slot set-not-multiset gate,
13740        // but the accessor must ship the raw slot verbatim so the
13741        // `feira build` `for entry in caixa.bibliotecas()` parse walk
13742        // sees the duplicate at the accessor boundary and struct-
13743        // literal `Caixa { bibliotecas: vec!["lib/foo.lisp".into(),
13744        // "lib/foo.lisp".into()], .. }` fixtures continue to expose
13745        // the duplicate at the accessor).
13746        //
13747        // Third outer top-level [`Caixa`] `&[T]`-return slice accessor
13748        // pin on the substrate primitive — folds on the "outer
13749        // [`Caixa`] `&[T]` slice" projection pattern
13750        // `autores_returns_autores_slice_verbatim_across_permutations`
13751        // (b5d813f) opened and
13752        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
13753        // (78c7d3c) folded on, sibling in shape and idiom. Pins
13754        // against a future silent detour that returned an owned
13755        // `Vec<String>` (which would type-check but silently clone on
13756        // every accessor call, breaking the zero-cost projection
13757        // every peer sibling slice accessor carries), a `[""] → []`
13758        // collapse (which would silently absorb the `CodePathEmpty`
13759        // refusal case at the accessor boundary), or a `["lib/foo.lisp",
13760        // "lib/foo.lisp"] → ["lib/foo.lisp"]` dedup collapse (which
13761        // would silently absorb the `CodePathDuplicate` refusal case
13762        // at the accessor boundary — the per-slot set-not-multiset
13763        // gate is downstream of the accessor and must not be silently
13764        // promoted into it).
13765        for bibliotecas in [
13766            vec![],
13767            vec![""],
13768            vec!["lib/demo.lisp"],
13769            vec!["lib/demo.lisp", "lib/helpers.lisp"],
13770            vec!["lib/foo.lisp", "lib/foo.lisp"],
13771        ] {
13772            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
13773            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
13774            assert_eq!(
13775                c.bibliotecas(),
13776                expected.as_slice(),
13777                "Caixa::bibliotecas must return :bibliotecas verbatim \
13778                 (got {:?}, expected {expected:?})",
13779                c.bibliotecas(),
13780            );
13781            assert_eq!(
13782                c.bibliotecas(),
13783                c.bibliotecas.as_slice(),
13784                "Caixa::bibliotecas must byte-equal the raw \
13785                 `self.bibliotecas.as_slice()` field access across \
13786                 every value in the Vec<String> accept-set",
13787            );
13788        }
13789    }
13790
13791    #[test]
13792    fn validate_code_paths_bibliotecas_empty_arm_routes_through_accessor() {
13793        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
13794        // empty-arm gate on the `:bibliotecas` slot must key off
13795        // [`Caixa::bibliotecas`], not a divergent raw
13796        // `&self.bibliotecas` field-borrow walk. Structurally: a
13797        // `Caixa { bibliotecas: vec!["".into()], .. }` must surface
13798        // the `CodePathEmpty { slot: ":bibliotecas" }` refusal
13799        // exactly, and a `Caixa { bibliotecas: vec!["lib/demo.lisp".
13800        // into()], .. }` (the canonical single-library form
13801        // `Caixa::template` scaffolds) must pass validate. The pair
13802        // jointly pins the accessor + validate-gate composition: any
13803        // future silent detour that had the accessor return an empty
13804        // slice on the `[""]` arm (a `.iter().filter(|s|
13805        // !s.is_empty()).collect()` collapse) would silently absorb
13806        // the `CodePathEmpty` refusal at the accessor boundary and
13807        // the validate gate would accept a struct-literal
13808        // `Caixa { bibliotecas: vec!["".into()], .. }` — the
13809        // composition pin catches that at caixa-core build time.
13810        //
13811        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
13812        // through_accessor` (b5d813f) and
13813        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
13814        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
13815        // composition axes — same "the validate / shape-gate
13816        // predicate must route through the substrate-primitive typed
13817        // dispatch" discipline extended onto the sibling outer top-
13818        // level [`Caixa`] `&[T]`-composition surface. Nominally the
13819        // in-tree `validate_code_paths` production body still keys
13820        // off the internal `[(":bibliotecas", &self.bibliotecas,
13821        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
13822        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
13823        // (the tuple's homogeneous slice-typed shape blocks a per-
13824        // element accessor swap in isolation — a future companion
13825        // lift for `:exe` and `:servicos` on the same outer-`Caixa`
13826        // `&[T]` slice-accessor axis closes that tuple onto the
13827        // triple of typed dispatches as a unit); the composition pin
13828        // catches any future accessor-side silent filter drop against
13829        // that eventual tuple-closure regardless of whether the
13830        // `:bibliotecas` slot is threaded through the accessor or the
13831        // raw field access at the tuple's construction site.
13832        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
13833        assert!(
13834            matches!(
13835                c.validate_code_paths(),
13836                Err(ManifestError::CodePathEmpty {
13837                    slot: ":bibliotecas"
13838                })
13839            ),
13840            "validate_code_paths must reject bibliotecas == vec![\"\"] \
13841             with CodePathEmpty {{ slot: \":bibliotecas\" }} — the \
13842             accessor and the validate gate must route through the \
13843             same substrate-primitive typed dispatch on the \
13844             :bibliotecas per-entry empty arm",
13845        );
13846        let c = caixa_with_code_paths(vec!["lib/demo.lisp"], vec![], vec![]);
13847        assert!(
13848            c.validate_code_paths().is_ok(),
13849            "validate_code_paths must accept bibliotecas == \
13850             vec![\"lib/demo.lisp\"] (the canonical single-library \
13851             shape every `feira init` template scaffolds)",
13852        );
13853    }
13854
13855    #[test]
13856    fn bibliotecas_projects_slice_by_borrow() {
13857        // The by-borrow pin: [`Caixa::bibliotecas`] returns
13858        // `&[String]` by borrow — the returned slice borrows the
13859        // underlying `Vec<String>` storage of the `:bibliotecas` slot
13860        // and the accessor must not clone the backing `Vec` on every
13861        // call. Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
13862        // (b5d813f) and `etiquetas_projects_slice_by_borrow` (78c7d3c)
13863        // by-borrow pins on the sibling outer top-level [`Caixa`]
13864        // `&[String]`-return axes — the accessor's returned slice
13865        // must borrow from `&self` (the returned reference's lifetime
13866        // is tied to `&self`), and calling the accessor twice on the
13867        // same [`Caixa`] must yield slices that are pointer-equal
13868        // (the underlying byte-buffer is the storage `Vec`'s
13869        // allocation, not a fresh copy) as well as value-equal
13870        // (idempotent, no side effects on `&self`).
13871        //
13872        // Pins against a future silent detour that returned an owned
13873        // `Vec<String>` (which would type-check but silently clone on
13874        // every call, breaking the zero-cost projection every peer
13875        // sibling slice accessor carries), a `&Vec<String>` return
13876        // (which would leak the backing `Vec`'s grow/push/reserve
13877        // surface no downstream consumer reaches for), or a one-arm-
13878        // only accessor that returned a saturating value on some
13879        // sentinel input (breaking the pass-through invariant the
13880        // sibling slice accessors carry).
13881        for bibliotecas in [
13882            vec![],
13883            vec!["lib/demo.lisp"],
13884            vec!["lib/demo.lisp", "lib/helpers.lisp"],
13885            vec!["lib/foo.lisp", "lib/foo.lisp"],
13886        ] {
13887            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
13888            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
13889            let first = c.bibliotecas();
13890            let second = c.bibliotecas();
13891            assert_eq!(
13892                first, second,
13893                "Caixa::bibliotecas must be idempotent — two \
13894                 successive calls on the same &self must return the \
13895                 same &[String]",
13896            );
13897            assert_eq!(
13898                first.as_ptr(),
13899                second.as_ptr(),
13900                "Caixa::bibliotecas must borrow the underlying \
13901                 Vec<String> storage — two successive calls must \
13902                 return slices with the same backing pointer (a \
13903                 fresh Vec<String> clone would change the pointer on \
13904                 every call)",
13905            );
13906            assert_eq!(
13907                first,
13908                expected.as_slice(),
13909                "Caixa::bibliotecas must return :bibliotecas verbatim \
13910                 by borrow — got {first:?}, expected {expected:?}",
13911            );
13912        }
13913    }
13914
13915    // ── Caixa::exe — outer top-level &[T] slice accessor ──────────────
13916
13917    #[test]
13918    fn exe_returns_exe_slice_verbatim_across_permutations() {
13919        // The canonical per-`Caixa` `:exe` universal-axis
13920        // nix-built-executable-entry-path-list slice pin: [`Caixa::exe`]
13921        // must return the `:exe` typed [`Vec<String>`] list verbatim as
13922        // a `&[String]`, byte-equal to the raw `self.exe.as_slice()`
13923        // access across every representative value in the accept-set —
13924        // `[]` (the "no executable declared" arm every `:kind` other
13925        // than `Binario` carries; the layout's [`crate::LayoutInvariants`]
13926        // `BinarioWithoutExe` arm-gate fires exactly on this empty-slot
13927        // + `Binario`-kind combination), `[""]` (a past-the-guard
13928        // sentinel that pins the accessor doesn't perform a silent
13929        // `[""] → []` collapse on the empty-entry arm — validate rejects
13930        // `[""]` through `CodePathEmpty { slot: ":exe" }` but the
13931        // accessor must ship the raw slot verbatim so a validate-time
13932        // gate regression surfaces at the layout / `feira nix` boundary
13933        // rather than being silently absorbed into an executable-drop),
13934        // `["exe/cli"]` (the canonical single-entry Binario form every
13935        // in-tree `caixa_with_code_paths` positive control uses),
13936        // `["exe/cli", "exe/serve"]` (the canonical multi-executable
13937        // form the `validate_code_paths_accepts_explicit_relative_paths_
13938        // on_every_slot` fixture emits), and `["exe/cli", "exe/cli"]`
13939        // (a past-the-guard duplicate sentinel — validate rejects
13940        // through `CodePathDuplicate { slot: ":exe" }` per the per-slot
13941        // set-not-multiset gate, but the accessor must ship the raw
13942        // slot verbatim so struct-literal `Caixa { exe: vec!["exe/cli".
13943        // into(), "exe/cli".into()], .. }` fixtures continue to expose
13944        // the duplicate at the accessor).
13945        //
13946        // Fourth outer top-level [`Caixa`] `&[T]`-return slice accessor
13947        // pin on the substrate primitive — folds on the "outer
13948        // [`Caixa`] `&[T]` slice" projection pattern
13949        // `autores_returns_autores_slice_verbatim_across_permutations`
13950        // (b5d813f) opened,
13951        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
13952        // (78c7d3c) folded on, and
13953        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
13954        // (8a36c23) closed the universal-axis text-tag family of.
13955        // Opens the outer-`Caixa` foreign-code-slot `&[T]` sub-family
13956        // the sibling `:servicos` future lift closes onto. Pins against
13957        // a future silent detour that returned an owned `Vec<String>`
13958        // (which would type-check but silently clone on every accessor
13959        // call, breaking the zero-cost projection every peer sibling
13960        // slice accessor carries), a `[""] → []` collapse (which would
13961        // silently absorb the `CodePathEmpty` refusal case at the
13962        // accessor boundary), or an `["exe/cli", "exe/cli"] →
13963        // ["exe/cli"]` dedup collapse (which would silently absorb the
13964        // `CodePathDuplicate` refusal case at the accessor boundary —
13965        // the per-slot set-not-multiset gate is downstream of the
13966        // accessor and must not be silently promoted into it).
13967        for exe in [
13968            vec![],
13969            vec![""],
13970            vec!["exe/cli"],
13971            vec!["exe/cli", "exe/serve"],
13972            vec!["exe/cli", "exe/cli"],
13973        ] {
13974            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
13975            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
13976            assert_eq!(
13977                c.exe(),
13978                expected.as_slice(),
13979                "Caixa::exe must return :exe verbatim (got {:?}, \
13980                 expected {expected:?})",
13981                c.exe(),
13982            );
13983            assert_eq!(
13984                c.exe(),
13985                c.exe.as_slice(),
13986                "Caixa::exe must byte-equal the raw \
13987                 `self.exe.as_slice()` field access across every value \
13988                 in the Vec<String> accept-set",
13989            );
13990        }
13991    }
13992
13993    #[test]
13994    fn validate_code_paths_exe_empty_arm_routes_through_accessor() {
13995        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
13996        // empty-arm gate on the `:exe` slot must key off
13997        // [`Caixa::exe`], not a divergent raw `&self.exe` field-borrow
13998        // walk. Structurally: a `Caixa { exe: vec!["".into()], .. }`
13999        // must surface the `CodePathEmpty { slot: ":exe" }` refusal
14000        // exactly, and a `Caixa { exe: vec!["exe/cli".into()], .. }`
14001        // (the canonical single-executable form every in-tree
14002        // `caixa_with_code_paths` positive control uses) must pass
14003        // validate. The pair jointly pins the accessor + validate-gate
14004        // composition: any future silent detour that had the accessor
14005        // return an empty slice on the `[""]` arm (a
14006        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
14007        // silently absorb the `CodePathEmpty` refusal at the accessor
14008        // boundary and the validate gate would accept a struct-literal
14009        // `Caixa { exe: vec!["".into()], .. }` — the composition pin
14010        // catches that at caixa-core build time.
14011        //
14012        // Peer of the per-`Caixa`
14013        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
14014        // (8a36c23), `validate_autores_empty_arm_routes_through_accessor`
14015        // (b5d813f), and
14016        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
14017        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
14018        // composition axes — same "the validate / shape-gate predicate
14019        // must route through the substrate-primitive typed dispatch"
14020        // discipline extended onto the sibling outer top-level [`Caixa`]
14021        // `&[T]`-composition surface. Nominally the in-tree
14022        // `validate_code_paths` production body still keys off the
14023        // internal `[(":bibliotecas", &self.bibliotecas,
14024        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
14025        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
14026        // (the tuple's homogeneous slice-typed shape blocks a per-
14027        // element accessor swap in isolation — a future companion lift
14028        // for `:servicos` on the same outer-`Caixa` `&[T]` slice-
14029        // accessor axis closes that tuple onto the triple of typed
14030        // dispatches as a unit); the composition pin catches any future
14031        // accessor-side silent filter drop against that eventual tuple-
14032        // closure regardless of whether the `:exe` slot is threaded
14033        // through the accessor or the raw field access at the tuple's
14034        // construction site.
14035        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
14036        assert!(
14037            matches!(
14038                c.validate_code_paths(),
14039                Err(ManifestError::CodePathEmpty { slot: ":exe" })
14040            ),
14041            "validate_code_paths must reject exe == vec![\"\"] \
14042             with CodePathEmpty {{ slot: \":exe\" }} — the \
14043             accessor and the validate gate must route through the \
14044             same substrate-primitive typed dispatch on the \
14045             :exe per-entry empty arm",
14046        );
14047        let c = caixa_with_code_paths(vec![], vec!["exe/cli"], vec![]);
14048        assert!(
14049            c.validate_code_paths().is_ok(),
14050            "validate_code_paths must accept exe == vec![\"exe/cli\"] \
14051             (the canonical single-executable shape every in-tree \
14052             `caixa_with_code_paths` positive control uses)",
14053        );
14054    }
14055
14056    #[test]
14057    fn exe_projects_slice_by_borrow() {
14058        // The by-borrow pin: [`Caixa::exe`] returns `&[String]` by
14059        // borrow — the returned slice borrows the underlying
14060        // `Vec<String>` storage of the `:exe` slot and the accessor
14061        // must not clone the backing `Vec` on every call. Peer of the
14062        // per-`Caixa` `autores_projects_slice_by_borrow` (b5d813f),
14063        // `etiquetas_projects_slice_by_borrow` (78c7d3c), and
14064        // `bibliotecas_projects_slice_by_borrow` (8a36c23) by-borrow
14065        // pins on the sibling outer top-level [`Caixa`] `&[String]`-
14066        // return axes — the accessor's returned slice must borrow from
14067        // `&self` (the returned reference's lifetime is tied to
14068        // `&self`), and calling the accessor twice on the same
14069        // [`Caixa`] must yield slices that are pointer-equal (the
14070        // underlying byte-buffer is the storage `Vec`'s allocation,
14071        // not a fresh copy) as well as value-equal (idempotent, no
14072        // side effects on `&self`).
14073        //
14074        // Pins against a future silent detour that returned an owned
14075        // `Vec<String>` (which would type-check but silently clone on
14076        // every call, breaking the zero-cost projection every peer
14077        // sibling slice accessor carries), a `&Vec<String>` return
14078        // (which would leak the backing `Vec`'s grow/push/reserve
14079        // surface no downstream consumer reaches for), or a one-arm-
14080        // only accessor that returned a saturating value on some
14081        // sentinel input (breaking the pass-through invariant the
14082        // sibling slice accessors carry).
14083        for exe in [
14084            vec![],
14085            vec!["exe/cli"],
14086            vec!["exe/cli", "exe/serve"],
14087            vec!["exe/cli", "exe/cli"],
14088        ] {
14089            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
14090            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
14091            let first = c.exe();
14092            let second = c.exe();
14093            assert_eq!(
14094                first, second,
14095                "Caixa::exe must be idempotent — two successive calls \
14096                 on the same &self must return the same &[String]",
14097            );
14098            assert_eq!(
14099                first.as_ptr(),
14100                second.as_ptr(),
14101                "Caixa::exe must borrow the underlying Vec<String> \
14102                 storage — two successive calls must return slices \
14103                 with the same backing pointer (a fresh Vec<String> \
14104                 clone would change the pointer on every call)",
14105            );
14106            assert_eq!(
14107                first,
14108                expected.as_slice(),
14109                "Caixa::exe must return :exe verbatim by borrow — \
14110                 got {first:?}, expected {expected:?}",
14111            );
14112        }
14113    }
14114
14115    // ── Caixa::servicos — outer top-level &[T] slice accessor ─────────
14116
14117    #[test]
14118    fn servicos_returns_servicos_slice_verbatim_across_permutations() {
14119        // The canonical per-`Caixa` `:servicos` universal-axis
14120        // ComputeUnit-CR-YAML-entry-path-list slice pin:
14121        // [`Caixa::servicos`] must return the `:servicos` typed
14122        // [`Vec<String>`] list verbatim as a `&[String]`, byte-equal to
14123        // the raw `self.servicos.as_slice()` access across every
14124        // representative value in the accept-set — `[]` (the "no
14125        // ComputeUnit-CR declared" arm every `:kind` other than
14126        // `Servico` carries; the layout's [`crate::LayoutInvariants`]
14127        // `ServicoWithoutServicos` arm-gate fires exactly on this
14128        // empty-slot + `Servico`-kind combination), `[""]` (a past-the-
14129        // guard sentinel that pins the accessor doesn't perform a
14130        // silent `[""] → []` collapse on the empty-entry arm — validate
14131        // rejects `[""]` through `CodePathEmpty { slot: ":servicos" }`
14132        // but the accessor must ship the raw slot verbatim so a
14133        // validate-time gate regression surfaces at the layout /
14134        // per-Servico renderer boundary rather than being silently
14135        // absorbed into a component-drop),
14136        // `["servicos/demo.computeunit.yaml"]` (the canonical
14137        // singleton V0-shape every in-tree `caixa_with_code_paths`
14138        // positive control uses; the same shape
14139        // [`crate::require_single_servico`] admits),
14140        // `["servicos/a.computeunit.yaml", "servicos/b.computeunit.
14141        // yaml"]` (a past-the-guard `len != 1` sentinel — the V0
14142        // singularity gate rejects through `ServicoCountMismatch
14143        // { count: 2 }` but the accessor must ship the raw slot
14144        // verbatim so struct-literal `Caixa { servicos: vec![...,
14145        // ...], .. }` fixtures continue to expose the count at the
14146        // accessor), and `["servicos/a.computeunit.yaml",
14147        // "servicos/a.computeunit.yaml"]` (a past-the-guard duplicate
14148        // sentinel — validate rejects through
14149        // `CodePathDuplicate { slot: ":servicos" }` per the per-slot
14150        // set-not-multiset gate, but the accessor must ship the raw
14151        // slot verbatim so struct-literal fixtures continue to expose
14152        // the duplicate at the accessor).
14153        //
14154        // Fifth and final outer top-level [`Caixa`] `&[T]`-return
14155        // slice accessor pin on the substrate primitive — folds on the
14156        // "outer [`Caixa`] `&[T]` slice" projection pattern
14157        // `autores_returns_autores_slice_verbatim_across_permutations`
14158        // (b5d813f) opened,
14159        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
14160        // (78c7d3c) folded on,
14161        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
14162        // (8a36c23) closed the universal-axis text-tag family of, and
14163        // `exe_returns_exe_slice_verbatim_across_permutations`
14164        // (65d9527) opened the foreign-code-slot sub-family of. Closes
14165        // the outer-`Caixa` foreign-code-slot `&[T]` sub-family — the
14166        // trio of code-surface list slots (`:bibliotecas` + `:exe` +
14167        // `:servicos`) now each carries a substrate-canonical slice
14168        // accessor. Pins against a future silent detour that returned
14169        // an owned `Vec<String>` (which would type-check but silently
14170        // clone on every accessor call, breaking the zero-cost
14171        // projection every peer sibling slice accessor carries), a
14172        // `[""] → []` collapse (which would silently absorb the
14173        // `CodePathEmpty` refusal case at the accessor boundary), an
14174        // `[a, a] → [a]` dedup collapse (which would silently absorb
14175        // the `CodePathDuplicate` refusal case at the accessor
14176        // boundary — the per-slot set-not-multiset gate is downstream
14177        // of the accessor and must not be silently promoted into it),
14178        // or a `[a, b] → [a]` singleton collapse (which would silently
14179        // absorb the V0 `ServicoCountMismatch` refusal case at the
14180        // accessor boundary — the V0 singularity gate is downstream of
14181        // the accessor and must not be silently promoted into it).
14182        for servicos in [
14183            vec![],
14184            vec![""],
14185            vec!["servicos/demo.computeunit.yaml"],
14186            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
14187            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
14188        ] {
14189            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
14190            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
14191            assert_eq!(
14192                c.servicos(),
14193                expected.as_slice(),
14194                "Caixa::servicos must return :servicos verbatim (got \
14195                 {:?}, expected {expected:?})",
14196                c.servicos(),
14197            );
14198            assert_eq!(
14199                c.servicos(),
14200                c.servicos.as_slice(),
14201                "Caixa::servicos must byte-equal the raw \
14202                 `self.servicos.as_slice()` field access across every \
14203                 value in the Vec<String> accept-set",
14204            );
14205        }
14206    }
14207
14208    #[test]
14209    fn validate_code_paths_servicos_empty_arm_routes_through_accessor() {
14210        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
14211        // empty-arm gate on the `:servicos` slot must key off
14212        // [`Caixa::servicos`], not a divergent raw `&self.servicos`
14213        // field-borrow walk. Structurally: a `Caixa { servicos:
14214        // vec!["".into()], .. }` must surface the `CodePathEmpty
14215        // { slot: ":servicos" }` refusal exactly, and a `Caixa
14216        // { servicos: vec!["servicos/demo.computeunit.yaml".into()],
14217        // .. }` (the canonical singleton V0-shape every in-tree
14218        // `caixa_with_code_paths` positive control uses) must pass
14219        // validate. The pair jointly pins the accessor + validate-gate
14220        // composition: any future silent detour that had the accessor
14221        // return an empty slice on the `[""]` arm (a `.iter().filter
14222        // (|s| !s.is_empty()).collect()` collapse) would silently
14223        // absorb the `CodePathEmpty` refusal at the accessor boundary
14224        // and the validate gate would accept a struct-literal
14225        // `Caixa { servicos: vec!["".into()], .. }` — the composition
14226        // pin catches that at caixa-core build time.
14227        //
14228        // Peer of the per-`Caixa`
14229        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
14230        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
14231        // (65d9527), `validate_autores_empty_arm_routes_through_accessor`
14232        // (b5d813f), and
14233        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
14234        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
14235        // composition axes — same "the validate / shape-gate predicate
14236        // must route through the substrate-primitive typed dispatch"
14237        // discipline extended onto the sibling outer top-level
14238        // [`Caixa`] `&[T]`-composition surface, closing the trio of
14239        // code-surface accessor-composition pins on the same axis.
14240        // Nominally the in-tree `validate_code_paths` production body
14241        // still keys off the internal
14242        // `[(":bibliotecas", &self.bibliotecas,
14243        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
14244        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
14245        // (the tuple's homogeneous `&Vec<String>`-typed shape blocks a
14246        // per-element accessor swap in isolation — a future companion
14247        // lift promotes the tuple's element type to `&[String]` and
14248        // threads the triple of typed dispatches through as a unit);
14249        // the composition pin catches any future accessor-side silent
14250        // filter drop against that eventual tuple-closure regardless
14251        // of whether the `:servicos` slot is threaded through the
14252        // accessor or the raw field access at the tuple's construction
14253        // site.
14254        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
14255        assert!(
14256            matches!(
14257                c.validate_code_paths(),
14258                Err(ManifestError::CodePathEmpty { slot: ":servicos" })
14259            ),
14260            "validate_code_paths must reject servicos == vec![\"\"] \
14261             with CodePathEmpty {{ slot: \":servicos\" }} — the \
14262             accessor and the validate gate must route through the \
14263             same substrate-primitive typed dispatch on the \
14264             :servicos per-entry empty arm",
14265        );
14266        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.computeunit.yaml"]);
14267        assert!(
14268            c.validate_code_paths().is_ok(),
14269            "validate_code_paths must accept servicos == \
14270             vec![\"servicos/demo.computeunit.yaml\"] (the canonical \
14271             singleton V0-shape every in-tree `caixa_with_code_paths` \
14272             positive control uses)",
14273        );
14274    }
14275
14276    #[test]
14277    fn servicos_projects_slice_by_borrow() {
14278        // The by-borrow pin: [`Caixa::servicos`] returns `&[String]` by
14279        // borrow — the returned slice borrows the underlying
14280        // `Vec<String>` storage of the `:servicos` slot and the
14281        // accessor must not clone the backing `Vec` on every call.
14282        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
14283        // (b5d813f), `etiquetas_projects_slice_by_borrow` (78c7d3c),
14284        // `bibliotecas_projects_slice_by_borrow` (8a36c23), and
14285        // `exe_projects_slice_by_borrow` (65d9527) by-borrow pins on
14286        // the sibling outer top-level [`Caixa`] `&[String]`-return
14287        // axes — the accessor's returned slice must borrow from
14288        // `&self` (the returned reference's lifetime is tied to
14289        // `&self`), and calling the accessor twice on the same
14290        // [`Caixa`] must yield slices that are pointer-equal (the
14291        // underlying byte-buffer is the storage `Vec`'s allocation,
14292        // not a fresh copy) as well as value-equal (idempotent, no
14293        // side effects on `&self`).
14294        //
14295        // Pins against a future silent detour that returned an owned
14296        // `Vec<String>` (which would type-check but silently clone on
14297        // every call, breaking the zero-cost projection every peer
14298        // sibling slice accessor carries), a `&Vec<String>` return
14299        // (which would leak the backing `Vec`'s grow/push/reserve
14300        // surface no downstream consumer reaches for), or a one-arm-
14301        // only accessor that returned a saturating value on some
14302        // sentinel input (breaking the pass-through invariant the
14303        // sibling slice accessors carry).
14304        for servicos in [
14305            vec![],
14306            vec!["servicos/demo.computeunit.yaml"],
14307            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
14308            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
14309        ] {
14310            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
14311            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
14312            let first = c.servicos();
14313            let second = c.servicos();
14314            assert_eq!(
14315                first, second,
14316                "Caixa::servicos must be idempotent — two successive \
14317                 calls on the same &self must return the same &[String]",
14318            );
14319            assert_eq!(
14320                first.as_ptr(),
14321                second.as_ptr(),
14322                "Caixa::servicos must borrow the underlying \
14323                 Vec<String> storage — two successive calls must \
14324                 return slices with the same backing pointer (a fresh \
14325                 Vec<String> clone would change the pointer on every \
14326                 call)",
14327            );
14328            assert_eq!(
14329                first,
14330                expected.as_slice(),
14331                "Caixa::servicos must return :servicos verbatim by \
14332                 borrow — got {first:?}, expected {expected:?}",
14333            );
14334        }
14335    }
14336
14337    // ── Caixa::deps — outer top-level &[Dep] slice accessor ───────────
14338
14339    fn caixa_with_deps(deps: Vec<Dep>) -> Caixa {
14340        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14341        c.deps = deps;
14342        c
14343    }
14344
14345    #[test]
14346    fn deps_returns_deps_slice_verbatim_across_permutations() {
14347        // The canonical per-`Caixa` `:deps` universal-axis runtime-
14348        // dependency-declaration-list slice pin: [`Caixa::deps`] must
14349        // return the `:deps` typed [`Vec<Dep>`] list verbatim as a
14350        // `&[Dep]`, element-equal to the raw `self.deps.as_slice()`
14351        // access across every representative value in the accept-set —
14352        // `[]` (the "no runtime deps declared" arm every existing
14353        // fixture without a `:deps` line carries; the
14354        // [`Caixa::template`] scaffold emits `:deps ()`), a canonical
14355        // single-entry list (the shape most consumer caixas carry), a
14356        // canonical two-entry list (the multi-dep runtime closure), and
14357        // two past-the-guard sentinels — a `[""]`-`:nome` entry
14358        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
14359        // `NomeInvalid` but the accessor must ship the raw slot
14360        // verbatim) and a `[a, a]` duplicate (validate rejects through
14361        // `DuplicateNome { list: ":deps" }` but the accessor must ship
14362        // the raw slot verbatim so struct-literal fixtures continue to
14363        // expose the duplicate at the accessor).
14364        //
14365        // First outer top-level [`Caixa`] `&[Dep]`-return slice accessor
14366        // pin on the substrate primitive — opens the outer-`Caixa`
14367        // dependency-slot `&[Dep]` sub-family the sibling `:deps-dev`
14368        // future lift closes on. Peer of the closed outer-`Caixa`
14369        // foreign-code-slot `&[String]` sub-family
14370        // (`bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
14371        // 8a36c23, `exe_returns_exe_slice_verbatim_across_permutations`
14372        // 65d9527, `servicos_returns_servicos_slice_verbatim_across_permutations`
14373        // 611f78b) and the outer-`Caixa` universal-axis text-tag family
14374        // (`autores_returns_autores_slice_verbatim_across_permutations`
14375        // b5d813f, `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
14376        // 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice"
14377        // projection pattern onto a novel element-type axis (`Dep`
14378        // composite vs the prior sibling family's `String` scalar).
14379        // Pins against a future silent detour that returned an owned
14380        // `Vec<Dep>` (which would type-check but silently clone on every
14381        // accessor call, breaking the zero-cost projection every peer
14382        // sibling slice accessor carries), a `[""] → []` collapse (which
14383        // would silently absorb the `NomeEmpty` refusal case at the
14384        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
14385        // would silently absorb the `DuplicateNome` refusal case at the
14386        // accessor boundary).
14387        for deps in [
14388            vec![],
14389            vec![Dep::simple("", "^0.1")],
14390            vec![Dep::simple("caixa-teia", "^0.1")],
14391            vec![
14392                Dep::simple("caixa-teia", "^0.1"),
14393                Dep::simple("caixa-core", "^0.1"),
14394            ],
14395            vec![
14396                Dep::simple("caixa-teia", "^0.1"),
14397                Dep::simple("caixa-teia", "^0.2"),
14398            ],
14399        ] {
14400            let c = caixa_with_deps(deps.clone());
14401            assert_eq!(
14402                c.deps(),
14403                deps.as_slice(),
14404                "Caixa::deps must return :deps verbatim (got {:?}, \
14405                 expected {deps:?})",
14406                c.deps(),
14407            );
14408            assert_eq!(
14409                c.deps(),
14410                c.deps.as_slice(),
14411                "Caixa::deps must element-equal the raw \
14412                 `self.deps.as_slice()` field access across every \
14413                 value in the Vec<Dep> accept-set",
14414            );
14415        }
14416    }
14417
14418    #[test]
14419    fn validate_deps_duplicate_arm_routes_through_accessor() {
14420        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps`
14421        // duplicate-`:nome` gate must key off [`Caixa::deps`], not the
14422        // raw `&self.deps` field-borrow walk. Structurally: a `Caixa
14423        // { deps: vec![Dep::simple("d", "^0.1"), Dep::simple("d",
14424        // "^0.2")], .. }` must surface the `DuplicateNome { list:
14425        // ":deps" }` refusal exactly, and a `Caixa { deps: vec![
14426        // Dep::simple("d", "^0.1")], .. }` (the canonical single-entry
14427        // form) must pass validate. The pair jointly pins the accessor +
14428        // validate-gate composition: any future silent detour that had
14429        // the accessor return a dedupped slice on the `[a, a]` arm (a
14430        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
14431        // would silently absorb the `DuplicateNome` refusal at the
14432        // accessor boundary and the validate gate would accept a
14433        // struct-literal `Caixa` carrying the drift — the composition
14434        // pin catches that at caixa-core build time.
14435        //
14436        // Peer of the per-`Caixa`
14437        // `validate_autores_empty_entry_arm_routes_through_accessor`
14438        // (b5d813f), `validate_etiquetas_empty_entry_arm_routes_through_accessor`
14439        // (78c7d3c), `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
14440        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
14441        // (65d9527), and `validate_code_paths_servicos_empty_arm_routes_through_accessor`
14442        // (611f78b) accessor-composition pins on the sibling `&[T]`-
14443        // composition axes — same "the validate gate must route through
14444        // the substrate-primitive typed dispatch" discipline extended
14445        // onto the sibling outer top-level [`Caixa`] `&[Dep]`-
14446        // composition surface, opening the outer-`Caixa` dependency-slot
14447        // arm of the composition-pin family.
14448        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
14449        let err = c.validate_deps().unwrap_err();
14450        assert!(
14451            matches!(
14452                err,
14453                DepError::DuplicateNome { ref nome, list } if nome == "d"
14454                    && list == crate::render::DEP_AUTHOR_KEY_DEPS
14455            ),
14456            "validate_deps must reject deps == \
14457             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
14458             DuplicateNome {{ nome: \"d\", list: \":deps\" }} — the \
14459             accessor and the validate gate must route through the \
14460             same substrate-primitive typed dispatch on the :deps \
14461             within-list duplicate arm (got {err:?})",
14462        );
14463        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1")]);
14464        assert!(
14465            c.validate_deps().is_ok(),
14466            "validate_deps must accept deps == vec![Dep(\"d\",\"^0.1\")] \
14467             (the canonical single-entry form)",
14468        );
14469    }
14470
14471    #[test]
14472    fn deps_projects_slice_by_borrow() {
14473        // The by-borrow pin: [`Caixa::deps`] returns `&[Dep]` by borrow
14474        // — the returned slice borrows the underlying `Vec<Dep>` storage
14475        // of the `:deps` slot and the accessor must not clone the
14476        // backing `Vec` on every call. Peer of the per-`Caixa`
14477        // `autores_projects_slice_by_borrow` (b5d813f),
14478        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
14479        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
14480        // `exe_projects_slice_by_borrow` (65d9527), and
14481        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
14482        // on the sibling outer top-level [`Caixa`] `&[String]`-return
14483        // axes — the accessor's returned slice must borrow from `&self`
14484        // (the returned reference's lifetime is tied to `&self`), and
14485        // calling the accessor twice on the same [`Caixa`] must yield
14486        // slices that are pointer-equal (the underlying byte-buffer is
14487        // the storage `Vec`'s allocation, not a fresh copy) as well as
14488        // value-equal (idempotent, no side effects on `&self`).
14489        //
14490        // Pins against a future silent detour that returned an owned
14491        // `Vec<Dep>` (which would type-check but silently clone on
14492        // every call), a `&Vec<Dep>` return (which would leak the
14493        // backing `Vec`'s grow/push/reserve surface no downstream
14494        // consumer reaches for), or a one-arm-only accessor that
14495        // returned a saturating value on some sentinel input.
14496        for deps in [
14497            vec![],
14498            vec![Dep::simple("caixa-teia", "^0.1")],
14499            vec![
14500                Dep::simple("caixa-teia", "^0.1"),
14501                Dep::simple("caixa-core", "^0.1"),
14502            ],
14503        ] {
14504            let c = caixa_with_deps(deps.clone());
14505            let first = c.deps();
14506            let second = c.deps();
14507            assert_eq!(
14508                first, second,
14509                "Caixa::deps must be idempotent — two successive calls \
14510                 on the same &self must return the same &[Dep]",
14511            );
14512            assert_eq!(
14513                first.as_ptr(),
14514                second.as_ptr(),
14515                "Caixa::deps must borrow the underlying Vec<Dep> \
14516                 storage — two successive calls must return slices \
14517                 with the same backing pointer (a fresh Vec<Dep> clone \
14518                 would change the pointer on every call)",
14519            );
14520            assert_eq!(
14521                first,
14522                deps.as_slice(),
14523                "Caixa::deps must return :deps verbatim by borrow — \
14524                 got {first:?}, expected {deps:?}",
14525            );
14526        }
14527    }
14528
14529    // ── Caixa::deps_dev — outer top-level &[Dep] slice accessor ──────
14530
14531    fn caixa_with_deps_dev(deps_dev: Vec<Dep>) -> Caixa {
14532        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14533        c.deps_dev = deps_dev;
14534        c
14535    }
14536
14537    #[test]
14538    fn deps_dev_returns_deps_dev_slice_verbatim_across_permutations() {
14539        // The canonical per-`Caixa` `:deps-dev` universal-axis dev-only-
14540        // dependency-declaration-list slice pin: [`Caixa::deps_dev`]
14541        // must return the `:deps-dev` typed [`Vec<Dep>`] list verbatim as
14542        // a `&[Dep]`, element-equal to the raw `self.deps_dev.as_slice()`
14543        // access across every representative value in the accept-set —
14544        // `[]` (the "no dev deps declared" arm every existing fixture
14545        // without a `:deps-dev` line carries; the [`Caixa::template`]
14546        // scaffold emits `:deps-dev ()`), a canonical single-entry list
14547        // (the shape most consumer caixas carry — a `tatara-check` dev
14548        // pin), a canonical two-entry list (the multi-dev-dep closure),
14549        // and two past-the-guard sentinels — a `[""]`-`:nome` entry
14550        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
14551        // `NomeInvalid` but the accessor must ship the raw slot
14552        // verbatim) and a `[a, a]` duplicate (validate rejects through
14553        // `DuplicateNome { list: ":deps-dev" }` but the accessor must
14554        // ship the raw slot verbatim so struct-literal fixtures continue
14555        // to expose the duplicate at the accessor).
14556        //
14557        // Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor
14558        // pin on the substrate primitive — closes the outer-`Caixa`
14559        // dependency-slot `&[Dep]` sub-family the sibling
14560        // `deps_returns_deps_slice_verbatim_across_permutations`
14561        // (ad34b4e) opened on. Folds the "outer [`Caixa`] `&[Dep]`
14562        // slice" projection pattern onto the sibling dev-dep axis —
14563        // pins against a future silent detour that returned an owned
14564        // `Vec<Dep>` (which would type-check but silently clone on every
14565        // accessor call, breaking the zero-cost projection every peer
14566        // sibling slice accessor carries), a `[""] → []` collapse (which
14567        // would silently absorb the `NomeEmpty` refusal case at the
14568        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
14569        // would silently absorb the `DuplicateNome` refusal case at the
14570        // accessor boundary).
14571        for deps_dev in [
14572            vec![],
14573            vec![Dep::simple("", "^0.1")],
14574            vec![Dep::simple("tatara-check", "^0.1")],
14575            vec![
14576                Dep::simple("tatara-check", "^0.1"),
14577                Dep::simple("caixa-lint", "^0.1"),
14578            ],
14579            vec![
14580                Dep::simple("tatara-check", "^0.1"),
14581                Dep::simple("tatara-check", "^0.2"),
14582            ],
14583        ] {
14584            let c = caixa_with_deps_dev(deps_dev.clone());
14585            assert_eq!(
14586                c.deps_dev(),
14587                deps_dev.as_slice(),
14588                "Caixa::deps_dev must return :deps-dev verbatim (got \
14589                 {:?}, expected {deps_dev:?})",
14590                c.deps_dev(),
14591            );
14592            assert_eq!(
14593                c.deps_dev(),
14594                c.deps_dev.as_slice(),
14595                "Caixa::deps_dev must element-equal the raw \
14596                 `self.deps_dev.as_slice()` field access across every \
14597                 value in the Vec<Dep> accept-set",
14598            );
14599        }
14600    }
14601
14602    #[test]
14603    fn validate_deps_duplicate_deps_dev_arm_routes_through_accessor() {
14604        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps-dev`
14605        // duplicate-`:nome` gate must key off [`Caixa::deps_dev`], not
14606        // the raw `&self.deps_dev` field-borrow walk. Structurally: a
14607        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1"),
14608        // Dep::simple("d", "^0.2")], .. }` must surface the
14609        // `DuplicateNome { list: ":deps-dev" }` refusal exactly, and a
14610        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1")], .. }` (the
14611        // canonical single-entry form) must pass validate. The pair
14612        // jointly pins the accessor + validate-gate composition: any
14613        // future silent detour that had the accessor return a dedupped
14614        // slice on the `[a, a]` arm (a
14615        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
14616        // would silently absorb the `DuplicateNome` refusal at the
14617        // accessor boundary and the validate gate would accept a
14618        // struct-literal `Caixa` carrying the drift — the composition
14619        // pin catches that at caixa-core build time.
14620        //
14621        // Peer of `validate_deps_duplicate_arm_routes_through_accessor`
14622        // (ad34b4e) on the sibling `:deps` axis — same "the validate
14623        // gate must route through the substrate-primitive typed
14624        // dispatch" discipline folded onto the sibling `:deps-dev`
14625        // axis, closing the two-list dep-graph composition-pin family.
14626        // The `:deps-dev` diagnostic must carry the
14627        // `DEP_AUTHOR_KEY_DEPS_DEV` list-tag (not
14628        // `DEP_AUTHOR_KEY_DEPS`) so the emitted error names the
14629        // offending list unambiguously.
14630        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
14631        let err = c.validate_deps().unwrap_err();
14632        assert!(
14633            matches!(
14634                err,
14635                DepError::DuplicateNome { ref nome, list } if nome == "d"
14636                    && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
14637            ),
14638            "validate_deps must reject deps_dev == \
14639             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
14640             DuplicateNome {{ nome: \"d\", list: \":deps-dev\" }} — the \
14641             accessor and the validate gate must route through the \
14642             same substrate-primitive typed dispatch on the :deps-dev \
14643             within-list duplicate arm (got {err:?})",
14644        );
14645        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1")]);
14646        assert!(
14647            c.validate_deps().is_ok(),
14648            "validate_deps must accept deps_dev == \
14649             vec![Dep(\"d\",\"^0.1\")] (the canonical single-entry form)",
14650        );
14651    }
14652
14653    #[test]
14654    fn deps_dev_projects_slice_by_borrow() {
14655        // The by-borrow pin: [`Caixa::deps_dev`] returns `&[Dep]` by
14656        // borrow — the returned slice borrows the underlying `Vec<Dep>`
14657        // storage of the `:deps-dev` slot and the accessor must not
14658        // clone the backing `Vec` on every call. Peer of
14659        // `deps_projects_slice_by_borrow` (ad34b4e) on the sibling
14660        // `:deps` axis, and of the per-`Caixa`
14661        // `autores_projects_slice_by_borrow` (b5d813f),
14662        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
14663        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
14664        // `exe_projects_slice_by_borrow` (65d9527), and
14665        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
14666        // on the sibling outer top-level [`Caixa`] `&[String]`-return
14667        // axes — the accessor's returned slice must borrow from `&self`
14668        // (the returned reference's lifetime is tied to `&self`), and
14669        // calling the accessor twice on the same [`Caixa`] must yield
14670        // slices that are pointer-equal (the underlying byte-buffer is
14671        // the storage `Vec`'s allocation, not a fresh copy) as well as
14672        // value-equal (idempotent, no side effects on `&self`).
14673        //
14674        // Pins against a future silent detour that returned an owned
14675        // `Vec<Dep>` (which would type-check but silently clone on
14676        // every call), a `&Vec<Dep>` return (which would leak the
14677        // backing `Vec`'s grow/push/reserve surface no downstream
14678        // consumer reaches for), or a one-arm-only accessor that
14679        // returned a saturating value on some sentinel input.
14680        for deps_dev in [
14681            vec![],
14682            vec![Dep::simple("tatara-check", "^0.1")],
14683            vec![
14684                Dep::simple("tatara-check", "^0.1"),
14685                Dep::simple("caixa-lint", "^0.1"),
14686            ],
14687        ] {
14688            let c = caixa_with_deps_dev(deps_dev.clone());
14689            let first = c.deps_dev();
14690            let second = c.deps_dev();
14691            assert_eq!(
14692                first, second,
14693                "Caixa::deps_dev must be idempotent — two successive \
14694                 calls on the same &self must return the same &[Dep]",
14695            );
14696            assert_eq!(
14697                first.as_ptr(),
14698                second.as_ptr(),
14699                "Caixa::deps_dev must borrow the underlying Vec<Dep> \
14700                 storage — two successive calls must return slices \
14701                 with the same backing pointer (a fresh Vec<Dep> clone \
14702                 would change the pointer on every call)",
14703            );
14704            assert_eq!(
14705                first,
14706                deps_dev.as_slice(),
14707                "Caixa::deps_dev must return :deps-dev verbatim by \
14708                 borrow — got {first:?}, expected {deps_dev:?}",
14709            );
14710        }
14711    }
14712
14713    // ── Caixa::limits — outer top-level Option<&LimitsSpec> composite-reference accessor ──
14714
14715    fn caixa_with_limits(limits: Option<crate::LimitsSpec>) -> Caixa {
14716        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14717        c.limits = limits;
14718        c
14719    }
14720
14721    #[test]
14722    fn limits_returns_limits_option_ref_verbatim_across_permutations() {
14723        // The canonical per-`Caixa` `:limits` M2 typed-slot outer-
14724        // composite optional-composite-reference-shape pin:
14725        // [`Caixa::limits`] must return the `:limits` typed
14726        // `Option<LimitsSpec>` verbatim as an `Option<&LimitsSpec>`
14727        // reference over the same backing storage the raw
14728        // `self.limits.as_ref()` field access borrows from, byte-equal
14729        // across every representative fixture in the accept-set — the
14730        // author-omitted `None` shape (the "engine-default applies"
14731        // partition every downstream Servico M2 overlay emitter treats
14732        // as "emit nothing"), the empty-composite `Some(LimitsSpec {
14733        // .. default })` shape ([`LimitsSpec::is_empty`] holds — every
14734        // per-axis cap is `None`, so the peer M2 overlay emitter's
14735        // `.is_empty()`-gated projection still emits nothing but the
14736        // outer presence-bit is `Some`, so [`Caixa::declared_servico_slots`]
14737        // still pushes the `M2_AUTHOR_KEY_LIMITS` label), a single-axis
14738        // fixture (only `:memory` set — the canonical shape most
14739        // memory-heavy Servicos carry), and a fully-populated composite
14740        // (every per-axis cap set — the canonical shape a
14741        // sandboxed-by-default Servico carries).
14742        //
14743        // Pins against a future silent detour that returned a fresh-
14744        // cloned [`LimitsSpec`] copy (which would type-check via the
14745        // `Clone` impl but silently break every downstream caller that
14746        // relied on the reference sharing the composite's backing
14747        // identity), a reference to an operator-resolved overlay (the
14748        // future per-cluster `:limits-overrides` slot — its resolution
14749        // must land at exactly this accessor body, not silently divert
14750        // the raw slot away from a second consumer), a
14751        // `None` → `Some(LimitsSpec::default)` cluster-default
14752        // projection (which would collapse the load-bearing
14753        // "author-omitted `:limits` ⇒ engine-default applies" partition
14754        // the peer [`crate::render::servico_m2_overlay`] emitter and
14755        // the peer [`Caixa::declared_servico_slots`] enumerator both
14756        // read), or an axis-shuffled projection (a future detour that
14757        // swapped `memory` and `fuel` through the accessor would
14758        // silently split the paired [`crate::StandardLayout::verify`]
14759        // per-`:limits` shape gate's traversal input from the peer
14760        // `servico_m2_overlay` emitter's projection input).
14761        //
14762        // First outer top-level [`Caixa`] `Option<&Composite>`-return
14763        // composite-reference accessor pin on the substrate primitive
14764        // — opens the outer-`Caixa` `Option<&Composite>` composite-
14765        // reference projection pattern the sibling `:behavior`
14766        // [`crate::BehaviorSpec`] / `:politicas`
14767        // [`crate::aplicacao::MeshPolicy`] / `:placement`
14768        // [`crate::aplicacao::Placement`] / `:entrada`
14769        // [`crate::aplicacao::Entrada`] future outer-composite lifts
14770        // fold on. Peer of the closed M3 outer-composite family the
14771        // sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
14772        // [`crate::AplicacaoSpec::placement`] (9abb8f0) /
14773        // [`crate::AplicacaoSpec::entrada`] (d32111c) composite-
14774        // reference accessor pins already carry on the outer
14775        // [`crate::AplicacaoSpec`] altitude — extends the outer-
14776        // accessor byte-equal-projection discipline onto the outer
14777        // top-level [`Caixa`] M2 Servico-runtime slot altitude.
14778        use crate::LimitsSpec;
14779        use std::time::Duration;
14780        let fixtures: Vec<Option<LimitsSpec>> = vec![
14781            None,
14782            Some(LimitsSpec::default()),
14783            Some(LimitsSpec {
14784                memory: Some(64 * 1024 * 1024),
14785                ..Default::default()
14786            }),
14787            Some(LimitsSpec {
14788                memory: Some(64 * 1024 * 1024),
14789                fuel: Some(1_000_000),
14790                wall_clock: Some(Duration::from_secs(30)),
14791                cpu: Some(500),
14792            }),
14793        ];
14794        for limits in fixtures {
14795            let c = caixa_with_limits(limits.clone());
14796            assert_eq!(
14797                c.limits(),
14798                limits.as_ref(),
14799                "Caixa::limits must return :limits verbatim (got {:?}, \
14800                 expected {:?})",
14801                c.limits(),
14802                limits.as_ref(),
14803            );
14804            match (c.limits(), c.limits.as_ref()) {
14805                (Some(a), Some(b)) => assert!(
14806                    std::ptr::eq(a, b),
14807                    "Caixa::limits accessor and self.limits.as_ref() \
14808                     field access must borrow the same backing storage \
14809                     — the accessor is the substrate-primitive typed \
14810                     dispatch every downstream Servico-M2-overlay \
14811                     composite consumer must route through, and a \
14812                     reference-identity split would silently break \
14813                     every consumer that relied on the borrow sharing \
14814                     the composite's storage",
14815                ),
14816                (None, None) => {}
14817                _ => panic!(
14818                    "Caixa::limits presence bit must byte-equal \
14819                     self.limits.is_some() — a presence-bit drift would \
14820                     silently split the paired StandardLayout::verify \
14821                     per-`:limits` shape gate's traversal head from \
14822                     the peer render::servico_m2_overlay M2 overlay \
14823                     emitter's traversal head from the peer \
14824                     Caixa::declared_servico_slots M2 declared-slot \
14825                     enumerator's presence probe",
14826                ),
14827            }
14828            assert_eq!(
14829                c.limits().is_some(),
14830                c.limits.is_some(),
14831                "Caixa::limits().is_some() must byte-equal \
14832                 self.limits.is_some() — a presence-bit drift would \
14833                 silently split every downstream Option<&LimitsSpec> \
14834                 consumer's partition on the engine-default arm",
14835            );
14836        }
14837    }
14838
14839    #[test]
14840    fn declared_servico_slots_limits_arm_routes_through_accessor() {
14841        // Composition pin: [`Caixa::declared_servico_slots`]'s
14842        // `:limits` presence-probe arm must key off [`Caixa::limits`],
14843        // not the raw `self.limits.is_some()` field-probe. Structurally:
14844        // a `Caixa { limits: Some(LimitsSpec::default()), .. }` must
14845        // still push `M2_AUTHOR_KEY_LIMITS` onto the declared-slot list
14846        // (the presence bit is `Some`, so the M2 kind-coherence gate
14847        // must surface the slot as "declared" even when every per-axis
14848        // cap is unset), and a `Caixa { limits: None, .. }` must NOT
14849        // push the label (the "author omitted the slot entirely"
14850        // partition). The pair jointly pins the accessor + declared-
14851        // slot enumerator composition: any future silent detour that
14852        // had the accessor collapse `Some(LimitsSpec::default())` to
14853        // `None` (a `.filter(|l| !l.is_empty())` projection) would
14854        // silently absorb the "declared but empty" arm at the
14855        // accessor boundary and the [`crate::LayoutError::ServicoSlotsOnNonServico`]
14856        // kind-coherence gate would silently accept a
14857        // struct-literal `Caixa` carrying the drift.
14858        //
14859        // Peer of the sibling per-`Caixa`
14860        // `validate_deps_duplicate_arm_routes_through_accessor` (ad34b4e)
14861        // and `validate_deps_duplicate_deps_dev_arm_routes_through_accessor`
14862        // (f7fd81e) accessor-composition pins on the sibling `:deps` /
14863        // `:deps-dev` outer-`&[Dep]`-composition axes — same "the
14864        // enumerator gate must route through the substrate-primitive
14865        // typed dispatch" discipline extended onto the outer top-level
14866        // [`Caixa`] `Option<&LimitsSpec>`-composition surface, opening
14867        // the outer-`Caixa` M2 Servico-runtime-slot arm of the
14868        // composition-pin family.
14869        use crate::LimitsSpec;
14870        let c = caixa_with_limits(Some(LimitsSpec::default()));
14871        let slots = c.declared_servico_slots();
14872        assert!(
14873            slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
14874            "declared_servico_slots must push M2_AUTHOR_KEY_LIMITS \
14875             when `:limits` is Some (even for LimitsSpec::default()) \
14876             — the accessor and the enumerator gate must route through \
14877             the same substrate-primitive typed dispatch on the outer \
14878             :limits presence bit (got slots={slots:?})",
14879        );
14880        let c = caixa_with_limits(None);
14881        let slots = c.declared_servico_slots();
14882        assert!(
14883            !slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
14884            "declared_servico_slots must NOT push M2_AUTHOR_KEY_LIMITS \
14885             when `:limits` is None — the author-omitted arm must \
14886             route through the accessor's None-return unchanged (got \
14887             slots={slots:?})",
14888        );
14889    }
14890
14891    #[test]
14892    fn servico_m2_overlay_limits_arm_routes_through_accessor() {
14893        // Composition pin: [`crate::render::servico_m2_overlay`]'s
14894        // per-`:limits` M2 overlay emit arm must key off
14895        // [`Caixa::limits`], not the raw `&caixa.limits` field-borrow.
14896        // Structurally: a `Caixa { limits: Some(LimitsSpec { memory:
14897        // Some(64 MiB), .. default }), .. }` must surface the
14898        // `M2_KEY_LIMITS` key with the per-axis
14899        // `memory: "64MiB"` sub-mapping in the overlay, a `Caixa {
14900        // limits: Some(LimitsSpec::default()), .. }` must omit the
14901        // key entirely (the `.is_empty()`-gated inner arm elides an
14902        // empty composite even when the outer presence bit is `Some`),
14903        // and a `Caixa { limits: None, .. }` must also omit the key
14904        // (the "author omitted the slot entirely" partition). The
14905        // three-fixture family jointly pins the accessor + M2 overlay
14906        // emitter composition: any future silent detour that had the
14907        // accessor return a fresh-cloned copy on the `Some` arm (a
14908        // `LimitsSpec::clone()` projection) would silently break the
14909        // reference-identity pin the peer per-axis
14910        // `serde_yaml::to_value(limits)` projection reads from.
14911        use crate::LimitsSpec;
14912        use crate::render::{M2_KEY_LIMITS, servico_m2_overlay};
14913        let c = caixa_with_limits(Some(LimitsSpec {
14914            memory: Some(64 * 1024 * 1024),
14915            ..Default::default()
14916        }));
14917        let overlay = servico_m2_overlay(&c).unwrap();
14918        assert!(
14919            overlay.contains_key(M2_KEY_LIMITS),
14920            "servico_m2_overlay must surface M2_KEY_LIMITS when \
14921             `:limits` carries a non-empty composite — the accessor \
14922             and the M2 overlay emitter must route through the same \
14923             substrate-primitive typed dispatch on the outer :limits \
14924             composite (got overlay={overlay:?})",
14925        );
14926        let c = caixa_with_limits(Some(LimitsSpec::default()));
14927        let overlay = servico_m2_overlay(&c).unwrap();
14928        assert!(
14929            !overlay.contains_key(M2_KEY_LIMITS),
14930            "servico_m2_overlay must omit M2_KEY_LIMITS when \
14931             `:limits` is Some(LimitsSpec::default()) — the empty \
14932             composite's `.is_empty()`-gated inner arm must elide \
14933             the key regardless of the outer presence bit (got \
14934             overlay={overlay:?})",
14935        );
14936        let c = caixa_with_limits(None);
14937        let overlay = servico_m2_overlay(&c).unwrap();
14938        assert!(
14939            !overlay.contains_key(M2_KEY_LIMITS),
14940            "servico_m2_overlay must omit M2_KEY_LIMITS when \
14941             `:limits` is None — the author-omitted arm must route \
14942             through the accessor's None-return unchanged (got \
14943             overlay={overlay:?})",
14944        );
14945    }
14946
14947    #[test]
14948    fn limits_projects_option_ref_by_borrow() {
14949        // The by-borrow pin: [`Caixa::limits`] returns
14950        // `Option<&LimitsSpec>` by borrow — the returned reference
14951        // borrows the underlying `Option<LimitsSpec>` storage of the
14952        // `:limits` slot and the accessor must not clone the backing
14953        // composite on every call. Peer of the sibling
14954        // `deps_projects_slice_by_borrow` (ad34b4e) /
14955        // `deps_dev_projects_slice_by_borrow` (f7fd81e) by-borrow pins
14956        // on the outer top-level [`Caixa`] `&[Dep]`-return axes —
14957        // extended here to the outer [`Caixa`] `Option<&Composite>`-
14958        // return axis: the accessor's returned reference must borrow
14959        // from `&self` (the returned reference's lifetime is tied to
14960        // `&self`), and calling the accessor twice on the same
14961        // [`Caixa`] must yield references that are pointer-equal (the
14962        // underlying byte-buffer is the storage `LimitsSpec`'s
14963        // allocation, not a fresh copy) as well as value-equal
14964        // (idempotent, no side effects on `&self`).
14965        //
14966        // Pins against a future silent detour that returned an owned
14967        // `LimitsSpec` (which would type-check via the `Clone` impl
14968        // but silently clone on every call), a `&LimitsSpec` panic-
14969        // return on the `None` arm (which would collapse the load-
14970        // bearing `Option` presence-bit into a runtime panic), or a
14971        // one-arm-only accessor that returned a saturating composite
14972        // on some sentinel input.
14973        use crate::LimitsSpec;
14974        use std::time::Duration;
14975        for limits in [
14976            Some(LimitsSpec::default()),
14977            Some(LimitsSpec {
14978                memory: Some(64 * 1024 * 1024),
14979                fuel: Some(1_000_000),
14980                wall_clock: Some(Duration::from_secs(30)),
14981                cpu: Some(500),
14982            }),
14983        ] {
14984            let c = caixa_with_limits(limits.clone());
14985            let first = c.limits().unwrap();
14986            let second = c.limits().unwrap();
14987            assert_eq!(
14988                first, second,
14989                "Caixa::limits must be idempotent — two successive \
14990                 calls on the same &self must return the same \
14991                 &LimitsSpec",
14992            );
14993            assert!(
14994                std::ptr::eq(first, second),
14995                "Caixa::limits must borrow the underlying \
14996                 Option<LimitsSpec> storage — two successive calls \
14997                 must return references with the same backing pointer \
14998                 (a fresh LimitsSpec clone would change the pointer \
14999                 on every call)",
15000            );
15001            assert_eq!(
15002                Some(first),
15003                limits.as_ref(),
15004                "Caixa::limits must return :limits verbatim by borrow \
15005                 — got {first:?}, expected {:?}",
15006                limits.as_ref(),
15007            );
15008        }
15009        let c = caixa_with_limits(None);
15010        assert!(
15011            c.limits().is_none(),
15012            "Caixa::limits must return None when :limits is absent — \
15013             the author-omitted arm must project through the \
15014             accessor's Option::None unchanged",
15015        );
15016    }
15017
15018    // ── Caixa::behavior — outer top-level Option<&BehaviorSpec> composite-reference accessor ──
15019
15020    fn caixa_with_behavior(behavior: Option<crate::BehaviorSpec>) -> Caixa {
15021        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15022        c.behavior = behavior;
15023        c
15024    }
15025
15026    #[test]
15027    fn behavior_returns_behavior_option_ref_verbatim_across_permutations() {
15028        // The canonical per-`Caixa` `:behavior` M2 typed-slot outer-
15029        // composite optional-composite-reference-shape pin:
15030        // [`Caixa::behavior`] must return the `:behavior` typed
15031        // `Option<BehaviorSpec>` verbatim as an `Option<&BehaviorSpec>`
15032        // reference over the same backing storage the raw
15033        // `self.behavior.as_ref()` field access borrows from, byte-equal
15034        // across every representative fixture in the accept-set — the
15035        // author-omitted `None` shape (the "runtime-default applies"
15036        // partition every downstream Servico M2 overlay emitter treats
15037        // as "emit nothing"), the empty-composite `Some(BehaviorSpec {
15038        // .. default })` shape ([`BehaviorSpec::is_empty`] holds —
15039        // every per-callback path is `None`, so the peer M2 overlay
15040        // emitter's `.is_empty()`-gated projection still emits nothing
15041        // but the outer presence-bit is `Some`, so
15042        // [`Caixa::declared_servico_slots`] still pushes the
15043        // `M2_AUTHOR_KEY_BEHAVIOR` label), a single-callback fixture
15044        // (only `:on-state-change` set — the canonical shape a caixa
15045        // that only wires the hot-upgrade migration path carries), and
15046        // a fully-populated composite (every per-callback path set —
15047        // the canonical shape a fully-instrumented gen_server-shaped
15048        // Servico carries).
15049        //
15050        // Peer of the sibling
15051        // `limits_returns_limits_option_ref_verbatim_across_permutations`
15052        // (b2bd9d7) opening fixture-family + reference-identity +
15053        // presence-bit tetrad pin on the outer top-level [`Caixa`]
15054        // `Option<&Composite>`-return sub-family — extended here to the
15055        // second axis of that sub-family so both of the currently-lifted
15056        // M2 Servico-runtime `Option<&Composite>` slots (`:limits` /
15057        // `:behavior`) carry the same "byte-equal, borrow-shared,
15058        // presence-bit-preserved" outer-accessor discipline.
15059        //
15060        // Pins against a future silent detour that returned a fresh-
15061        // cloned [`crate::BehaviorSpec`] copy (which would type-check
15062        // via the `Clone` impl but silently break every downstream
15063        // caller that relied on the reference sharing the composite's
15064        // backing identity), a reference to an operator-resolved
15065        // overlay (a future per-cluster `:behavior-overrides` slot —
15066        // its resolution must land at exactly this accessor body, not
15067        // silently divert the raw slot away from a second consumer), a
15068        // `None` → `Some(BehaviorSpec::default)` cluster-default
15069        // projection (which would collapse the load-bearing
15070        // "author-omitted `:behavior` ⇒ runtime-default applies"
15071        // partition the peer [`crate::render::servico_m2_overlay`]
15072        // emitter, the peer [`Caixa::declared_servico_slots`]
15073        // enumerator, and the cross-slot
15074        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
15075        // gate all read), or a callback-shuffled projection (a future
15076        // detour that swapped `on_init` and `on_terminate` through the
15077        // accessor would silently split the paired
15078        // [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
15079        // traversal input from the peer `servico_m2_overlay` emitter's
15080        // projection input from the cross-slot `:state-change`
15081        // composition gate's traversal input).
15082        use crate::BehaviorSpec;
15083        use std::path::PathBuf;
15084        let fixtures: Vec<Option<BehaviorSpec>> = vec![
15085            None,
15086            Some(BehaviorSpec::default()),
15087            Some(BehaviorSpec {
15088                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
15089                ..Default::default()
15090            }),
15091            Some(BehaviorSpec {
15092                on_init: Some(PathBuf::from("lib/init.lisp")),
15093                on_call: Some(PathBuf::from("lib/handlers.lisp")),
15094                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
15095                on_info: Some(PathBuf::from("lib/handlers.lisp")),
15096                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
15097                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
15098            }),
15099        ];
15100        for behavior in fixtures {
15101            let c = caixa_with_behavior(behavior.clone());
15102            assert_eq!(
15103                c.behavior(),
15104                behavior.as_ref(),
15105                "Caixa::behavior must return :behavior verbatim (got \
15106                 {:?}, expected {:?})",
15107                c.behavior(),
15108                behavior.as_ref(),
15109            );
15110            match (c.behavior(), c.behavior.as_ref()) {
15111                (Some(a), Some(b)) => assert!(
15112                    std::ptr::eq(a, b),
15113                    "Caixa::behavior accessor and self.behavior.as_ref() \
15114                     field access must borrow the same backing storage \
15115                     — the accessor is the substrate-primitive typed \
15116                     dispatch every downstream Servico-M2-overlay \
15117                     composite consumer must route through, and a \
15118                     reference-identity split would silently break \
15119                     every consumer that relied on the borrow sharing \
15120                     the composite's storage",
15121                ),
15122                (None, None) => {}
15123                _ => panic!(
15124                    "Caixa::behavior presence bit must byte-equal \
15125                     self.behavior.is_some() — a presence-bit drift \
15126                     would silently split the paired \
15127                     StandardLayout::verify per-`:behavior` shape \
15128                     gate's traversal head from the peer \
15129                     render::servico_m2_overlay M2 overlay emitter's \
15130                     traversal head from the cross-slot \
15131                     validate_upgrade_from_against_behavior \
15132                     composition gate's traversal head from the peer \
15133                     Caixa::declared_servico_slots M2 declared-slot \
15134                     enumerator's presence probe",
15135                ),
15136            }
15137            assert_eq!(
15138                c.behavior().is_some(),
15139                c.behavior.is_some(),
15140                "Caixa::behavior().is_some() must byte-equal \
15141                 self.behavior.is_some() — a presence-bit drift would \
15142                 silently split every downstream Option<&BehaviorSpec> \
15143                 consumer's partition on the runtime-default arm",
15144            );
15145        }
15146    }
15147
15148    #[test]
15149    fn declared_servico_slots_behavior_arm_routes_through_accessor() {
15150        // Composition pin: [`Caixa::declared_servico_slots`]'s
15151        // `:behavior` presence-probe arm must key off
15152        // [`Caixa::behavior`], not the raw `self.behavior.is_some()`
15153        // field-probe. Structurally: a `Caixa { behavior:
15154        // Some(BehaviorSpec::default()), .. }` must still push
15155        // `M2_AUTHOR_KEY_BEHAVIOR` onto the declared-slot list (the
15156        // presence bit is `Some`, so the M2 kind-coherence gate must
15157        // surface the slot as "declared" even when every per-callback
15158        // path is unset), and a `Caixa { behavior: None, .. }` must
15159        // NOT push the label (the "author omitted the slot entirely"
15160        // partition). The pair jointly pins the accessor + declared-
15161        // slot enumerator composition: any future silent detour that
15162        // had the accessor collapse `Some(BehaviorSpec::default())`
15163        // to `None` (a `.filter(|b| !b.is_empty())` projection) would
15164        // silently absorb the "declared but empty" arm at the
15165        // accessor boundary and the
15166        // [`crate::LayoutError::ServicoSlotsOnNonServico`]
15167        // kind-coherence gate would silently accept a struct-literal
15168        // `Caixa` carrying the drift.
15169        //
15170        // Peer of the sibling
15171        // `declared_servico_slots_limits_arm_routes_through_accessor`
15172        // (b2bd9d7) composition pin on the sibling `:limits` outer-
15173        // `Option<&LimitsSpec>` arm of the same
15174        // [`Caixa::declared_servico_slots`] M2 declared-slot
15175        // enumerator's traversal — same "the enumerator gate must
15176        // route through the substrate-primitive typed dispatch"
15177        // discipline extended onto the outer top-level [`Caixa`]
15178        // `Option<&BehaviorSpec>`-composition surface.
15179        use crate::BehaviorSpec;
15180        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
15181        let slots = c.declared_servico_slots();
15182        assert!(
15183            slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
15184            "declared_servico_slots must push M2_AUTHOR_KEY_BEHAVIOR \
15185             when `:behavior` is Some (even for BehaviorSpec::default()) \
15186             — the accessor and the enumerator gate must route through \
15187             the same substrate-primitive typed dispatch on the outer \
15188             :behavior presence bit (got slots={slots:?})",
15189        );
15190        let c = caixa_with_behavior(None);
15191        let slots = c.declared_servico_slots();
15192        assert!(
15193            !slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
15194            "declared_servico_slots must NOT push M2_AUTHOR_KEY_BEHAVIOR \
15195             when `:behavior` is None — the author-omitted arm must \
15196             route through the accessor's None-return unchanged (got \
15197             slots={slots:?})",
15198        );
15199    }
15200
15201    #[test]
15202    fn servico_m2_overlay_behavior_arm_routes_through_accessor() {
15203        // Composition pin: [`crate::render::servico_m2_overlay`]'s
15204        // per-`:behavior` M2 overlay emit arm must key off
15205        // [`Caixa::behavior`], not the raw `&caixa.behavior`
15206        // field-borrow. Structurally: a `Caixa { behavior:
15207        // Some(BehaviorSpec { on_state_change: Some(...), .. default
15208        // }), .. }` must surface the `M2_KEY_BEHAVIOR` key with the
15209        // per-callback `onStateChange` sub-mapping in the overlay, a
15210        // `Caixa { behavior: Some(BehaviorSpec::default()), .. }`
15211        // must omit the key entirely (the `.is_empty()`-gated inner
15212        // arm elides an empty composite even when the outer presence
15213        // bit is `Some`), and a `Caixa { behavior: None, .. }` must
15214        // also omit the key (the "author omitted the slot entirely"
15215        // partition). The three-fixture family jointly pins the
15216        // accessor + M2 overlay emitter composition: any future
15217        // silent detour that had the accessor return a fresh-cloned
15218        // copy on the `Some` arm (a `BehaviorSpec::clone()`
15219        // projection) would silently break the reference-identity
15220        // pin the peer per-callback `serde_yaml::to_value(behavior)`
15221        // projection reads from.
15222        //
15223        // Peer of the sibling
15224        // `servico_m2_overlay_limits_arm_routes_through_accessor`
15225        // (b2bd9d7) composition pin on the sibling `:limits` outer-
15226        // `Option<&LimitsSpec>` arm of the same
15227        // [`crate::render::servico_m2_overlay`] M2 overlay emitter's
15228        // traversal — same "the emitter must route through the
15229        // substrate-primitive typed dispatch on the outer composite"
15230        // discipline extended onto the outer top-level [`Caixa`]
15231        // `Option<&BehaviorSpec>`-composition surface.
15232        use crate::BehaviorSpec;
15233        use crate::render::{M2_KEY_BEHAVIOR, servico_m2_overlay};
15234        use std::path::PathBuf;
15235        let c = caixa_with_behavior(Some(BehaviorSpec {
15236            on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
15237            ..Default::default()
15238        }));
15239        let overlay = servico_m2_overlay(&c).unwrap();
15240        assert!(
15241            overlay.contains_key(M2_KEY_BEHAVIOR),
15242            "servico_m2_overlay must surface M2_KEY_BEHAVIOR when \
15243             `:behavior` carries a non-empty composite — the accessor \
15244             and the M2 overlay emitter must route through the same \
15245             substrate-primitive typed dispatch on the outer :behavior \
15246             composite (got overlay={overlay:?})",
15247        );
15248        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
15249        let overlay = servico_m2_overlay(&c).unwrap();
15250        assert!(
15251            !overlay.contains_key(M2_KEY_BEHAVIOR),
15252            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
15253             `:behavior` is Some(BehaviorSpec::default()) — the empty \
15254             composite's `.is_empty()`-gated inner arm must elide the \
15255             key regardless of the outer presence bit (got \
15256             overlay={overlay:?})",
15257        );
15258        let c = caixa_with_behavior(None);
15259        let overlay = servico_m2_overlay(&c).unwrap();
15260        assert!(
15261            !overlay.contains_key(M2_KEY_BEHAVIOR),
15262            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
15263             `:behavior` is None — the author-omitted arm must route \
15264             through the accessor's None-return unchanged (got \
15265             overlay={overlay:?})",
15266        );
15267    }
15268
15269    #[test]
15270    fn behavior_projects_option_ref_by_borrow() {
15271        // The by-borrow pin: [`Caixa::behavior`] returns
15272        // `Option<&BehaviorSpec>` by borrow — the returned reference
15273        // borrows the underlying `Option<BehaviorSpec>` storage of the
15274        // `:behavior` slot and the accessor must not clone the backing
15275        // composite on every call. Peer of the sibling
15276        // `limits_projects_option_ref_by_borrow` (b2bd9d7) by-borrow
15277        // pin on the outer top-level [`Caixa`] `Option<&Composite>`-
15278        // return sub-family — extended here to the second axis of the
15279        // same sub-family: the accessor's returned reference must
15280        // borrow from `&self` (the returned reference's lifetime is
15281        // tied to `&self`), and calling the accessor twice on the same
15282        // [`Caixa`] must yield references that are pointer-equal (the
15283        // underlying byte-buffer is the storage `BehaviorSpec`'s
15284        // allocation, not a fresh copy) as well as value-equal
15285        // (idempotent, no side effects on `&self`).
15286        //
15287        // Pins against a future silent detour that returned an owned
15288        // `BehaviorSpec` (which would type-check via the `Clone` impl
15289        // but silently clone on every call), a `&BehaviorSpec` panic-
15290        // return on the `None` arm (which would collapse the load-
15291        // bearing `Option` presence-bit into a runtime panic), or a
15292        // one-arm-only accessor that returned a saturating composite
15293        // on some sentinel input.
15294        use crate::BehaviorSpec;
15295        use std::path::PathBuf;
15296        for behavior in [
15297            Some(BehaviorSpec::default()),
15298            Some(BehaviorSpec {
15299                on_init: Some(PathBuf::from("lib/init.lisp")),
15300                on_call: Some(PathBuf::from("lib/handlers.lisp")),
15301                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
15302                on_info: Some(PathBuf::from("lib/handlers.lisp")),
15303                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
15304                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
15305            }),
15306        ] {
15307            let c = caixa_with_behavior(behavior.clone());
15308            let first = c.behavior().unwrap();
15309            let second = c.behavior().unwrap();
15310            assert_eq!(
15311                first, second,
15312                "Caixa::behavior must be idempotent — two successive \
15313                 calls on the same &self must return the same \
15314                 &BehaviorSpec",
15315            );
15316            assert!(
15317                std::ptr::eq(first, second),
15318                "Caixa::behavior must borrow the underlying \
15319                 Option<BehaviorSpec> storage — two successive calls \
15320                 must return references with the same backing pointer \
15321                 (a fresh BehaviorSpec clone would change the pointer \
15322                 on every call)",
15323            );
15324            assert_eq!(
15325                Some(first),
15326                behavior.as_ref(),
15327                "Caixa::behavior must return :behavior verbatim by \
15328                 borrow — got {first:?}, expected {:?}",
15329                behavior.as_ref(),
15330            );
15331        }
15332        let c = caixa_with_behavior(None);
15333        assert!(
15334            c.behavior().is_none(),
15335            "Caixa::behavior must return None when :behavior is absent \
15336             — the author-omitted arm must project through the \
15337             accessor's Option::None unchanged",
15338        );
15339    }
15340
15341    // ── Caixa::politicas — outer top-level Option<&MeshPolicy> composite-reference accessor ──
15342
15343    fn caixa_aplicacao_with_politicas(politicas: Option<crate::aplicacao::MeshPolicy>) -> Caixa {
15344        use crate::aplicacao::{Membro, WitContract};
15345        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15346        c.kind = CaixaKind::Aplicacao;
15347        c.membros = vec![Membro {
15348            caixa: "a".into(),
15349            versao: "^0.1".into(),
15350        }];
15351        c.contratos = vec![WitContract {
15352            de: "a".into(),
15353            para: "a".into(),
15354            wit: "wasi:http/proxy".into(),
15355            endpoint: Some("/x".into()),
15356            subject: None,
15357            slot: None,
15358        }];
15359        c.politicas = politicas;
15360        c
15361    }
15362
15363    #[test]
15364    fn politicas_returns_politicas_option_ref_verbatim_across_permutations() {
15365        // The canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
15366        // composite optional-composite-reference-shape pin:
15367        // [`Caixa::politicas`] must return the `:politicas` typed
15368        // `Option<MeshPolicy>` verbatim as an `Option<&MeshPolicy>`
15369        // reference over the same backing storage the raw
15370        // `self.politicas.as_ref()` field access borrows from,
15371        // byte-equal across every representative fixture in the
15372        // accept-set — the author-omitted `None` shape (the "cluster-
15373        // default applies" partition every downstream mesh-artifact
15374        // emitter treats as "emit no `:politicas` overlay"), the
15375        // empty-composite `Some(MeshPolicy { .. default })` shape
15376        // ([`crate::aplicacao::MeshPolicy::is_empty`] holds — every
15377        // per-axis mesh-policy scalar is `None`, so the peer inner
15378        // [`crate::AplicacaoSpec::politicas`] `.is_empty()`-gated
15379        // caixa-mesh overlay elides every per-axis emit but the outer
15380        // presence-bit is `Some`, so [`Caixa::declared_mesh_slots`]
15381        // still pushes the `M3_AUTHOR_KEY_POLITICAS` label), a
15382        // single-axis fixture (only `:timeout` set — the canonical
15383        // shape a latency-sensitive Aplicacao carries), and a
15384        // fully-populated composite (every per-axis mesh-policy
15385        // scalar set — the canonical shape a fully-governed
15386        // Aplicacao carries).
15387        //
15388        // Pins against a future silent detour that returned a fresh-
15389        // cloned [`crate::aplicacao::MeshPolicy`] copy (which would
15390        // type-check via the `Clone` impl but silently break every
15391        // downstream caller that relied on the reference sharing the
15392        // composite's backing identity), a reference to an operator-
15393        // resolved overlay (the future per-cluster
15394        // `:politicas-overrides` slot — its resolution must land at
15395        // exactly this accessor body, not silently divert the raw
15396        // slot away from the peer [`Caixa::declared_mesh_slots`]
15397        // enumerator's presence probe), a
15398        // `None` → `Some(MeshPolicy::default)` cluster-default
15399        // projection (which would collapse the load-bearing
15400        // "author-omitted `:politicas` ⇒ cluster-default applies"
15401        // partition the peer [`Caixa::declared_mesh_slots`]
15402        // enumerator and the peer [`Caixa::aplicacao_view`]
15403        // Aplicacao-composition seed both read), or an axis-shuffled
15404        // projection (a future detour that swapped `timeout` and
15405        // `retries` through the accessor would silently split the
15406        // paired [`Caixa::aplicacao_view`] seed's fold input from the
15407        // sibling M3 mesh-artifact emitter's projection input).
15408        //
15409        // Third outer top-level [`Caixa`] `Option<&Composite>`-return
15410        // composite-reference accessor pin on the substrate primitive
15411        // — peer of the sibling
15412        // `limits_returns_limits_option_ref_verbatim_across_permutations`
15413        // (b2bd9d7) and
15414        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
15415        // (35d8b52) opening tetrad pins on the outer top-level
15416        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
15417        // here to the first of the three M3 mesh-slot axes so the
15418        // opening third of the outer `Option<&Composite>` sub-family
15419        // carries the same "byte-equal, borrow-shared, presence-bit-
15420        // preserved" outer-accessor discipline.
15421        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
15422        use std::time::Duration;
15423        let fixtures: Vec<Option<MeshPolicy>> = vec![
15424            None,
15425            Some(MeshPolicy::default()),
15426            Some(MeshPolicy {
15427                timeout: Some(Duration::from_secs(30)),
15428                ..Default::default()
15429            }),
15430            Some(MeshPolicy {
15431                timeout: Some(Duration::from_secs(30)),
15432                retries: Some(3),
15433                circuit_breaker: Some(CircuitBreaker {
15434                    max_failures: 5,
15435                    window: Duration::from_secs(60),
15436                }),
15437                mtls_required: Some(true),
15438                rate_limit: Some(RateLimit {
15439                    rate: 100,
15440                    window: Duration::from_secs(1),
15441                }),
15442            }),
15443        ];
15444        for politicas in fixtures {
15445            let c = caixa_aplicacao_with_politicas(politicas.clone());
15446            assert_eq!(
15447                c.politicas(),
15448                politicas.as_ref(),
15449                "Caixa::politicas must return :politicas verbatim (got \
15450                 {:?}, expected {:?})",
15451                c.politicas(),
15452                politicas.as_ref(),
15453            );
15454            match (c.politicas(), c.politicas.as_ref()) {
15455                (Some(a), Some(b)) => assert!(
15456                    std::ptr::eq(a, b),
15457                    "Caixa::politicas accessor and self.politicas.as_ref() \
15458                     field access must borrow the same backing storage \
15459                     — the accessor is the substrate-primitive typed \
15460                     dispatch every downstream Aplicacao-mesh-overlay \
15461                     composite consumer must route through, and a \
15462                     reference-identity split would silently break \
15463                     every consumer that relied on the borrow sharing \
15464                     the composite's storage",
15465                ),
15466                (None, None) => {}
15467                _ => panic!(
15468                    "Caixa::politicas presence bit must byte-equal \
15469                     self.politicas.is_some() — a presence-bit drift \
15470                     would silently split the paired \
15471                     Caixa::aplicacao_view Aplicacao-composition seed's \
15472                     traversal head from the peer \
15473                     Caixa::declared_mesh_slots M3 declared-slot \
15474                     enumerator's presence probe",
15475                ),
15476            }
15477            assert_eq!(
15478                c.politicas().is_some(),
15479                c.politicas.is_some(),
15480                "Caixa::politicas().is_some() must byte-equal \
15481                 self.politicas.is_some() — a presence-bit drift would \
15482                 silently split every downstream Option<&MeshPolicy> \
15483                 consumer's partition on the cluster-default arm",
15484            );
15485        }
15486    }
15487
15488    #[test]
15489    fn declared_mesh_slots_politicas_arm_routes_through_accessor() {
15490        // Composition pin: [`Caixa::declared_mesh_slots`]'s
15491        // `:politicas` presence-probe arm must key off
15492        // [`Caixa::politicas`], not the raw `self.politicas.is_some()`
15493        // field-probe. Structurally: a `Caixa { politicas:
15494        // Some(MeshPolicy::default()), .. }` must still push
15495        // `M3_AUTHOR_KEY_POLITICAS` onto the declared-slot list (the
15496        // presence bit is `Some`, so the M3 kind-coherence gate must
15497        // surface the slot as "declared" even when every per-axis
15498        // scalar is unset), and a `Caixa { politicas: None, .. }` must
15499        // NOT push the label (the "author omitted the slot entirely"
15500        // partition). The pair jointly pins the accessor + declared-
15501        // slot enumerator composition: any future silent detour that
15502        // had the accessor collapse `Some(MeshPolicy::default())` to
15503        // `None` (a `.filter(|p| !p.is_empty())` projection) would
15504        // silently absorb the "declared but empty" arm at the
15505        // accessor boundary and the
15506        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
15507        // coherence gate would silently accept a struct-literal
15508        // `Caixa` carrying the drift.
15509        //
15510        // Peer of the sibling
15511        // `declared_servico_slots_limits_arm_routes_through_accessor`
15512        // (b2bd9d7) and
15513        // `declared_servico_slots_behavior_arm_routes_through_accessor`
15514        // (35d8b52) composition pins on the sibling `:limits` /
15515        // `:behavior` outer-`Option<&Composite>` arms of the peer
15516        // [`Caixa::declared_servico_slots`] M2 declared-slot
15517        // enumerator's traversal — same "the enumerator gate must
15518        // route through the substrate-primitive typed dispatch"
15519        // discipline extended onto the outer top-level [`Caixa`] M3
15520        // mesh-slot family so the [`Caixa::declared_mesh_slots`]
15521        // enumerator carries the same routing invariant as its M2
15522        // sibling.
15523        use crate::aplicacao::MeshPolicy;
15524        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
15525        let slots = c.declared_mesh_slots();
15526        assert!(
15527            slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
15528            "declared_mesh_slots must push M3_AUTHOR_KEY_POLITICAS \
15529             when `:politicas` is Some (even for MeshPolicy::default()) \
15530             — the accessor and the enumerator gate must route through \
15531             the same substrate-primitive typed dispatch on the outer \
15532             :politicas presence bit (got slots={slots:?})",
15533        );
15534        let c = caixa_aplicacao_with_politicas(None);
15535        let slots = c.declared_mesh_slots();
15536        assert!(
15537            !slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
15538            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_POLITICAS \
15539             when `:politicas` is None — the author-omitted arm must \
15540             route through the accessor's None-return unchanged (got \
15541             slots={slots:?})",
15542        );
15543    }
15544
15545    #[test]
15546    fn aplicacao_view_politicas_arm_folds_through_accessor() {
15547        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:politicas`
15548        // Aplicacao-composition seed must fold through
15549        // [`Caixa::politicas`], not the raw
15550        // `self.politicas.clone().unwrap_or_default()` field-borrow.
15551        // Structurally: a `Caixa { politicas: Some(MeshPolicy {
15552        // timeout: Some(30s), .. default }), kind: Aplicacao, .. }`
15553        // must surface a projected [`crate::AplicacaoSpec`] whose
15554        // `politicas().timeout()` field byte-equals the outer
15555        // composite's `timeout` scalar (the fold must project the
15556        // authored composite verbatim), a `Caixa { politicas:
15557        // Some(MeshPolicy::default()), kind: Aplicacao, .. }` must
15558        // surface an [`crate::AplicacaoSpec`] whose `politicas()`
15559        // byte-equals [`crate::aplicacao::MeshPolicy::default`] (the
15560        // fold's empty-composite arm collapses to the same default the
15561        // author-omitted arm does), and a `Caixa { politicas: None,
15562        // kind: Aplicacao, .. }` must surface an
15563        // [`crate::AplicacaoSpec`] whose `politicas()` byte-equals
15564        // [`crate::aplicacao::MeshPolicy::default`] (the "author
15565        // omitted the slot entirely" arm folds through the
15566        // `unwrap_or_default` onto the cluster-default). The triad
15567        // jointly pins the accessor + Aplicacao-composition seed
15568        // composition: any future silent detour that had the accessor
15569        // divert the raw slot away from the seed's fold (an operator-
15570        // resolved overlay's default-fold arm silently differing from
15571        // the raw slot's default-fold arm) would silently split the
15572        // build-time mesh-artifact emission gate from the caixa-mesh
15573        // renderer's Aplicacao-view input at the composition boundary.
15574        use crate::aplicacao::MeshPolicy;
15575        use std::time::Duration;
15576        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy {
15577            timeout: Some(Duration::from_secs(30)),
15578            ..Default::default()
15579        }));
15580        let view = c.aplicacao_view().unwrap();
15581        assert_eq!(
15582            view.politicas().timeout(),
15583            Some(Duration::from_secs(30)),
15584            "Caixa::aplicacao_view must fold the authored :politicas \
15585             :timeout scalar through the accessor verbatim onto the \
15586             projected AplicacaoSpec — a future silent detour at the \
15587             seed's fold arm would surface here as a projected-scalar \
15588             drift (got {:?})",
15589            view.politicas().timeout(),
15590        );
15591        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
15592        let view = c.aplicacao_view().unwrap();
15593        assert_eq!(
15594            view.politicas(),
15595            &MeshPolicy::default(),
15596            "Caixa::aplicacao_view must fold Some(MeshPolicy::default()) \
15597             through the accessor onto MeshPolicy::default — the empty- \
15598             composite arm collapses to the same default the author- \
15599             omitted arm does (got {:?})",
15600            view.politicas(),
15601        );
15602        let c = caixa_aplicacao_with_politicas(None);
15603        let view = c.aplicacao_view().unwrap();
15604        assert_eq!(
15605            view.politicas(),
15606            &MeshPolicy::default(),
15607            "Caixa::aplicacao_view must fold None through the accessor's \
15608             unwrap_or_default onto MeshPolicy::default — the author- \
15609             omitted arm must route through the accessor's None-return \
15610             unchanged (got {:?})",
15611            view.politicas(),
15612        );
15613    }
15614
15615    #[test]
15616    fn politicas_projects_option_ref_by_borrow() {
15617        // The by-borrow pin: [`Caixa::politicas`] returns
15618        // `Option<&MeshPolicy>` by borrow — the returned reference
15619        // borrows the underlying `Option<MeshPolicy>` storage of the
15620        // `:politicas` slot and the accessor must not clone the
15621        // backing composite on every call. Peer of the sibling
15622        // `limits_projects_option_ref_by_borrow` (b2bd9d7) and
15623        // `behavior_projects_option_ref_by_borrow` (35d8b52) by-borrow
15624        // pins on the outer top-level [`Caixa`]
15625        // `Option<&Composite>`-return sub-family — extended here to
15626        // the third axis of the same sub-family: the accessor's
15627        // returned reference must borrow from `&self` (the returned
15628        // reference's lifetime is tied to `&self`), and calling the
15629        // accessor twice on the same [`Caixa`] must yield references
15630        // that are pointer-equal (the underlying byte-buffer is the
15631        // storage `MeshPolicy`'s allocation, not a fresh copy) as
15632        // well as value-equal (idempotent, no side effects on
15633        // `&self`).
15634        //
15635        // Pins against a future silent detour that returned an owned
15636        // `MeshPolicy` (which would type-check via the `Clone` impl
15637        // but silently clone on every call), a `&MeshPolicy` panic-
15638        // return on the `None` arm (which would collapse the load-
15639        // bearing `Option` presence-bit into a runtime panic), or a
15640        // one-arm-only accessor that returned a saturating composite
15641        // on some sentinel input.
15642        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
15643        use std::time::Duration;
15644        for politicas in [
15645            Some(MeshPolicy::default()),
15646            Some(MeshPolicy {
15647                timeout: Some(Duration::from_secs(30)),
15648                retries: Some(3),
15649                circuit_breaker: Some(CircuitBreaker {
15650                    max_failures: 5,
15651                    window: Duration::from_secs(60),
15652                }),
15653                mtls_required: Some(true),
15654                rate_limit: Some(RateLimit {
15655                    rate: 100,
15656                    window: Duration::from_secs(1),
15657                }),
15658            }),
15659        ] {
15660            let c = caixa_aplicacao_with_politicas(politicas.clone());
15661            let first = c.politicas().unwrap();
15662            let second = c.politicas().unwrap();
15663            assert_eq!(
15664                first, second,
15665                "Caixa::politicas must be idempotent — two successive \
15666                 calls on the same &self must return the same \
15667                 &MeshPolicy",
15668            );
15669            assert!(
15670                std::ptr::eq(first, second),
15671                "Caixa::politicas must borrow the underlying \
15672                 Option<MeshPolicy> storage — two successive calls \
15673                 must return references with the same backing pointer \
15674                 (a fresh MeshPolicy clone would change the pointer on \
15675                 every call)",
15676            );
15677            assert_eq!(
15678                Some(first),
15679                politicas.as_ref(),
15680                "Caixa::politicas must return :politicas verbatim by \
15681                 borrow — got {first:?}, expected {:?}",
15682                politicas.as_ref(),
15683            );
15684        }
15685        let c = caixa_aplicacao_with_politicas(None);
15686        assert!(
15687            c.politicas().is_none(),
15688            "Caixa::politicas must return None when :politicas is \
15689             absent — the author-omitted arm must project through the \
15690             accessor's Option::None unchanged",
15691        );
15692    }
15693
15694    // ── Caixa::placement — outer top-level Option<&Placement> composite-reference accessor ──
15695
15696    fn caixa_aplicacao_with_placement(placement: Option<crate::aplicacao::Placement>) -> Caixa {
15697        use crate::aplicacao::{Membro, WitContract};
15698        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15699        c.kind = CaixaKind::Aplicacao;
15700        c.membros = vec![Membro {
15701            caixa: "a".into(),
15702            versao: "^0.1".into(),
15703        }];
15704        c.contratos = vec![WitContract {
15705            de: "a".into(),
15706            para: "a".into(),
15707            wit: "wasi:http/proxy".into(),
15708            endpoint: Some("/x".into()),
15709            subject: None,
15710            slot: None,
15711        }];
15712        c.placement = placement;
15713        c
15714    }
15715
15716    #[test]
15717    fn placement_returns_placement_option_ref_verbatim_across_permutations() {
15718        // The canonical per-`Caixa` `:placement` M3 mesh-slot outer-
15719        // composite optional-composite-reference-shape pin:
15720        // [`Caixa::placement`] must return the `:placement` typed
15721        // `Option<Placement>` verbatim as an `Option<&Placement>`
15722        // reference over the same backing storage the raw
15723        // `self.placement.as_ref()` field access borrows from,
15724        // byte-equal across every representative fixture in the
15725        // accept-set — the author-omitted `None` shape (the
15726        // "cluster-default applies" partition every downstream mesh-
15727        // artifact emitter treats as "emit no `:placement` overlay"),
15728        // the empty-composite `Some(Placement { .. default })` shape
15729        // (`estrategia: SingleNode`, empty clusters, no shard-key /
15730        // affinity — the outer presence-bit is `Some` so
15731        // [`Caixa::declared_mesh_slots`] still pushes the
15732        // `M3_AUTHOR_KEY_PLACEMENT` label), a single-axis
15733        // `Replicated`-on-two-clusters fixture (the canonical shape a
15734        // stateless HTTP Aplicacao carries), and a fully-populated
15735        // `Sharded`-with-shard-key-and-affinity fixture (the canonical
15736        // shape a stateful Akka-style cluster-sharding Aplicacao
15737        // carries).
15738        //
15739        // Pins against a future silent detour that returned a fresh-
15740        // cloned [`crate::aplicacao::Placement`] copy (which would
15741        // type-check via the `Clone` impl but silently break every
15742        // downstream caller that relied on the reference sharing the
15743        // composite's backing identity), a reference to an operator-
15744        // resolved overlay (the future per-cluster
15745        // `:placement-overrides` slot — its resolution must land at
15746        // exactly this accessor body, not silently divert the raw
15747        // slot away from the peer [`Caixa::declared_mesh_slots`]
15748        // enumerator's presence probe), a `None` →
15749        // `Some(Placement::default)` cluster-default projection (which
15750        // would collapse the load-bearing "author-omitted `:placement`
15751        // ⇒ cluster-default applies" partition the peer
15752        // [`Caixa::declared_mesh_slots`] enumerator and the peer
15753        // [`Caixa::aplicacao_view`] Aplicacao-composition seed both
15754        // read), or an axis-shuffled projection (a future detour that
15755        // swapped `clusters` and `affinity` through the accessor would
15756        // silently split the paired [`Caixa::aplicacao_view`] seed's
15757        // fold input from the sibling M3 mesh-artifact emitter's
15758        // projection input).
15759        //
15760        // Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
15761        // composite-reference accessor pin on the substrate primitive
15762        // — peer of the sibling
15763        // `limits_returns_limits_option_ref_verbatim_across_permutations`
15764        // (b2bd9d7),
15765        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
15766        // (35d8b52), and
15767        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
15768        // (5d23d29) opening triad pins on the outer top-level
15769        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
15770        // here to the second of the three M3 mesh-slot axes so the
15771        // opening four-fifths of the outer `Option<&Composite>` sub-
15772        // family carries the same "byte-equal, borrow-shared,
15773        // presence-bit-preserved" outer-accessor discipline.
15774        use crate::aplicacao::{Placement, PlacementStrategy};
15775        let fixtures: Vec<Option<Placement>> = vec![
15776            None,
15777            Some(Placement::default()),
15778            Some(Placement {
15779                estrategia: PlacementStrategy::Replicated,
15780                clusters: vec!["rio".into(), "sao-paulo".into()],
15781                affinity: None,
15782                shard_key: None,
15783            }),
15784            Some(Placement {
15785                estrategia: PlacementStrategy::Sharded,
15786                clusters: vec!["rio".into(), "sao-paulo".into(), "brasilia".into()],
15787                affinity: Some("data-locality".into()),
15788                shard_key: Some("$tenantId".into()),
15789            }),
15790        ];
15791        for placement in fixtures {
15792            let c = caixa_aplicacao_with_placement(placement.clone());
15793            assert_eq!(
15794                c.placement(),
15795                placement.as_ref(),
15796                "Caixa::placement must return :placement verbatim (got \
15797                 {:?}, expected {:?})",
15798                c.placement(),
15799                placement.as_ref(),
15800            );
15801            match (c.placement(), c.placement.as_ref()) {
15802                (Some(a), Some(b)) => assert!(
15803                    std::ptr::eq(a, b),
15804                    "Caixa::placement accessor and self.placement.as_ref() \
15805                     field access must borrow the same backing storage \
15806                     — the accessor is the substrate-primitive typed \
15807                     dispatch every downstream Aplicacao-distribution- \
15808                     overlay composite consumer must route through, and \
15809                     a reference-identity split would silently break \
15810                     every consumer that relied on the borrow sharing \
15811                     the composite's storage",
15812                ),
15813                (None, None) => {}
15814                _ => panic!(
15815                    "Caixa::placement presence bit must byte-equal \
15816                     self.placement.is_some() — a presence-bit drift \
15817                     would silently split the paired \
15818                     Caixa::aplicacao_view Aplicacao-composition seed's \
15819                     traversal head from the peer \
15820                     Caixa::declared_mesh_slots M3 declared-slot \
15821                     enumerator's presence probe",
15822                ),
15823            }
15824            assert_eq!(
15825                c.placement().is_some(),
15826                c.placement.is_some(),
15827                "Caixa::placement().is_some() must byte-equal \
15828                 self.placement.is_some() — a presence-bit drift would \
15829                 silently split every downstream Option<&Placement> \
15830                 consumer's partition on the cluster-default arm",
15831            );
15832        }
15833    }
15834
15835    #[test]
15836    fn declared_mesh_slots_placement_arm_routes_through_accessor() {
15837        // Composition pin: [`Caixa::declared_mesh_slots`]'s
15838        // `:placement` presence-probe arm must key off
15839        // [`Caixa::placement`], not the raw `self.placement.is_some()`
15840        // field-probe. Structurally: a `Caixa { placement:
15841        // Some(Placement::default()), .. }` must still push
15842        // `M3_AUTHOR_KEY_PLACEMENT` onto the declared-slot list (the
15843        // presence bit is `Some`, so the M3 kind-coherence gate must
15844        // surface the slot as "declared" even when every per-axis
15845        // scalar defers to the cluster-default arm), and a `Caixa {
15846        // placement: None, .. }` must NOT push the label (the "author
15847        // omitted the slot entirely" partition). The pair jointly pins
15848        // the accessor + declared-slot enumerator composition: any
15849        // future silent detour that had the accessor collapse
15850        // `Some(Placement::default())` to `None` (a `.filter(|p|
15851        // p.clusters().is_empty().not())` projection) would silently
15852        // absorb the "declared but empty" arm at the accessor boundary
15853        // and the [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
15854        // kind-coherence gate would silently accept a struct-literal
15855        // `Caixa` carrying the drift.
15856        //
15857        // Peer of the sibling
15858        // `declared_servico_slots_limits_arm_routes_through_accessor`
15859        // (b2bd9d7),
15860        // `declared_servico_slots_behavior_arm_routes_through_accessor`
15861        // (35d8b52), and
15862        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
15863        // (5d23d29) composition pins on the sibling `:limits` /
15864        // `:behavior` / `:politicas` outer-`Option<&Composite>` arms
15865        // — same "the enumerator gate must route through the
15866        // substrate-primitive typed dispatch" discipline extended onto
15867        // the second of the three M3 mesh-slot axes so the
15868        // [`Caixa::declared_mesh_slots`] enumerator carries the same
15869        // routing invariant on the `:placement` arm as the peer
15870        // `:politicas` arm.
15871        use crate::aplicacao::Placement;
15872        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
15873        let slots = c.declared_mesh_slots();
15874        assert!(
15875            slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
15876            "declared_mesh_slots must push M3_AUTHOR_KEY_PLACEMENT \
15877             when `:placement` is Some (even for Placement::default()) \
15878             — the accessor and the enumerator gate must route through \
15879             the same substrate-primitive typed dispatch on the outer \
15880             :placement presence bit (got slots={slots:?})",
15881        );
15882        let c = caixa_aplicacao_with_placement(None);
15883        let slots = c.declared_mesh_slots();
15884        assert!(
15885            !slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
15886            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_PLACEMENT \
15887             when `:placement` is None — the author-omitted arm must \
15888             route through the accessor's None-return unchanged (got \
15889             slots={slots:?})",
15890        );
15891    }
15892
15893    #[test]
15894    fn aplicacao_view_placement_arm_folds_through_accessor() {
15895        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:placement`
15896        // Aplicacao-composition seed must fold through
15897        // [`Caixa::placement`], not the raw
15898        // `self.placement.clone().unwrap_or_default()` field-borrow.
15899        // Structurally: a `Caixa { placement: Some(Placement {
15900        // estrategia: Replicated, clusters: ["rio"], .. default }),
15901        // kind: Aplicacao, .. }` must surface a projected
15902        // [`crate::AplicacaoSpec`] whose `placement().estrategia()` +
15903        // `placement().clusters()` byte-equal the outer composite's
15904        // authored values (the fold must project the authored
15905        // composite verbatim), a `Caixa { placement:
15906        // Some(Placement::default()), kind: Aplicacao, .. }` must
15907        // surface an [`crate::AplicacaoSpec`] whose `placement()`
15908        // byte-equals [`crate::aplicacao::Placement::default`] (the
15909        // fold's empty-composite arm collapses to the same default
15910        // the author-omitted arm does), and a `Caixa { placement:
15911        // None, kind: Aplicacao, .. }` must surface an
15912        // [`crate::AplicacaoSpec`] whose `placement()` byte-equals
15913        // [`crate::aplicacao::Placement::default`] (the "author
15914        // omitted the slot entirely" arm folds through the
15915        // `unwrap_or_default` onto the cluster-default). The triad
15916        // jointly pins the accessor + Aplicacao-composition seed
15917        // composition: any future silent detour that had the accessor
15918        // divert the raw slot away from the seed's fold (an operator-
15919        // resolved overlay's default-fold arm silently differing from
15920        // the raw slot's default-fold arm) would silently split the
15921        // build-time distribution-artifact emission gate from the
15922        // caixa-mesh renderer's Aplicacao-view input at the
15923        // composition boundary.
15924        use crate::aplicacao::{Placement, PlacementStrategy};
15925        let c = caixa_aplicacao_with_placement(Some(Placement {
15926            estrategia: PlacementStrategy::Replicated,
15927            clusters: vec!["rio".into()],
15928            affinity: None,
15929            shard_key: None,
15930        }));
15931        let view = c.aplicacao_view().unwrap();
15932        assert_eq!(
15933            view.placement().estrategia(),
15934            PlacementStrategy::Replicated,
15935            "Caixa::aplicacao_view must fold the authored :placement \
15936             :estrategia scalar through the accessor verbatim onto the \
15937             projected AplicacaoSpec — a future silent detour at the \
15938             seed's fold arm would surface here as a projected-scalar \
15939             drift (got {:?})",
15940            view.placement().estrategia(),
15941        );
15942        assert_eq!(
15943            view.placement().clusters(),
15944            &["rio"],
15945            "Caixa::aplicacao_view must fold the authored :placement \
15946             :clusters list through the accessor verbatim onto the \
15947             projected AplicacaoSpec — a future silent detour at the \
15948             seed's fold arm would surface here as a projected-list \
15949             drift (got {:?})",
15950            view.placement().clusters(),
15951        );
15952        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
15953        let view = c.aplicacao_view().unwrap();
15954        assert_eq!(
15955            view.placement(),
15956            &Placement::default(),
15957            "Caixa::aplicacao_view must fold Some(Placement::default()) \
15958             through the accessor onto Placement::default — the empty- \
15959             composite arm collapses to the same default the author- \
15960             omitted arm does (got {:?})",
15961            view.placement(),
15962        );
15963        let c = caixa_aplicacao_with_placement(None);
15964        let view = c.aplicacao_view().unwrap();
15965        assert_eq!(
15966            view.placement(),
15967            &Placement::default(),
15968            "Caixa::aplicacao_view must fold None through the accessor's \
15969             unwrap_or_default onto Placement::default — the author- \
15970             omitted arm must route through the accessor's None-return \
15971             unchanged (got {:?})",
15972            view.placement(),
15973        );
15974    }
15975
15976    #[test]
15977    fn placement_projects_option_ref_by_borrow() {
15978        // The by-borrow pin: [`Caixa::placement`] returns
15979        // `Option<&Placement>` by borrow — the returned reference
15980        // borrows the underlying `Option<Placement>` storage of the
15981        // `:placement` slot and the accessor must not clone the
15982        // backing composite on every call. Peer of the sibling
15983        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
15984        // `behavior_projects_option_ref_by_borrow` (35d8b52), and
15985        // `politicas_projects_option_ref_by_borrow` (5d23d29) by-borrow
15986        // pins on the outer top-level [`Caixa`]
15987        // `Option<&Composite>`-return sub-family — extended here to
15988        // the fourth axis of the same sub-family: the accessor's
15989        // returned reference must borrow from `&self` (the returned
15990        // reference's lifetime is tied to `&self`), and calling the
15991        // accessor twice on the same [`Caixa`] must yield references
15992        // that are pointer-equal (the underlying byte-buffer is the
15993        // storage `Placement`'s allocation, not a fresh copy) as well
15994        // as value-equal (idempotent, no side effects on `&self`).
15995        //
15996        // Pins against a future silent detour that returned an owned
15997        // `Placement` (which would type-check via the `Clone` impl
15998        // but silently clone on every call), a `&Placement` panic-
15999        // return on the `None` arm (which would collapse the load-
16000        // bearing `Option` presence-bit into a runtime panic), or a
16001        // one-arm-only accessor that returned a saturating composite
16002        // on some sentinel input.
16003        use crate::aplicacao::{Placement, PlacementStrategy};
16004        for placement in [
16005            Some(Placement::default()),
16006            Some(Placement {
16007                estrategia: PlacementStrategy::Sharded,
16008                clusters: vec!["rio".into(), "sao-paulo".into()],
16009                affinity: Some("data-locality".into()),
16010                shard_key: Some("$tenantId".into()),
16011            }),
16012        ] {
16013            let c = caixa_aplicacao_with_placement(placement.clone());
16014            let first = c.placement().unwrap();
16015            let second = c.placement().unwrap();
16016            assert_eq!(
16017                first, second,
16018                "Caixa::placement must be idempotent — two successive \
16019                 calls on the same &self must return the same \
16020                 &Placement",
16021            );
16022            assert!(
16023                std::ptr::eq(first, second),
16024                "Caixa::placement must borrow the underlying \
16025                 Option<Placement> storage — two successive calls \
16026                 must return references with the same backing pointer \
16027                 (a fresh Placement clone would change the pointer on \
16028                 every call)",
16029            );
16030            assert_eq!(
16031                Some(first),
16032                placement.as_ref(),
16033                "Caixa::placement must return :placement verbatim by \
16034                 borrow — got {first:?}, expected {:?}",
16035                placement.as_ref(),
16036            );
16037        }
16038        let c = caixa_aplicacao_with_placement(None);
16039        assert!(
16040            c.placement().is_none(),
16041            "Caixa::placement must return None when :placement is \
16042             absent — the author-omitted arm must project through the \
16043             accessor's Option::None unchanged",
16044        );
16045    }
16046
16047    // ── Caixa::entrada — outer top-level Option<&Entrada> composite-reference accessor ──
16048
16049    fn caixa_aplicacao_with_entrada(entrada: Option<crate::aplicacao::Entrada>) -> Caixa {
16050        use crate::aplicacao::{Membro, WitContract};
16051        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16052        c.kind = CaixaKind::Aplicacao;
16053        c.membros = vec![Membro {
16054            caixa: "a".into(),
16055            versao: "^0.1".into(),
16056        }];
16057        c.contratos = vec![WitContract {
16058            de: "a".into(),
16059            para: "a".into(),
16060            wit: "wasi:http/proxy".into(),
16061            endpoint: Some("/x".into()),
16062            subject: None,
16063            slot: None,
16064        }];
16065        c.entrada = entrada;
16066        c
16067    }
16068
16069    #[test]
16070    fn entrada_returns_entrada_option_ref_verbatim_across_permutations() {
16071        // The canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
16072        // composite optional-composite-reference-shape pin:
16073        // [`Caixa::entrada`] must return the `:entrada` typed
16074        // `Option<Entrada>` verbatim as an `Option<&Entrada>`
16075        // reference over the same backing storage the raw
16076        // `self.entrada.as_ref()` field access borrows from,
16077        // byte-equal across every representative fixture in the
16078        // accept-set — the author-omitted `None` shape (the
16079        // "cluster-internal Aplicacao" partition every downstream
16080        // Gateway-API emitter treats as "emit no listener + no
16081        // HTTPRoute"), a bare-`host`/`para` minimum-composite fixture
16082        // (empty `paths` — the resolved-paths fallback the peer
16083        // [`crate::aplicacao::Entrada::resolved_paths`] cascade folds
16084        // onto the substrate catch-all), and a fully-populated
16085        // multi-path-with-non-default-port fixture (the canonical
16086        // shape a public HTTP Aplicacao carries).
16087        //
16088        // Pins against a future silent detour that returned a fresh-
16089        // cloned [`crate::aplicacao::Entrada`] copy (which would
16090        // type-check via the `Clone` impl but silently break every
16091        // downstream caller that relied on the reference sharing the
16092        // composite's backing identity), a reference to an operator-
16093        // resolved overlay (the future per-cluster
16094        // `:entrada-overrides` slot — its resolution must land at
16095        // exactly this accessor body, not silently divert the raw
16096        // slot away from the peer [`Caixa::declared_mesh_slots`]
16097        // enumerator's presence probe), or an axis-shuffled projection
16098        // (a future detour that swapped `host` and `para` through the
16099        // accessor would silently split the paired
16100        // [`Caixa::aplicacao_view`] seed's forward input from the
16101        // sibling M3 gateway-artifact emitter's projection input).
16102        //
16103        // Fifth and final outer top-level [`Caixa`]
16104        // `Option<&Composite>`-return composite-reference accessor pin
16105        // on the substrate primitive — peer of the sibling
16106        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16107        // (b2bd9d7),
16108        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
16109        // (35d8b52),
16110        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
16111        // (5d23d29), and
16112        // `placement_returns_placement_option_ref_verbatim_across_permutations`
16113        // (4fb8074) opening tetrad pins on the outer top-level
16114        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
16115        // here to the third and final M3 mesh-slot axis so the closed
16116        // outer `Option<&Composite>` sub-family carries the same
16117        // "byte-equal, borrow-shared, presence-bit-preserved" outer-
16118        // accessor discipline across all five arms.
16119        use crate::aplicacao::Entrada;
16120        let fixtures: Vec<Option<Entrada>> = vec![
16121            None,
16122            Some(Entrada {
16123                host: "checkout.quero.cloud".into(),
16124                para: "gateway".into(),
16125                paths: Vec::new(),
16126                port: crate::DEFAULT_SERVICO_PORT,
16127            }),
16128            Some(Entrada {
16129                host: "api.pleme.io".into(),
16130                para: "public-api".into(),
16131                paths: vec!["/v1".into(), "/v2".into()],
16132                port: 8080,
16133            }),
16134        ];
16135        for entrada in fixtures {
16136            let c = caixa_aplicacao_with_entrada(entrada.clone());
16137            assert_eq!(
16138                c.entrada(),
16139                entrada.as_ref(),
16140                "Caixa::entrada must return :entrada verbatim (got \
16141                 {:?}, expected {:?})",
16142                c.entrada(),
16143                entrada.as_ref(),
16144            );
16145            match (c.entrada(), c.entrada.as_ref()) {
16146                (Some(a), Some(b)) => assert!(
16147                    std::ptr::eq(a, b),
16148                    "Caixa::entrada accessor and self.entrada.as_ref() \
16149                     field access must borrow the same backing storage \
16150                     — the accessor is the substrate-primitive typed \
16151                     dispatch every downstream Aplicacao-external- \
16152                     gateway composite consumer must route through, and \
16153                     a reference-identity split would silently break \
16154                     every consumer that relied on the borrow sharing \
16155                     the composite's storage",
16156                ),
16157                (None, None) => {}
16158                _ => panic!(
16159                    "Caixa::entrada presence bit must byte-equal \
16160                     self.entrada.is_some() — a presence-bit drift \
16161                     would silently split the paired \
16162                     Caixa::aplicacao_view Aplicacao-composition seed's \
16163                     traversal head from the peer \
16164                     Caixa::declared_mesh_slots M3 declared-slot \
16165                     enumerator's presence probe",
16166                ),
16167            }
16168            assert_eq!(
16169                c.entrada().is_some(),
16170                c.entrada.is_some(),
16171                "Caixa::entrada().is_some() must byte-equal \
16172                 self.entrada.is_some() — a presence-bit drift would \
16173                 silently split every downstream Option<&Entrada> \
16174                 consumer's partition on the cluster-internal arm",
16175            );
16176        }
16177    }
16178
16179    #[test]
16180    fn declared_mesh_slots_entrada_arm_routes_through_accessor() {
16181        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:entrada`
16182        // presence-probe arm must key off [`Caixa::entrada`], not the
16183        // raw `self.entrada.is_some()` field-probe. Structurally: a
16184        // `Caixa { entrada: Some(Entrada { host: "...", para: "...",
16185        // paths: [], port: DEFAULT_SERVICO_PORT }), .. }` must push
16186        // `M3_AUTHOR_KEY_ENTRADA` onto the declared-slot list (the
16187        // presence bit is `Some`, so the M3 kind-coherence gate must
16188        // surface the slot as "declared" even when every per-axis
16189        // scalar defers to the substrate catch-all / default port),
16190        // and a `Caixa { entrada: None, .. }` must NOT push the label
16191        // (the "author omitted the slot entirely" partition). The pair
16192        // jointly pins the accessor + declared-slot enumerator
16193        // composition: any future silent detour that had the accessor
16194        // collapse `Some(Entrada { paths: [], .. })` to `None` (a
16195        // `.filter(|e| !e.paths.is_empty())` projection) would silently
16196        // absorb the "declared but empty-paths" arm at the accessor
16197        // boundary and the
16198        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
16199        // coherence gate would silently accept a struct-literal
16200        // `Caixa` carrying the drift.
16201        //
16202        // Peer of the sibling
16203        // `declared_servico_slots_limits_arm_routes_through_accessor`
16204        // (b2bd9d7),
16205        // `declared_servico_slots_behavior_arm_routes_through_accessor`
16206        // (35d8b52),
16207        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
16208        // (5d23d29), and
16209        // `declared_mesh_slots_placement_arm_routes_through_accessor`
16210        // (4fb8074) composition pins on the sibling `:limits` /
16211        // `:behavior` / `:politicas` / `:placement` outer-
16212        // `Option<&Composite>` arms — same "the enumerator gate must
16213        // route through the substrate-primitive typed dispatch"
16214        // discipline extended onto the third and final M3 mesh-slot
16215        // axis so the [`Caixa::declared_mesh_slots`] enumerator now
16216        // carries the routing invariant on every M3 mesh-slot arm.
16217        use crate::aplicacao::Entrada;
16218        let c = caixa_aplicacao_with_entrada(Some(Entrada {
16219            host: "checkout.quero.cloud".into(),
16220            para: "gateway".into(),
16221            paths: Vec::new(),
16222            port: crate::DEFAULT_SERVICO_PORT,
16223        }));
16224        let slots = c.declared_mesh_slots();
16225        assert!(
16226            slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
16227            "declared_mesh_slots must push M3_AUTHOR_KEY_ENTRADA when \
16228             `:entrada` is Some (even for empty-paths / default-port) \
16229             — the accessor and the enumerator gate must route through \
16230             the same substrate-primitive typed dispatch on the outer \
16231             :entrada presence bit (got slots={slots:?})",
16232        );
16233        let c = caixa_aplicacao_with_entrada(None);
16234        let slots = c.declared_mesh_slots();
16235        assert!(
16236            !slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
16237            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_ENTRADA \
16238             when `:entrada` is None — the author-omitted arm must \
16239             route through the accessor's None-return unchanged (got \
16240             slots={slots:?})",
16241        );
16242    }
16243
16244    #[test]
16245    fn aplicacao_view_entrada_arm_folds_through_accessor() {
16246        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:entrada`
16247        // Aplicacao-composition seed must fold through
16248        // [`Caixa::entrada`], not the raw `self.entrada.clone()` field-
16249        // borrow. Structurally: a `Caixa { entrada: Some(Entrada {
16250        // host: "api.pleme.io", para: "public-api", paths: ["/v1"],
16251        // port: 8080 }), kind: Aplicacao, .. }` must surface a projected
16252        // [`crate::AplicacaoSpec`] whose `entrada().unwrap()` byte-
16253        // equals the outer composite's authored value (the fold must
16254        // project the authored composite verbatim), and a `Caixa {
16255        // entrada: None, kind: Aplicacao, .. }` must surface an
16256        // [`crate::AplicacaoSpec`] whose `entrada()` is `None` (the
16257        // "author omitted the slot entirely" arm folds through the
16258        // accessor's `Option::cloned` onto the same `None` presence
16259        // bit — unlike the peer `:politicas` / `:placement` arms
16260        // `:entrada` has no cluster-default fold, the omitted arm
16261        // stays omitted). The pair jointly pins the accessor +
16262        // Aplicacao-composition seed composition: any future silent
16263        // detour that had the accessor divert the raw slot away from
16264        // the seed's fold (an operator-resolved overlay's forward arm
16265        // silently differing from the raw slot's forward arm) would
16266        // silently split the build-time gateway-artifact emission gate
16267        // from the caixa-mesh renderer's Aplicacao-view input at the
16268        // composition boundary.
16269        use crate::aplicacao::Entrada;
16270        let authored = Entrada {
16271            host: "api.pleme.io".into(),
16272            para: "public-api".into(),
16273            paths: vec!["/v1".into()],
16274            port: 8080,
16275        };
16276        let c = caixa_aplicacao_with_entrada(Some(authored.clone()));
16277        let view = c.aplicacao_view().unwrap();
16278        assert_eq!(
16279            view.entrada(),
16280            Some(&authored),
16281            "Caixa::aplicacao_view must fold the authored :entrada \
16282             composite through the accessor verbatim onto the \
16283             projected AplicacaoSpec — a future silent detour at the \
16284             seed's fold arm would surface here as a projected- \
16285             composite drift (got {:?})",
16286            view.entrada(),
16287        );
16288        let c = caixa_aplicacao_with_entrada(None);
16289        let view = c.aplicacao_view().unwrap();
16290        assert!(
16291            view.entrada().is_none(),
16292            "Caixa::aplicacao_view must fold None through the \
16293             accessor's Option::cloned onto None — the author- \
16294             omitted arm must route through the accessor's None-return \
16295             unchanged (got {:?})",
16296            view.entrada(),
16297        );
16298    }
16299
16300    #[test]
16301    fn entrada_projects_option_ref_by_borrow() {
16302        // The by-borrow pin: [`Caixa::entrada`] returns
16303        // `Option<&Entrada>` by borrow — the returned reference
16304        // borrows the underlying `Option<Entrada>` storage of the
16305        // `:entrada` slot and the accessor must not clone the backing
16306        // composite on every call. Peer of the sibling
16307        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
16308        // `behavior_projects_option_ref_by_borrow` (35d8b52),
16309        // `politicas_projects_option_ref_by_borrow` (5d23d29), and
16310        // `placement_projects_option_ref_by_borrow` (4fb8074) by-
16311        // borrow pins on the outer top-level [`Caixa`]
16312        // `Option<&Composite>`-return sub-family — extended here to
16313        // the fifth and final axis of the same sub-family, closing
16314        // the discipline: the accessor's returned reference must
16315        // borrow from `&self` (the returned reference's lifetime is
16316        // tied to `&self`), and calling the accessor twice on the
16317        // same [`Caixa`] must yield references that are pointer-equal
16318        // (the underlying byte-buffer is the storage `Entrada`'s
16319        // allocation, not a fresh copy) as well as value-equal
16320        // (idempotent, no side effects on `&self`).
16321        //
16322        // Pins against a future silent detour that returned an owned
16323        // `Entrada` (which would type-check via the `Clone` impl but
16324        // silently clone on every call), a `&Entrada` panic-return on
16325        // the `None` arm (which would collapse the load-bearing
16326        // `Option` presence-bit into a runtime panic), or a one-arm-
16327        // only accessor that returned a saturating composite on some
16328        // sentinel input.
16329        use crate::aplicacao::Entrada;
16330        for entrada in [
16331            Some(Entrada {
16332                host: "checkout.quero.cloud".into(),
16333                para: "gateway".into(),
16334                paths: Vec::new(),
16335                port: crate::DEFAULT_SERVICO_PORT,
16336            }),
16337            Some(Entrada {
16338                host: "api.pleme.io".into(),
16339                para: "public-api".into(),
16340                paths: vec!["/v1".into(), "/v2".into()],
16341                port: 8080,
16342            }),
16343        ] {
16344            let c = caixa_aplicacao_with_entrada(entrada.clone());
16345            let first = c.entrada().unwrap();
16346            let second = c.entrada().unwrap();
16347            assert_eq!(
16348                first, second,
16349                "Caixa::entrada must be idempotent — two successive \
16350                 calls on the same &self must return the same &Entrada",
16351            );
16352            assert!(
16353                std::ptr::eq(first, second),
16354                "Caixa::entrada must borrow the underlying \
16355                 Option<Entrada> storage — two successive calls must \
16356                 return references with the same backing pointer (a \
16357                 fresh Entrada clone would change the pointer on every \
16358                 call)",
16359            );
16360            assert_eq!(
16361                Some(first),
16362                entrada.as_ref(),
16363                "Caixa::entrada must return :entrada verbatim by \
16364                 borrow — got {first:?}, expected {:?}",
16365                entrada.as_ref(),
16366            );
16367        }
16368        let c = caixa_aplicacao_with_entrada(None);
16369        assert!(
16370            c.entrada().is_none(),
16371            "Caixa::entrada must return None when :entrada is absent \
16372             — the author-omitted arm must project through the \
16373             accessor's Option::None unchanged",
16374        );
16375    }
16376
16377    // ── Caixa::estrategia — outer top-level Option<RestartStrategy> flat-spread supervisor-tree accessor ──
16378
16379    fn caixa_with_estrategia(estrategia: Option<crate::supervisor::RestartStrategy>) -> Caixa {
16380        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16381        c.estrategia = estrategia;
16382        c
16383    }
16384
16385    #[test]
16386    fn estrategia_returns_estrategia_option_verbatim_across_permutations() {
16387        // The canonical per-`Caixa` `:estrategia` M2 supervisor-tree-slot
16388        // flat-spread `Option<RestartStrategy>`-return `Copy`-composite-
16389        // enum-arm scalar shape pin: [`Caixa::estrategia`] must return
16390        // the `:estrategia` typed `Option<crate::supervisor::RestartStrategy>`
16391        // verbatim as an `Option<RestartStrategy>` `Copy`-projected value
16392        // over the same discriminant the raw `self.estrategia` field
16393        // access carries, byte-equal across every representative fixture
16394        // in the accept-set — the author-omitted `None` shape (the
16395        // "defer to [`RestartStrategy::default`] through the
16396        // [`Self::supervisor_view`] `unwrap_or_default()` fold" partition
16397        // every non-`Supervisor`-kind `defcaixa` carries by
16398        // `#[serde(default)]`), and each of the four closed-set variants
16399        // [`RestartStrategy::OneForOne`] / [`RestartStrategy::OneForAll`]
16400        // / [`RestartStrategy::RestForOne`] /
16401        // [`RestartStrategy::SimpleOneForOne`] the author-declared arm
16402        // partitions on.
16403        //
16404        // Pins against a future silent detour that re-derived the
16405        // strategy from a peer axis (an accidental fallback to
16406        // `if children.is_empty() { SimpleOneForOne } else { OneForOne }`
16407        // collapse that read the outer `:children` list-length axis into
16408        // the strategy discriminator at the accessor boundary), a
16409        // stale-derive detour that substituted [`RestartStrategy::default`]
16410        // when the outer `Option` held `None` (which would silently
16411        // collapse the load-bearing "author explicitly declared
16412        // `:estrategia OneForOne`" vs "author omitted the slot and
16413        // inherited the default" partition the [`Self::declared_supervisor_slots`]
16414        // presence-probe reads — the enumerator gate would still push
16415        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` on the omitted arm, silently
16416        // splitting the paired [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
16417        // kind-coherence gate's traversal head from the
16418        // [`Self::supervisor_view`] `unwrap_or_default()` fold's
16419        // composition head), a reference to an operator-resolved overlay
16420        // (the future per-cluster `:estrategia-overrides` slot — its
16421        // resolution must land at exactly this accessor body, not
16422        // silently divert the raw slot away from a second consumer), or
16423        // an axis-remap projection (a future detour that mapped
16424        // `OneForAll` through the accessor onto `OneForOne` would
16425        // silently split every downstream sibling-restart-strategy
16426        // consumer's per-arm fan-out).
16427        //
16428        // First outer top-level [`Caixa`] `Option<Copy>`-return
16429        // supervisor-tree-slot flat-spread accessor pin on the substrate
16430        // primitive — opens the outer-`Caixa` `Option<Copy>` flat-spread
16431        // projection pattern the sibling per-`Caixa` `:max-restarts` /
16432        // `:restart-window` future outer-scalar pins fold on. Peer of
16433        // the inner-altitude
16434        // `supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
16435        // (eafb619) pin on the post-composition [`SupervisorSpec`]
16436        // altitude — same "the substrate-primitive accessor must byte-
16437        // equal the raw field access verbatim across every author-
16438        // declared value" discipline extended onto the pre-composition
16439        // outer author-surface [`Caixa`] altitude. Peer of the closed
16440        // outer-`Caixa` `Option<&Composite>` composite-reference family
16441        // the sibling `limits` / `behavior` / `politicas` / `placement` /
16442        // `entrada`
16443        // `..._returns_..._option_ref_verbatim_across_permutations` pins
16444        // already carry on the outer `Option<&Composite>` altitude.
16445        use crate::supervisor::RestartStrategy;
16446        let fixtures: Vec<Option<RestartStrategy>> = vec![
16447            None,
16448            Some(RestartStrategy::OneForOne),
16449            Some(RestartStrategy::OneForAll),
16450            Some(RestartStrategy::RestForOne),
16451            Some(RestartStrategy::SimpleOneForOne),
16452        ];
16453        for estrategia in fixtures {
16454            let c = caixa_with_estrategia(estrategia);
16455            assert_eq!(
16456                c.estrategia(),
16457                estrategia,
16458                "Caixa::estrategia must return :estrategia verbatim (got \
16459                 {:?}, expected {:?})",
16460                c.estrategia(),
16461                estrategia,
16462            );
16463            assert_eq!(
16464                c.estrategia(),
16465                c.estrategia,
16466                "Caixa::estrategia accessor and self.estrategia field \
16467                 access must byte-equal — the accessor is the substrate-\
16468                 primitive typed dispatch every downstream supervisor-\
16469                 tree flat-spread consumer must route through, and a \
16470                 discriminant split would silently break every consumer \
16471                 that relied on the accessor sharing the field's own \
16472                 Option<Copy> shape",
16473            );
16474            assert_eq!(
16475                c.estrategia().is_some(),
16476                c.estrategia.is_some(),
16477                "Caixa::estrategia().is_some() must byte-equal \
16478                 self.estrategia.is_some() — a presence-bit drift would \
16479                 silently split the paired Caixa::declared_supervisor_slots \
16480                 presence-probe arm from the Caixa::supervisor_view \
16481                 unwrap_or_default() fold's composition input",
16482            );
16483        }
16484    }
16485
16486    #[test]
16487    fn declared_supervisor_slots_estrategia_arm_routes_through_accessor() {
16488        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
16489        // `:estrategia` presence-probe arm must key off
16490        // [`Caixa::estrategia`], not the raw `self.estrategia.is_some()`
16491        // field-probe. Structurally: every `Caixa { estrategia:
16492        // Some(RestartStrategy::_), .. }` variant must push
16493        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` onto the declared-slot list
16494        // (the presence bit is `Some` for every closed-set variant, so
16495        // the M2 supervisor-tree kind-coherence gate must surface the
16496        // slot as "declared" regardless of which variant the author
16497        // picked), and a `Caixa { estrategia: None, .. }` must NOT push
16498        // the label (the "author omitted the slot entirely, deferring
16499        // to [`RestartStrategy::default`] through the supervisor_view
16500        // fold" partition). The pair jointly pins the accessor +
16501        // declared-slot enumerator composition: any future silent detour
16502        // that had the accessor collapse `Some(RestartStrategy::default())`
16503        // to `None` (a `.filter(|e| *e != RestartStrategy::default())`
16504        // projection) would silently absorb the "declared but default-
16505        // valued" arm at the accessor boundary and the
16506        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
16507        // coherence gate would silently accept a struct-literal `Caixa`
16508        // carrying the drift.
16509        //
16510        // Peer of the sibling per-`Caixa`
16511        // `declared_servico_slots_limits_arm_routes_through_accessor`
16512        // (b2bd9d7) accessor-composition pin on the sibling outer-`Caixa`
16513        // `Option<&LimitsSpec>` composition axis — same "the enumerator
16514        // gate must route through the substrate-primitive typed
16515        // dispatch" discipline extended onto the flat-spread M2
16516        // supervisor-tree `Option<RestartStrategy>`-composition surface,
16517        // opening the outer-`Caixa` supervisor-tree-slot arm of the
16518        // composition-pin family.
16519        use crate::supervisor::RestartStrategy;
16520        for estrategia in [
16521            RestartStrategy::OneForOne,
16522            RestartStrategy::OneForAll,
16523            RestartStrategy::RestForOne,
16524            RestartStrategy::SimpleOneForOne,
16525        ] {
16526            let c = caixa_with_estrategia(Some(estrategia));
16527            let slots = c.declared_supervisor_slots();
16528            assert!(
16529                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
16530                "declared_supervisor_slots must push \
16531                 SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is \
16532                 Some({estrategia:?}) — the accessor and the enumerator \
16533                 gate must route through the same substrate-primitive \
16534                 typed dispatch on the outer :estrategia presence bit \
16535                 (got slots={slots:?})",
16536            );
16537        }
16538        let c = caixa_with_estrategia(None);
16539        let slots = c.declared_supervisor_slots();
16540        assert!(
16541            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
16542            "declared_supervisor_slots must NOT push \
16543             SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is None \
16544             — the author-omitted arm must route through the accessor's \
16545             None-return unchanged (got slots={slots:?})",
16546        );
16547    }
16548
16549    #[test]
16550    fn supervisor_view_estrategia_arm_routes_through_accessor() {
16551        // Composition pin: [`Caixa::supervisor_view`]'s per-`:estrategia`
16552        // [`SupervisorSpec`] construction arm must key off
16553        // [`Caixa::estrategia`]'s `unwrap_or_default()` fold, not the raw
16554        // `self.estrategia.unwrap_or_default()` field-fold. Structurally:
16555        // for every `:kind Supervisor` `Caixa` carrying an author-
16556        // declared `Some(RestartStrategy::_)` variant, the composed
16557        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal the
16558        // outer accessor's declared variant unchanged; and for a
16559        // `:kind Supervisor` `Caixa` carrying `None`, the composed
16560        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal
16561        // [`RestartStrategy::default`] (the [`RestartStrategy::OneForOne`]
16562        // arm the flat-spread `unwrap_or_default()` fold projects to on
16563        // the author-omitted arm — this is the *composition* between the
16564        // outer `Option<RestartStrategy>` accessor's presence-bit
16565        // surface and the inner post-composition non-`Option`
16566        // [`SupervisorSpec::estrategia`] altitude). The pair jointly
16567        // pins the accessor + supervisor_view composition: any future
16568        // silent detour that had the accessor promote `None` to
16569        // `Some(RestartStrategy::default())` (a `.or_else(|| Some(RestartStrategy::default()))`
16570        // projection) would silently collapse the two arms into one at
16571        // the accessor boundary and the [`Self::declared_supervisor_slots`]
16572        // presence probe would silently drift from the composition site.
16573        //
16574        // Peer of the sibling M2 supervisor-slot post-composition
16575        // `validate_reads_through_lifted_estrategia_accessor` (eafb619)
16576        // pin on the [`SupervisorSpec::validate`] altitude — this pin
16577        // extends that inner-altitude accessor-routing discipline onto
16578        // the pre-composition outer author-surface [`Caixa`] altitude,
16579        // pinning the composition edge between the flat-spread outer
16580        // `Option<RestartStrategy>` and the composed [`SupervisorSpec`]
16581        // `RestartStrategy` axes.
16582        use crate::CaixaKind;
16583        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
16584        for estrategia in [
16585            RestartStrategy::OneForOne,
16586            RestartStrategy::OneForAll,
16587            RestartStrategy::RestForOne,
16588            RestartStrategy::SimpleOneForOne,
16589        ] {
16590            let mut c = caixa_with_estrategia(Some(estrategia));
16591            c.kind = CaixaKind::Supervisor;
16592            // Route the `SimpleOneForOne ↔ non-SimpleOneForOne` fixture-
16593            // shape partition through the [`gen_platform::IsVariant`]
16594            // derive-generated
16595            // [`RestartStrategy::is_simple_one_for_one`] predicate rather
16596            // than the raw `matches!(estrategia, RestartStrategy::
16597            // SimpleOneForOne)` open-coded pattern-match — same closed-
16598            // set-typed-enum arm-discriminator dispatch discipline the
16599            // sibling [`crate::upgrade::UpgradeInstruction::is_restart`]
16600            // convergence (915a934) extended onto its two paired positive
16601            // / negated `matches!` sites and the peer
16602            // [`crate::aplicacao::PlacementStrategy`] `IsVariant`-derived
16603            // predicate convergence (766ec63) extended onto the M3 mesh-
16604            // slot per-`:placement` distribution-strategy discriminator
16605            // axis. See the sibling `supervisor::tests::
16606            // round_trip_all_strategies` and
16607            // `supervisor::tests::supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
16608            // fixtures — the three sites (all test-only,
16609            // acknowledged in 915a934's Prior-commits footnote as the
16610            // outstanding follow-up) now consult one typed dispatch on
16611            // the substrate primitive.
16612            c.children = if estrategia.is_simple_one_for_one() {
16613                Vec::new()
16614            } else {
16615                vec![ChildSpec {
16616                    caixa: "worker".into(),
16617                    versao: "^0.1".into(),
16618                    restart: RestartPolicy::Permanent,
16619                }]
16620            };
16621            let view = c.supervisor_view().expect(
16622                "supervisor_view must materialize a SupervisorSpec for a \
16623                 :kind Supervisor Caixa carrying a Some(:estrategia) slot",
16624            );
16625            assert_eq!(
16626                view.estrategia(),
16627                c.estrategia().unwrap(),
16628                "supervisor_view must carry the outer Caixa::estrategia() \
16629                 declared variant onto the composed SupervisorSpec.estrategia \
16630                 field verbatim on the Some arm (got {:?}, expected {:?})",
16631                view.estrategia(),
16632                c.estrategia().unwrap(),
16633            );
16634        }
16635        // The author-omitted arm: outer `None` → composed
16636        // `RestartStrategy::default()` through the flat-spread
16637        // `unwrap_or_default()` fold.
16638        let mut c = caixa_with_estrategia(None);
16639        c.kind = CaixaKind::Supervisor;
16640        // Populate children so the sibling supervisor slots are coherent
16641        // for the [`Self::supervisor_view`] projection; the `:estrategia`
16642        // arm still defers to [`RestartStrategy::default`] on the
16643        // author-omitted arm even when the sibling slots carry values.
16644        c.children = vec![ChildSpec {
16645            caixa: "worker".into(),
16646            versao: "^0.1".into(),
16647            restart: RestartPolicy::Permanent,
16648        }];
16649        let view = c.supervisor_view().expect(
16650            "supervisor_view must materialize a SupervisorSpec for a \
16651             :kind Supervisor Caixa carrying a None `:estrategia` slot",
16652        );
16653        assert_eq!(
16654            view.estrategia(),
16655            RestartStrategy::default(),
16656            "supervisor_view must project the outer Caixa::estrategia() \
16657             None arm onto RestartStrategy::default() through the flat-\
16658             spread unwrap_or_default() fold (got {:?}, expected {:?})",
16659            view.estrategia(),
16660            RestartStrategy::default(),
16661        );
16662        assert!(
16663            c.estrategia().is_none(),
16664            "Caixa::estrategia() must remain None on the author-omitted \
16665             arm — the supervisor_view fold must not mutate the outer \
16666             flat-spread presence bit",
16667        );
16668    }
16669
16670    #[test]
16671    fn estrategia_projects_option_by_copy() {
16672        // The by-`Copy` pin: [`Caixa::estrategia`] returns
16673        // `Option<RestartStrategy>` by value (`RestartStrategy: Copy`) —
16674        // the accessor does not borrow `&self` past the call (no
16675        // lifetime on the return type), and calling the accessor twice
16676        // on the same [`Caixa`] must yield discriminant-equal values
16677        // (idempotent, no side effects on `&self`). Peer of the sibling
16678        // outer-`Caixa` `Option<&Composite>` by-borrow
16679        // `limits_projects_option_ref_by_borrow` (b2bd9d7) /
16680        // `behavior_projects_option_ref_by_borrow` (35d8b52) /
16681        // `politicas_projects_option_ref_by_borrow` (5d23d29) /
16682        // `placement_projects_option_ref_by_borrow` (4fb8074) /
16683        // `entrada_projects_option_ref_by_borrow` (e4128e4) by-borrow
16684        // pins on the outer-`Caixa` `Option<&Composite>`-return axes —
16685        // extended here to the outer-`Caixa` `Option<Copy>`-return
16686        // flat-spread axis. The `Copy` discipline replaces the pointer-
16687        // equality claim the by-borrow siblings pin (a fresh `Copy` of a
16688        // `Copy` discriminant is definitionally the same discriminant, so
16689        // the axis reduces to discriminant equality).
16690        //
16691        // Pins against a future silent detour that returned a fresh
16692        // `Option<&RestartStrategy>` (which would type-check but silently
16693        // introduce a borrow of `&self` past the call, collapsing the
16694        // load-bearing "no lifetime on the return type" `Copy` projection
16695        // the flat-spread axis's `Option<Copy>` shape carries), a stale-
16696        // read side effect that flipped the outer discriminant on
16697        // successive calls, or an axis-remap projection that returned a
16698        // different variant than the field storage.
16699        use crate::supervisor::RestartStrategy;
16700        for estrategia in [
16701            Some(RestartStrategy::OneForOne),
16702            Some(RestartStrategy::OneForAll),
16703            Some(RestartStrategy::RestForOne),
16704            Some(RestartStrategy::SimpleOneForOne),
16705        ] {
16706            let c = caixa_with_estrategia(estrategia);
16707            let first = c.estrategia();
16708            let second = c.estrategia();
16709            assert_eq!(
16710                first, second,
16711                "Caixa::estrategia must be idempotent — two successive \
16712                 calls on the same &self must return the same \
16713                 Option<RestartStrategy>",
16714            );
16715            assert_eq!(
16716                first, estrategia,
16717                "Caixa::estrategia must return :estrategia verbatim by \
16718                 Copy — got {first:?}, expected {estrategia:?}",
16719            );
16720        }
16721        let c = caixa_with_estrategia(None);
16722        assert!(
16723            c.estrategia().is_none(),
16724            "Caixa::estrategia must return None when :estrategia is \
16725             absent — the author-omitted arm must project through the \
16726             accessor's Option::None unchanged",
16727        );
16728    }
16729
16730    // ── Caixa::max_restarts / Caixa::restart_window —
16731    //    outer top-level M2 supervisor-tree-slot flat-spread accessors
16732    //    (Option<u32> / Option<&str>) folding on the ed04d3c
16733    //    Caixa::estrategia Option<Copy> sub-family ─────────────────────
16734
16735    fn caixa_with_max_restarts(max_restarts: Option<u32>) -> Caixa {
16736        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16737        c.max_restarts = max_restarts;
16738        c
16739    }
16740
16741    fn caixa_supervisor_with_max_restarts_and_window(
16742        max_restarts: Option<u32>,
16743        restart_window: Option<&str>,
16744    ) -> Caixa {
16745        use crate::CaixaKind;
16746        use crate::supervisor::{ChildSpec, RestartPolicy};
16747        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
16748        c.kind = CaixaKind::Supervisor;
16749        c.max_restarts = max_restarts;
16750        c.restart_window = restart_window.map(str::to_string);
16751        c.children = vec![ChildSpec {
16752            caixa: "worker".into(),
16753            versao: "^0.1".into(),
16754            restart: RestartPolicy::Permanent,
16755        }];
16756        c
16757    }
16758
16759    #[test]
16760    fn max_restarts_returns_max_restarts_option_verbatim_across_permutations() {
16761        // Value-shape pin: [`Caixa::max_restarts`] returns the
16762        // `:max-restarts` typed `Option<u32>` verbatim, `Copy`-projected
16763        // from the typed slot's own storage, byte-equal across the
16764        // author-omitted `None` arm (the "defer to the
16765        // [`Self::supervisor_view`] `unwrap_or(5)` OTP-canonical
16766        // `{intensity, 5, 60}` default" partition every
16767        // non-`Supervisor`-kind caixa carries by `#[serde(default)]`)
16768        // and each of the representative fixtures in the accept-set —
16769        // `0` (the zero-floor arm the peer
16770        // [`crate::supervisor::SupervisorSpec::validate`]
16771        // [`crate::SupervisorError::ZeroMaxRestarts`] gate refuses on
16772        // the post-composition altitude — the accessor must ship the
16773        // raw slot verbatim so struct-literal fixtures continue to
16774        // expose the zero at the accessor boundary), the OTP-canonical
16775        // `5` default (`{intensity, 5, 60}` worker-supervisor from
16776        // Learn You Some Erlang), `1000` (the
16777        // [`SUPERVISOR_MAX_RESTARTS_MAX`] cap the peer post-composition
16778        // upper-bound gate accepts on the boundary), `u32::MAX` (a
16779        // past-the-cap sentinel that the substrate-primitive accessor
16780        // must still ship verbatim). Second outer top-level
16781        // [`Caixa`] `Option<Copy>`-return supervisor-tree flat-spread
16782        // pin — folds on the sibling
16783        // `estrategia_returns_estrategia_option_verbatim_across_permutations`
16784        // (ed04d3c) pin's `Option<Copy>` shape, extending the sub-family
16785        // onto the sibling `Option<u32>` restart-budget-count arm.
16786        let fixtures: Vec<Option<u32>> = vec![None, Some(0), Some(5), Some(1000), Some(u32::MAX)];
16787        for max_restarts in fixtures {
16788            let c = caixa_with_max_restarts(max_restarts);
16789            assert_eq!(
16790                c.max_restarts(),
16791                max_restarts,
16792                "Caixa::max_restarts must return :max-restarts verbatim \
16793                 (got {:?}, expected {max_restarts:?})",
16794                c.max_restarts(),
16795            );
16796            assert_eq!(
16797                c.max_restarts(),
16798                c.max_restarts,
16799                "Caixa::max_restarts accessor and self.max_restarts \
16800                 field access must byte-equal — a presence-bit or count \
16801                 drift would silently split the paired \
16802                 Caixa::declared_supervisor_slots presence-probe arm \
16803                 from the Caixa::supervisor_view unwrap_or(5) fold's \
16804                 composition input",
16805            );
16806        }
16807    }
16808
16809    #[test]
16810    fn max_restarts_projects_option_by_copy() {
16811        // The by-`Copy` pin: [`Caixa::max_restarts`] returns
16812        // `Option<u32>` by value (`u32: Copy`) — the accessor does not
16813        // borrow `&self` past the call (no lifetime on the return type),
16814        // and calling the accessor twice on the same [`Caixa`] must
16815        // yield equal values (idempotent, no side effects). Peer of the
16816        // sibling `estrategia_projects_option_by_copy` (ed04d3c) pin on
16817        // the outer-`Caixa` `Option<Copy>`-return flat-spread axis.
16818        for max_restarts in [Some(0u32), Some(5), Some(1000), Some(u32::MAX), None] {
16819            let c = caixa_with_max_restarts(max_restarts);
16820            let first = c.max_restarts();
16821            let second = c.max_restarts();
16822            assert_eq!(
16823                first, second,
16824                "Caixa::max_restarts must be idempotent — two successive \
16825                 calls on the same &self must return the same Option<u32>",
16826            );
16827            assert_eq!(
16828                first, max_restarts,
16829                "Caixa::max_restarts must return :max-restarts verbatim \
16830                 by Copy — got {first:?}, expected {max_restarts:?}",
16831            );
16832        }
16833    }
16834
16835    #[test]
16836    fn declared_supervisor_slots_max_restarts_arm_routes_through_accessor() {
16837        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
16838        // `:max-restarts` presence-probe arm must key off
16839        // [`Caixa::max_restarts`], not the raw
16840        // `self.max_restarts.is_some()` field-probe. Structurally: every
16841        // `Caixa { max_restarts: Some(_), .. }` variant must push
16842        // `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS` onto the declared-slot
16843        // list (the presence bit is `Some` for every representative
16844        // count, so the M2 kind-coherence gate must surface the slot as
16845        // "declared"), and a `Caixa { max_restarts: None, .. }` must
16846        // NOT push the label. Peer of the sibling
16847        // `declared_supervisor_slots_estrategia_arm_routes_through_accessor`
16848        // (ed04d3c) composition pin — same routing-through-accessor
16849        // discipline extended onto the sibling flat-spread `Option<u32>`
16850        // arm.
16851        for max_restarts in [0u32, 5, 1000, u32::MAX] {
16852            let c = caixa_with_max_restarts(Some(max_restarts));
16853            let slots = c.declared_supervisor_slots();
16854            assert!(
16855                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
16856                "declared_supervisor_slots must push \
16857                 SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` \
16858                 is Some({max_restarts}) — the accessor and the \
16859                 enumerator gate must route through the same \
16860                 substrate-primitive typed dispatch on the outer \
16861                 :max-restarts presence bit (got slots={slots:?})",
16862            );
16863        }
16864        let c = caixa_with_max_restarts(None);
16865        let slots = c.declared_supervisor_slots();
16866        assert!(
16867            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
16868            "declared_supervisor_slots must NOT push \
16869             SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` is \
16870             None — the author-omitted arm must route through the \
16871             accessor's None-return unchanged (got slots={slots:?})",
16872        );
16873    }
16874
16875    #[test]
16876    fn supervisor_view_max_restarts_arm_routes_through_accessor() {
16877        // Composition pin: [`Caixa::supervisor_view`]'s per-`:max-restarts`
16878        // [`SupervisorSpec`] construction arm must key off
16879        // [`Caixa::max_restarts`]'s `unwrap_or(5)` fold, not the raw
16880        // `self.max_restarts.unwrap_or(5)` field-fold. Structurally: for
16881        // every `:kind Supervisor` `Caixa` carrying an author-declared
16882        // `Some(n)`, the composed [`SupervisorSpec`]'s `.max_restarts()`
16883        // must byte-equal `n`; and for a `:kind Supervisor` `Caixa`
16884        // carrying `None`, the composed [`SupervisorSpec`]'s
16885        // `.max_restarts()` must byte-equal the OTP-canonical `5`. Peer
16886        // of the sibling
16887        // `supervisor_view_estrategia_arm_routes_through_accessor`
16888        // (ed04d3c) composition pin.
16889        for max_restarts in [1u32, 5, 1000] {
16890            let c = caixa_supervisor_with_max_restarts_and_window(Some(max_restarts), None);
16891            let view = c.supervisor_view().expect(
16892                "supervisor_view must materialize a SupervisorSpec for a \
16893                 :kind Supervisor Caixa carrying a Some(:max-restarts)",
16894            );
16895            assert_eq!(
16896                view.max_restarts(),
16897                max_restarts,
16898                "supervisor_view must carry the outer \
16899                 Caixa::max_restarts() Some arm onto the composed \
16900                 SupervisorSpec.max_restarts field verbatim (got {}, \
16901                 expected {max_restarts})",
16902                view.max_restarts(),
16903            );
16904        }
16905        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
16906        let view = c.supervisor_view().expect(
16907            "supervisor_view must materialize a SupervisorSpec for a \
16908             :kind Supervisor Caixa carrying a None :max-restarts",
16909        );
16910        assert_eq!(
16911            view.max_restarts(),
16912            5,
16913            "supervisor_view must project the outer \
16914             Caixa::max_restarts() None arm onto the OTP-canonical \
16915             {{intensity, 5, 60}} default (5) through the flat-spread \
16916             unwrap_or(5) fold (got {})",
16917            view.max_restarts(),
16918        );
16919        assert!(
16920            c.max_restarts().is_none(),
16921            "Caixa::max_restarts() must remain None on the author-\
16922             omitted arm — the supervisor_view fold must not mutate \
16923             the outer flat-spread presence bit",
16924        );
16925    }
16926
16927    #[test]
16928    fn supervisor_view_estrategia_fallback_routes_through_lifted_default() {
16929        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
16930        // `:estrategia` arm must degrade onto the substrate-canonical
16931        // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
16932        // `pub const` — the Erlang/OTP-canonical `one_for_one` strategy
16933        // half of Learn You Some Erlang's `{one_for_one, intensity, 5, 60}`
16934        // worker-supervisor default — rather than the transitively-
16935        // derived [`crate::supervisor::RestartStrategy::default`] route
16936        // the prior `.unwrap_or_default()` fold reached for. Prior to the
16937        // lift the composition site carried `.unwrap_or_default()` with
16938        // no compile-time link back to the shared OTP-canonical strategy
16939        // default that the paired [`crate::supervisor::Default for
16940        // RestartStrategy`] impl and the [`crate::supervisor::Default for
16941        // SupervisorSpec`] impl's struct-literal `estrategia` field both
16942        // (now) route through the same lifted constant — so a future
16943        // rebrand of the OTP-canonical strategy default (an OTP
16944        // `rest_for_one` widening once the substrate discovers startup-
16945        // order-coupled child cohorts as the more common worker-
16946        // supervisor shape, a per-cluster overlay the operator pins
16947        // through the MESH-COMPOSITION §III.2 supervision-canary
16948        // `:estrategia-overrides` roadmap slot) would have had to migrate
16949        // the paired `MaxIntensity` + `Period` halves through the lifted
16950        // constants and the `one_for_one` half through a
16951        // `RestartStrategy::default()` route in lockstep or a
16952        // `:kind Supervisor` caixa carrying an author-omitted
16953        // `:estrategia` slot would silently resolve to a `SupervisorSpec`
16954        // whose `estrategia` disagreed with the paired
16955        // `SupervisorSpec::default()` view. Byte-parity against the
16956        // lifted constant closes the split. Peer of the sibling
16957        // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
16958        // composition pin on the paired `MaxIntensity` half + the
16959        // [`crate::supervisor::restart_strategy_default_routes_through_lifted_default`]
16960        // + [`crate::supervisor::supervisor_spec_default_estrategia_routes_through_lifted_default`]
16961        // pins on the sibling entry points onto the shared substrate
16962        // constant.
16963        use crate::CaixaKind;
16964        use crate::supervisor::{ChildSpec, RestartPolicy};
16965        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
16966        c.kind = CaixaKind::Supervisor;
16967        c.estrategia = None;
16968        c.children = vec![ChildSpec {
16969            caixa: "worker".into(),
16970            versao: "^0.1".into(),
16971            restart: RestartPolicy::Permanent,
16972        }];
16973        let view = c.supervisor_view().expect(
16974            "supervisor_view must materialize a SupervisorSpec for a \
16975             :kind Supervisor Caixa carrying a None :estrategia",
16976        );
16977        assert_eq!(
16978            view.estrategia(),
16979            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
16980            "supervisor_view must degrade the outer \
16981             Caixa::estrategia() None arm onto the lifted \
16982             SUPERVISOR_ESTRATEGIA_DEFAULT typed pub const (got {:?}, \
16983             expected {:?})",
16984            view.estrategia(),
16985            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
16986        );
16987    }
16988
16989    #[test]
16990    fn supervisor_view_max_restarts_fallback_routes_through_lifted_default() {
16991        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
16992        // `:max-restarts` arm must degrade onto the substrate-canonical
16993        // [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`] typed
16994        // `pub const` — the Erlang/OTP-canonical `{intensity, 5, 60}`
16995        // `MaxIntensity` default — rather than a raw `5` literal. Prior
16996        // to the lift the composition site carried an inline
16997        // `.unwrap_or(5)` with no compile-time link back to the shared
16998        // OTP-canonical default that the serde-side
16999        // `#[serde(default = "default_max_restarts")]` wire-format arm
17000        // and the [`Default for crate::supervisor::SupervisorSpec`]
17001        // struct-literal default arm both key off — so a future rebrand
17002        // of the OTP-canonical default (Elixir's `Supervisor` `3`
17003        // default, a per-cluster overlay the operator pins through the
17004        // MESH-COMPOSITION §III.2 supervision-canary
17005        // `:supervisor :max-restarts-overrides` roadmap slot) would
17006        // have had to be threaded through both the serde-side helper
17007        // and this view-construction arm in lockstep or a `:kind
17008        // Supervisor` caixa carrying `:max-restarts ()` would silently
17009        // resolve to a `SupervisorSpec` whose `max_restarts` disagreed
17010        // with the same fixture's serde-side `SupervisorSpec` view (an
17011        // author-omitted slot round-tripping through
17012        // `SupervisorSpec::default()` to the lifted constant, then
17013        // splitting to a stale literal past `supervisor_view`).
17014        // Byte-parity against the lifted constant closes the split.
17015        // Peer of the sibling
17016        // [`crate::supervisor::default_max_restarts_helper_routes_through_lifted_default`]
17017        // + [`crate::supervisor::supervisor_spec_default_max_restarts_routes_through_lifted_default`]
17018        // composition pins that close the same routing on the two
17019        // sibling entry points onto the shared substrate constant.
17020        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
17021        let view = c.supervisor_view().expect(
17022            "supervisor_view must materialize a SupervisorSpec for a \
17023             :kind Supervisor Caixa carrying a None :max-restarts",
17024        );
17025        assert_eq!(
17026            view.max_restarts(),
17027            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
17028            "supervisor_view must degrade the outer \
17029             Caixa::max_restarts() None arm onto the lifted \
17030             SUPERVISOR_MAX_RESTARTS_DEFAULT typed pub const (got {}, \
17031             expected {})",
17032            view.max_restarts(),
17033            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
17034        );
17035    }
17036
17037    #[test]
17038    fn restart_window_returns_restart_window_option_verbatim_across_permutations() {
17039        // Value-shape pin: [`Caixa::restart_window`] returns the
17040        // `:restart-window` typed `Option<String>` verbatim as an
17041        // `Option<&str>`, borrowed from the typed slot's own storage,
17042        // byte-equal across the author-omitted `None` arm and each of
17043        // the representative fixtures in the accept-set — the canonical
17044        // `"60s"` from `{intensity, 5, 60}`, the sibling
17045        // canonical-magnitude forms (`"5m"` / `"1h"` / `"500ms"` / `"30"`
17046        // / `"0s"`) the shared codec's positive-set sweep pin covers,
17047        // plus a past-the-guard sentinel (`"1.5s"` — the fractional-
17048        // seconds drift the sibling [`Self::validate_restart_window`]
17049        // gate refuses; the accessor must ship the raw slot verbatim
17050        // so struct-literal fixtures continue to expose the drift at
17051        // the accessor boundary). Third outer top-level [`Caixa`]
17052        // supervisor-tree flat-spread pin — extends the sub-family onto
17053        // the sibling `Option<&str>` raw-duration-string arm.
17054        for window in [
17055            None,
17056            Some("60s"),
17057            Some("5m"),
17058            Some("1h"),
17059            Some("500ms"),
17060            Some("1.5s"),
17061            Some(""),
17062        ] {
17063            let c = caixa_with_restart_window(window);
17064            assert_eq!(
17065                c.restart_window(),
17066                window,
17067                "Caixa::restart_window must return :restart-window \
17068                 verbatim as Option<&str> (got {:?}, expected {window:?})",
17069                c.restart_window(),
17070            );
17071            assert_eq!(
17072                c.restart_window(),
17073                c.restart_window.as_deref(),
17074                "Caixa::restart_window accessor and \
17075                 self.restart_window.as_deref() field access must \
17076                 byte-equal — a byte-level drift would silently split \
17077                 the paired Caixa::declared_supervisor_slots \
17078                 presence-probe arm from the \
17079                 Caixa::validate_restart_window shared-codec gate and \
17080                 the Caixa::supervisor_view soft-swallowing fold",
17081            );
17082        }
17083    }
17084
17085    #[test]
17086    fn restart_window_projects_slice_by_borrow() {
17087        // The by-borrow pin: [`Caixa::restart_window`] returns
17088        // `Option<&str>` by borrow — the returned string slice borrows
17089        // the underlying `Option<String>` storage of the `:restart-window`
17090        // slot and the accessor must not clone on every call. Peer of
17091        // the sibling outer top-level [`Caixa`] `Option<&str>`-return
17092        // by-borrow pins on the universal-axis scalar family
17093        // (`licenca_projects_option_ref_by_borrow` /
17094        // `descricao_projects_option_ref_by_borrow` and siblings) —
17095        // extended onto the M2 supervisor-tree flat-spread
17096        // `Option<&str>` raw-duration-string axis.
17097        for window in [None, Some("60s"), Some("5m"), Some("")] {
17098            let c = caixa_with_restart_window(window);
17099            let first = c.restart_window();
17100            let second = c.restart_window();
17101            assert_eq!(
17102                first, second,
17103                "Caixa::restart_window must be idempotent — two \
17104                 successive calls on the same &self must return the \
17105                 same Option<&str>",
17106            );
17107            if let (Some(a), Some(b)) = (first, second) {
17108                assert_eq!(
17109                    a.as_ptr(),
17110                    b.as_ptr(),
17111                    "Caixa::restart_window must borrow the underlying \
17112                     String storage — two successive Some-arm calls must \
17113                     return slices with the same backing pointer (a fresh \
17114                     String clone would change the pointer on every call)",
17115                );
17116            }
17117            assert_eq!(
17118                first, window,
17119                "Caixa::restart_window must return :restart-window \
17120                 verbatim by borrow — got {first:?}, expected {window:?}",
17121            );
17122        }
17123    }
17124
17125    #[test]
17126    fn declared_supervisor_slots_restart_window_arm_routes_through_accessor() {
17127        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
17128        // `:restart-window` presence-probe arm must key off
17129        // [`Caixa::restart_window`], not the raw
17130        // `self.restart_window.is_some()` field-probe. Structurally:
17131        // every `Caixa { restart_window: Some(_), .. }` must push
17132        // `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` onto the declared-slot
17133        // list, and a `Caixa { restart_window: None, .. }` must NOT
17134        // push the label. Peer of the sibling
17135        // `declared_supervisor_slots_max_restarts_arm_routes_through_accessor`
17136        // routing pin.
17137        for window in ["60s", "5m", "1h", "500ms", "1.5s", ""] {
17138            let c = caixa_with_restart_window(Some(window));
17139            let slots = c.declared_supervisor_slots();
17140            assert!(
17141                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
17142                "declared_supervisor_slots must push \
17143                 SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when \
17144                 `:restart-window` is Some({window:?}) — the accessor \
17145                 and the enumerator gate must route through the same \
17146                 substrate-primitive typed dispatch on the outer \
17147                 :restart-window presence bit (got slots={slots:?})",
17148            );
17149        }
17150        let c = caixa_with_restart_window(None);
17151        let slots = c.declared_supervisor_slots();
17152        assert!(
17153            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
17154            "declared_supervisor_slots must NOT push \
17155             SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when `:restart-window` \
17156             is None — the author-omitted arm must route through the \
17157             accessor's None-return unchanged (got slots={slots:?})",
17158        );
17159    }
17160
17161    #[test]
17162    fn validate_restart_window_arm_routes_through_accessor() {
17163        // Composition pin: [`Caixa::validate_restart_window`]'s
17164        // shared-codec fold arm must key off [`Caixa::restart_window`],
17165        // not the raw `self.restart_window.as_deref()` field-projection.
17166        // Structurally: (1) `None` → `Ok(())` (the "omit the slot to
17167        // express no reset" canonical shape); (2) a canonical `Some`
17168        // arm (`"60s"`) → `Ok(())`; (3) a codec-rejected `Some` arm
17169        // (`"1.5s"`) → `Err(RestartWindowMalformed { restart_window,
17170        // .. })` carrying the offending raw string verbatim. The three
17171        // arms jointly pin that the validator's raw-string binding is
17172        // the accessor's return, not a peer projection — any future
17173        // silent detour that had the accessor collapse `Some("")` to
17174        // `None` would silently absorb the empty-after-trim refusal
17175        // case at the accessor boundary.
17176        caixa_with_restart_window(None)
17177            .validate_restart_window()
17178            .expect("None :restart-window must validate through the accessor");
17179        caixa_with_restart_window(Some("60s"))
17180            .validate_restart_window()
17181            .expect("canonical :restart-window \"60s\" must validate through the accessor");
17182        let err = caixa_with_restart_window(Some("1.5s"))
17183            .validate_restart_window()
17184            .expect_err("fractional-seconds :restart-window must fail through the accessor");
17185        assert!(
17186            matches!(
17187                err,
17188                ManifestError::RestartWindowMalformed { ref restart_window, .. }
17189                    if restart_window == "1.5s"
17190            ),
17191            "validator must carry the offending raw string verbatim \
17192             from the accessor's borrowed &str (got {err:?})",
17193        );
17194    }
17195
17196    #[test]
17197    fn supervisor_view_restart_window_arm_routes_through_accessor() {
17198        // Composition pin: [`Caixa::supervisor_view`]'s
17199        // per-`:restart-window` [`SupervisorSpec`] construction arm
17200        // must key off [`Caixa::restart_window`]'s soft-swallowing
17201        // `.and_then(|s| duration_codec::parse(s).ok())` fold, not the
17202        // raw `self.restart_window.as_deref().and_then(…)` field-fold.
17203        // Structurally: (1) `None` → `SupervisorSpec.restart_window ==
17204        // None` (the "never reset" sentinel); (2) canonical `Some("60s")`
17205        // → `SupervisorSpec.restart_window == Some(Duration::from_secs(60))`
17206        // (the shared codec's canonical parse); (3) codec-rejected
17207        // `Some("1.5s")` → `SupervisorSpec.restart_window == None`
17208        // (the soft-swallow preserving the view's best-effort shape).
17209        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
17210        let view = c.supervisor_view().expect("Supervisor kind has a view");
17211        assert_eq!(
17212            view.restart_window(),
17213            None,
17214            "supervisor_view must project outer None :restart-window \
17215             onto None on the composed SupervisorSpec (never-reset \
17216             sentinel) through the accessor's None-return unchanged",
17217        );
17218
17219        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("60s"));
17220        let view = c.supervisor_view().expect("Supervisor kind has a view");
17221        assert_eq!(
17222            view.restart_window(),
17223            Some(std::time::Duration::from_secs(60)),
17224            "supervisor_view must fold outer Some(\"60s\") through the \
17225             shared duration_codec into Duration::from_secs(60) on the \
17226             composed SupervisorSpec (accessor's Some(&str) → codec \
17227             parse → Some(Duration))",
17228        );
17229
17230        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("1.5s"));
17231        let view = c.supervisor_view().expect("Supervisor kind has a view");
17232        assert_eq!(
17233            view.restart_window(),
17234            None,
17235            "supervisor_view must soft-swallow the shared-codec parse \
17236             failure to None (the view's best-effort shape the sibling \
17237             manifest-level validate_restart_window surfaces as \
17238             RestartWindowMalformed); the accessor's raw-string return \
17239             is the single input every downstream consumer keys off",
17240        );
17241    }
17242
17243    // ── Caixa::upgrade_from — outer top-level &[UpgradeFromEntry] composite-slice accessor ──
17244
17245    fn caixa_with_upgrade_from(upgrade_from: Vec<crate::upgrade::UpgradeFromEntry>) -> Caixa {
17246        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17247        c.upgrade_from = upgrade_from;
17248        c
17249    }
17250
17251    #[test]
17252    fn upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations() {
17253        // The canonical per-`Caixa` `:upgrade-from` M2 typed-slot
17254        // outer-composite `&[UpgradeFromEntry]`-return slice-shape
17255        // pin: [`Caixa::upgrade_from`] must return the `:upgrade-from`
17256        // typed `Vec<UpgradeFromEntry>` verbatim as a
17257        // `&[UpgradeFromEntry]` slice-view over the same backing
17258        // buffer the raw `self.upgrade_from.as_slice()` field access
17259        // borrows from, element-equal across every representative
17260        // fixture in the accept-set — `[]` (the "no hot-upgrade path
17261        // declared" arm every `defcaixa` without an `:upgrade-from`
17262        // block carries; `#[serde(default)]` folds an omitted slot
17263        // onto `Vec::new()`), a canonical single-entry `Restart`
17264        // fixture (the shape most Servicos carry — a single prior
17265        // version with the fallback strategy), a canonical multi-
17266        // entry list carrying every typed instruction variant
17267        // (`LoadModule` / `StateChange` / `SoftPurge` / `Purge` /
17268        // `Restart`), and a past-the-guard sentinel — a duplicate-
17269        // `:from` `[(0.1.0, Restart), (0.1.0, Restart)]` entry pair
17270        // ([`crate::upgrade::validate_upgrade_from`] rejects through
17271        // `DuplicateFrom { from: "0.1.0" }` but the accessor must
17272        // ship the raw slot verbatim so struct-literal fixtures
17273        // continue to expose the duplicate at the accessor boundary).
17274        //
17275        // Pins against a future silent detour that returned an owned
17276        // `Vec<UpgradeFromEntry>` (which would type-check but silently
17277        // clone on every accessor call, breaking the zero-cost
17278        // projection every peer sibling slice accessor carries), a
17279        // `[dup, dup] → [dup]` dedup collapse (which would silently
17280        // absorb the `DuplicateFrom` refusal case at the accessor
17281        // boundary and the [`crate::StandardLayout::verify`] cross-
17282        // entry gate would silently accept a struct-literal `Caixa`
17283        // carrying the drift), a reference to an operator-resolved
17284        // overlay (the future per-cluster `:upgrade-overrides` slot
17285        // — its resolution must land at exactly this accessor body,
17286        // not silently divert the raw slot away from a second
17287        // consumer), or an axis-shuffled projection (a future detour
17288        // that reordered entries through the accessor would silently
17289        // split the paired [`crate::StandardLayout::verify`] per-
17290        // `:upgrade-from` shape gate's traversal input from the peer
17291        // [`crate::render::servico_m2_overlay`] emitter's projection
17292        // input, since the operator's hot-upgrade dispatch matches
17293        // per-`:from` and axis reordering would silently split the
17294        // per-entry script-path existence probe's iteration order
17295        // from the M2 overlay emitter's serialized-entry order).
17296        //
17297        // First outer top-level [`Caixa`] `&[Composite]`-return
17298        // slice accessor pin on the substrate primitive for M2 / M3
17299        // typed-slot vec-carry axes — opens the outer-`Caixa`
17300        // `&[Composite]` composite-slice projection pattern the
17301        // sibling `:children` [`crate::supervisor::ChildSpec`] /
17302        // `:membros` [`crate::aplicacao::Membro`] / `:contratos`
17303        // [`crate::aplicacao::WitContract`] future outer-composite-
17304        // slice pins fold on. Peer of the closed outer-`Caixa`
17305        // scalar `Option<&Composite>` composite-reference family the
17306        // sibling `limits` / `behavior` / `politicas` / `placement`
17307        // / `entrada` `..._returns_..._option_ref_verbatim_across_
17308        // permutations` pins closed (b2bd9d7 → e4128e4) — extends
17309        // the "byte-equal, borrow-shared" outer-accessor discipline
17310        // onto the outer-`Caixa` `&[Composite]` vec-carry altitude.
17311        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
17312        let fixtures: Vec<Vec<UpgradeFromEntry>> = vec![
17313            vec![],
17314            vec![UpgradeFromEntry {
17315                from: "0.0.1".into(),
17316                instructions: vec![UpgradeInstruction::Restart],
17317            }],
17318            vec![
17319                UpgradeFromEntry {
17320                    from: "0.0.1".into(),
17321                    instructions: vec![
17322                        UpgradeInstruction::LoadModule {
17323                            module: "demo".into(),
17324                        },
17325                        UpgradeInstruction::SoftPurge {
17326                            module: "demo".into(),
17327                        },
17328                    ],
17329                },
17330                UpgradeFromEntry {
17331                    from: "0.0.2".into(),
17332                    instructions: vec![
17333                        UpgradeInstruction::StateChange {
17334                            script: "servicos/upgrade.lisp".into(),
17335                        },
17336                        UpgradeInstruction::Purge {
17337                            module: "demo".into(),
17338                        },
17339                        UpgradeInstruction::Restart,
17340                    ],
17341                },
17342            ],
17343            vec![
17344                UpgradeFromEntry {
17345                    from: "0.1.0".into(),
17346                    instructions: vec![UpgradeInstruction::Restart],
17347                },
17348                UpgradeFromEntry {
17349                    from: "0.1.0".into(),
17350                    instructions: vec![UpgradeInstruction::Restart],
17351                },
17352            ],
17353        ];
17354        for upgrade_from in fixtures {
17355            let c = caixa_with_upgrade_from(upgrade_from.clone());
17356            assert_eq!(
17357                c.upgrade_from(),
17358                upgrade_from.as_slice(),
17359                "Caixa::upgrade_from must return :upgrade-from \
17360                 verbatim (got {:?}, expected {upgrade_from:?})",
17361                c.upgrade_from(),
17362            );
17363            assert_eq!(
17364                c.upgrade_from(),
17365                c.upgrade_from.as_slice(),
17366                "Caixa::upgrade_from must element-equal the raw \
17367                 `self.upgrade_from.as_slice()` field access across \
17368                 every value in the Vec<UpgradeFromEntry> accept-set",
17369            );
17370            assert_eq!(
17371                c.upgrade_from().is_empty(),
17372                c.upgrade_from.is_empty(),
17373                "Caixa::upgrade_from().is_empty() must byte-equal \
17374                 self.upgrade_from.is_empty() — a presence-bit drift \
17375                 would silently split the paired \
17376                 Caixa::declared_servico_slots M2 declared-slot \
17377                 enumerator's presence probe from the peer \
17378                 crate::render::servico_m2_overlay M2 overlay \
17379                 emitter's presence gate",
17380            );
17381        }
17382    }
17383
17384    #[test]
17385    fn declared_servico_slots_upgrade_from_arm_routes_through_accessor() {
17386        // Composition pin: [`Caixa::declared_servico_slots`]'s
17387        // `:upgrade-from` presence-probe arm must key off
17388        // [`Caixa::upgrade_from`], not the raw
17389        // `self.upgrade_from.is_empty()` field-probe. Structurally: a
17390        // `Caixa { upgrade_from: vec![UpgradeFromEntry { from: "0.0.1",
17391        // instructions: vec![Restart] }], .. }` must push
17392        // `M2_AUTHOR_KEY_UPGRADE_FROM` onto the declared-slot list
17393        // (the presence bit is non-empty, so the M2 kind-coherence
17394        // gate must surface the slot as "declared"), and a `Caixa {
17395        // upgrade_from: vec![], .. }` must NOT push the label (the
17396        // "author omitted the slot entirely" arm — the empty-slice
17397        // partition the serde-default folds onto). The pair jointly
17398        // pins the accessor + declared-slot enumerator composition:
17399        // any future silent detour that had the accessor collapse
17400        // `[Restart]` to `[]` (a `.filter(|e| !e.instructions.
17401        // is_empty())` projection) would silently absorb the
17402        // "declared but degenerate" arm at the accessor boundary and
17403        // the [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-
17404        // coherence gate would silently accept a struct-literal
17405        // `Caixa` carrying the drift.
17406        //
17407        // Peer of the sibling
17408        // `declared_servico_slots_limits_arm_routes_through_accessor`
17409        // (b2bd9d7) and
17410        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17411        // (35d8b52) composition pins on the sibling `:limits` /
17412        // `:behavior` outer-`Option<&Composite>` arms — same "the
17413        // enumerator gate must route through the substrate-primitive
17414        // typed dispatch" discipline extended onto the third M2
17415        // Servico-runtime slot axis, closing the enumerator's routing
17416        // invariant on every M2 arm.
17417        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
17418        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
17419            from: "0.0.1".into(),
17420            instructions: vec![UpgradeInstruction::Restart],
17421        }]);
17422        let slots = c.declared_servico_slots();
17423        assert!(
17424            slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
17425            "declared_servico_slots must push \
17426             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
17427             non-empty — the accessor and the enumerator gate must \
17428             route through the same substrate-primitive typed \
17429             dispatch on the outer :upgrade-from presence bit (got \
17430             slots={slots:?})",
17431        );
17432        let c = caixa_with_upgrade_from(vec![]);
17433        let slots = c.declared_servico_slots();
17434        assert!(
17435            !slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
17436            "declared_servico_slots must NOT push \
17437             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
17438             empty — the author-omitted arm must route through the \
17439             accessor's empty-slice return unchanged (got \
17440             slots={slots:?})",
17441        );
17442    }
17443
17444    #[test]
17445    fn servico_m2_overlay_upgrade_from_arm_routes_through_accessor() {
17446        // Composition pin: [`crate::render::servico_m2_overlay`]'s
17447        // per-`:upgrade-from` M2 overlay emit arm must key off
17448        // [`Caixa::upgrade_from`], not the raw
17449        // `!caixa.upgrade_from.is_empty()` presence gate + the
17450        // `serde_yaml::to_value(&caixa.upgrade_from)` projection.
17451        // Structurally: a `Caixa { upgrade_from: vec![UpgradeFromEntry
17452        // { from: "0.0.1", instructions: vec![Restart] }], .. }` must
17453        // surface the `M2_KEY_UPGRADE_FROM` key with a per-entry
17454        // sequence in the overlay (the emitter fans onto the serde
17455        // slice-serialization), and a `Caixa { upgrade_from: vec![],
17456        // .. }` must omit the key entirely (the empty-slice
17457        // partition — the `!.is_empty()` outer gate elides the key
17458        // when the author omitted the slot). The pair jointly pins
17459        // the accessor + M2 overlay emitter composition: any future
17460        // silent detour that had the accessor return a fresh-cloned
17461        // `Vec<UpgradeFromEntry>` copy would silently break the
17462        // reference-identity pin the peer per-entry
17463        // `serde_yaml::to_value(caixa.upgrade_from())` projection
17464        // reads from — the projection would clone once per accessor
17465        // call instead of borrowing the storage buffer verbatim.
17466        //
17467        // Peer of the sibling
17468        // `servico_m2_overlay_limits_arm_routes_through_accessor`
17469        // (b2bd9d7) and
17470        // `servico_m2_overlay_behavior_arm_routes_through_accessor`
17471        // (35d8b52) composition pins on the sibling `:limits` /
17472        // `:behavior` outer-`Option<&Composite>` arms — same "the
17473        // M2 overlay emitter must route through the substrate-
17474        // primitive typed dispatch" discipline extended onto the
17475        // third M2 Servico-runtime slot axis, closing the overlay
17476        // emitter's routing invariant on every M2 arm.
17477        use crate::render::{M2_KEY_UPGRADE_FROM, servico_m2_overlay};
17478        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
17479        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
17480            from: "0.0.1".into(),
17481            instructions: vec![UpgradeInstruction::Restart],
17482        }]);
17483        let overlay = servico_m2_overlay(&c).unwrap();
17484        assert!(
17485            overlay.contains_key(M2_KEY_UPGRADE_FROM),
17486            "servico_m2_overlay must surface M2_KEY_UPGRADE_FROM when \
17487             `:upgrade-from` is non-empty — the accessor and the M2 \
17488             overlay emitter must route through the same substrate- \
17489             primitive typed dispatch on the outer :upgrade-from \
17490             slice (got overlay={overlay:?})",
17491        );
17492        let c = caixa_with_upgrade_from(vec![]);
17493        let overlay = servico_m2_overlay(&c).unwrap();
17494        assert!(
17495            !overlay.contains_key(M2_KEY_UPGRADE_FROM),
17496            "servico_m2_overlay must omit M2_KEY_UPGRADE_FROM when \
17497             `:upgrade-from` is empty — the empty-slice partition \
17498             must route through the accessor's empty-slice return \
17499             unchanged (got overlay={overlay:?})",
17500        );
17501    }
17502
17503    #[test]
17504    fn upgrade_from_projects_slice_by_borrow() {
17505        // The by-borrow pin: [`Caixa::upgrade_from`] returns
17506        // `&[UpgradeFromEntry]` by borrow — the returned slice
17507        // borrows the underlying `Vec<UpgradeFromEntry>` storage of
17508        // the `:upgrade-from` slot and the accessor must not clone
17509        // the backing `Vec` on every call. Peer of the sibling
17510        // outer top-level [`Caixa`] `&[T]`-return by-borrow pins
17511        // (`autores_projects_slice_by_borrow` b5d813f,
17512        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
17513        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
17514        // `exe_projects_slice_by_borrow` 65d9527,
17515        // `servicos_projects_slice_by_borrow` 611f78b,
17516        // `deps_projects_slice_by_borrow` ad34b4e,
17517        // `deps_dev_projects_slice_by_borrow` f7fd81e) on the
17518        // sibling outer top-level [`Caixa`] scalar-element `&[T]`
17519        // axes — extended here to the first outer-`Caixa`
17520        // composite-element `&[Composite]` axis: the accessor's
17521        // returned slice must borrow from `&self` (the returned
17522        // reference's lifetime is tied to `&self`), and calling the
17523        // accessor twice on the same [`Caixa`] must yield slices
17524        // that are pointer-equal (the underlying byte-buffer is the
17525        // storage `Vec`'s allocation, not a fresh copy) as well as
17526        // value-equal (idempotent, no side effects on `&self`).
17527        //
17528        // Pins against a future silent detour that returned an owned
17529        // `Vec<UpgradeFromEntry>` (which would type-check but
17530        // silently clone on every call), a `&Vec<UpgradeFromEntry>`
17531        // return (which would leak the backing `Vec`'s
17532        // grow/push/reserve surface no downstream consumer reaches
17533        // for), or a one-arm-only accessor that returned a
17534        // saturating value on some sentinel input.
17535        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
17536        for upgrade_from in [
17537            vec![],
17538            vec![UpgradeFromEntry {
17539                from: "0.0.1".into(),
17540                instructions: vec![UpgradeInstruction::Restart],
17541            }],
17542            vec![
17543                UpgradeFromEntry {
17544                    from: "0.0.1".into(),
17545                    instructions: vec![UpgradeInstruction::Restart],
17546                },
17547                UpgradeFromEntry {
17548                    from: "0.0.2".into(),
17549                    instructions: vec![UpgradeInstruction::SoftPurge {
17550                        module: "demo".into(),
17551                    }],
17552                },
17553            ],
17554        ] {
17555            let c = caixa_with_upgrade_from(upgrade_from.clone());
17556            let first = c.upgrade_from();
17557            let second = c.upgrade_from();
17558            assert_eq!(
17559                first, second,
17560                "Caixa::upgrade_from must be idempotent — two \
17561                 successive calls on the same &self must return the \
17562                 same &[UpgradeFromEntry]",
17563            );
17564            assert_eq!(
17565                first.as_ptr(),
17566                second.as_ptr(),
17567                "Caixa::upgrade_from must borrow the underlying \
17568                 Vec<UpgradeFromEntry> storage — two successive calls \
17569                 must return slices with the same backing pointer (a \
17570                 fresh Vec<UpgradeFromEntry> clone would change the \
17571                 pointer on every call)",
17572            );
17573            assert_eq!(
17574                first,
17575                upgrade_from.as_slice(),
17576                "Caixa::upgrade_from must return :upgrade-from \
17577                 verbatim by borrow — got {first:?}, expected \
17578                 {upgrade_from:?}",
17579            );
17580        }
17581    }
17582
17583    // ── Caixa::children — outer top-level &[ChildSpec] composite-slice accessor ──
17584
17585    fn caixa_with_children(children: Vec<crate::supervisor::ChildSpec>) -> Caixa {
17586        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17587        c.children = children;
17588        c
17589    }
17590
17591    #[test]
17592    fn children_returns_children_slice_verbatim_across_permutations() {
17593        // The canonical per-`Caixa` `:children` M2 supervisor-tree-slot
17594        // outer-composite `&[ChildSpec]`-return slice-shape pin:
17595        // [`Caixa::children`] must return the `:children` typed
17596        // `Vec<ChildSpec>` verbatim as a `&[ChildSpec]` slice-view over
17597        // the same backing buffer the raw `self.children.as_slice()`
17598        // field access borrows from, element-equal across every
17599        // representative fixture in the accept-set — `[]` (the "no
17600        // static children declared" arm every non-`Supervisor`-kind
17601        // `defcaixa` carries by `#[serde(default)]` and every
17602        // `SimpleOneForOne` supervisor carries by cross-slot refusal),
17603        // a canonical single-child `Permanent` fixture (the shape
17604        // most `OneForOne` supervisors carry — a single long-running
17605        // worker child), a canonical multi-child list carrying every
17606        // typed restart-policy variant (`Permanent` / `Transient` /
17607        // `Temporary`), and a past-the-guard sentinel — a duplicate
17608        // `:caixa` `[("w", ...), ("w", ...)]` entry pair
17609        // ([`crate::SupervisorSpec::validate`] rejects through
17610        // `DuplicateChildNome { nome: "w" }` but the accessor must
17611        // ship the raw slot verbatim so struct-literal fixtures
17612        // continue to expose the duplicate at the accessor boundary).
17613        //
17614        // Pins against a future silent detour that returned an owned
17615        // `Vec<ChildSpec>` (which would type-check but silently clone
17616        // on every accessor call, breaking the zero-cost projection
17617        // every peer sibling slice accessor carries), a `[dup, dup] →
17618        // [dup]` dedup collapse (which would silently absorb the
17619        // `DuplicateChildNome` refusal case at the accessor boundary
17620        // and the [`crate::StandardLayout::verify`] cross-child gate
17621        // would silently accept a struct-literal `Caixa` carrying the
17622        // drift), a reference to an operator-resolved overlay (the
17623        // future per-cluster `:children-overrides` slot — its
17624        // resolution must land at exactly this accessor body, not
17625        // silently divert the raw slot away from a second consumer),
17626        // or an axis-shuffled projection (a future detour that
17627        // reordered children through the accessor would silently
17628        // split the paired [`crate::StandardLayout::verify`] per-
17629        // supervisor gate's traversal input from the peer
17630        // [`Self::supervisor_view`] fold-in path's clone-order input,
17631        // since the OTP `RestForOne` restart strategy dispatches on
17632        // declared child order and axis reordering would silently
17633        // split the operator's per-cluster restart-fan-out order
17634        // from the caixa.lisp source-order).
17635        //
17636        // Second outer top-level [`Caixa`] `&[Composite]`-return slice
17637        // accessor pin on the substrate primitive for M2 / M3 typed-
17638        // slot vec-carry axes — folds on the outer-`Caixa`
17639        // `&[Composite]` composite-slice sub-family the sibling
17640        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
17641        // (2a1f907) pin opened, peer at the outer altitude of the
17642        // closed inner-`SupervisorSpec` `SupervisorSpec::children`
17643        // (bc92bce) accessor on the same OTP-supervisor static-child-
17644        // list axis.
17645        use crate::supervisor::{ChildSpec, RestartPolicy};
17646        let fixtures: Vec<Vec<ChildSpec>> = vec![
17647            vec![],
17648            vec![ChildSpec {
17649                caixa: "worker".into(),
17650                versao: "^0.1".into(),
17651                restart: RestartPolicy::Permanent,
17652            }],
17653            vec![
17654                ChildSpec {
17655                    caixa: "worker-a".into(),
17656                    versao: "^0.1".into(),
17657                    restart: RestartPolicy::Permanent,
17658                },
17659                ChildSpec {
17660                    caixa: "worker-b".into(),
17661                    versao: "^0.1".into(),
17662                    restart: RestartPolicy::Transient,
17663                },
17664                ChildSpec {
17665                    caixa: "worker-c".into(),
17666                    versao: "^0.1".into(),
17667                    restart: RestartPolicy::Temporary,
17668                },
17669            ],
17670            vec![
17671                ChildSpec {
17672                    caixa: "w".into(),
17673                    versao: "^0.1".into(),
17674                    restart: RestartPolicy::Permanent,
17675                },
17676                ChildSpec {
17677                    caixa: "w".into(),
17678                    versao: "^0.1".into(),
17679                    restart: RestartPolicy::Permanent,
17680                },
17681            ],
17682        ];
17683        for children in fixtures {
17684            let c = caixa_with_children(children.clone());
17685            assert_eq!(
17686                c.children(),
17687                children.as_slice(),
17688                "Caixa::children must return :children verbatim \
17689                 (got {:?}, expected {children:?})",
17690                c.children(),
17691            );
17692            assert_eq!(
17693                c.children(),
17694                c.children.as_slice(),
17695                "Caixa::children must element-equal the raw \
17696                 `self.children.as_slice()` field access across \
17697                 every value in the Vec<ChildSpec> accept-set",
17698            );
17699            assert_eq!(
17700                c.children().is_empty(),
17701                c.children.is_empty(),
17702                "Caixa::children().is_empty() must byte-equal \
17703                 self.children.is_empty() — a presence-bit drift \
17704                 would silently split the paired \
17705                 Caixa::declared_supervisor_slots supervisor-tree \
17706                 declared-slot enumerator's presence probe from the \
17707                 peer Caixa::supervisor_view typed-view composer's \
17708                 fold-in path",
17709            );
17710        }
17711    }
17712
17713    #[test]
17714    fn declared_supervisor_slots_children_arm_routes_through_accessor() {
17715        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
17716        // `:children` presence-probe arm must key off
17717        // [`Caixa::children`], not the raw
17718        // `!self.children.is_empty()` field-probe. Structurally: a
17719        // `Caixa { children: vec![ChildSpec { caixa: "w", versao:
17720        // "^0.1", restart: Permanent }], .. }` must push
17721        // `SUPERVISOR_AUTHOR_KEY_CHILDREN` onto the declared-slot list
17722        // (the presence bit is non-empty, so the supervisor-tree
17723        // kind-coherence gate must surface the slot as "declared"),
17724        // and a `Caixa { children: vec![], .. }` must NOT push the
17725        // label (the "author omitted the slot entirely" arm — the
17726        // empty-slice partition the serde-default folds onto). The
17727        // pair jointly pins the accessor + declared-slot enumerator
17728        // composition: any future silent detour that had the accessor
17729        // collapse `[Permanent]` to `[]` (a `.filter(|c| c.nome() !=
17730        // "__reserved__")` projection) would silently absorb the
17731        // "declared but degenerate" arm at the accessor boundary and
17732        // the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
17733        // kind-coherence gate would silently accept a struct-literal
17734        // `Caixa` carrying the drift.
17735        //
17736        // Peer of the sibling
17737        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
17738        // (2a1f907) on the M2 `:upgrade-from` composite-slice arm —
17739        // same "the enumerator gate must route through the substrate-
17740        // primitive typed dispatch" discipline extended onto the
17741        // supervisor-tree `:children` composite-slice arm.
17742        use crate::supervisor::{ChildSpec, RestartPolicy};
17743        let c = caixa_with_children(vec![ChildSpec {
17744            caixa: "w".into(),
17745            versao: "^0.1".into(),
17746            restart: RestartPolicy::Permanent,
17747        }]);
17748        let slots = c.declared_supervisor_slots();
17749        assert!(
17750            slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
17751            "declared_supervisor_slots must push \
17752             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
17753             non-empty — the accessor and the enumerator gate must \
17754             route through the same substrate-primitive typed \
17755             dispatch on the outer :children presence bit (got \
17756             slots={slots:?})",
17757        );
17758        let c = caixa_with_children(vec![]);
17759        let slots = c.declared_supervisor_slots();
17760        assert!(
17761            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
17762            "declared_supervisor_slots must NOT push \
17763             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
17764             empty — the author-omitted arm must route through the \
17765             accessor's empty-slice return unchanged (got \
17766             slots={slots:?})",
17767        );
17768    }
17769
17770    #[test]
17771    fn supervisor_view_children_arm_routes_through_accessor() {
17772        // Composition pin: [`Caixa::supervisor_view`]'s per-`:children`
17773        // fold-in arm must key off [`Caixa::children`], not the raw
17774        // `self.children.clone()` field-clone. Structurally: a `Caixa {
17775        // kind: Supervisor, estrategia: Some(OneForOne), children:
17776        // vec![ChildSpec { caixa: "w", .. }], .. }` must fold the
17777        // per-child list through the accessor into the typed
17778        // [`SupervisorSpec`] view's `children` field verbatim — every
17779        // entry the accessor surfaces must land in the view's
17780        // `children` slot in the same order. The pair jointly pins the
17781        // accessor + view-composer composition: any future silent
17782        // detour that had the accessor return a fresh-cloned
17783        // `Vec<ChildSpec>` copy would silently break the reference-
17784        // identity pin the peer `supervisor_view` fold-in path reads
17785        // from — the fold would clone once more per accessor call
17786        // instead of borrowing the storage buffer verbatim once.
17787        //
17788        // Peer of the sibling
17789        // `supervisor_view_kind_gate_routes_through_accessor` (35d8b52-
17790        // family) composition pin on the peer kind-gate arm — same
17791        // "the view composer must route through the substrate-
17792        // primitive typed dispatch" discipline extended onto the
17793        // per-`:children` fold-in arm, closing the supervisor-view
17794        // composer's routing invariant on the composite-slice input.
17795        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
17796        let mut c = caixa_with_children(vec![
17797            ChildSpec {
17798                caixa: "worker-a".into(),
17799                versao: "^0.1".into(),
17800                restart: RestartPolicy::Permanent,
17801            },
17802            ChildSpec {
17803                caixa: "worker-b".into(),
17804                versao: "^0.1".into(),
17805                restart: RestartPolicy::Transient,
17806            },
17807        ]);
17808        c.kind = crate::CaixaKind::Supervisor;
17809        c.estrategia = Some(RestartStrategy::OneForOne);
17810        let view = c
17811            .supervisor_view()
17812            .expect("Supervisor kind must produce a supervisor_view");
17813        assert_eq!(
17814            view.children(),
17815            c.children(),
17816            "supervisor_view must fold Caixa::children verbatim into \
17817             SupervisorSpec::children — the accessor and the view \
17818             composer must route through the same substrate-primitive \
17819             typed dispatch on the outer :children slice (got view \
17820             children={:?}, expected {:?})",
17821            view.children(),
17822            c.children(),
17823        );
17824    }
17825
17826    #[test]
17827    fn children_projects_slice_by_borrow() {
17828        // The by-borrow pin: [`Caixa::children`] returns
17829        // `&[ChildSpec]` by borrow — the returned slice borrows the
17830        // underlying `Vec<ChildSpec>` storage of the `:children` slot
17831        // and the accessor must not clone the backing `Vec` on every
17832        // call. Peer of the sibling outer top-level [`Caixa`]
17833        // `&[T]`-return by-borrow pins (`autores_projects_slice_by_borrow`
17834        // b5d813f, `etiquetas_projects_slice_by_borrow` 78c7d3c,
17835        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
17836        // `exe_projects_slice_by_borrow` 65d9527,
17837        // `servicos_projects_slice_by_borrow` 611f78b,
17838        // `deps_projects_slice_by_borrow` ad34b4e,
17839        // `deps_dev_projects_slice_by_borrow` f7fd81e,
17840        // `upgrade_from_projects_slice_by_borrow` 2a1f907) on the
17841        // sibling outer top-level [`Caixa`] scalar-element and
17842        // composite-element `&[T]` axes — folds on the outer-`Caixa`
17843        // composite-element `&[Composite]` axis: the accessor's
17844        // returned slice must borrow from `&self` (the returned
17845        // reference's lifetime is tied to `&self`), and calling the
17846        // accessor twice on the same [`Caixa`] must yield slices
17847        // that are pointer-equal (the underlying byte-buffer is the
17848        // storage `Vec`'s allocation, not a fresh copy) as well as
17849        // value-equal (idempotent, no side effects on `&self`).
17850        //
17851        // Pins against a future silent detour that returned an owned
17852        // `Vec<ChildSpec>` (which would type-check but silently clone
17853        // on every call), a `&Vec<ChildSpec>` return (which would leak
17854        // the backing `Vec`'s grow/push/reserve surface no downstream
17855        // consumer reaches for), or a one-arm-only accessor that
17856        // returned a saturating value on some sentinel input.
17857        use crate::supervisor::{ChildSpec, RestartPolicy};
17858        for children in [
17859            vec![],
17860            vec![ChildSpec {
17861                caixa: "w".into(),
17862                versao: "^0.1".into(),
17863                restart: RestartPolicy::Permanent,
17864            }],
17865            vec![
17866                ChildSpec {
17867                    caixa: "worker-a".into(),
17868                    versao: "^0.1".into(),
17869                    restart: RestartPolicy::Permanent,
17870                },
17871                ChildSpec {
17872                    caixa: "worker-b".into(),
17873                    versao: "^0.1".into(),
17874                    restart: RestartPolicy::Transient,
17875                },
17876            ],
17877        ] {
17878            let c = caixa_with_children(children.clone());
17879            let first = c.children();
17880            let second = c.children();
17881            assert_eq!(
17882                first, second,
17883                "Caixa::children must be idempotent — two successive \
17884                 calls on the same &self must return the same \
17885                 &[ChildSpec]",
17886            );
17887            assert_eq!(
17888                first.as_ptr(),
17889                second.as_ptr(),
17890                "Caixa::children must borrow the underlying \
17891                 Vec<ChildSpec> storage — two successive calls must \
17892                 return slices with the same backing pointer (a fresh \
17893                 Vec<ChildSpec> clone would change the pointer on \
17894                 every call)",
17895            );
17896            assert_eq!(
17897                first,
17898                children.as_slice(),
17899                "Caixa::children must return :children verbatim by \
17900                 borrow — got {first:?}, expected {children:?}",
17901            );
17902        }
17903    }
17904
17905    // ── Caixa::membros — outer top-level &[Membro] composite-slice accessor ──
17906
17907    fn caixa_aplicacao_with_membros(membros: Vec<crate::aplicacao::Membro>) -> Caixa {
17908        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17909        c.kind = CaixaKind::Aplicacao;
17910        c.membros = membros;
17911        c
17912    }
17913
17914    #[test]
17915    fn membros_returns_membros_slice_verbatim_across_permutations() {
17916        // The canonical per-`Caixa` `:membros` M3 mesh-slot outer-
17917        // composite `&[Membro]`-return slice-shape pin:
17918        // [`Caixa::membros`] must return the `:membros` typed
17919        // `Vec<Membro>` verbatim as a `&[Membro]` slice-view over the
17920        // same backing buffer the raw `self.membros.as_slice()` field
17921        // access borrows from, element-equal across every
17922        // representative fixture in the accept-set — `[]` (the "no
17923        // members declared" arm every non-`Aplicacao`-kind `defcaixa`
17924        // carries by `#[serde(default)]` and every partially-authored
17925        // Aplicacao carries before the
17926        // [`crate::AplicacaoError::MembrosEmpty`] gate fires), a
17927        // canonical single-member fixture (the shape a minimal
17928        // Aplicacao carries — one Servico wrapping one contained
17929        // computation), a canonical multi-member list carrying three
17930        // distinct entries (the canonical checkout-shape Aplicacao —
17931        // cart / pricing / auth — every canonical example carries), and
17932        // a past-the-guard sentinel — a duplicate `:caixa`
17933        // `[("cart", ...), ("cart", ...)]` entry pair
17934        // ([`crate::AplicacaoSpec::validate`] rejects through
17935        // `DuplicateMembro { nome: "cart" }` but the accessor must ship
17936        // the raw slot verbatim so struct-literal fixtures continue to
17937        // expose the duplicate at the accessor boundary).
17938        //
17939        // Pins against a future silent detour that returned an owned
17940        // `Vec<Membro>` (which would type-check but silently clone on
17941        // every accessor call, breaking the zero-cost projection every
17942        // peer sibling slice accessor carries), a `[dup, dup] → [dup]`
17943        // dedup collapse (which would silently absorb the
17944        // `DuplicateMembro` refusal case at the accessor boundary and
17945        // the [`crate::StandardLayout::verify`] cross-member gate would
17946        // silently accept a struct-literal `Caixa` carrying the drift),
17947        // a reference to an operator-resolved overlay (the future per-
17948        // cluster `:membros-overrides` slot — its resolution must land
17949        // at exactly this accessor body, not silently divert the raw
17950        // slot away from a second consumer), or an axis-shuffled
17951        // projection (a future detour that reordered members through
17952        // the accessor would silently split the paired
17953        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
17954        // traversal input from the peer [`Self::aplicacao_view`] fold-
17955        // in path's clone-order input, since the canonical `:contratos`
17956        // `:de`/`:para` and `:entrada :para` cross-slot refusal probes
17957        // read the member set through the same slice).
17958        //
17959        // Third outer top-level [`Caixa`] `&[Composite]`-return slice
17960        // accessor pin on the substrate primitive for M2 / M3 typed-
17961        // slot vec-carry axes — opens the outer-`Caixa` M3 mesh-slot
17962        // arm of the `&[Composite]` composite-slice sub-family the
17963        // sibling M2 `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
17964        // (2a1f907) and
17965        // `children_returns_children_slice_verbatim_across_permutations`
17966        // (c17b51e) pins opened, peer at the outer altitude of the
17967        // closed inner-[`crate::AplicacaoSpec::membros`] (6c77e36)
17968        // accessor on the same MESH-COMPOSITION per-Aplicacao member-
17969        // list axis.
17970        use crate::aplicacao::Membro;
17971        let fixtures: Vec<Vec<Membro>> = vec![
17972            vec![],
17973            vec![Membro {
17974                caixa: "cart".into(),
17975                versao: "^0.1".into(),
17976            }],
17977            vec![
17978                Membro {
17979                    caixa: "cart".into(),
17980                    versao: "^0.1".into(),
17981                },
17982                Membro {
17983                    caixa: "pricing".into(),
17984                    versao: "^0.2".into(),
17985                },
17986                Membro {
17987                    caixa: "auth".into(),
17988                    versao: "^1.0".into(),
17989                },
17990            ],
17991            vec![
17992                Membro {
17993                    caixa: "cart".into(),
17994                    versao: "^0.1".into(),
17995                },
17996                Membro {
17997                    caixa: "cart".into(),
17998                    versao: "^0.1".into(),
17999                },
18000            ],
18001        ];
18002        for membros in fixtures {
18003            let c = caixa_aplicacao_with_membros(membros.clone());
18004            assert_eq!(
18005                c.membros(),
18006                membros.as_slice(),
18007                "Caixa::membros must return :membros verbatim \
18008                 (got {:?}, expected {membros:?})",
18009                c.membros(),
18010            );
18011            assert_eq!(
18012                c.membros(),
18013                c.membros.as_slice(),
18014                "Caixa::membros must element-equal the raw \
18015                 `self.membros.as_slice()` field access across every \
18016                 value in the Vec<Membro> accept-set",
18017            );
18018            assert_eq!(
18019                c.membros().is_empty(),
18020                c.membros.is_empty(),
18021                "Caixa::membros().is_empty() must byte-equal \
18022                 self.membros.is_empty() — a presence-bit drift would \
18023                 silently split the paired Caixa::declared_mesh_slots \
18024                 mesh declared-slot enumerator's presence probe from \
18025                 the peer Caixa::aplicacao_view typed-view composer's \
18026                 fold-in path",
18027            );
18028        }
18029    }
18030
18031    #[test]
18032    fn declared_mesh_slots_membros_arm_routes_through_accessor() {
18033        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:membros`
18034        // presence-probe arm must key off [`Caixa::membros`], not the
18035        // raw `!self.membros.is_empty()` field-probe. Structurally: a
18036        // `Caixa { membros: vec![Membro { caixa: "cart", versao:
18037        // "^0.1" }], .. }` must push `M3_AUTHOR_KEY_MEMBROS` onto the
18038        // declared-slot list (the presence bit is non-empty, so the
18039        // mesh kind-coherence gate must surface the slot as
18040        // "declared"), and a `Caixa { membros: vec![], .. }` must NOT
18041        // push the label (the "author omitted the slot entirely" arm
18042        // — the empty-slice partition the serde-default folds onto).
18043        // The pair jointly pins the accessor + declared-slot
18044        // enumerator composition: any future silent detour that had
18045        // the accessor collapse `[Membro { .. }]` to `[]` (a
18046        // `.filter(|m| m.nome() != "__reserved__")` projection) would
18047        // silently absorb the "declared but degenerate" arm at the
18048        // accessor boundary and the
18049        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
18050        // coherence gate would silently accept a struct-literal
18051        // `Caixa` carrying the drift.
18052        //
18053        // Peer of the sibling
18054        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
18055        // (2a1f907) and
18056        // `declared_supervisor_slots_children_arm_routes_through_accessor`
18057        // (c17b51e) composition pins on the M2 `:upgrade-from` /
18058        // `:children` composite-slice arms — same "the enumerator gate
18059        // must route through the substrate-primitive typed dispatch"
18060        // discipline extended onto the M3 `:membros` composite-slice
18061        // arm, opening the M3 arm of the declared-slot enumerator's
18062        // routing invariant.
18063        use crate::aplicacao::Membro;
18064        let c = caixa_aplicacao_with_membros(vec![Membro {
18065            caixa: "cart".into(),
18066            versao: "^0.1".into(),
18067        }]);
18068        let slots = c.declared_mesh_slots();
18069        assert!(
18070            slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
18071            "declared_mesh_slots must push M3_AUTHOR_KEY_MEMBROS when \
18072             `:membros` is non-empty — the accessor and the enumerator \
18073             gate must route through the same substrate-primitive \
18074             typed dispatch on the outer :membros presence bit (got \
18075             slots={slots:?})",
18076        );
18077        let c = caixa_aplicacao_with_membros(vec![]);
18078        let slots = c.declared_mesh_slots();
18079        assert!(
18080            !slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
18081            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_MEMBROS \
18082             when `:membros` is empty — the author-omitted arm must \
18083             route through the accessor's empty-slice return unchanged \
18084             (got slots={slots:?})",
18085        );
18086    }
18087
18088    #[test]
18089    fn aplicacao_view_membros_arm_routes_through_accessor() {
18090        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:membros`
18091        // fold-in arm must key off [`Caixa::membros`], not the raw
18092        // `self.membros.clone()` field-clone. Structurally: a `Caixa {
18093        // kind: Aplicacao, membros: vec![Membro { caixa: "cart", .. },
18094        // Membro { caixa: "pricing", .. }], .. }` must fold the per-
18095        // member list through the accessor into the typed
18096        // [`crate::AplicacaoSpec`] view's `membros` slot verbatim —
18097        // every entry the accessor surfaces must land in the view's
18098        // `membros` slot in the same order. The pair jointly pins the
18099        // accessor + view-composer composition: any future silent
18100        // detour that had the accessor return a fresh-cloned
18101        // `Vec<Membro>` copy would silently break the reference-
18102        // identity pin the peer `aplicacao_view` fold-in path reads
18103        // from — the fold would clone once more per accessor call
18104        // instead of borrowing the storage buffer verbatim once.
18105        //
18106        // Peer of the sibling
18107        // `aplicacao_view_politicas_arm_folds_through_accessor`
18108        // (5d23d29) /
18109        // `aplicacao_view_placement_arm_folds_through_accessor`
18110        // (4fb8074) /
18111        // `aplicacao_view_entrada_arm_folds_through_accessor` (e4128e4)
18112        // composition pins on the M3 `:politicas` / `:placement` /
18113        // `:entrada` outer-`Option<&Composite>` arms — extended here to
18114        // the M3 `:membros` outer-`&[Composite]` composite-slice arm,
18115        // closing the aplicacao-view composer's routing invariant on
18116        // the composite-slice input.
18117        use crate::aplicacao::Membro;
18118        let c = caixa_aplicacao_with_membros(vec![
18119            Membro {
18120                caixa: "cart".into(),
18121                versao: "^0.1".into(),
18122            },
18123            Membro {
18124                caixa: "pricing".into(),
18125                versao: "^0.2".into(),
18126            },
18127        ]);
18128        let view = c
18129            .aplicacao_view()
18130            .expect("Aplicacao kind must produce an aplicacao_view");
18131        assert_eq!(
18132            view.membros(),
18133            c.membros(),
18134            "aplicacao_view must fold Caixa::membros verbatim into \
18135             AplicacaoSpec::membros — the accessor and the view \
18136             composer must route through the same substrate-primitive \
18137             typed dispatch on the outer :membros slice (got view \
18138             membros={:?}, expected {:?})",
18139            view.membros(),
18140            c.membros(),
18141        );
18142    }
18143
18144    #[test]
18145    fn membros_projects_slice_by_borrow() {
18146        // The by-borrow pin: [`Caixa::membros`] returns `&[Membro]` by
18147        // borrow — the returned slice borrows the underlying
18148        // `Vec<Membro>` storage of the `:membros` slot and the
18149        // accessor must not clone the backing `Vec` on every call.
18150        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
18151        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
18152        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
18153        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
18154        // `exe_projects_slice_by_borrow` 65d9527,
18155        // `servicos_projects_slice_by_borrow` 611f78b,
18156        // `deps_projects_slice_by_borrow` ad34b4e,
18157        // `deps_dev_projects_slice_by_borrow` f7fd81e,
18158        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
18159        // `children_projects_slice_by_borrow` c17b51e) on the sibling
18160        // outer top-level [`Caixa`] scalar-element and composite-
18161        // element `&[T]` axes — folds on the outer-`Caixa` M3 mesh-
18162        // slot composite-element `&[Composite]` axis: the accessor's
18163        // returned slice must borrow from `&self` (the returned
18164        // reference's lifetime is tied to `&self`), and calling the
18165        // accessor twice on the same [`Caixa`] must yield slices that
18166        // are pointer-equal (the underlying byte-buffer is the storage
18167        // `Vec`'s allocation, not a fresh copy) as well as value-equal
18168        // (idempotent, no side effects on `&self`).
18169        //
18170        // Pins against a future silent detour that returned an owned
18171        // `Vec<Membro>` (which would type-check but silently clone on
18172        // every call), a `&Vec<Membro>` return (which would leak the
18173        // backing `Vec`'s grow/push/reserve surface no downstream
18174        // consumer reaches for), or a one-arm-only accessor that
18175        // returned a saturating value on some sentinel input.
18176        use crate::aplicacao::Membro;
18177        for membros in [
18178            vec![],
18179            vec![Membro {
18180                caixa: "cart".into(),
18181                versao: "^0.1".into(),
18182            }],
18183            vec![
18184                Membro {
18185                    caixa: "cart".into(),
18186                    versao: "^0.1".into(),
18187                },
18188                Membro {
18189                    caixa: "pricing".into(),
18190                    versao: "^0.2".into(),
18191                },
18192            ],
18193        ] {
18194            let c = caixa_aplicacao_with_membros(membros.clone());
18195            let first = c.membros();
18196            let second = c.membros();
18197            assert_eq!(
18198                first, second,
18199                "Caixa::membros must be idempotent — two successive \
18200                 calls on the same &self must return the same &[Membro]",
18201            );
18202            assert_eq!(
18203                first.as_ptr(),
18204                second.as_ptr(),
18205                "Caixa::membros must borrow the underlying Vec<Membro> \
18206                 storage — two successive calls must return slices with \
18207                 the same backing pointer (a fresh Vec<Membro> clone \
18208                 would change the pointer on every call)",
18209            );
18210            assert_eq!(
18211                first,
18212                membros.as_slice(),
18213                "Caixa::membros must return :membros verbatim by borrow \
18214                 — got {first:?}, expected {membros:?}",
18215            );
18216        }
18217    }
18218
18219    // ── Caixa::contratos — outer top-level &[WitContract] composite-slice accessor ──
18220
18221    fn caixa_aplicacao_with_contratos(contratos: Vec<crate::aplicacao::WitContract>) -> Caixa {
18222        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18223        c.kind = CaixaKind::Aplicacao;
18224        c.contratos = contratos;
18225        c
18226    }
18227
18228    fn contrato_http_for_test(
18229        de: &str,
18230        para: &str,
18231        endpoint: &str,
18232    ) -> crate::aplicacao::WitContract {
18233        crate::aplicacao::WitContract {
18234            de: de.into(),
18235            para: para.into(),
18236            wit: "wasi:http/proxy".into(),
18237            endpoint: Some(endpoint.into()),
18238            subject: None,
18239            slot: None,
18240        }
18241    }
18242
18243    #[test]
18244    fn contratos_returns_contratos_slice_verbatim_across_permutations() {
18245        // The canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
18246        // composite `&[WitContract]`-return slice-shape pin:
18247        // [`Caixa::contratos`] must return the `:contratos` typed
18248        // `Vec<WitContract>` verbatim as a `&[WitContract]` slice-view
18249        // over the same backing buffer the raw
18250        // `self.contratos.as_slice()` field access borrows from,
18251        // element-equal across every representative fixture in the
18252        // accept-set — `[]` (the "no contracts declared" arm every
18253        // non-`Aplicacao`-kind `defcaixa` carries by
18254        // `#[serde(default)]` and every leaf-Aplicacao with a single
18255        // member carries), a canonical single-edge fixture (the
18256        // minimal directed-graph shape: one HTTP-shape `(cart → catalog)`
18257        // edge), and a canonical multi-edge fixture with three distinct
18258        // edges (the checkout-shape Aplicacao's HTTP-fan pattern:
18259        // `(cart → catalog)`, `(cart → pricing)`, `(cart → auth)`).
18260        //
18261        // Pins against a future silent detour that returned an owned
18262        // `Vec<WitContract>` (which would type-check but silently clone
18263        // on every accessor call, breaking the zero-cost projection
18264        // every peer sibling slice accessor carries), an axis-shuffled
18265        // projection (a future detour that reordered edges through the
18266        // accessor would silently split the paired
18267        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
18268        // traversal input from the peer [`Self::aplicacao_view`] fold-
18269        // in path's clone-order input, since every canonical
18270        // `caixa-mesh` renderer's per-`(:de, :para)` adjacency-list
18271        // seed dispatch reads the edge set through the same slice),
18272        // or a reference to an operator-resolved overlay (the future
18273        // per-cluster `:contratos-overrides` slot — its resolution
18274        // must land at exactly this accessor body, not silently divert
18275        // the raw slot away from a second consumer).
18276        //
18277        // Fourth outer top-level [`Caixa`] `&[Composite]`-return slice
18278        // accessor pin on the substrate primitive for M2 / M3 typed-
18279        // slot vec-carry axes — closes the outer-`Caixa`
18280        // `&[Composite]` composite-slice sub-family the sibling M2
18281        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
18282        // (2a1f907) and
18283        // `children_returns_children_slice_verbatim_across_permutations`
18284        // (c17b51e) pins opened and the M3
18285        // `membros_returns_membros_slice_verbatim_across_permutations`
18286        // (0f26987) pin folded on, closing the outer-`Caixa` M3 mesh-
18287        // slot arm of the composite-slice sub-family. Peer at the outer
18288        // altitude of the closed inner-
18289        // [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
18290        // same MESH-COMPOSITION per-Aplicacao contract-list axis.
18291        let fixtures: Vec<Vec<crate::aplicacao::WitContract>> = vec![
18292            vec![],
18293            vec![contrato_http_for_test("cart", "catalog", "/items")],
18294            vec![
18295                contrato_http_for_test("cart", "catalog", "/items"),
18296                contrato_http_for_test("cart", "pricing", "/price"),
18297                contrato_http_for_test("cart", "auth", "/whoami"),
18298            ],
18299        ];
18300        for contratos in fixtures {
18301            let c = caixa_aplicacao_with_contratos(contratos.clone());
18302            assert_eq!(
18303                c.contratos(),
18304                contratos.as_slice(),
18305                "Caixa::contratos must return :contratos verbatim \
18306                 (got {:?}, expected {contratos:?})",
18307                c.contratos(),
18308            );
18309            assert_eq!(
18310                c.contratos(),
18311                c.contratos.as_slice(),
18312                "Caixa::contratos must element-equal the raw \
18313                 `self.contratos.as_slice()` field access across every \
18314                 value in the Vec<WitContract> accept-set",
18315            );
18316            assert_eq!(
18317                c.contratos().is_empty(),
18318                c.contratos.is_empty(),
18319                "Caixa::contratos().is_empty() must byte-equal \
18320                 self.contratos.is_empty() — a presence-bit drift would \
18321                 silently split the paired Caixa::declared_mesh_slots \
18322                 mesh declared-slot enumerator's presence probe from \
18323                 the peer Caixa::aplicacao_view typed-view composer's \
18324                 fold-in path",
18325            );
18326        }
18327    }
18328
18329    #[test]
18330    fn declared_mesh_slots_contratos_arm_routes_through_accessor() {
18331        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:contratos`
18332        // presence-probe arm must key off [`Caixa::contratos`], not the
18333        // raw `!self.contratos.is_empty()` field-probe. Structurally: a
18334        // `Caixa { contratos: vec![WitContract { .. }], .. }` must push
18335        // `M3_AUTHOR_KEY_CONTRATOS` onto the declared-slot list (the
18336        // presence bit is non-empty, so the mesh kind-coherence gate
18337        // must surface the slot as "declared"), and a `Caixa {
18338        // contratos: vec![], .. }` must NOT push the label (the "author
18339        // omitted the slot entirely" arm — the empty-slice partition
18340        // the serde-default folds onto). The pair jointly pins the
18341        // accessor + declared-slot enumerator composition: any future
18342        // silent detour that had the accessor collapse
18343        // `[WitContract { .. }]` to `[]` (a `.filter(|c| c.de() !=
18344        // "__reserved__")` projection) would silently absorb the
18345        // "declared but degenerate" arm at the accessor boundary and
18346        // the [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
18347        // coherence gate would silently accept a struct-literal
18348        // `Caixa` carrying the drift.
18349        //
18350        // Peer of the sibling
18351        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
18352        // (2a1f907),
18353        // `declared_supervisor_slots_children_arm_routes_through_accessor`
18354        // (c17b51e), and
18355        // `declared_mesh_slots_membros_arm_routes_through_accessor`
18356        // (0f26987) composition pins on the M2 `:upgrade-from` /
18357        // `:children` / M3 `:membros` composite-slice arms — same "the
18358        // enumerator gate must route through the substrate-primitive
18359        // typed dispatch" discipline extended onto the M3 `:contratos`
18360        // composite-slice arm, closing the M3 mesh-slot arm of the
18361        // declared-slot enumerator's routing invariant on the
18362        // composite-slice inputs.
18363        let c = caixa_aplicacao_with_contratos(vec![contrato_http_for_test(
18364            "cart", "catalog", "/items",
18365        )]);
18366        let slots = c.declared_mesh_slots();
18367        assert!(
18368            slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
18369            "declared_mesh_slots must push M3_AUTHOR_KEY_CONTRATOS when \
18370             `:contratos` is non-empty — the accessor and the enumerator \
18371             gate must route through the same substrate-primitive \
18372             typed dispatch on the outer :contratos presence bit (got \
18373             slots={slots:?})",
18374        );
18375        let c = caixa_aplicacao_with_contratos(vec![]);
18376        let slots = c.declared_mesh_slots();
18377        assert!(
18378            !slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
18379            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_CONTRATOS \
18380             when `:contratos` is empty — the author-omitted arm must \
18381             route through the accessor's empty-slice return unchanged \
18382             (got slots={slots:?})",
18383        );
18384    }
18385
18386    #[test]
18387    fn aplicacao_view_contratos_arm_routes_through_accessor() {
18388        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:contratos`
18389        // fold-in arm must key off [`Caixa::contratos`], not the raw
18390        // `self.contratos.clone()` field-clone. Structurally: a `Caixa
18391        // { kind: Aplicacao, contratos: vec![WitContract { de: "cart",
18392        // .. }, WitContract { de: "pricing", .. }], .. }` must fold the
18393        // per-edge list through the accessor into the typed
18394        // [`crate::AplicacaoSpec`] view's `contratos` slot verbatim —
18395        // every entry the accessor surfaces must land in the view's
18396        // `contratos` slot in the same order. The pair jointly pins
18397        // the accessor + view-composer composition: a future silent
18398        // detour that had the accessor shuffle or drop an edge would
18399        // silently split the paired declared-slot enumerator's
18400        // presence bit from the typed-view composer's edge-list, a
18401        // two-consumer split at the enumerator and the view composer
18402        // far from the source `caixa.lisp`.
18403        //
18404        // Peer of the sibling
18405        // `aplicacao_view_membros_arm_routes_through_accessor`
18406        // (0f26987) composition pin on the M3 `:membros` outer-
18407        // `&[Composite]` composite-slice arm, closing the aplicacao-
18408        // view composer's routing invariant on the composite-slice
18409        // inputs at the outer altitude.
18410        let c = caixa_aplicacao_with_contratos(vec![
18411            contrato_http_for_test("cart", "catalog", "/items"),
18412            contrato_http_for_test("cart", "pricing", "/price"),
18413        ]);
18414        let view = c
18415            .aplicacao_view()
18416            .expect("Aplicacao kind must produce an aplicacao_view");
18417        assert_eq!(
18418            view.contratos(),
18419            c.contratos(),
18420            "aplicacao_view must fold Caixa::contratos verbatim into \
18421             AplicacaoSpec::contratos — the accessor and the view \
18422             composer must route through the same substrate-primitive \
18423             typed dispatch on the outer :contratos slice (got view \
18424             contratos={:?}, expected {:?})",
18425            view.contratos(),
18426            c.contratos(),
18427        );
18428    }
18429
18430    #[test]
18431    fn contratos_projects_slice_by_borrow() {
18432        // The by-borrow pin: [`Caixa::contratos`] returns `&[WitContract]`
18433        // by borrow — the returned slice borrows the underlying
18434        // `Vec<WitContract>` storage of the `:contratos` slot and the
18435        // accessor must not clone the backing `Vec` on every call.
18436        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
18437        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
18438        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
18439        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
18440        // `exe_projects_slice_by_borrow` 65d9527,
18441        // `servicos_projects_slice_by_borrow` 611f78b,
18442        // `deps_projects_slice_by_borrow` ad34b4e,
18443        // `deps_dev_projects_slice_by_borrow` f7fd81e,
18444        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
18445        // `children_projects_slice_by_borrow` c17b51e,
18446        // `membros_projects_slice_by_borrow` 0f26987) on the sibling
18447        // outer top-level [`Caixa`] scalar-element and composite-
18448        // element `&[T]` axes — closes the outer-`Caixa` M3 mesh-slot
18449        // composite-element `&[Composite]` axis on the by-borrow pin:
18450        // the accessor's returned slice must borrow from `&self` (the
18451        // returned reference's lifetime is tied to `&self`), and
18452        // calling the accessor twice on the same [`Caixa`] must yield
18453        // slices that are pointer-equal (the underlying byte-buffer is
18454        // the storage `Vec`'s allocation, not a fresh copy) as well as
18455        // value-equal (idempotent, no side effects on `&self`).
18456        //
18457        // Pins against a future silent detour that returned an owned
18458        // `Vec<WitContract>` (which would type-check but silently clone
18459        // on every call), a `&Vec<WitContract>` return (which would
18460        // leak the backing `Vec`'s grow/push/reserve surface no
18461        // downstream consumer reaches for), or a one-arm-only accessor
18462        // that returned a saturating value on some sentinel input.
18463        for contratos in [
18464            vec![],
18465            vec![contrato_http_for_test("cart", "catalog", "/items")],
18466            vec![
18467                contrato_http_for_test("cart", "catalog", "/items"),
18468                contrato_http_for_test("cart", "pricing", "/price"),
18469            ],
18470        ] {
18471            let c = caixa_aplicacao_with_contratos(contratos.clone());
18472            let first = c.contratos();
18473            let second = c.contratos();
18474            assert_eq!(
18475                first, second,
18476                "Caixa::contratos must be idempotent — two successive \
18477                 calls on the same &self must return the same \
18478                 &[WitContract]",
18479            );
18480            assert_eq!(
18481                first.as_ptr(),
18482                second.as_ptr(),
18483                "Caixa::contratos must borrow the underlying \
18484                 Vec<WitContract> storage — two successive calls must \
18485                 return slices with the same backing pointer (a fresh \
18486                 Vec<WitContract> clone would change the pointer on \
18487                 every call)",
18488            );
18489            assert_eq!(
18490                first,
18491                contratos.as_slice(),
18492                "Caixa::contratos must return :contratos verbatim by \
18493                 borrow — got {first:?}, expected {contratos:?}",
18494            );
18495        }
18496    }
18497
18498    // ── drift-detection: Caixa top-level multi-word serde-derive-to-const identity ──
18499
18500    #[test]
18501    fn caixa_multi_word_serde_keys_match_lifted_top_level_key_consts() {
18502        // Load-bearing invariant: every multi-word top-level [`Caixa`]
18503        // serde-derived JSON key routes through a lifted `&'static str`
18504        // const. The Rust field names are `snake_case`
18505        // (`deps_dev` / `upgrade_from` / `max_restarts` /
18506        // `restart_window`); [`Caixa`]'s `#[serde(rename_all =
18507        // "camelCase")]` derive attribute maps each to the camelCase
18508        // byte-string the [`Caixa::to_lisp`] round-trip's
18509        // `serde_json::to_value(self)` step lands under before
18510        // `tatara_lisp::domain::json_to_sexp` re-projects the JSON keys
18511        // to the kebab-case `:deps-dev` / `:upgrade-from` /
18512        // `:max-restarts` / `:restart-window` author surface. Serialize
18513        // a fully-populated [`Caixa`] and pin that each canonical
18514        // byte-sequence appears verbatim in the JSON — a future
18515        // accidental `rename_all = "snake_case"` / `"kebab-case"` /
18516        // verbatim-field-name flip at the derive attribute (any of
18517        // which would silently break every [`Caixa::to_lisp`]
18518        // round-trip and the future M4 operator-side manifest ingest's
18519        // `Value::get(<key>)` navigation) surfaces here as a build-time
18520        // test failure at `manifest.rs`, not as an apply-time
18521        // `.get(<stale-canonical-const>)` returning `None` far from the
18522        // derive-attr drift's commit. Same discipline the sibling
18523        // `supervisor_spec_serde_keys_match_lifted_supervisor_key_consts`
18524        // (40cc4e5), `membro_serde_keys_match_lifted_membro_key_consts`
18525        // (ce80ca0), and `upgrade_from_entry_serde_keys_match_lifted_
18526        // m2_upgrade_from_key_consts` (36ffe65) pins established on the
18527        // sibling M2 supervision-tree, M3 [`Membro`] per-entry, and M2
18528        // [`UpgradeFromEntry`] per-entry axes — extended here to the
18529        // enclosing M0 [`Caixa`] top-level axis so the last of the four
18530        // multi-word top-level [`Caixa`] serde-derived JSON keys
18531        // (`depsDev`) joins the substrate's "one canonical byte-string
18532        // per typed serialized-key axis" discipline.
18533        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
18534        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18535        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18536        c.deps_dev = vec![Dep::simple("tatara-check", "^0.1")];
18537        c.upgrade_from = vec![UpgradeFromEntry {
18538            from: "0.0.1".into(),
18539            instructions: vec![UpgradeInstruction::Restart],
18540        }];
18541        c.estrategia = Some(RestartStrategy::OneForOne);
18542        c.max_restarts = Some(3);
18543        c.restart_window = Some("60s".into());
18544        c.children = vec![ChildSpec {
18545            caixa: "child".into(),
18546            versao: "^0.1".into(),
18547            restart: RestartPolicy::Permanent,
18548        }];
18549        let json = serde_json::to_string(&c).unwrap();
18550        for key in [
18551            crate::render::CAIXA_KEY_DEPS_DEV,
18552            crate::render::M2_KEY_UPGRADE_FROM,
18553            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
18554            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
18555        ] {
18556            let quoted = format!("\"{key}\"");
18557            assert!(
18558                json.contains(&quoted),
18559                "serialized Caixa must carry the lifted top-level \
18560                 multi-word byte-sequence {quoted} verbatim in the JSON \
18561                 emission (got: {json})",
18562            );
18563        }
18564    }
18565
18566    #[test]
18567    fn caixa_top_level_multi_word_key_consts_are_pairwise_distinct() {
18568        // Cross-axis drift-detection pin: a future collapse of the four
18569        // canonical [`Caixa`] top-level multi-word byte-strings onto the
18570        // same value (e.g. an accidental copy-paste flip of
18571        // [`crate::render::CAIXA_KEY_DEPS_DEV`] to also read
18572        // `"upgradeFrom"`) would silently reroute every downstream
18573        // `Value::get(<key>)` probe on one axis onto the sibling axis's
18574        // top-level entry and pass every propagation-probe test that
18575        // expected only the stale axis's value. Peer of the sibling
18576        // four-way distinct pin on the `SUPERVISOR_KEY_*` tetrad
18577        // (40cc4e5) and the two-way pin on `MEMBRO_KEY_*` (ce80ca0).
18578        let all = [
18579            crate::render::CAIXA_KEY_DEPS_DEV,
18580            crate::render::M2_KEY_UPGRADE_FROM,
18581            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
18582            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
18583        ];
18584        for (i, a) in all.iter().enumerate() {
18585            for b in all.iter().skip(i + 1) {
18586                assert_ne!(
18587                    a, b,
18588                    "Caixa top-level multi-word key consts must be \
18589                     pairwise-distinct canonical byte-sequences — got \
18590                     `{a}` == `{b}`",
18591                );
18592            }
18593        }
18594    }
18595
18596    #[test]
18597    fn caixa_top_level_multi_word_key_consts_are_lower_camel_case_shape() {
18598        // Shape-pin: every [`Caixa`] top-level multi-word key const must
18599        // be a lowerCamelCase byte-sequence (no `snake_case`
18600        // underscores, no `kebab-case` hyphens, no leading colon, no
18601        // `PascalCase` leading capital, no whitespace / dots) — the
18602        // canonical shape the `#[serde(rename_all = "camelCase")]`
18603        // derive produces on [`Caixa`]. A future flip to a
18604        // non-camelCase attribute at the derive surfaces both here
18605        // (this test fails on the stale-constant shape) and at
18606        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
18607        // (that test fails on the mismatch between const and derive).
18608        // Peer with `membro_key_consts_are_lower_camel_case_shape`
18609        // (ce80ca0) and `supervisor_key_consts_are_lower_camel_case_shape`
18610        // (40cc4e5) on the sibling per-entry / supervisor-tree axes.
18611        for key in [
18612            crate::render::CAIXA_KEY_DEPS_DEV,
18613            crate::render::M2_KEY_UPGRADE_FROM,
18614            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
18615            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
18616        ] {
18617            assert!(
18618                !key.is_empty(),
18619                "Caixa top-level multi-word key const must be non-empty \
18620                 (got {key:?})"
18621            );
18622            let first = key.chars().next().unwrap();
18623            assert!(
18624                first.is_ascii_lowercase(),
18625                "Caixa top-level multi-word key const must lead with an \
18626                 ASCII-lowercase byte (got {key:?}, leads with {first:?})",
18627            );
18628            assert!(
18629                key.chars().all(|c| c.is_ascii_alphanumeric()),
18630                "Caixa top-level multi-word key const must be \
18631                 ASCII-alphanumeric only — no `_` / `-` / `:` / `.` / \
18632                 whitespace (got {key:?})",
18633            );
18634        }
18635    }
18636
18637    #[test]
18638    fn caixa_key_deps_dev_pins_canonical_camel_case_byte_string() {
18639        // Scalar-value pin: the byte-string the
18640        // [`crate::render::CAIXA_KEY_DEPS_DEV`] const resolves to,
18641        // asserted verbatim. A future rebrand (`depsDev` → `devDeps`
18642        // matching Cargo's verbatim `dev-dependencies` axis, `depsDev`
18643        // → `depsTest` matching a hypothetical per-test-target
18644        // vocabulary flip) lands as an edit to exactly one const AND
18645        // one derive attribute — the sibling
18646        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
18647        // pin already ties the const to the derive attribute, so a
18648        // rebrand that touches only one side of the pair fails at
18649        // caixa-core build time. Same "scalar-value pin per const"
18650        // discipline the sibling
18651        // `m2_top_level_author_key_consts_pin_canonical_kebab_case_labels`
18652        // (f49c8b0) and `contrato_key_consts_pin_canonical_camel_case_labels`
18653        // (ca463a4) pins carry on the peer M2 / M3 top-level slot axes.
18654        assert_eq!(crate::render::CAIXA_KEY_DEPS_DEV, "depsDev");
18655    }
18656
18657    #[test]
18658    fn caixa_key_deps_pins_canonical_byte_string() {
18659        // Scalar-value pin: the byte-string the
18660        // [`crate::render::CAIXA_KEY_DEPS`] const resolves to, asserted
18661        // verbatim. Peer of `caixa_key_deps_dev_pins_canonical_camel_case_byte_string`
18662        // on the two-list dep-graph serialized-key axis — the sibling
18663        // pin covers the multi-word `deps_dev → depsDev` camelCase
18664        // arm, this pin covers the single-word `deps → deps` no-op arm
18665        // (the [`crate::Caixa::deps`] field name carries no `_`, so the
18666        // `#[serde(rename_all = "camelCase")]` derive is a no-op on this
18667        // axis and the emitted JSON key equals the source-side field
18668        // name byte-for-byte). A future [`crate::Caixa::deps`] field
18669        // rename (`deps` → `dependencies` matching Cargo's verbatim
18670        // `[dependencies]` axis, `deps` → `runtime_deps` matching a
18671        // hypothetical per-runtime-target vocabulary flip) OR an added
18672        // `#[serde(rename = "…")]` explicit override lands as an edit
18673        // to exactly one const AND one derive-attr / field name — the
18674        // sibling `caixa_deps_serde_key_matches_lifted_caixa_key_deps`
18675        // pin ties the const to the emitted JSON key, so a rebrand
18676        // that touches only one side of the pair fails at caixa-core
18677        // build time.
18678        assert_eq!(crate::render::CAIXA_KEY_DEPS, "deps");
18679    }
18680
18681    #[test]
18682    fn caixa_deps_serde_key_matches_lifted_caixa_key_deps() {
18683        // Load-bearing invariant on the single-word `deps` top-level
18684        // axis: the byte-string [`crate::render::CAIXA_KEY_DEPS`] pins
18685        // must appear verbatim in the JSON [`Caixa::to_lisp`]'s
18686        // `serde_json::to_value(self)` step emits. Serialize a
18687        // populated [`Caixa`] whose `:deps` slot carries at least one
18688        // entry (the `#[serde(default)]` attribute on the field emits
18689        // an empty `[]` even without members, but a non-empty vec
18690        // additionally covers the codec's per-`Dep`-entry emission
18691        // path) and pin that `"deps"` appears verbatim in the JSON
18692        // emission — a future accidental `rename_all = "snake_case"` /
18693        // `"kebab-case"` flip at the derive attribute (or an added
18694        // `#[serde(rename = "…")]` explicit override on the field, or
18695        // a Rust field rename) would break every [`Caixa::to_lisp`]
18696        // round-trip and the future M4 operator-side manifest ingest's
18697        // `Value::get(CAIXA_KEY_DEPS)` navigation — surfaces here as a
18698        // build-time test failure at `manifest.rs`, not as an
18699        // apply-time `.get(<stale-canonical-const>)` returning `None`
18700        // far from the drift's commit. Peer of the sibling
18701        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
18702        // multi-word pin on the same M0 [`Caixa`] top-level
18703        // serialized-key axis, extended here to the single-word arm
18704        // the multi-word test's `rename_all = "camelCase"` sweep can't
18705        // reach (single-word `deps → deps` is a no-op the multi-word
18706        // pin's `\"depsDev\"` / `\"upgradeFrom\"` / `\"maxRestarts\"` /
18707        // `\"restartWindow\"` byte-scan can never observe).
18708        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18709        c.deps = vec![Dep::simple("caixa-core", "^0.1")];
18710        let json = serde_json::to_string(&c).unwrap();
18711        let quoted = format!("\"{}\"", crate::render::CAIXA_KEY_DEPS);
18712        assert!(
18713            json.contains(&quoted),
18714            "serialized Caixa must carry the lifted top-level `deps` \
18715             byte-sequence {quoted} verbatim in the JSON emission (got: \
18716             {json})",
18717        );
18718    }
18719
18720    #[test]
18721    fn caixa_dep_graph_two_list_key_consts_are_pairwise_distinct() {
18722        // Cross-axis drift-detection pin on the two-list dep-graph
18723        // renderer-side wire-key axis: a future collapse of the
18724        // canonical [`crate::render::CAIXA_KEY_DEPS`] /
18725        // [`crate::render::CAIXA_KEY_DEPS_DEV`] byte-strings onto the
18726        // same value (e.g. an accidental copy-paste flip of
18727        // `CAIXA_KEY_DEPS_DEV` to also read `"deps"`) would silently
18728        // reroute every downstream `Value::get(<key>)` probe on one
18729        // axis onto the sibling axis's dep-list and pass every
18730        // propagation-probe test that expected only the stale axis's
18731        // value — a dev-only dep would land in the runtime closure at
18732        // publish time, or a runtime dep would be excluded from the
18733        // published lacre. Peer of the sibling four-way distinct pin
18734        // on the top-level multi-word tetrad
18735        // (`caixa_top_level_multi_word_key_consts_are_pairwise_distinct`)
18736        // and the two-way pin on the sibling
18737        // [`DEP_AUTHOR_KEY_DEPS`] / [`DEP_AUTHOR_KEY_DEPS_DEV`]
18738        // author-facing arm (4da6fba's test), extended here to the
18739        // renderer-side wire-key arm of the same two-list dep-graph
18740        // axis so both halves of the "one canonical byte-string per
18741        // typed axis per (author, wire)" grid carry the same
18742        // distinct-ness discipline.
18743        assert_ne!(
18744            crate::render::CAIXA_KEY_DEPS,
18745            crate::render::CAIXA_KEY_DEPS_DEV,
18746            "CAIXA_KEY_DEPS and CAIXA_KEY_DEPS_DEV must be distinct \
18747             canonical byte-sequences on the two-list dep-graph \
18748             renderer-side wire-key axis"
18749        );
18750    }
18751
18752    // ── DepList / Caixa::push_dep pin ────────────────────────────────
18753    //
18754    // The compounding pin: the two-arm closed-set typed enum
18755    // [`crate::dep::DepList`] carries the runtime-closure `:deps`
18756    // (`Prod`) vs dev-only-closure `:deps-dev` (`Dev`) dispatch every
18757    // consumer of the top-level manifest's dep-mutation surface reads
18758    // through, and the typed dispatch [`Caixa::push_dep`] on the
18759    // substrate primitive folds the "select list → check within-list
18760    // dup → push" cascade onto one method call. Prior to this landing
18761    // the two axes lived across two `&'static str` constants
18762    // (`DEP_AUTHOR_KEY_DEPS`, `DEP_AUTHOR_KEY_DEPS_DEV`) with no closed-
18763    // set type carrying the pair; the `feira add` mutation site's
18764    // inline `if self.dev { &mut caixa.deps_dev } else { &mut
18765    // caixa.deps }` dispatch expressed no compile-time link back to
18766    // the substrate primitive, and a future third dep-list axis would
18767    // have silently split at every open-coded mutation site.
18768
18769    #[test]
18770    fn dep_list_as_str_routes_through_lifted_author_key_constants() {
18771        // Every arm returns the same `&'static str` the substrate's
18772        // canonical `DEP_AUTHOR_KEY_DEPS` / `DEP_AUTHOR_KEY_DEPS_DEV`
18773        // constants carry. A future rebrand on either constant reaches
18774        // the enum through one edit; a regression to inline literals
18775        // (e.g. `Prod => ":deps"`) would silently split the diagnostic
18776        // quotes from the wire-format constants every consumer routes
18777        // through and this pin flags it at build time.
18778        assert_eq!(
18779            crate::dep::DepList::Prod.as_str(),
18780            crate::render::DEP_AUTHOR_KEY_DEPS
18781        );
18782        assert_eq!(
18783            crate::dep::DepList::Dev.as_str(),
18784            crate::render::DEP_AUTHOR_KEY_DEPS_DEV
18785        );
18786    }
18787
18788    #[test]
18789    fn dep_list_display_routes_through_as_str() {
18790        // Same as-str-through-Display convergence discipline the
18791        // sibling closed-set typed enums carry — a `format!("{list}")`
18792        // call must land byte-for-byte on the accessor's return so a
18793        // future consumer that formats the enum for a diagnostic line
18794        // reaches the same wire-format constant the wire-format
18795        // producers do.
18796        assert_eq!(
18797            format!("{}", crate::dep::DepList::Prod),
18798            crate::dep::DepList::Prod.as_str()
18799        );
18800        assert_eq!(
18801            format!("{}", crate::dep::DepList::Dev),
18802            crate::dep::DepList::Dev.as_str()
18803        );
18804    }
18805
18806    #[test]
18807    fn dep_list_all_enumerates_every_variant_once() {
18808        // Exhaustive-iteration pin — every arm appears exactly once in
18809        // `ALL`, matching the closed set the compiler enforces on the
18810        // sibling `match self` arms. A future variant addition that
18811        // extends only one method's match without extending `ALL`
18812        // would silently drop the new arm from every consumer that
18813        // iterates the slice.
18814        let variants: &[crate::dep::DepList] = crate::dep::DepList::ALL;
18815        assert!(variants.contains(&crate::dep::DepList::Prod));
18816        assert!(variants.contains(&crate::dep::DepList::Dev));
18817        assert_eq!(variants.len(), 2);
18818    }
18819
18820    #[test]
18821    fn dep_list_from_wire_returns_prod_on_deps_wire_scalar() {
18822        // Reverse projection on the two-list dep-graph axis: the
18823        // author-surface wire tag the sibling `as_str` emitter walks
18824        // for `Prod` (`:deps` via `DEP_AUTHOR_KEY_DEPS`) parses back to
18825        // `Some(DepList::Prod)`. A regression that hand-rolled the
18826        // per-arm match without routing through the lifted
18827        // `DEP_AUTHOR_KEY_DEPS` const would silently disagree on any
18828        // future wire-tag rebrand and this pin flags it at build time.
18829        assert_eq!(
18830            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS),
18831            Some(crate::dep::DepList::Prod)
18832        );
18833    }
18834
18835    #[test]
18836    fn dep_list_from_wire_returns_dev_on_deps_dev_wire_scalar() {
18837        // Peer of the `Prod`-arm pin on the dev-only axis: the
18838        // author-surface wire tag the sibling `as_str` emitter walks
18839        // for `Dev` (`:deps-dev` via `DEP_AUTHOR_KEY_DEPS_DEV`) parses
18840        // back to `Some(DepList::Dev)`. Same drift-detection posture
18841        // as the peer arm — the sibling method `match` arms are
18842        // compiler-checked exhaustive so a future variant addition
18843        // trips at build time.
18844        assert_eq!(
18845            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS_DEV),
18846            Some(crate::dep::DepList::Dev)
18847        );
18848    }
18849
18850    #[test]
18851    fn dep_list_from_wire_returns_none_on_unknown_wire_scalar() {
18852        // Every input outside the closed-set arm-string set the
18853        // sibling `as_str` emitter walks lands on the terminal `None`
18854        // fallback — no silent-accept surface. Sweeps a set of
18855        // plausibly-adjacent scalars (unprefixed wire form, PascalCase
18856        // rebrand candidates, foreign wire tags, empty string) so a
18857        // future variant addition that widened one wire form without
18858        // extending the emitter's arm-set would trip the sibling
18859        // round-trip pin below rather than silently accepting the new
18860        // form here.
18861        for candidate in [
18862            "",
18863            "deps",
18864            "deps-dev",
18865            ":deps ",
18866            ":Deps",
18867            ":DEPS",
18868            ":build-dep",
18869            ":tool-dep",
18870            "prod",
18871            "dev",
18872        ] {
18873            assert_eq!(
18874                crate::dep::DepList::from_wire(candidate),
18875                None,
18876                "from_wire({candidate:?}) must return None; every input outside \
18877                 the {{DEP_AUTHOR_KEY_DEPS, DEP_AUTHOR_KEY_DEPS_DEV}} accept-set \
18878                 the sibling as_str emitter walks lands on the terminal fallback",
18879            );
18880        }
18881    }
18882
18883    #[test]
18884    fn dep_list_round_trips_through_as_str_and_from_wire() {
18885        // Load-bearing round-trip pin: every arm the `ALL` iteration
18886        // exposes survives the `as_str` → `from_wire` composition
18887        // byte-for-byte. Same discipline the sibling closed-set enums
18888        // carry — `CaixaKind` /
18889        // `RestartStrategy` / `RestartPolicy` /
18890        // `PlacementStrategy` — extended onto the two-list dep-graph
18891        // axis. A future variant addition that extends `ALL` +
18892        // `as_str` without extending `from_wire` (or vice versa)
18893        // trips at build time on this iteration because the compiler
18894        // enforces exhaustiveness on the sibling `match self` arms.
18895        for &list in crate::dep::DepList::ALL {
18896            assert_eq!(
18897                crate::dep::DepList::from_wire(list.as_str()),
18898                Some(list),
18899                "DepList::from_wire(as_str({list:?})) must round-trip to Some({list:?}) — \
18900                 a silent split between the forward emitter and the reverse parser \
18901                 would drift the two halves of the two-list dep-graph axis's typed dispatch",
18902            );
18903        }
18904    }
18905
18906    #[test]
18907    fn push_dep_routes_to_deps_slot_on_prod_arm() {
18908        // The `Prod` arm dispatches to the runtime-closure `:deps`
18909        // slot every downstream lacre-pipeline consumer resolves at
18910        // build time. A future arm that regressed to inline `&mut
18911        // self.deps_dev` on the `Prod` path would silently reroute
18912        // every runtime dep into the dev-only closure at publish time
18913        // — this pin refuses that regression.
18914        let src = Caixa::template("host");
18915        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18916        let before_deps = caixa.deps().len();
18917        let before_deps_dev = caixa.deps_dev().len();
18918        let dep = Dep {
18919            nome: "caixa-teia".to_string(),
18920            versao: "^0.1".to_string(),
18921            fonte: None,
18922            opcional: false,
18923            caracteristicas: Vec::new(),
18924        };
18925        caixa
18926            .push_dep(crate::dep::DepList::Prod, dep)
18927            .expect("first push into :deps succeeds");
18928        assert_eq!(caixa.deps().len(), before_deps + 1);
18929        assert_eq!(caixa.deps_dev().len(), before_deps_dev);
18930        assert_eq!(caixa.deps().last().unwrap().nome(), "caixa-teia");
18931    }
18932
18933    #[test]
18934    fn push_dep_routes_to_deps_dev_slot_on_dev_arm() {
18935        // Peer of the sibling `Prod`-arm dispatch pin — the `Dev` arm
18936        // must dispatch to the dev-only-closure `:deps-dev` slot every
18937        // downstream test-facing artifact resolver reads. A future
18938        // regression that inverted the two arms would silently route
18939        // every dev-only dep into the runtime closure at publish time
18940        // and this pin catches it before the drift ships.
18941        let src = Caixa::template("host");
18942        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18943        let dep = Dep {
18944            nome: "tatara-check".to_string(),
18945            versao: "*".to_string(),
18946            fonte: None,
18947            opcional: false,
18948            caracteristicas: Vec::new(),
18949        };
18950        caixa
18951            .push_dep(crate::dep::DepList::Dev, dep)
18952            .expect("first push into :deps-dev succeeds");
18953        assert!(caixa.deps().is_empty());
18954        assert_eq!(caixa.deps_dev().len(), 1);
18955        assert_eq!(caixa.deps_dev().last().unwrap().nome(), "tatara-check");
18956    }
18957
18958    #[test]
18959    fn push_dep_refuses_within_list_duplicate_nome_with_typed_error() {
18960        // Within-list dup check routes through the canonical
18961        // [`DepError::DuplicateNome`] carrier — the substrate's typed
18962        // diagnostic for the same axis [`Caixa::validate_deps`]'s
18963        // parse-time [`crate::render::insert_first_seen`] walk raises
18964        // on. Prior to the lift the mutation site's inline
18965        // `bail!("dep '{}' already declared", …)` string-diagnostic
18966        // path expressed no through-line back to the typed error;
18967        // routing every dep-list refusal through one carrier means an
18968        // author reading a `feira add` refusal and a `feira build`
18969        // refusal reaches for the same corrective surface without
18970        // switching diagnostic idioms.
18971        let src = Caixa::template("host");
18972        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18973        let dep = Dep {
18974            nome: "caixa-teia".to_string(),
18975            versao: "^0.1".to_string(),
18976            fonte: None,
18977            opcional: false,
18978            caracteristicas: Vec::new(),
18979        };
18980        caixa
18981            .push_dep(crate::dep::DepList::Prod, dep.clone())
18982            .expect("first push succeeds");
18983        let dup = Dep {
18984            nome: "caixa-teia".to_string(),
18985            versao: "^0.2".to_string(),
18986            fonte: None,
18987            opcional: false,
18988            caracteristicas: Vec::new(),
18989        };
18990        let err = caixa
18991            .push_dep(crate::dep::DepList::Prod, dup)
18992            .expect_err("second push with same :nome refuses");
18993        assert_eq!(
18994            err,
18995            DepError::DuplicateNome {
18996                nome: "caixa-teia".to_string(),
18997                list: crate::render::DEP_AUTHOR_KEY_DEPS,
18998            }
18999        );
19000        // The refused mutation must not corrupt the target list —
19001        // exactly one entry lives past the refusal, matching the
19002        // canonical single-source-of-truth invariant `Caixa::deps()`
19003        // carries.
19004        assert_eq!(caixa.deps().len(), 1);
19005    }
19006
19007    #[test]
19008    fn push_dep_refuses_dup_on_dev_list_arm_names_deps_dev_key() {
19009        // Peer of the sibling `Prod`-arm dup-refusal pin — the `Dev`
19010        // arm's refusal must carry `DEP_AUTHOR_KEY_DEPS_DEV` in the
19011        // `list` payload so a future author reading the refusal grep's
19012        // for the correct `:deps-dev` block in their `caixa.lisp`,
19013        // not the sibling `:deps` block the runtime closure resolves.
19014        let src = Caixa::template("host");
19015        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19016        let dep = Dep {
19017            nome: "tatara-check".to_string(),
19018            versao: "*".to_string(),
19019            fonte: None,
19020            opcional: false,
19021            caracteristicas: Vec::new(),
19022        };
19023        caixa
19024            .push_dep(crate::dep::DepList::Dev, dep.clone())
19025            .expect("first push succeeds");
19026        let err = caixa
19027            .push_dep(crate::dep::DepList::Dev, dep)
19028            .expect_err("second push with same :nome refuses");
19029        assert!(matches!(
19030            err,
19031            DepError::DuplicateNome {
19032                ref nome,
19033                list,
19034            } if nome == "tatara-check"
19035                && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
19036        ));
19037    }
19038
19039    #[test]
19040    fn push_dep_allows_same_nome_across_prod_and_dev_lists() {
19041        // The within-list dup check is scoped to the target arm — a
19042        // caixa may legitimately carry the same `:nome` under both
19043        // `:deps` and `:deps-dev` (though the substrate's peer
19044        // [`crate::Caixa::validate_deps`] walk still refuses the
19045        // shape at parse time; the mutation-site refusal is scoped to
19046        // the mutation-site's list to match the peer parse-time
19047        // per-list [`crate::render::insert_first_seen`] discipline).
19048        // The two arms hold independent seen-sets.
19049        let src = Caixa::template("host");
19050        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19051        let dep_prod = Dep {
19052            nome: "shared".to_string(),
19053            versao: "^0.1".to_string(),
19054            fonte: None,
19055            opcional: false,
19056            caracteristicas: Vec::new(),
19057        };
19058        let dep_dev = Dep {
19059            nome: "shared".to_string(),
19060            versao: "*".to_string(),
19061            fonte: None,
19062            opcional: false,
19063            caracteristicas: Vec::new(),
19064        };
19065        caixa
19066            .push_dep(crate::dep::DepList::Prod, dep_prod)
19067            .expect("push into :deps succeeds");
19068        caixa
19069            .push_dep(crate::dep::DepList::Dev, dep_dev)
19070            .expect("push same :nome into :deps-dev succeeds");
19071        assert_eq!(caixa.deps().len(), 1);
19072        assert_eq!(caixa.deps_dev().len(), 1);
19073    }
19074
19075    #[test]
19076    fn deps_of_prod_returns_the_deps_slot_verbatim() {
19077        // The `Prod` arm of the typed-dispatch [`Caixa::deps_of`] read
19078        // accessor must project onto the runtime-closure `:deps` slot —
19079        // element-equal and length-equal to the sibling per-slot
19080        // [`Caixa::deps`] accessor's return over every per-caixa fixture.
19081        // A future arm that regressed to `self.deps_dev()` on the `Prod`
19082        // path would silently reroute every downstream typed-dispatch
19083        // walker (the [`Caixa::validate_deps`] per-list
19084        // [`crate::render::insert_first_seen`] dedup walk, any future
19085        // per-axis-parametrised consumer) into the sibling dev-only
19086        // closure and this pin refuses that regression.
19087        let src = Caixa::template("host");
19088        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19089        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
19090        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 0);
19091        let dep = Dep {
19092            nome: "caixa-teia".to_string(),
19093            versao: "^0.1".to_string(),
19094            fonte: None,
19095            opcional: false,
19096            caracteristicas: Vec::new(),
19097        };
19098        caixa
19099            .push_dep(crate::dep::DepList::Prod, dep.clone())
19100            .expect("push into :deps succeeds");
19101        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
19102        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 1);
19103        assert_eq!(
19104            caixa.deps_of(crate::dep::DepList::Prod)[0].nome(),
19105            "caixa-teia"
19106        );
19107    }
19108
19109    #[test]
19110    fn deps_of_dev_returns_the_deps_dev_slot_verbatim() {
19111        // Peer of the sibling `Prod`-arm pin — the `Dev` arm of
19112        // [`Caixa::deps_of`] must project onto the dev-only-closure
19113        // `:deps-dev` slot, element-equal and length-equal to the
19114        // sibling per-slot [`Caixa::deps_dev`] accessor's return. A
19115        // future regression that inverted the two arms would silently
19116        // route every dev-list walker onto the runtime closure and this
19117        // pin catches it before the drift ships.
19118        let src = Caixa::template("host");
19119        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19120        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
19121        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 0);
19122        let dep = Dep {
19123            nome: "tatara-check".to_string(),
19124            versao: "*".to_string(),
19125            fonte: None,
19126            opcional: false,
19127            caracteristicas: Vec::new(),
19128        };
19129        caixa
19130            .push_dep(crate::dep::DepList::Dev, dep)
19131            .expect("push into :deps-dev succeeds");
19132        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
19133        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 1);
19134        assert_eq!(
19135            caixa.deps_of(crate::dep::DepList::Dev)[0].nome(),
19136            "tatara-check"
19137        );
19138    }
19139
19140    #[test]
19141    fn deps_of_exhaustive_over_dep_list_all_covers_the_two_slots() {
19142        // Composition pin: iterating [`crate::dep::DepList::ALL`] through
19143        // [`Caixa::deps_of`] must land on the same two-slot partition the
19144        // per-slot [`Caixa::deps`] / [`Caixa::deps_dev`] accessors
19145        // expose — the canonical dispatch a future per-axis-parametrised
19146        // walker (a future `feira app graph` per-list dep summary, a
19147        // future M4 per-cluster dev-closure-audit overlay the CR
19148        // materializer resolves per-CR) reads through. Prior to the
19149        // lift the two-block iteration lived open-coded at every walker,
19150        // so a future third dep-list axis (`:deps-build`, per CAIXA-SDLC
19151        // §I) would have had to grow a third block at every consumer.
19152        // A regression that dropped the `Dev` arm from `ALL` would flip
19153        // the collected pairs to `[(":deps", &[])]` alone and this pin
19154        // refuses that shape.
19155        let src = Caixa::template("host");
19156        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19157        let prod_dep = Dep {
19158            nome: "caixa-teia".to_string(),
19159            versao: "^0.1".to_string(),
19160            fonte: None,
19161            opcional: false,
19162            caracteristicas: Vec::new(),
19163        };
19164        let dev_dep = Dep {
19165            nome: "tatara-check".to_string(),
19166            versao: "*".to_string(),
19167            fonte: None,
19168            opcional: false,
19169            caracteristicas: Vec::new(),
19170        };
19171        caixa
19172            .push_dep(crate::dep::DepList::Prod, prod_dep)
19173            .expect("push into :deps succeeds");
19174        caixa
19175            .push_dep(crate::dep::DepList::Dev, dev_dep)
19176            .expect("push into :deps-dev succeeds");
19177        let collected: Vec<(&'static str, usize, &str)> = crate::dep::DepList::ALL
19178            .iter()
19179            .map(|&list| {
19180                let slice = caixa.deps_of(list);
19181                (list.as_str(), slice.len(), slice[0].nome())
19182            })
19183            .collect();
19184        assert_eq!(
19185            collected,
19186            vec![
19187                (crate::render::DEP_AUTHOR_KEY_DEPS, 1, "caixa-teia"),
19188                (crate::render::DEP_AUTHOR_KEY_DEPS_DEV, 1, "tatara-check"),
19189            ]
19190        );
19191    }
19192
19193    #[test]
19194    fn caixa_deps_of_is_const_fn() {
19195        // Fail-before-pass-after pin on [`Caixa::deps_of`]'s
19196        // `const`-eval-surface posture. The typed-dispatch read
19197        // accessor forwards through the sibling `pub const fn`
19198        // [`Caixa::deps`] / [`Caixa::deps_dev`] per-slot slice
19199        // accessors on the two [`crate::dep::DepList`] enum arms —
19200        // every operator in the body is already `const`-callable
19201        // (`DepList` is a plain `#[derive(Copy)]` closed-set
19202        // discriminator so the `match` arms are const-evaluable, and
19203        // each arm dispatches through the sibling `pub const fn`
19204        // slice accessor). Any future accidental downgrade to
19205        // non-`const` fails the `deps_of_via_const_fn` wrapper below
19206        // at caixa-core build time with E0015 (`cannot call non-const
19207        // method`), strictly stronger than a runtime `assert!` and
19208        // side-stepping the destructor-in-const restriction the
19209        // `Caixa` fixture's owning `String` / `Vec<Dep>` carriers
19210        // rule out on the direct-`const _: () = assert!(...)`
19211        // residence.
19212        //
19213        // Peer of the sibling outer-`Caixa` accessor family pins
19214        // ([`caixa_outer_string_slice_return_accessor_family_is_const_fn`]
19215        // on the `&[String]` universal-axis surface,
19216        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
19217        // on the outer `&[T]` composite-slice surface,
19218        // [`caixa_outer_option_composite_reference_return_accessor_family_is_const_fn`]
19219        // on the outer `Option<&Composite>` surface) — this pin
19220        // extends the `const`-eval-surface discipline onto the outer-
19221        // `Caixa` typed-dispatch read surface on the [`DepList`]-keyed
19222        // dep-list axis, closing the outer-`Caixa` accessor family's
19223        // last unlifted `pub fn` on the read side.
19224        const fn deps_of_via_const_fn(c: &Caixa, list: crate::dep::DepList) -> &[Dep] {
19225            c.deps_of(list)
19226        }
19227        let src = Caixa::template("host");
19228        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19229        // Empty-list arm: both `Prod` and `Dev` degenerate to the
19230        // empty slice with no silent `None` collapse — the
19231        // `#[serde(default)]` `Vec::new()` fold every `defcaixa` form
19232        // that omits the slot lands on.
19233        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod).is_empty());
19234        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev).is_empty());
19235        assert_eq!(
19236            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
19237            caixa.deps()
19238        );
19239        assert_eq!(
19240            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
19241            caixa.deps_dev()
19242        );
19243        // Populated arms: each list carries its own entry, and the
19244        // wrapper / direct dispatches agree byte-for-byte on the
19245        // slice-view under both non-empty arms.
19246        let prod_dep = Dep {
19247            nome: "caixa-teia".to_string(),
19248            versao: "^0.1".to_string(),
19249            fonte: None,
19250            opcional: false,
19251            caracteristicas: Vec::new(),
19252        };
19253        let dev_dep = Dep {
19254            nome: "tatara-check".to_string(),
19255            versao: "*".to_string(),
19256            fonte: None,
19257            opcional: false,
19258            caracteristicas: Vec::new(),
19259        };
19260        caixa
19261            .push_dep(crate::dep::DepList::Prod, prod_dep)
19262            .expect("push into :deps succeeds");
19263        caixa
19264            .push_dep(crate::dep::DepList::Dev, dev_dep)
19265            .expect("push into :deps-dev succeeds");
19266        assert_eq!(
19267            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
19268            caixa.deps()
19269        );
19270        assert_eq!(
19271            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
19272            caixa.deps_dev()
19273        );
19274        assert_eq!(
19275            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod)[0].nome(),
19276            "caixa-teia"
19277        );
19278        assert_eq!(
19279            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev)[0].nome(),
19280            "tatara-check"
19281        );
19282    }
19283
19284    #[test]
19285    fn validate_deps_iterates_through_dep_list_all_via_deps_of() {
19286        // Composition pin: the [`Caixa::validate_deps`] parse-time gate
19287        // must route its per-list [`crate::render::insert_first_seen`]
19288        // dedup walk through [`Caixa::deps_of`] + [`crate::dep::DepList::ALL`]
19289        // rather than the pre-lift open-coded two-block iteration over
19290        // `self.deps()` + `self.deps_dev()`. A regression that dropped
19291        // one arm (e.g. hand-inlining `self.deps()` alone) would silently
19292        // stop refusing within-list dups on the sibling arm; a
19293        // regression that flipped the arm-to-list-key mapping
19294        // (`Dev => DEP_AUTHOR_KEY_DEPS`) would silently mislabel the
19295        // diagnostic surface. Both drifts surface here through a paired
19296        // duplicate-name refusal per arm plus an offending-list-key
19297        // check on the emitted [`DepError::DuplicateNome`] carrier.
19298        for &list in crate::dep::DepList::ALL {
19299            let src = Caixa::template("host");
19300            let mut caixa = Caixa::from_lisp(&src).expect("template parses");
19301            let dup = Dep {
19302                nome: "twin".to_string(),
19303                versao: "^0.1".to_string(),
19304                fonte: None,
19305                opcional: false,
19306                caracteristicas: Vec::new(),
19307            };
19308            match list {
19309                crate::dep::DepList::Prod => {
19310                    caixa.deps.push(dup.clone());
19311                    caixa.deps.push(dup);
19312                }
19313                crate::dep::DepList::Dev => {
19314                    caixa.deps_dev.push(dup.clone());
19315                    caixa.deps_dev.push(dup);
19316                }
19317            }
19318            let err = caixa
19319                .validate_deps()
19320                .expect_err("within-list duplicate :nome must refuse");
19321            assert_eq!(
19322                err,
19323                DepError::DuplicateNome {
19324                    nome: "twin".to_string(),
19325                    list: list.as_str(),
19326                },
19327                "validate_deps on {list} arm must emit \
19328                 DepError::DuplicateNome carrying the arm's own \
19329                 as_str() diagnostic — the arm-to-list-key mapping \
19330                 flowed through DepList::ALL + Caixa::deps_of"
19331            );
19332        }
19333    }
19334
19335    #[test]
19336    fn caixa_licenca_default_pins_canonical_mit_byte() {
19337        // Bridge-arm pin: [`CAIXA_LICENCA_DEFAULT`] resolves to the
19338        // canonical SPDX-`"MIT"` byte today, the same license expression
19339        // every peer substrate-side consumer of the author-omitted
19340        // `:licenca` slot ([`caixa-helm`]'s `build_readme` fallback arm at
19341        // `caixa-helm/src/lib.rs`, the future M4
19342        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-CR
19343        // `Chart.yaml annotations["artifacthub.io/license"]` emitter this
19344        // crate's [`Caixa::validate_licenca`] docstring roadmap already
19345        // names as the second consumer) fills into its per-consumer
19346        // README/annotation emit site. Pin the literal here (peer with the
19347        // [`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`] /
19348        // [`crate::version::DEFAULT_GIT_REMOTE`] /
19349        // [`crate::version::DEFAULT_PLEME_GIT_ORG`] canonical-literal pins
19350        // on the sibling lifted-constant surfaces) so a future
19351        // substrate-side license-fallback rebrand surfaces here as a
19352        // coordinated edit-point: the sibling caixa-helm
19353        // `build_readme_license_line_routes_through_lifted_caixa_licenca_default`
19354        // pinning test already pins the equality at the renderer-emit
19355        // axis; this pin closes the second coordinate of the pair by
19356        // anchoring the lifted constant's current byte to the canonical
19357        // CAIXA-SDLC §I license scaffold's documented shape.
19358        assert_eq!(CAIXA_LICENCA_DEFAULT, "MIT");
19359    }
19360
19361    // ── Caixa::validate_upgrade_from — compound per-Caixa entry gate on ──
19362    // ── the M2 `:upgrade-from` slot: folds the three top-level        ──
19363    // ── `crate::upgrade` validators (per-entry + cross-entry           ──
19364    // ── duplicate-`:from`, cross-slot `:from < :versao` precedence,   ──
19365    // ── cross-slot `:state-change` ↔ `:on-state-change` composition)  ──
19366    // ── onto one substrate primitive. Byte-for-byte equivalent to the ──
19367    // ── pre-fold three-block cascade at                               ──
19368    // ── `crate::layout::StandardLayout::verify` under the same        ──
19369    // ── canonical dispatch order.                                     ──
19370
19371    #[test]
19372    fn validate_upgrade_from_folds_per_entry_arm_matches_gate() {
19373        // Fail-before-pass-after per-arm equivalence pin on the
19374        // per-entry + cross-entry axis: a fixture whose `:upgrade-from`
19375        // carries a per-entry-invalid `:from` (git-tag shape `"v0.1.0"`,
19376        // which `semver::Version::parse` rejects) surfaces the same
19377        // [`crate::UpgradeError`] through the compound gate
19378        // [`Caixa::validate_upgrade_from`] and the standalone per-entry
19379        // gate [`crate::upgrade::validate_upgrade_from`] on the same
19380        // [`Caixa::upgrade_from`] slice. Pins the fold — a silent
19381        // regression that de-folded the per-entry arm would surface here
19382        // as a mismatch between the two dispatches. Sibling in shape to
19383        // the peer per-slot-≡-standalone equivalence pins the
19384        // [`crate::AplicacaoSpec::validate_contratos`] /
19385        // [`crate::MeshPolicy::validate`] /
19386        // [`crate::SupervisorSpec::validate_children`] compound gates
19387        // each carry on their axes.
19388        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19389        c.upgrade_from = vec![crate::UpgradeFromEntry {
19390            from: "v0.1.0".into(),
19391            instructions: vec![crate::UpgradeInstruction::Restart],
19392        }];
19393        let via_method = c.validate_upgrade_from().unwrap_err();
19394        let via_standalone = crate::upgrade::validate_upgrade_from(c.upgrade_from()).unwrap_err();
19395        assert_eq!(
19396            via_method, via_standalone,
19397            "Caixa::validate_upgrade_from must surface the per-entry \
19398             axis's diagnostic byte-equal to the standalone \
19399             `crate::upgrade::validate_upgrade_from` on the same \
19400             upgrade_from() slice"
19401        );
19402        assert!(
19403            matches!(
19404                via_method,
19405                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.1.0"
19406            ),
19407            "expected FromInvalid on the git-tag-shape `:from`, got {via_method:?}"
19408        );
19409    }
19410
19411    #[test]
19412    fn validate_upgrade_from_folds_versao_arm_matches_gate() {
19413        // Per-arm equivalence pin on the cross-slot `:from ↔ :versao`
19414        // precedence axis: a fixture with a well-formed `:from` (so the
19415        // per-entry arm passes) whose parsed semver is >= the caixa's
19416        // `:versao` under SemVer-2 precedence surfaces the same
19417        // [`crate::UpgradeError::FromNotBeforeVersao`] through both the
19418        // compound gate and the standalone
19419        // [`crate::upgrade::validate_upgrade_from_against_versao`] gate
19420        // keyed off the same `(upgrade_from, versao)` pair. Pins the
19421        // fold's second arm — reaching this arm through the compound
19422        // gate requires the per-entry arm to pass first, which itself
19423        // pins the per-arm cross-arm ordering.
19424        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19425        c.versao = "0.1.0".into();
19426        c.upgrade_from = vec![crate::UpgradeFromEntry {
19427            from: "0.2.0".into(),
19428            instructions: vec![crate::UpgradeInstruction::Restart],
19429        }];
19430        let via_method = c.validate_upgrade_from().unwrap_err();
19431        let via_standalone =
19432            crate::upgrade::validate_upgrade_from_against_versao(c.upgrade_from(), c.versao())
19433                .unwrap_err();
19434        assert_eq!(
19435            via_method, via_standalone,
19436            "Caixa::validate_upgrade_from must surface the \
19437             `:from >= :versao` diagnostic byte-equal to the standalone \
19438             `crate::upgrade::validate_upgrade_from_against_versao` on \
19439             the same (upgrade_from, versao) pair"
19440        );
19441        assert!(
19442            matches!(
19443                via_method,
19444                crate::UpgradeError::FromNotBeforeVersao { ref from, ref versao }
19445                    if from == "0.2.0" && versao == "0.1.0"
19446            ),
19447            "expected FromNotBeforeVersao carrying the offending pair, got {via_method:?}"
19448        );
19449    }
19450
19451    #[test]
19452    fn validate_upgrade_from_folds_behavior_arm_matches_gate() {
19453        // Per-arm equivalence pin on the cross-slot `:state-change ↔
19454        // :on-state-change` composition axis: a fixture with a
19455        // well-formed `:from` strictly less than `:versao` (so the
19456        // per-entry and versao arms both pass) whose `:instructions`
19457        // list carries a `(:state-change …)` instruction with no
19458        // `:behavior :on-state-change` callback declared surfaces the
19459        // same [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
19460        // through both the compound gate and the standalone
19461        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
19462        // gate keyed off the same `(upgrade_from, behavior)` pair.
19463        // Reaching this arm through the compound gate requires both
19464        // prior arms to pass first — the ordering pin below pins the
19465        // per-arm dispatch order explicitly.
19466        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19467        c.versao = "0.2.0".into();
19468        c.behavior = None;
19469        c.upgrade_from = vec![crate::UpgradeFromEntry {
19470            from: "0.1.0".into(),
19471            instructions: vec![
19472                crate::UpgradeInstruction::LoadModule {
19473                    module: "demo".into(),
19474                },
19475                crate::UpgradeInstruction::StateChange {
19476                    script: std::path::PathBuf::from("lib/m.lisp"),
19477                },
19478                crate::UpgradeInstruction::SoftPurge {
19479                    module: "demo-old".into(),
19480                },
19481            ],
19482        }];
19483        let via_method = c.validate_upgrade_from().unwrap_err();
19484        let via_standalone =
19485            crate::upgrade::validate_upgrade_from_against_behavior(c.upgrade_from(), c.behavior())
19486                .unwrap_err();
19487        assert_eq!(
19488            via_method, via_standalone,
19489            "Caixa::validate_upgrade_from must surface the \
19490             `:state-change` ↔ `:on-state-change` composition \
19491             diagnostic byte-equal to the standalone \
19492             `crate::upgrade::validate_upgrade_from_against_behavior` \
19493             on the same (upgrade_from, behavior) pair"
19494        );
19495        assert!(
19496            matches!(
19497                via_method,
19498                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback {
19499                    ref from,
19500                    ref script,
19501                } if from == "0.1.0" && script == &std::path::PathBuf::from("lib/m.lisp")
19502            ),
19503            "expected StateChangeWithoutOnStateChangeCallback carrying \
19504             the offending (from, script) pair, got {via_method:?}"
19505        );
19506    }
19507
19508    #[test]
19509    fn validate_upgrade_from_per_entry_arm_fires_before_versao_arm() {
19510        // Cross-arm ordering pin between the first two arms of the
19511        // fold: a fixture carrying BOTH a per-entry-invalid `:from`
19512        // (`"v0.0.5"` — git-tag shape rejected by
19513        // [`crate::upgrade::validate_upgrade_from`]) AND a would-be
19514        // versao-precedence violation on a second entry (`"0.2.0" >=
19515        // :versao "0.1.0"`) surfaces the per-entry diagnostic first
19516        // through the compound gate. Sanity assertion: the second
19517        // entry alone under the same `:versao` trips the versao arm
19518        // on its own via the standalone
19519        // [`crate::upgrade::validate_upgrade_from_against_versao`], so
19520        // the per-entry-first surfacing is a real ordering property,
19521        // not a case where the versao arm silently accepts the
19522        // fixture. Pins the pre-fold layout wire-up's canonical
19523        // dispatch order (per-entry → versao → behavior) as a
19524        // property of the substrate primitive rather than a
19525        // convention of the layout call site.
19526        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19527        c.versao = "0.1.0".into();
19528        c.upgrade_from = vec![
19529            crate::UpgradeFromEntry {
19530                from: "v0.0.5".into(),
19531                instructions: vec![crate::UpgradeInstruction::Restart],
19532            },
19533            crate::UpgradeFromEntry {
19534                from: "0.2.0".into(),
19535                instructions: vec![crate::UpgradeInstruction::Restart],
19536            },
19537        ];
19538        let err = c.validate_upgrade_from().unwrap_err();
19539        assert!(
19540            matches!(
19541                err,
19542                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.0.5"
19543            ),
19544            "per-entry arm must fire before versao arm — expected \
19545             FromInvalid on `v0.0.5`, got {err:?}"
19546        );
19547        // Sanity: the versao-violating second entry alone under the
19548        // same `:versao` trips the versao arm on its own — proves the
19549        // per-entry-first surfacing above is a real ordering property.
19550        let sanity = crate::upgrade::validate_upgrade_from_against_versao(
19551            &[crate::UpgradeFromEntry {
19552                from: "0.2.0".into(),
19553                instructions: vec![crate::UpgradeInstruction::Restart],
19554            }],
19555            "0.1.0",
19556        )
19557        .unwrap_err();
19558        assert!(
19559            matches!(sanity, crate::UpgradeError::FromNotBeforeVersao { .. }),
19560            "sanity: the versao-violating fixture alone must trip the \
19561             versao arm — got {sanity:?}"
19562        );
19563    }
19564
19565    #[test]
19566    fn validate_upgrade_from_versao_arm_fires_before_behavior_arm() {
19567        // Cross-arm ordering pin between the second and third arms of
19568        // the fold: a fixture carrying BOTH a versao-precedence
19569        // violation (`:from "0.2.0" >= :versao "0.1.0"`) AND a
19570        // would-be missing-callback violation (a `(:state-change …)`
19571        // instruction with no `:behavior :on-state-change`) surfaces
19572        // the versao diagnostic first through the compound gate.
19573        // Sanity assertion: the missing-callback fixture alone (with
19574        // the versao-precedence violation removed by bumping
19575        // `:versao` past `:from`) trips the behavior arm on its own
19576        // via the standalone
19577        // [`crate::upgrade::validate_upgrade_from_against_behavior`],
19578        // so the versao-first surfacing is a real ordering property,
19579        // not a case where the behavior arm silently accepts the
19580        // fixture.
19581        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19582        c.versao = "0.1.0".into();
19583        c.behavior = None;
19584        c.upgrade_from = vec![crate::UpgradeFromEntry {
19585            from: "0.2.0".into(),
19586            instructions: vec![
19587                crate::UpgradeInstruction::LoadModule {
19588                    module: "demo".into(),
19589                },
19590                crate::UpgradeInstruction::StateChange {
19591                    script: std::path::PathBuf::from("lib/m.lisp"),
19592                },
19593            ],
19594        }];
19595        let err = c.validate_upgrade_from().unwrap_err();
19596        assert!(
19597            matches!(
19598                err,
19599                crate::UpgradeError::FromNotBeforeVersao { ref from, .. } if from == "0.2.0"
19600            ),
19601            "versao arm must fire before behavior arm — expected \
19602             FromNotBeforeVersao on `0.2.0`, got {err:?}"
19603        );
19604        // Sanity: the same instructions under a `:versao` that
19605        // accepts the `:from` (so the versao arm passes) trips the
19606        // behavior arm — proves the versao-first surfacing above is a
19607        // real ordering property.
19608        let sanity = crate::upgrade::validate_upgrade_from_against_behavior(
19609            &[crate::UpgradeFromEntry {
19610                from: "0.2.0".into(),
19611                instructions: vec![
19612                    crate::UpgradeInstruction::LoadModule {
19613                        module: "demo".into(),
19614                    },
19615                    crate::UpgradeInstruction::StateChange {
19616                        script: std::path::PathBuf::from("lib/m.lisp"),
19617                    },
19618                ],
19619            }],
19620            None,
19621        )
19622        .unwrap_err();
19623        assert!(
19624            matches!(
19625                sanity,
19626                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback { .. }
19627            ),
19628            "sanity: the missing-callback fixture alone must trip the \
19629             behavior arm — got {sanity:?}"
19630        );
19631    }
19632
19633    #[test]
19634    fn validate_upgrade_from_accepts_clean_fixture() {
19635        // Positive control: a well-formed `:upgrade-from` (single entry
19636        // with `:from` strictly less than `:versao`, no
19637        // `:state-change` instruction so the behavior arm is vacuous)
19638        // passes the compound gate cleanly. A future tightening of any
19639        // one arm's accepted set surfaces here as a test failure
19640        // first. Mirrors the peer `validate_versao_accepts_canonical_forms`
19641        // positive-control posture on the sibling per-Caixa gate.
19642        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19643        c.versao = "0.2.0".into();
19644        c.upgrade_from = vec![crate::UpgradeFromEntry {
19645            from: "0.1.0".into(),
19646            instructions: vec![crate::UpgradeInstruction::Restart],
19647        }];
19648        c.validate_upgrade_from()
19649            .expect("clean fixture must pass the compound `:upgrade-from` gate");
19650    }
19651
19652    #[test]
19653    fn validate_upgrade_from_accepts_empty_upgrade_from() {
19654        // Positive control on the empty-list arm: a caixa without any
19655        // `:upgrade-from` block (the default `Vec::new()`
19656        // `#[serde(default)]` folds an omitted slot onto) passes the
19657        // compound gate cleanly regardless of `:versao` or `:behavior`
19658        // — each of the three standalone validators is vacuous on the
19659        // empty entry list. Pins the identity element of the fold on
19660        // the empty-slot side.
19661        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19662        assert!(
19663            c.upgrade_from().is_empty(),
19664            "template caixa must carry an empty :upgrade-from — got {:?}",
19665            c.upgrade_from()
19666        );
19667        c.validate_upgrade_from()
19668            .expect("empty :upgrade-from must pass the compound gate cleanly");
19669    }
19670
19671    // ── Caixa::validate_limits — compound per-Caixa entry gate on   ──
19672    // ── the M2 `:limits` slot: folds the                            ──
19673    // ── [`crate::LimitsSpec::validate`] four-axis cascade on the    ──
19674    // ── present-slot arm and the `Option::None` identity element on ──
19675    // ── the absent-slot arm onto one substrate primitive.           ──
19676    // ── Byte-for-byte equivalent to the pre-fold                    ──
19677    // ── `if let Some(l) = caixa.limits() { l.validate() }`          ──
19678    // ── unwrap-and-dispatch pattern at                              ──
19679    // ── `crate::layout::StandardLayout::verify` (`layout.rs`).      ──
19680
19681    #[test]
19682    fn validate_limits_folds_arm_matches_gate() {
19683        // Fail-before-pass-after per-arm equivalence pin on the
19684        // present-slot arm: a fixture whose `:limits` carries a
19685        // zero-floor-violating `:fuel` (`Some(0)`, which
19686        // [`crate::LimitsSpec::validate`] rejects through
19687        // [`crate::LimitsError::FuelZero`]) surfaces the same
19688        // [`crate::LimitsError`] byte-equal through both the compound
19689        // gate [`Caixa::validate_limits`] and the standalone
19690        // [`crate::LimitsSpec::validate`] gate on the same `LimitsSpec`
19691        // value. Pins the fold — a silent regression that de-folded
19692        // the present-slot arm would surface here as a mismatch
19693        // between the two dispatches. Sibling in shape to the peer
19694        // per-arm equivalence pins the
19695        // [`crate::AplicacaoSpec::validate_contratos`] /
19696        // [`crate::MeshPolicy::validate`] /
19697        // [`crate::SupervisorSpec::validate_children`] /
19698        // [`Caixa::validate_upgrade_from`] compound gates each carry
19699        // on their axes.
19700        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19701        let l = crate::LimitsSpec {
19702            memory: None,
19703            fuel: Some(0),
19704            wall_clock: None,
19705            cpu: None,
19706        };
19707        c.limits = Some(l);
19708        let via_method = c.validate_limits().unwrap_err();
19709        let via_standalone = l.validate().unwrap_err();
19710        assert_eq!(
19711            via_method, via_standalone,
19712            "Caixa::validate_limits must surface the present-slot \
19713             arm's diagnostic byte-equal to the standalone \
19714             `LimitsSpec::validate` on the same `LimitsSpec` value"
19715        );
19716        assert!(
19717            matches!(via_method, crate::LimitsError::FuelZero),
19718            "expected FuelZero on the zero-floor-violating `:fuel`, \
19719             got {via_method:?}"
19720        );
19721    }
19722
19723    #[test]
19724    fn validate_limits_accepts_none() {
19725        // Positive control on the absent-slot arm (the fold's identity
19726        // element): a caixa without any `:limits` block (the
19727        // canonical "no bound declared — engine-default applies"
19728        // author shape [`crate::LimitsSpec::is_empty`]'s per-axis
19729        // `None` cascade reads, and the shape the [`Caixa::template`]
19730        // scaffold emits by construction) passes the compound gate
19731        // cleanly, regardless of any per-axis defect a subsequent
19732        // `Some(_)` binding would surface. Pins the identity element
19733        // of the fold on the absent-slot side, matching the peer
19734        // `validate_upgrade_from_accepts_empty_upgrade_from` positive-
19735        // control posture on the sibling M2 slot.
19736        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19737        assert!(
19738            c.limits().is_none(),
19739            "template caixa must carry an absent :limits — got {:?}",
19740            c.limits()
19741        );
19742        c.validate_limits()
19743            .expect("absent :limits must pass the compound gate cleanly");
19744    }
19745
19746    #[test]
19747    fn validate_limits_accepts_clean_fixture() {
19748        // Positive control on the present-slot arm: a caixa whose
19749        // `:limits` is `Some(LimitsSpec::default())` (all four axes
19750        // `None` — every axis absent under the outer `Some(_)`
19751        // binding, so every present-slot arm on
19752        // [`crate::LimitsSpec::validate`] is vacuous) passes the
19753        // compound gate cleanly. A future tightening of any one axis
19754        // that surfaces a diagnostic on the all-`None` `LimitsSpec`
19755        // would land here as a test failure first. Pins the
19756        // present-slot arm's accept-shape on the canonical
19757        // "declared-but-empty" author fixture the
19758        // `limits_round_trip_via_json` peer already round-trips
19759        // (`caixa-core/src/manifest.rs:6971`).
19760        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19761        c.limits = Some(crate::LimitsSpec::default());
19762        c.validate_limits()
19763            .expect("Some(LimitsSpec::default()) must pass the compound gate cleanly");
19764    }
19765
19766    // ── Caixa::validate_behavior — compound per-Caixa entry gate on ──
19767    // ── the M2 `:behavior` slot's pure value-shape surface: folds   ──
19768    // ── the [`crate::BehaviorSpec::validate`] six-slot cascade on   ──
19769    // ── the present-slot arm and the `Option::None` identity        ──
19770    // ── element on the absent-slot arm onto one substrate primitive.──
19771    // ── Byte-for-byte equivalent to the pre-fold                    ──
19772    // ── `if let Some(b) = caixa.behavior() { b.validate() }`        ──
19773    // ── unwrap-and-dispatch pattern at                              ──
19774    // ── `crate::layout::StandardLayout::verify` (`layout.rs`). The  ──
19775    // ── on-disk callback-path existence walk stays open-coded at    ──
19776    // ── the layout altitude because it needs the                    ──
19777    // ── [`crate::layout::LayoutInvariants::exists`] filesystem       ──
19778    // ── oracle the pure typed-shape surface has no reference to —   ──
19779    // ── mirror of the peer M2 `:upgrade-from` per-instruction       ──
19780    // ── script-path existence probe that stayed at the layout       ──
19781    // ── altitude after the [`Caixa::validate_upgrade_from`] lift    ──
19782    // ── (d6801df) for the same reason.                              ──
19783
19784    #[test]
19785    fn validate_behavior_folds_arm_matches_gate() {
19786        // Fail-before-pass-after per-arm equivalence pin on the
19787        // present-slot arm: a fixture whose `:behavior` carries an
19788        // absolute-path `:on-init` (`"/etc/passwd"`, which
19789        // [`crate::BehaviorSpec::validate`] rejects through
19790        // [`crate::BehaviorError::AbsolutePath`]) surfaces the same
19791        // [`crate::BehaviorError`] byte-equal through both the
19792        // compound gate [`Caixa::validate_behavior`] and the standalone
19793        // [`crate::BehaviorSpec::validate`] gate on the same
19794        // `BehaviorSpec` value. Pins the fold — a silent regression
19795        // that de-folded the present-slot arm would surface here as a
19796        // mismatch between the two dispatches. Sibling in shape to the
19797        // peer per-arm equivalence pins the
19798        // [`Caixa::validate_limits`] (baa4688),
19799        // [`Caixa::validate_upgrade_from`] (d6801df),
19800        // [`crate::MeshPolicy::validate`],
19801        // [`crate::AplicacaoSpec::validate_contratos`], and
19802        // [`crate::SupervisorSpec::validate_children`] compound gates
19803        // each carry on their axes.
19804        use crate::BehaviorSpec;
19805        use std::path::PathBuf;
19806        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19807        let b = BehaviorSpec {
19808            on_init: Some(PathBuf::from("/etc/passwd")),
19809            ..Default::default()
19810        };
19811        c.behavior = Some(b.clone());
19812        let via_method = c.validate_behavior().unwrap_err();
19813        let via_standalone = b.validate().unwrap_err();
19814        assert_eq!(
19815            via_method, via_standalone,
19816            "Caixa::validate_behavior must surface the present-slot \
19817             arm's diagnostic byte-equal to the standalone \
19818             `BehaviorSpec::validate` on the same `BehaviorSpec` value"
19819        );
19820        assert!(
19821            matches!(via_method, crate::BehaviorError::AbsolutePath { .. }),
19822            "expected AbsolutePath on the absolute `:on-init` path, \
19823             got {via_method:?}"
19824        );
19825    }
19826
19827    #[test]
19828    fn validate_behavior_accepts_none() {
19829        // Positive control on the absent-slot arm (the fold's identity
19830        // element): a caixa without any `:behavior` block (the
19831        // canonical "no callback declared — the runtime falls back to
19832        // the wasm-engine's default per arm" author shape
19833        // [`crate::BehaviorSpec::is_empty`]'s per-slot `None` cascade
19834        // reads, and the shape the [`Caixa::template`] scaffold emits
19835        // by construction) passes the compound gate cleanly,
19836        // regardless of any per-slot defect a subsequent `Some(_)`
19837        // binding would surface. Pins the identity element of the fold
19838        // on the absent-slot side, matching the peer
19839        // `validate_limits_accepts_none` (baa4688) and
19840        // `validate_upgrade_from_accepts_empty_upgrade_from` (d6801df)
19841        // positive-control postures on the sibling M2 slots.
19842        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19843        assert!(
19844            c.behavior().is_none(),
19845            "template caixa must carry an absent :behavior — got {:?}",
19846            c.behavior()
19847        );
19848        c.validate_behavior()
19849            .expect("absent :behavior must pass the compound gate cleanly");
19850    }
19851
19852    #[test]
19853    fn validate_behavior_accepts_clean_fixture() {
19854        // Positive control on the present-slot arm: a caixa whose
19855        // `:behavior` is `Some(BehaviorSpec::default())` (all six
19856        // slots `None` — every slot absent under the outer `Some(_)`
19857        // binding, so every present-slot arm on
19858        // [`crate::BehaviorSpec::validate`] is vacuous) passes the
19859        // compound gate cleanly. A future tightening of any one arm
19860        // that surfaces a diagnostic on the all-`None` `BehaviorSpec`
19861        // would land here as a test failure first. Pins the
19862        // present-slot arm's accept-shape on the canonical
19863        // "declared-but-empty" author fixture the sibling
19864        // `empty_behavior_round_trip` peer already round-trips
19865        // (`caixa-core/src/behavior.rs` tests). Mirror of the peer
19866        // `validate_limits_accepts_clean_fixture` (baa4688)
19867        // positive-control posture on the sibling M2 `:limits` slot.
19868        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19869        c.behavior = Some(crate::BehaviorSpec::default());
19870        c.validate_behavior()
19871            .expect("Some(BehaviorSpec::default()) must pass the compound gate cleanly");
19872    }
19873
19874    // ── Caixa::validate_deps — compound per-Caixa entry gate on the ──
19875    // ── dep-graph axis: folds the two standalone validators         ──
19876    // ── (per-entry + within-list duplicate walk that this method    ──
19877    // ── opened on, cross-slot self-edge via                         ──
19878    // ── `crate::dep::validate_no_self_dep`) onto one substrate      ──
19879    // ── primitive. Byte-for-byte equivalent to the pre-fold         ──
19880    // ── two-block cascade at                                        ──
19881    // ── `crate::layout::StandardLayout::verify` under the same      ──
19882    // ── canonical dispatch order (per-entry → self-edge).           ──
19883
19884    #[test]
19885    fn validate_deps_folds_per_entry_arm_matches_gate() {
19886        // Fail-before-pass-after per-arm equivalence pin on the
19887        // per-entry + within-list duplicate axis: a fixture whose
19888        // `:deps` carries a per-entry-invalid `:versao` (`"^bad"`,
19889        // which [`crate::parse_requirement`] rejects) surfaces the
19890        // same [`crate::DepError`] through the compound gate
19891        // [`Caixa::validate_deps`] and the standalone per-entry walk
19892        // ([`Dep::validate`]) on the offending entry. Pins the
19893        // fold — a silent regression that de-folded the per-entry arm
19894        // would surface here as a mismatch between the two
19895        // dispatches. Sibling in shape to the peer
19896        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
19897        // per-arm equivalence pin (d6801df) on the M2
19898        // `:upgrade-from` compound gate's per-entry arm, extended
19899        // here onto the universal-axis `:deps` compound gate's
19900        // per-entry arm.
19901        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19902        c.deps = vec![Dep::simple("d", "^bad")];
19903        let via_method = c.validate_deps().unwrap_err();
19904        let via_standalone = c.deps()[0].validate().unwrap_err();
19905        assert_eq!(
19906            via_method, via_standalone,
19907            "Caixa::validate_deps must surface the per-entry arm's \
19908             diagnostic byte-equal to the standalone \
19909             `Dep::validate` on the same offending entry",
19910        );
19911        assert!(
19912            matches!(
19913                via_method,
19914                DepError::VersaoInvalid { ref nome, .. } if nome == "d"
19915            ),
19916            "expected VersaoInvalid on the malformed :versao, got {via_method:?}",
19917        );
19918    }
19919
19920    #[test]
19921    fn validate_deps_folds_self_edge_arm_matches_gate() {
19922        // Per-arm equivalence pin on the cross-slot self-edge axis:
19923        // a fixture whose `:deps` lists the caixa's own `:nome`
19924        // (a self-dep, which
19925        // [`crate::dep::validate_no_self_dep`] rejects as a
19926        // structurally-invalid one-node cycle in the lacre closure's
19927        // dep-graph) surfaces the same [`crate::DepError::DepIsSelf`]
19928        // through both the compound gate and the standalone
19929        // [`crate::dep::validate_no_self_dep`] gate keyed off the
19930        // same `(deps, deps_dev, nome)` triple. Pins the fold's
19931        // second arm — reaching this arm through the compound gate
19932        // requires the per-entry + within-list duplicate walk to
19933        // pass first, which itself pins one cross-arm ordering step.
19934        // Sibling in shape to the peer
19935        // `validate_upgrade_from_folds_versao_arm_matches_gate` /
19936        // `_folds_behavior_arm_matches_gate` cross-slot equivalence
19937        // pins (d6801df) on the M2 `:upgrade-from` compound gate's
19938        // cross-slot arms.
19939        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19940        c.deps = vec![Dep::simple("demo", "^0.1")];
19941        let via_method = c.validate_deps().unwrap_err();
19942        let via_standalone =
19943            crate::dep::validate_no_self_dep(c.deps(), c.deps_dev(), c.nome()).unwrap_err();
19944        assert_eq!(
19945            via_method, via_standalone,
19946            "Caixa::validate_deps must surface the cross-slot \
19947             self-edge diagnostic byte-equal to the standalone \
19948             `crate::dep::validate_no_self_dep` on the same \
19949             (deps, deps_dev, nome) triple",
19950        );
19951        assert!(
19952            matches!(
19953                via_method,
19954                DepError::DepIsSelf { ref nome, list }
19955                    if nome == "demo" && list == crate::render::DEP_AUTHOR_KEY_DEPS
19956            ),
19957            "expected DepIsSelf carrying (nome=\"demo\", list=\":deps\"), got {via_method:?}",
19958        );
19959    }
19960
19961    #[test]
19962    fn validate_deps_per_entry_arm_fires_before_self_edge_arm() {
19963        // Cross-arm ordering pin between the two arms of the fold:
19964        // a fixture carrying BOTH a per-entry-invalid `:versao`
19965        // (`"^bad"` — [`crate::parse_requirement`] rejects the
19966        // requirement grammar) on a non-self-dep entry AND a
19967        // would-be self-edge violation on a second entry (the
19968        // caixa's own `:nome` "demo") surfaces the per-entry
19969        // diagnostic first through the compound gate. Sanity
19970        // assertion: the second entry alone under the same parent
19971        // `:nome` trips the self-edge arm on its own via the
19972        // standalone [`crate::dep::validate_no_self_dep`], so the
19973        // per-entry-first surfacing is a real ordering property,
19974        // not a case where the self-edge arm silently accepts the
19975        // fixture. Pins the pre-fold layout wire-up's canonical
19976        // dispatch order (per-entry + within-list duplicate →
19977        // self-edge) as a property of the substrate primitive
19978        // rather than a convention of the layout call site. Sibling
19979        // in shape to
19980        // `validate_upgrade_from_per_entry_arm_fires_before_versao_arm`
19981        // (d6801df) on the M2 `:upgrade-from` compound gate's
19982        // per-arm ordering property.
19983        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19984        c.deps = vec![
19985            Dep::simple("orquestra", "^bad"),
19986            Dep::simple("demo", "^0.1"),
19987        ];
19988        let err = c.validate_deps().unwrap_err();
19989        assert!(
19990            matches!(
19991                err,
19992                DepError::VersaoInvalid { ref nome, .. } if nome == "orquestra"
19993            ),
19994            "per-entry arm must fire before self-edge arm — expected \
19995             VersaoInvalid on \"orquestra\", got {err:?}",
19996        );
19997        // Sanity: the self-referential entry alone under the same
19998        // parent `:nome` trips the self-edge arm on its own — proves
19999        // the per-entry-first surfacing above is a real ordering
20000        // property, not a case where the self-edge arm silently
20001        // accepts the fixture.
20002        let sanity = crate::dep::validate_no_self_dep(&[Dep::simple("demo", "^0.1")], &[], "demo")
20003            .unwrap_err();
20004        assert!(
20005            matches!(sanity, DepError::DepIsSelf { ref nome, .. } if nome == "demo"),
20006            "sanity: the self-referential entry alone must trip the \
20007             self-edge arm — got {sanity:?}",
20008        );
20009    }
20010
20011    #[test]
20012    fn validate_deps_accepts_clean_fixture() {
20013        // Positive control: a well-formed dep-graph (one `:deps`
20014        // entry naming a non-self DNS-1123 nome + Cargo-shaped
20015        // requirement, one `:deps-dev` entry on a distinct non-self
20016        // nome) passes the compound gate cleanly. A future
20017        // tightening of either arm's accepted set surfaces here as
20018        // a test failure first. Mirrors the peer
20019        // `validate_upgrade_from_accepts_clean_fixture` positive-
20020        // control posture on the sibling per-Caixa compound gate.
20021        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20022        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
20023        c.deps_dev = vec![Dep::simple("caixa-lint", "^0.2")];
20024        c.validate_deps()
20025            .expect("clean fixture must pass the compound `:deps` gate");
20026    }
20027
20028    #[test]
20029    fn validate_deps_accepts_empty_deps_lists() {
20030        // Positive control on the empty-list arm: a caixa without
20031        // any `:deps` or `:deps-dev` entries (the default
20032        // `Vec::new()` `#[serde(default)]` folds an omitted slot
20033        // onto) passes the compound gate cleanly regardless of
20034        // `:nome` — both the per-entry walk and the self-edge walk
20035        // are vacuous on the empty entry list. Pins the identity
20036        // element of the fold on the empty-slot side, peer with the
20037        // `validate_upgrade_from_accepts_empty_upgrade_from` empty-
20038        // arm positive control (d6801df) on the sibling
20039        // `:upgrade-from` compound gate.
20040        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20041        assert!(
20042            c.deps().is_empty(),
20043            "template caixa must carry an empty :deps — got {:?}",
20044            c.deps(),
20045        );
20046        assert!(
20047            c.deps_dev().is_empty(),
20048            "template caixa must carry an empty :deps-dev — got {:?}",
20049            c.deps_dev(),
20050        );
20051        c.validate_deps()
20052            .expect("empty :deps / :deps-dev must pass the compound gate cleanly");
20053    }
20054}