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 fn licenca(&self) -> Option<&str> {
513        self.licenca.as_deref()
514    }
515
516    /// Substrate-canonical per-`Caixa` `:repositorio` git-repo-URL scalar
517    /// accessor every consumer of the top-level manifest's homepage /
518    /// source-of-truth axis keys off — returns the author-declared
519    /// `:repositorio` byte-string verbatim as an `Option<&str>`, borrowed
520    /// from the typed slot's own `Option<String>` storage. `None` when
521    /// the slot is absent (the canonical "omit to defer to the renderer's
522    /// per-target placeholder" shape — [`caixa-helm`]'s `ChartYaml.home`
523    /// carries the `Option<String>` through verbatim so an author-omitted
524    /// `:repositorio` renders a `Chart.yaml` without a `home:` field
525    /// (`skip_serializing_if = "Option::is_none"`), while [`caixa-flux`]'s
526    /// `ClusterBundleOpts::for_caixa` folds the omitted slot through a
527    /// `format!("https://github.com/{DEFAULT_PLEME_GIT_ORG}/{nome}")`
528    /// fallback derived from `caixa.nome`).
529    ///
530    /// The `:repositorio` slot carries the universal-axis git-repo-URL
531    /// homepage identifier every kind of caixa emits under (CAIXA-SDLC
532    /// §I — the author-facing surface every `defcaixa` form supplies) —
533    /// the typed slot's `Option<String>` accept-set (empty-string
534    /// rejected through [`ManifestError::RepositorioEmpty`], git-repo-URL-
535    /// shape-invalid rejected through [`ManifestError::RepositorioInvalid`]
536    /// past the shared [`crate::render::is_git_repo_url`] predicate the
537    /// peer per-`:deps :fonte :repo` axis also routes through) maps onto
538    /// four load-bearing downstream consumers:
539    ///
540    ///   - [`Self::validate_repositorio`]'s empty-arm + shape-predicate
541    ///     gate binding at caixa-core/src/manifest.rs:1456 — the
542    ///     universal-axis identity gate wired at caixa-build time.
543    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.home` fold at
544    ///     caixa-helm/src/lib.rs:840 — the rendered `lareira-<nome>`
545    ///     Helm chart's `Chart.yaml` `home:` field, which every registry
546    ///     that ingests the chart (ArtifactHub, chartmuseum,
547    ///     `helm search repo`) surfaces as the chart's canonical source-
548    ///     of-truth link.
549    ///   - [`caixa-helm`]'s `build_readme` `## Source` fold at
550    ///     caixa-helm/src/lib.rs:957 — the rendered `lareira-<nome>`
551    ///     chart's `README.md` header link back to the source repo,
552    ///     which every author who inspects the rendered chart bundle
553    ///     lands at.
554    ///   - [`caixa-flux`]'s `ClusterBundleOpts::for_caixa`
555    ///     `GitRepository.spec.url` fold at caixa-flux/src/lib.rs:2006 —
556    ///     the rendered `GitRepository` CR's `spec.url` field, which
557    ///     FluxCD's `source-controller` polls to reconcile the caixa's
558    ///     manifest bundle from git.
559    ///
560    /// Prior to this lift the `.repositorio` field was accessed inline
561    /// at four production sites — [`Self::validate_repositorio`]'s
562    /// `self.repositorio.as_deref()` empty-and-shape gate binding, the
563    /// caixa-helm `build_chart_yaml` `caixa.repositorio.clone()`
564    /// `Chart.yaml` `home:` field fold, the caixa-helm `build_readme`
565    /// `caixa.repositorio.clone().unwrap_or_else(|| caixa.nome.clone())`
566    /// `README.md` `## Source` fold, and the caixa-flux
567    /// `ClusterBundleOpts::for_caixa`
568    /// `caixa.repositorio.clone().unwrap_or_else(|| format!(...))`
569    /// `GitRepository.spec.url` fold — four open-coded field-accesses
570    /// that expressed no compile-time link back to the typed slot. A
571    /// future extension of the `:repositorio` axis to a richer author
572    /// surface — a per-`:repositorio` structured
573    /// [`crate::render::GitRepoUrl`]-shaped scheme+host+path parse
574    /// (the future tightening [`Self::validate_repositorio`]'s
575    /// docstring anticipates alongside the peer per-`:deps :fonte
576    /// :repo` axis), a per-cluster repo-mirror overlay the M4 CR
577    /// materializer resolves per-CR (the "cluster policy rewrites
578    /// `github:pleme-io/...` to `git.internal/mirror/pleme-io/...`"
579    /// arm the private-registry story acknowledges), a promotion of
580    /// the plain `Option<String>` byte-string to a richer
581    /// `RepoUrl` enum discriminated on scheme — would have had to be
582    /// threaded through all four open-coded copies in lockstep or the
583    /// validate gate and the three emit paths would silently disagree
584    /// on which URL a given [`Caixa`] resolves to (an author's
585    /// `:repositorio "github:pleme-io/checkout"` would satisfy validate
586    /// while one of the emit paths silently rendered a stale URL, or
587    /// vice versa). Lifting the resolution to a typed method on the
588    /// substrate primitive means every downstream consumer of the
589    /// caixa's per-`Caixa` repo-URL surface reaches for exactly one
590    /// typed dispatch — the resolver's accept-set migrates as a unit on
591    /// any future axis addition.
592    ///
593    /// Second outer top-level [`Caixa`] `Option<&str>`-return scalar
594    /// accessor — sibling of [`Self::licenca`] (6d5bc28), the accessor
595    /// that opened the "outer [`Caixa`] `Option<&str>` scalar"
596    /// projection pattern this lift folds on. Same "one typed dispatch
597    /// on the substrate primitive, thin projections at each consumer"
598    /// discipline the peer per-`:placement`
599    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
600    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
601    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
602    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
603    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
604    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
605    /// typed-slot atom axes, extended here to the second outer top-level
606    /// `Caixa` universal-axis surface. Named `repositorio()` to match
607    /// the storage field's name; the accessor's identity maps onto the
608    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
609    /// carries.
610    #[must_use]
611    pub fn repositorio(&self) -> Option<&str> {
612        self.repositorio.as_deref()
613    }
614
615    /// Substrate-canonical per-`Caixa` **resolved-git-repo-URL** composer —
616    /// returns the caixa's canonical git-source-of-truth URL as an owned
617    /// [`String`], author-declared `:repositorio` byte-string verbatim on
618    /// the `Some` arm and the substrate's canonical pleme-org github URL
619    /// fallback ([`crate::DEFAULT_PLEME_GIT_ORG`] and [`Self::nome`]
620    /// interpolated into `https://github.com/<org>/<nome>`) on the
621    /// `None` arm. Every substrate-side consumer that resolves
622    /// "which git URL does this caixa's source live at?" reaches for
623    /// exactly one typed dispatch on the substrate primitive — the raw
624    /// `caixa.repositorio().map(str::to_owned).unwrap_or_else(|| format!(
625    /// "https://github.com/{org}/{nome}", org = DEFAULT_PLEME_GIT_ORG,
626    /// nome = caixa.nome()))` open-coded composition every prior caller
627    /// re-derived collapses onto one canonical arm.
628    ///
629    /// Distinct from [`Self::repositorio`] (`Option<&str>`, exposes the
630    /// author-omitted / author-declared partition to the caller) — this
631    /// accessor is the **resolved** URL surface, folding the fallback in
632    /// at the substrate-primitive boundary. Every consumer that keys off
633    /// the `Option::is_none()` discriminator (a [`Chart.yaml`] `home:`
634    /// field emit that must omit the field entirely on an author-omitted
635    /// `:repositorio`, per the [`Self::repositorio`] docstring's
636    /// documented four-consumer list) reaches through the raw
637    /// [`Self::repositorio`] `Option<&str>` accessor by construction — the
638    /// resolved-URL composer sits alongside it as the second projection
639    /// on the same underlying `:repositorio` slot rather than replacing
640    /// the raw accessor.
641    ///
642    /// The fallback branch is the exact byte-image of the prior inline
643    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url` composer at
644    /// caixa-flux/src/lib.rs:2080 — pinned by the sibling caixa-flux
645    /// byte-parity test
646    /// `cluster_bundle_opts_for_caixa_git_url_routes_through_canonical_git_url_accessor`
647    /// against a future implementation of this method that reordered the
648    /// `format!` template arguments, migrated the `<org>` segment to a
649    /// different constant (the [`crate::DEFAULT_PLEME_GIT_ORG`] axis a
650    /// future substrate-side git-org migration may split off), or
651    /// silently absorbed the empty-string arm (a hypothetical
652    /// `Some("") → fallback` collapse the raw [`Self::repositorio`]
653    /// accessor's docstring explicitly rejects on the sibling raw
654    /// accessor).
655    ///
656    /// Peer of the sibling per-`&Caixa`-axis composed helpers
657    /// [`caixa-flux::cluster_bundle_for_caixa`] (06d52d7) on the sibling
658    /// substrate-side renderer surface — same "close the composed
659    /// substrate-primitive at one canonical arm on the single-`&Caixa`
660    /// dispatch, converge every prior open-coded caller onto the arm"
661    /// discipline extended onto the resolved-git-URL projection of the
662    /// per-`Caixa` `:repositorio` axis. Owns per-call [`String`]
663    /// allocation on both arms (the `Some` arm's `str::to_owned` and the
664    /// `None` arm's `format!`) — the by-value return matches every
665    /// downstream consumer's field-fill shape (the caixa-flux
666    /// `ClusterBundleOpts::git_url: String` field, every future
667    /// `Chart.yaml` `home:` fold's `Option<String>` field-fill on the
668    /// `Some` arm).
669    #[must_use]
670    pub fn canonical_git_url(&self) -> String {
671        self.repositorio().map_or_else(
672            || {
673                format!(
674                    "https://github.com/{org}/{nome}",
675                    org = crate::DEFAULT_PLEME_GIT_ORG,
676                    nome = self.nome(),
677                )
678            },
679            str::to_owned,
680        )
681    }
682
683    /// Substrate-canonical per-`Caixa` **resolved-publish-tag** composer —
684    /// returns the caixa's canonical Zig-style git-publish-tag as an owned
685    /// [`String`], derived by concatenating
686    /// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] with the typed
687    /// [`Self::versao`] byte-string on a single `format!` template.
688    /// Every substrate-side consumer that resolves "which git tag does this
689    /// caixa publish under?" reaches for exactly one typed dispatch on the
690    /// substrate primitive — the raw `format!("{prefix}{versao}", prefix =
691    /// caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao = caixa.versao())`
692    /// open-coded composition every prior caller re-derived collapses onto
693    /// one canonical arm.
694    ///
695    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
696    /// git-URL composer on the paired per-`Caixa` git-remote axis — same
697    /// "close the composed substrate-primitive at one canonical arm on the
698    /// single-`&Caixa` dispatch, converge every prior open-coded caller
699    /// onto the arm" discipline extended from the resolved-URL projection
700    /// of the per-`Caixa` `:repositorio` axis onto the resolved-tag
701    /// projection of the per-`Caixa` `:versao` axis. The two accessors
702    /// jointly close the pair of scalars every `FluxCD` `GitRepository` CR
703    /// keys off (`spec.url` via [`Self::canonical_git_url`],
704    /// `spec.ref.tag` via [`Self::publish_tag`]) at the substrate primitive
705    /// — a downstream consumer that reaches through both accessors reads
706    /// the complete published-git-identity of a caixa through two typed
707    /// dispatches, not four open-coded field accesses.
708    ///
709    /// The reader-side (`caixa-flux::cluster_bundle` /
710    /// `ClusterBundleOpts::for_caixa`'s `git_ref` field, every future
711    /// per-cluster snapshot bundle emitter, the future M4
712    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's tag-carrier
713    /// slot on the tatara `Process` intent) always resolves the tag under
714    /// the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] prefix — this
715    /// method encodes that reader-side convention. The writer-side
716    /// (`caixa-feira`'s `feira publish` `--prefix` clap flag) allows the
717    /// operator to override the prefix at publish time; the two surfaces
718    /// intentionally sit on the "canonical default + operator override"
719    /// pair the sibling [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] constant's
720    /// own docstring documents — a `feira publish --prefix release/`
721    /// override is the operator's explicit opt-out from the substrate
722    /// default, not a supported drift axis.
723    ///
724    /// The composition body is the exact byte-image of the prior inline
725    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_ref` composer at
726    /// caixa-flux/src/lib.rs:2105 — pinned by the sibling caixa-flux
727    /// byte-parity test
728    /// `cluster_bundle_opts_for_caixa_git_ref_routes_through_publish_tag_accessor`
729    /// against a future implementation of this method that reordered the
730    /// `format!` template arguments, migrated the `<prefix>` segment to a
731    /// different constant (the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] axis
732    /// a future Zig-style-tag rebrand may split off — the constant's own
733    /// docstring anticipates a substrate-side move to `release/<versao>`
734    /// or bare `<versao>` shapes once a sibling forge convention adopts a
735    /// slash-namespaced or bare-scalar form), interposed a canonicalization
736    /// pass on the `:versao` axis (a SemVer-2 build-metadata strip an OCI-
737    /// tag normalizer might apply once the M4 registry-alignment slot
738    /// lands), or silently absorbed an empty `:versao` arm (which cannot
739    /// occur past the [`Self::validate_versao`] gate but which a
740    /// hypothetical bypass on the accessor path must not silently paper
741    /// over).
742    ///
743    /// Owns per-call [`String`] allocation via the single `format!`
744    /// invocation — the by-value return matches every downstream
745    /// consumer's field-fill shape (the caixa-flux `GitRefSpec::Tag(String)`
746    /// variant's owned payload, every future `intent.aplicacao.tag: String`
747    /// field-fill on the M4 CR materializer's tag-carrier slot).
748    #[must_use]
749    pub fn publish_tag(&self) -> String {
750        format!(
751            "{prefix}{versao}",
752            prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
753            versao = self.versao(),
754        )
755    }
756
757    /// Substrate-canonical per-`Caixa` **resolved-Helm-chart-name** composer
758    /// — returns the caixa's canonical `lareira-<nome>` per-Servico Helm
759    /// chart identity as an owned [`String`], derived by dispatching through
760    /// the substrate-canonical [`crate::lareira_chart_name`] helper against
761    /// the typed [`Self::nome`] byte-string. Every substrate-side consumer
762    /// that resolves "which Helm chart identity does this caixa render
763    /// under?" reaches for exactly one typed dispatch on the substrate
764    /// primitive — the raw `caixa_core::lareira_chart_name(caixa.nome())`
765    /// two-step compose every prior caller re-derived collapses onto one
766    /// canonical arm on the single-`&Caixa` dispatch.
767    ///
768    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
769    /// git-URL composer + [`Self::publish_tag`] (07e05b8) resolved-publish-
770    /// tag composer on the paired per-`Caixa` published-artifact-identity
771    /// axis — same "close the composed substrate-primitive at one canonical
772    /// arm on the single-`&Caixa` dispatch, converge every prior open-coded
773    /// caller onto the arm" discipline extended from the resolved-URL /
774    /// resolved-tag projections of the `:repositorio` / `:versao` axes onto
775    /// the resolved-chart-name projection of the `:nome` axis. The three
776    /// accessors jointly close the triple of scalars every per-Servico
777    /// deploy artifact keys off (git source URL via
778    /// [`Self::canonical_git_url`], git source tag via
779    /// [`Self::publish_tag`], per-Servico Helm chart identity via
780    /// [`Self::lareira_chart_name`]) at the substrate primitive — a
781    /// downstream consumer that reaches through all three reads the
782    /// complete deploy-artifact identity of a caixa through three typed
783    /// dispatches, not six open-coded compositions across three renderer
784    /// crates.
785    ///
786    /// The reader-side (three production sites at the time of the lift —
787    /// [`caixa-helm::render_chart_for_servico_with`]'s `ChartDir.name`
788    /// composer at caixa-helm/src/lib.rs:778, the peer
789    /// [`caixa-flux::cluster_bundle`]'s per-CR `chart_name` binding at
790    /// caixa-flux/src/lib.rs:2219, and
791    /// [`caixa-tatara::process_for_aplicacao`]'s `release_name`
792    /// composer at caixa-tatara/src/lib.rs:227, plus every future
793    /// per-Servico OCI publish emitter the CAIXA-SDLC §II
794    /// `caixa-publish.yml` reusable workflow's `skopeo push` step keys
795    /// off, the future per-cluster snapshot bundle emitter, the future
796    /// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
797    /// per-member chart-carrier slot on the tatara `Process` intent) —
798    /// always resolves the chart name under the canonical
799    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] prefix; this method encodes
800    /// that reader-side convention. The joint-length invariant the peer
801    /// [`Self::validate_nome_chart_name_budget`] gate enforces at
802    /// caixa-build time (author-declared `:nome` + fixed prefix ≤
803    /// [`crate::DNS_1123_LABEL_MAX_LEN`]) is verified on the input to
804    /// this composer by construction, so the produced `lareira-<nome>`
805    /// string is a valid Helm chart-name segment on every accept-set
806    /// input.
807    ///
808    /// The composition body is the exact byte-image of the prior inline
809    /// `caixa_core::lareira_chart_name(caixa.nome())` two-step form every
810    /// prior caller re-derived — pinned by the sibling caixa-helm /
811    /// caixa-flux / caixa-tatara byte-parity tests
812    /// `<crate>_lareira_chart_name_routes_through_caixa_accessor` against
813    /// a future implementation of this method that reordered the
814    /// composition arguments, migrated the `<prefix>` segment to a
815    /// different constant (the [`crate::LAREIRA_CHART_NAME_PREFIX`] axis a
816    /// future substrate-side chart-family rebrand may split off — the
817    /// constant's own docstring anticipates a substrate-side move once
818    /// the `lareira-` scoping intent outlives the family it names),
819    /// interposed a canonicalization pass on the `:nome` axis (a per-
820    /// registry namespace-qualification an M4 CR materializer might apply
821    /// per-CR — the "`pleme-io/checkout` vs `partner-org/checkout`
822    /// collision" arm the multi-tenant-registry story acknowledges), or
823    /// silently absorbed an empty `:nome` arm (which cannot occur past
824    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
825    /// on the accessor path must not silently paper over).
826    ///
827    /// Owns per-call [`String`] allocation via the single
828    /// [`crate::lareira_chart_name`] `format!` invocation — the by-value
829    /// return matches every downstream consumer's field-fill shape (the
830    /// caixa-helm `ChartDir.name: String` field, the caixa-flux per-CR
831    /// `chart_name: String` binding, the caixa-tatara
832    /// `AplicacaoIntent.release_name: Option<String>` field-fill on the
833    /// `Some` arm).
834    #[must_use]
835    pub fn lareira_chart_name(&self) -> String {
836        crate::lareira_chart_name(self.nome())
837    }
838
839    /// Substrate-canonical per-`Caixa` **resolved-OCI-chart-ref** composer
840    /// — returns the caixa's canonical `oci://<registry>/lareira-<nome>`
841    /// per-Servico Helm chart OCI artifact reference as an owned
842    /// [`String`], derived by dispatching through the substrate-canonical
843    /// [`crate::oci_chart_ref`] helper (which itself composes
844    /// [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied `registry` +
845    /// [`crate::lareira_chart_name`]-of-[`Self::nome`]) against the
846    /// caller-supplied `registry` and the typed [`Self::nome`] byte-string.
847    /// Every substrate-side consumer that resolves "which OCI chart
848    /// artifact does this caixa publish under, in this registry?" reaches
849    /// for exactly one typed dispatch on the substrate primitive — the raw
850    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step compose
851    /// every prior caller re-derived collapses onto one canonical arm on
852    /// the single-`(&Caixa, &str)` dispatch.
853    ///
854    /// Fourth member of the paired per-`Caixa` published-artifact-identity
855    /// axis alongside [`Self::canonical_git_url`] (124f864) /
856    /// [`Self::publish_tag`] (07e05b8) / [`Self::lareira_chart_name`]
857    /// (a8f0bee) — same "close the composed substrate-primitive at one
858    /// canonical arm on the single-`&Caixa` dispatch, converge every
859    /// prior open-coded caller onto the arm" discipline extended from the
860    /// resolved-URL / resolved-tag / resolved-chart-name projections of
861    /// the `:repositorio` / `:versao` / `:nome` axes onto the resolved-
862    /// OCI-ref projection over the paired `(registry, :nome)` inputs. The
863    /// four accessors jointly close the per-`Caixa` published-artifact-
864    /// identity surface every downstream consumer of a caixa's published
865    /// deploy artifacts keys off (git source URL via
866    /// [`Self::canonical_git_url`], git source tag via
867    /// [`Self::publish_tag`], per-Servico Helm chart identity via
868    /// [`Self::lareira_chart_name`], per-registry OCI chart artifact
869    /// reference via [`Self::oci_chart_ref`]) at the substrate primitive
870    /// — a downstream consumer that reaches through all four reads the
871    /// complete deploy-artifact identity of a caixa through four typed
872    /// dispatches, not eight open-coded compositions across four renderer
873    /// crates. The unique-signature dispatch (`(&Caixa, &str)` on this
874    /// method vs. `&Caixa` on the sibling three) reflects the extra input
875    /// axis this composer folds in: unlike the git-URL / git-tag / chart-
876    /// name axes (each derived purely from a `&Caixa`), the OCI-ref axis
877    /// pairs the caixa's per-`:nome` chart identity with the caller-
878    /// supplied per-registry authority segment, so the accessor threads
879    /// the registry byte-string through as a positional `&str`.
880    ///
881    /// The reader-side (one production site at the time of the lift —
882    /// [`caixa-tatara::process_for_aplicacao`]'s `derive_chart_ref` helper
883    /// at caixa-tatara/src/lib.rs:333 that composes the emitted
884    /// `AplicacaoIntent.chart_ref` scalar the tatara-reconciler feeds into
885    /// `helm install`, plus every future per-Servico OCI publish emitter
886    /// the CAIXA-SDLC §II `caixa-publish.yml` reusable workflow's
887    /// `skopeo push` step keys off, the future per-cluster snapshot bundle
888    /// emitter's per-CR `oci://…` field-fill on the M4 registry-alignment
889    /// slot, the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
890    /// materializer's per-member `chart_ref` slot on the tatara `Process`
891    /// intent, the `FluxCD` `HelmRelease` `spec.chart.spec.chart` field-fill
892    /// on the OCI-source path an M4 per-cluster registry-rewrite overlay
893    /// applies per-CR) — always resolves the OCI ref under the canonical
894    /// [`crate::OCI_SCHEME_PREFIX`] scheme prefix + the canonical
895    /// [`Self::lareira_chart_name`] chart-name segment; this method
896    /// encodes that reader-side convention.
897    ///
898    /// The composition body is the exact byte-image of the prior inline
899    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step form
900    /// every prior caller re-derived — pinned by the sibling caixa-tatara
901    /// byte-parity test
902    /// `derive_chart_ref_routes_through_caixa_oci_chart_ref_accessor`
903    /// against a future implementation of this method that reordered the
904    /// composition arguments, migrated the `<scheme>` segment to a
905    /// different constant (the [`crate::OCI_SCHEME_PREFIX`] axis a future
906    /// substrate-side registry-protocol rebrand may split off — the
907    /// constant's own docstring anticipates a substrate-side move once
908    /// Helm 3 / `FluxCD` introduce a successor scheme past `oci://`),
909    /// migrated the `<chart>` segment off the paired
910    /// [`crate::lareira_chart_name`] composer (a per-registry
911    /// namespace-qualification an M4 CR materializer might apply per-CR),
912    /// interposed a canonicalization pass on the `registry` axis (an OCI-
913    /// authority normalization once the M4 registry-alignment slot lands),
914    /// or silently absorbed an empty `:nome` arm (which cannot occur past
915    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
916    /// on the accessor path must not silently paper over).
917    ///
918    /// Owns per-call [`String`] allocation via the single
919    /// [`crate::oci_chart_ref`] `format!` invocation — the by-value return
920    /// matches every downstream consumer's field-fill shape (the caixa-
921    /// tatara `AplicacaoIntent.chart_ref: String` field-fill, every
922    /// future `intent.aplicacao.chart_ref: String` field-fill on the M4
923    /// CR materializer's chart-ref-carrier slot, every future
924    /// `HelmRelease.spec.chart.spec.chart: String` field-fill on the OCI-
925    /// source path).
926    #[must_use]
927    pub fn oci_chart_ref(&self, registry: &str) -> String {
928        crate::oci_chart_ref(registry, self.nome())
929    }
930
931    /// Substrate-canonical per-`Caixa` `:descricao` free-form-prose
932    /// chart-description scalar accessor every consumer of the top-level
933    /// manifest's Chart.yaml `description:` axis keys off — returns the
934    /// author-declared `:descricao` byte-string verbatim as an
935    /// `Option<&str>`, borrowed from the typed slot's own
936    /// `Option<String>` storage. `None` when the slot is absent (the
937    /// canonical "omit to defer to the per-renderer `caixa.nome`-derived
938    /// fallback" shape — [`caixa-helm`]'s `build_chart_yaml` folds the
939    /// omitted slot through a `format!("Generated chart for caixa Servico
940    /// {}", caixa.nome)` fallback, [`caixa-helm`]'s `build_readme` folds
941    /// it through a `format!("caixa Servico {}", caixa.nome)` fallback,
942    /// and [`caixa-feira`]'s `render_flake` folds it through a
943    /// `format!("caixa {}", c.nome)` `flake.nix` `description = ""`
944    /// fallback — each derived from `caixa.nome` on the null-carrier arm).
945    ///
946    /// The `:descricao` slot carries the universal-axis free-form-prose
947    /// chart-description identifier every kind of caixa emits under
948    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa` form
949    /// supplies) — the typed slot's `Option<String>` accept-set
950    /// (empty-string rejected through [`ManifestError::DescricaoEmpty`],
951    /// chart-description-shape-invalid rejected through
952    /// [`ManifestError::DescricaoInvalid`] past the shared
953    /// [`crate::render::is_chart_description_shape`] predicate the peer
954    /// per-`Caixa` `:descricao` axis also routes through) maps onto four
955    /// load-bearing downstream consumers:
956    ///
957    ///   - [`Self::validate_descricao`]'s empty-arm + shape-predicate
958    ///     gate binding — the universal-axis identity gate wired at
959    ///     caixa-build time.
960    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.description`
961    ///     `Chart.yaml` field fold — the rendered `lareira-<nome>` Helm
962    ///     chart's `Chart.yaml` `description:` field, which
963    ///     `apiVersion: v2` charts require non-empty (`helm lint` fires
964    ///     `WARNING [chart.metadata.description]: description is required`
965    ///     when absent) and which every registry that ingests the chart
966    ///     (ArtifactHub, chartmuseum, `helm search repo`) surfaces as the
967    ///     chart's canonical one-line prose descriptor.
968    ///   - [`caixa-helm`]'s `build_readme` chart-`README.md` header fold
969    ///     — the rendered `lareira-<nome>` chart's `README.md` prose
970    ///     header directly beneath the `# <chart-name>` title, which
971    ///     every author who inspects the rendered chart bundle lands at.
972    ///   - [`caixa-feira`]'s `render_flake` `flake.nix` `description = ""`
973    ///     top-level fold — the emitted `flake.nix`'s `description`
974    ///     field, which every Nix consumer (`nix flake show`,
975    ///     `nix flake metadata`, downstream flake-registry ingestors)
976    ///     surfaces as the flake's canonical descriptor.
977    ///
978    /// Prior to this lift the `.descricao` field was accessed inline at
979    /// four production sites — [`Self::validate_descricao`]'s
980    /// `self.descricao.as_deref()` empty-and-shape gate binding, the
981    /// caixa-helm `build_chart_yaml`
982    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
983    /// `Chart.yaml` `description:` fold, the caixa-helm `build_readme`
984    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
985    /// `README.md` header fold, and the caixa-feira `render_flake`
986    /// `c.descricao.clone().unwrap_or_else(|| format!(...))` `flake.nix`
987    /// `description = ""` fold — four open-coded field-accesses that
988    /// expressed no compile-time link back to the typed slot. A future
989    /// extension of the `:descricao` axis to a richer author surface —
990    /// a per-`:descricao` locale-tagged multi-language descriptor map
991    /// (the "one caixa, N language-tagged prose descriptions" arm
992    /// author-tooling internationalization anticipates), a
993    /// per-registry-target length-and-shape overlay the M4 CR
994    /// materializer resolves per-CR (the "ArtifactHub caps description
995    /// at 512 bytes but the internal registry caps at 256" arm), a
996    /// promotion of the plain `Option<String>` byte-string to a richer
997    /// `ChartDescription` newtype guaranteeing the
998    /// `is_chart_description_shape` predicate at the type level — would
999    /// have had to be threaded through all four open-coded copies in
1000    /// lockstep or the validate gate and the three emit paths would
1001    /// silently disagree on which prose string a given [`Caixa`]
1002    /// resolves to (an author's
1003    /// `:descricao "Checkout flow orchestration."` would satisfy
1004    /// validate while one of the emit paths silently rendered a stale
1005    /// `caixa.nome`-derived fallback, or vice versa). Lifting the
1006    /// resolution to a typed method on the substrate primitive means
1007    /// every downstream consumer of the caixa's per-`Caixa`
1008    /// chart-description surface reaches for exactly one typed dispatch
1009    /// — the resolver's accept-set migrates as a unit on any future
1010    /// axis addition.
1011    ///
1012    /// Third outer top-level [`Caixa`] `Option<&str>`-return scalar
1013    /// accessor — sibling of [`Self::licenca`] (6d5bc28) and
1014    /// [`Self::repositorio`] (cc7332d), the accessors that opened the
1015    /// "outer [`Caixa`] `Option<&str>` scalar" projection pattern this
1016    /// lift folds on. Same "one typed dispatch on the substrate
1017    /// primitive, thin projections at each consumer" discipline the
1018    /// peer per-`:placement`
1019    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1020    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1021    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1022    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1023    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1024    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1025    /// typed-slot atom axes, extended here to the third outer top-level
1026    /// `Caixa` universal-axis surface. Named `descricao()` to match the
1027    /// storage field's name; the accessor's identity maps onto the
1028    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1029    /// carries. The one remaining universal `Option<String>` slot
1030    /// (`:edicao`) folds on this pattern next.
1031    #[must_use]
1032    pub fn descricao(&self) -> Option<&str> {
1033        self.descricao.as_deref()
1034    }
1035
1036    /// Substrate-canonical per-`Caixa` `:edicao` language-edition scalar
1037    /// accessor every consumer of the top-level manifest's tatara-lisp
1038    /// edition-selector axis keys off — returns the author-declared
1039    /// `:edicao` byte-string verbatim as an `Option<&str>`, borrowed from
1040    /// the typed slot's own `Option<String>` storage. `None` when the
1041    /// slot is absent (the canonical "omit the slot to defer to the
1042    /// substrate's default edition" shape every existing
1043    /// [`caixa-resolver`] integration test fixture carries via
1044    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`;
1045    /// the peer [`Self::validate_edicao`] gate is a no-op on the omitted
1046    /// arm by construction, so an author-omitted `:edicao` round-trips
1047    /// to a build without triggering the year-shape predicate).
1048    ///
1049    /// The `:edicao` slot carries the universal-axis 4-digit-ASCII-
1050    /// decimal-year language-edition identifier every kind of caixa
1051    /// emits under (CAIXA-SDLC §I — the author-facing surface every
1052    /// `defcaixa` form supplies) — the typed slot's `Option<String>`
1053    /// accept-set (empty-string rejected through
1054    /// [`ManifestError::EdicaoEmpty`], year-shape-invalid rejected
1055    /// through [`ManifestError::EdicaoInvalid`] past the 4-digit-ASCII-
1056    /// decimal-year predicate [`Self::validate_edicao`] enforces) maps
1057    /// onto one load-bearing downstream consumer today
1058    /// ([`Self::validate_edicao`]'s empty-arm + year-shape-predicate
1059    /// gate binding at caixa-core/src/manifest.rs:1959) plus every
1060    /// future edition-aware substrate consumer the CAIXA-SDLC §I
1061    /// roadmap anticipates (the tatara-lisp compiler's macro-surface
1062    /// selector every edition-aware build step keys off, the future
1063    /// per-edition compatibility-flag overlay the M4 CR materializer
1064    /// resolves per-CR, the peer [`Caixa::template`] canonical
1065    /// `:edicao "2026"` scaffold every `feira init` emits verbatim,
1066    /// and the renderer-side fixtures at `caixa-helm/src/lib.rs:978` /
1067    /// `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208` that
1068    /// carry `edicao: Some("2026".into())` by construction).
1069    ///
1070    /// Prior to this lift the `.edicao` field was accessed inline at
1071    /// one production site — [`Self::validate_edicao`]'s
1072    /// `self.edicao.as_deref()` empty-and-shape gate binding — one
1073    /// open-coded field-access that expressed no compile-time link
1074    /// back to the typed slot. A future extension of the `:edicao`
1075    /// axis to a richer author surface — a per-`:edicao` known-
1076    /// edition allowlist (the future tightening
1077    /// [`Self::validate_edicao`]'s docstring acknowledges past the
1078    /// structural year-shape floor, rejecting year-shaped values that
1079    /// don't name a tatara-lisp edition the substrate actually
1080    /// understands — `"1999"` is year-shaped but no `1999` edition
1081    /// exists), a per-edition compatibility-flag overlay the M4 CR
1082    /// materializer resolves per-CR (the "edition `"2026"` enables
1083    /// macro-surface features the sibling `"2018"` gates behind a
1084    /// feature flag" arm the edition-selector story anticipates), a
1085    /// promotion of the plain `Option<String>` byte-string to a
1086    /// richer `CaixaEdition` enum discriminated on year once a sibling
1087    /// edition to `"2026"` lands — would have had to be threaded
1088    /// through the open-coded copy in lockstep with every future
1089    /// edition-aware consumer, or the validate gate and the future
1090    /// edition-aware consumer path would silently disagree on which
1091    /// edition a given [`Caixa`] resolves to (an author's
1092    /// `:edicao "2026"` would satisfy validate while a future
1093    /// edition-aware consumer silently defaulted to a stale edition,
1094    /// or vice versa). Lifting the resolution to a typed method on
1095    /// the substrate primitive means every downstream consumer of the
1096    /// caixa's per-`Caixa` edition surface reaches for exactly one
1097    /// typed dispatch — the resolver's accept-set migrates as a unit
1098    /// on any future axis addition.
1099    ///
1100    /// Fourth and final outer top-level [`Caixa`] `Option<&str>`-return
1101    /// scalar accessor — sibling of [`Self::licenca`] (6d5bc28),
1102    /// [`Self::repositorio`] (cc7332d), and [`Self::descricao`]
1103    /// (3f16e2f), the accessors that opened the "outer [`Caixa`]
1104    /// `Option<&str>` scalar" projection pattern this lift folds on.
1105    /// Same "one typed dispatch on the substrate primitive, thin
1106    /// projections at each consumer" discipline the peer per-`:placement`
1107    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1108    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1109    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1110    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1111    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1112    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1113    /// typed-slot atom axes, extended here to close the outer top-level
1114    /// `Caixa` universal-axis surface's last unlifted `Option<String>`
1115    /// slot. Named `edicao()` to match the storage field's name; the
1116    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1117    /// vocabulary the slot's docstring already carries.
1118    #[must_use]
1119    pub fn edicao(&self) -> Option<&str> {
1120        self.edicao.as_deref()
1121    }
1122
1123    /// Substrate-canonical per-`Caixa` `:nome` universal-axis DNS-1123-
1124    /// label caixa-identity scalar accessor every consumer of the top-
1125    /// level manifest's identity axis keys off — returns the author-
1126    /// declared `:nome` byte-string verbatim as an `&str`, borrowed from
1127    /// the typed slot's own `String` storage. Non-optional (`:nome` is
1128    /// a required-axis scalar every `defcaixa` form must supply; the
1129    /// [`Self::from_lisp`] derive rejects an omitted / non-string
1130    /// `:nome` at parse time, so a `Caixa` past parse definitionally
1131    /// carries a non-`None` `:nome`).
1132    ///
1133    /// The `:nome` slot carries the universal-axis DNS-1123-label
1134    /// caixa-identity every kind of caixa emits under (CAIXA-SDLC §I —
1135    /// the primary identity axis every `defcaixa` form supplies
1136    /// alongside `:versao` / `:kind`; the substrate-wide identity every
1137    /// other typed surface that names a caixa reaches through — `:deps`
1138    /// entries, `:membros` entries, `:children` entries, the
1139    /// `lareira-<nome>` Helm chart name every per-Servico renderer
1140    /// derives, the `pleme-program-<nome>` label every per-Aplicacao
1141    /// renderer emits) — the typed slot's `String` accept-set (empty
1142    /// rejected through [`ManifestError::NomeEmpty`], DNS-1123-shape-
1143    /// invalid rejected through [`ManifestError::NomeInvalid`] past
1144    /// the shared [`crate::render::require_valid_dns_1123_label`] gate
1145    /// the peer name axes each land on, joint-length-with-`lareira-`-
1146    /// prefix rejected through
1147    /// [`ManifestError::NomeChartNameBudgetExceeded`] past
1148    /// [`crate::render::is_lareira_chart_name_shape`]) maps onto every
1149    /// load-bearing downstream consumer the substrate carries — the
1150    /// two universal-axis validate gates at caixa-build time
1151    /// ([`Self::validate_nome`] + [`Self::validate_nome_chart_name_budget`]),
1152    /// [`crate::lareira_chart_name`]'s `lareira-<nome>` Helm chart-name
1153    /// derivation every per-Servico renderer keys off, the caixa-helm
1154    /// `Chart.yaml`'s `name:` axis, caixa-flux's `programs.yaml` entry
1155    /// `name:` axis, caixa-mesh's Cilium `CiliumNetworkPolicy` /
1156    /// `HTTPRoute` per-Aplicacao name axes at
1157    /// caixa-mesh/src/lib.rs:{2650, 2797, 2919, 2925},
1158    /// [`crate::pleme_program_selector`] /
1159    /// [`crate::pleme_program_in_aplicacao_selector`] label-selector
1160    /// derivations, and every future substrate renderer that emits an
1161    /// artifact keyed by the caixa's identity.
1162    ///
1163    /// Prior to this lift the `.nome` field was accessed inline at a
1164    /// dozen production sites across `caixa-core` (the two universal-
1165    /// axis validate gates + [`Dep::validate`]-adjacent duplicate
1166    /// tracking), `caixa-helm` (the `lareira_chart_name` fold, the
1167    /// `ChartYaml.name` / `ChartYaml.description` / `Chart.yaml`
1168    /// `keywords` fallback), `caixa-flux` (the `programs.yaml`
1169    /// entry `name:` fold, the `flux_kustomization_source_subtree`
1170    /// per-cluster subpath derivation), and `caixa-mesh` (the
1171    /// `pleme_program_in_aplicacao_selector` label-selector fold, the
1172    /// `cilium_network_policy_name` / `gateway_api_http_route_name`
1173    /// per-CR name derivations, the `LABEL_APLICACAO` labels-map
1174    /// insert) — a dozen open-coded field-accesses that expressed no
1175    /// compile-time link back to the typed slot. A future extension of
1176    /// the `:nome` axis to a richer author surface — a per-`:nome`
1177    /// structured `CaixaIdentity` newtype that carries the joint-
1178    /// length-with-prefix invariant [`Self::validate_nome_chart_name_budget`]
1179    /// enforces at the type level (rather than as a validate-time
1180    /// gate), a per-registry `:nome` namespacing overlay the M4 CR
1181    /// materializer resolves per-CR (the "`pleme-io/checkout` vs
1182    /// `partner-org/checkout` collision" arm the multi-tenant-registry
1183    /// story acknowledges), a promotion of the plain `String` byte-
1184    /// string to a richer `CaixaNome` newtype discriminated on
1185    /// namespace prefix — would have had to be threaded through every
1186    /// open-coded copy in lockstep or the two validate gates and the
1187    /// dozen emit paths would silently disagree on which identity a
1188    /// given [`Caixa`] resolves to (an author's `:nome "checkout"`
1189    /// would satisfy validate while one of the emit paths silently
1190    /// rendered a drifted other identity, or vice versa). Lifting the
1191    /// resolution to a typed method on the substrate primitive means
1192    /// every downstream consumer of the caixa's per-`Caixa` identity
1193    /// surface reaches for exactly one typed dispatch — the resolver's
1194    /// accept-set migrates as a unit on any future axis addition.
1195    ///
1196    /// First outer top-level [`Caixa`] `&str`-return required-scalar
1197    /// accessor — opens the "outer [`Caixa`] `&str` required-scalar"
1198    /// projection pattern the sibling per-`Caixa` `:versao` future lift
1199    /// folds on. Sibling in shape to the peer per-`:membros`
1200    /// [`crate::aplicacao::Membro::nome`] (4a32abf) / per-`:contratos`
1201    /// [`crate::aplicacao::WitContract::source`] /
1202    /// [`crate::aplicacao::WitContract::destination`] (7f0fd43),
1203    /// [`crate::aplicacao::WitContract::world_ref`] (0804823),
1204    /// [`crate::aplicacao::Membro::versao_requirement`] (a40b0e3),
1205    /// [`crate::aplicacao::Entrada::destination`] (6db982c),
1206    /// [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062),
1207    /// per-sub-struct required-axis accessors carry on the sibling M3
1208    /// mesh-slot-atom scalar-value axes, extended here to open the
1209    /// outer top-level [`Caixa`] `&str`-return required-scalar surface.
1210    /// Named `nome()` to match the storage field's name; the accessor's
1211    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1212    /// slot's docstring already carries.
1213    #[must_use]
1214    pub fn nome(&self) -> &str {
1215        &self.nome
1216    }
1217
1218    /// Substrate-canonical per-`Caixa` `:versao` universal-axis SemVer-2
1219    /// pinned-version scalar accessor every consumer of the top-level
1220    /// manifest's version axis keys off — returns the author-declared
1221    /// `:versao` byte-string verbatim as an `&str`, borrowed from the
1222    /// typed slot's own `String` storage. Non-optional (`:versao` is a
1223    /// required-axis scalar every `defcaixa` form must supply alongside
1224    /// `:nome` / `:kind`; the [`Self::from_lisp`] derive rejects an
1225    /// omitted / non-string `:versao` at parse time, so a `Caixa` past
1226    /// parse definitionally carries a non-`None` `:versao`).
1227    ///
1228    /// The `:versao` slot carries the universal-axis SemVer-2
1229    /// concrete-version body every kind of caixa emits under
1230    /// (CAIXA-SDLC §I — the required-scalar every `defcaixa` form
1231    /// supplies alongside `:nome` / `:kind`; the substrate-wide
1232    /// pinned-version every downstream artifact-emitting consumer
1233    /// composes under — the `lareira-<nome>` Helm chart's `Chart.yaml`
1234    /// `version:` + `appVersion:` axes, the `feira publish` Zig-style
1235    /// `v<versao>` git tag the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
1236    /// prefix composes on top of, the programs.yaml entry's `versao:`
1237    /// value the `lareira-fleet-programs` aggregator carries onto each
1238    /// rendered `ComputeUnit`, the OCI image's `:v<versao>` / `:latest`
1239    /// tags every substrate-side `skopeo push` writes, the lacre
1240    /// closure's pinned `concrete_versao`, and the `:upgrade-from :from`
1241    /// prior-version references peers in the exact same SemVer-2 shape).
1242    /// The typed slot's `String` accept-set (empty rejected through
1243    /// [`ManifestError::VersaoEmpty`], SemVer-2-shape-invalid rejected
1244    /// through [`ManifestError::VersaoInvalid`] past
1245    /// [`semver::Version::parse`]) maps onto every load-bearing
1246    /// downstream consumer the substrate carries — the [`Self::validate_versao`]
1247    /// universal-axis validate gate at caixa-build time, the
1248    /// [`crate::CaixaVersion::parse`] typed-wrapper resolver,
1249    /// [`caixa-helm`]'s `Chart.yaml` `version:` / `appVersion:` fold,
1250    /// [`caixa-flux`]'s `programs.yaml` entry `versao:` fold + the
1251    /// `cluster_bundle` `GitRepository` `ref: { tag: v<versao> }`
1252    /// derivation, [`caixa-mesh`]'s per-Aplicacao `programs.yaml` fan-
1253    /// out entry `versao:` fold, [`caixa-feira`]'s `feira publish` git-
1254    /// tag derivation (`format!("{prefix}{versao}")`), and every future
1255    /// substrate renderer that emits an artifact keyed by the caixa's
1256    /// pinned version.
1257    ///
1258    /// Prior to this lift the `.versao` field was accessed inline at a
1259    /// dozen production sites across `caixa-core` (the universal-axis
1260    /// [`Self::validate_versao`] gate + [`Dep::validate`]-adjacent
1261    /// version-shape gates), `caixa-helm` (the `ChartYaml.version` /
1262    /// `ChartYaml.app_version` folds), `caixa-flux` (the `programs.yaml`
1263    /// entry `versao:` fold, the `cluster_bundle` `GitRepository` `ref:
1264    /// { tag: v<versao> }` derivation), `caixa-mesh` (the per-Aplicacao
1265    /// `programs.yaml` fan-out entry `versao:` fold), and `caixa-feira`
1266    /// (the `feira publish` git-tag derivation + the `feira app graph` /
1267    /// `feira app deploy` diagnostic renderers) — a dozen open-coded
1268    /// field-accesses that expressed no compile-time link back to the
1269    /// typed slot. A future extension of the `:versao` axis to a richer
1270    /// author surface — a per-`:versao` structured `CaixaVersion` at the
1271    /// storage layer (the substrate already carries a `CaixaVersion`
1272    /// newtype at [`crate::version::CaixaVersion`], deferred until the
1273    /// serde-transparent-newtype-through-DeriveTataraDomain path lands),
1274    /// a per-registry `:versao` immutability overlay the M4 CR
1275    /// materializer enforces per-CR, a promotion of the plain `String`
1276    /// byte-string to a richer `PinnedVersao` newtype discriminated on
1277    /// SemVer-2 pre-release / build-metadata presence — would have had
1278    /// to be threaded through every open-coded copy in lockstep or the
1279    /// validate gate and the dozen emit paths would silently disagree
1280    /// on which version a given [`Caixa`] resolves to (an author's
1281    /// `:versao "0.1.0"` would satisfy validate while one of the emit
1282    /// paths silently rendered a drifted other version, or vice versa).
1283    /// Lifting the resolution to a typed method on the substrate
1284    /// primitive means every downstream consumer of the caixa's
1285    /// per-`Caixa` pinned-version surface reaches for exactly one typed
1286    /// dispatch — the resolver's accept-set migrates as a unit on any
1287    /// future axis addition.
1288    ///
1289    /// Second outer top-level [`Caixa`] `&str`-return required-scalar
1290    /// accessor — folds on the "outer [`Caixa`] `&str` required-scalar"
1291    /// projection pattern the sibling per-`Caixa` [`Self::nome`]
1292    /// (e6b7d97) opened. Sibling in shape to the peer per-`:membros`
1293    /// [`crate::aplicacao::Membro::versao_requirement`] (4127bb6) /
1294    /// per-`:children` [`crate::supervisor::ChildSpec::versao_requirement`]
1295    /// (2c053c8) / per-`:upgrade-from` [`crate::UpgradeFromEntry::prior_versao`]
1296    /// (75d27a8) per-sub-struct `:versao`-shaped `&str`-return accessors
1297    /// on the sibling per-typed-slot version-carrier axes, extended here
1298    /// to close the second outer top-level [`Caixa`] required-`&str`-
1299    /// carrying axis so the two universal-axis identity-carrying
1300    /// scalars every `defcaixa` form supplies (`:nome` + `:versao`)
1301    /// share the same "one typed dispatch per axis" discipline. Named
1302    /// `versao()` to match the storage field's name; the accessor's
1303    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1304    /// slot's docstring already carries.
1305    #[must_use]
1306    pub fn versao(&self) -> &str {
1307        &self.versao
1308    }
1309
1310    /// Substrate-canonical per-`Caixa` `:kind` universal-axis
1311    /// closed-set-enum discriminant accessor every consumer of the top-
1312    /// level manifest's kind axis keys off — returns the author-declared
1313    /// `:kind` variant verbatim as a [`CaixaKind`], `Copy`-projected
1314    /// from the typed slot's own [`CaixaKind`] storage. Non-optional
1315    /// (`:kind` is a required-axis discriminant every `defcaixa` form
1316    /// must supply alongside `:nome` / `:versao`; the [`Self::from_lisp`]
1317    /// derive rejects an omitted / non-symbol `:kind` at parse time, so
1318    /// a `Caixa` past parse definitionally carries a valid [`CaixaKind`]
1319    /// variant).
1320    ///
1321    /// The `:kind` slot carries the universal-axis closed-set typed-
1322    /// discriminant every substrate-side dispatch keys off (CAIXA-SDLC
1323    /// §I — the primary shape gate every renderer / verifier /
1324    /// operator branches on; the five variants `Biblioteca` /
1325    /// `Binario` / `Servico` / `Supervisor` / `Aplicacao` partition
1326    /// the caixa surface into disjoint runtime contracts) — the typed
1327    /// slot's [`CaixaKind`] accept-set (parse-time-rejected non-symbol
1328    /// values through the derive-macro's symbol-arm gate, exhaustively
1329    /// matched at every downstream dispatch site) maps onto every
1330    /// load-bearing downstream consumer the substrate carries:
1331    ///
1332    ///   - [`crate::render::require_kind`]'s per-renderer entry-gate
1333    ///     predicate — the canonical two-line
1334    ///     `require_kind(caixa, Servico)?` prelude every per-Servico
1335    ///     renderer (`caixa-helm`, `caixa-flux`, the future `caixa-otel`
1336    ///     / per-Servico OCI packager / M4 `wasm.pleme.io/v1alpha1/
1337    ///     ComputeUnit` CR materializer) runs at its entry-point,
1338    ///     alongside the [`crate::render::KindMismatch`] error carrier's
1339    ///     `actual:` field the diagnostic surfaces to name the offending
1340    ///     caixa's variant.
1341    ///   - [`Self::aplicacao_view`]'s + [`Self::supervisor_view`]'s
1342    ///     per-view kind-gate binding — the two `Option<TypedSpec>`
1343    ///     `_view` composers that fold the flat mesh-slot / supervisor-
1344    ///     slot columns into their typed sub-spec only when the kind
1345    ///     matches (returns `None` otherwise); the future per-Servico
1346    ///     M2-view composer (`servico_view`) will follow the same shape.
1347    ///   - [`Self::declared_foreign_code_slots`]'s per-slot kind-
1348    ///     coherence gate — the `!self.kind.requires_exe()` /
1349    ///     `!self.kind.requires_servicos()` predicates that fence
1350    ///     each code-surface slot from the wrong owning kind.
1351    ///   - [`crate::LayoutInvariants::verify`]'s kind ↔ code-surface
1352    ///     coherence gates — the six `caixa.kind == CaixaKind::X` /
1353    ///     `caixa.kind != CaixaKind::X` predicates and the four kind-
1354    ///     coherence error carriers (`SupervisorOwnsCode` /
1355    ///     `AplicacaoOwnsCode` / `MeshSlotsOnNonAplicacao` /
1356    ///     `SupervisorSlotsOnNonSupervisor` / `ServicoSlotsOnNonServico`
1357    ///     / `ForeignCodeSlot`) which each name the offending caixa's
1358    ///     variant in their `kind:` field.
1359    ///
1360    /// Prior to this lift the `.kind` field was accessed inline at
1361    /// twenty-plus production sites across `caixa-core` (the
1362    /// [`crate::render::require_kind`] entry-gate predicate + the
1363    /// [`crate::render::KindMismatch`] `actual:` field, the two `_view`
1364    /// composers, the `declared_foreign_code_slots` per-slot kind-
1365    /// coherence gate, and the six [`crate::LayoutInvariants::verify`]
1366    /// kind ↔ code-surface predicates + four error carriers) — a score
1367    /// of open-coded field-accesses that expressed no compile-time link
1368    /// back to the typed slot. A future extension of the `:kind` axis
1369    /// to a richer author surface — a per-`:kind` sub-variant discriminant
1370    /// (e.g. `Servico(ServicoRuntime)` splitting the current single
1371    /// variant across the wasm-component / legacy-container / native-
1372    /// binary runtime axes the M5 roadmap acknowledges), a per-cluster
1373    /// kind-overlay the M4 CR materializer resolves per-CR (the
1374    /// "cluster policy demotes `Aplicacao` to `Servico` on a single-
1375    /// tenant cluster" arm), a promotion of the plain [`CaixaKind`]
1376    /// enum to a richer `KindWithRuntime` discriminated on the
1377    /// component-model world axis — would have had to be threaded
1378    /// through every open-coded copy in lockstep or the entry gate,
1379    /// the view composers, and the layout invariants would silently
1380    /// disagree on which kind a given [`Caixa`] resolves to. Lifting
1381    /// the resolution to a typed method on the substrate primitive
1382    /// means every downstream consumer of the caixa's per-`Caixa`
1383    /// kind surface reaches for exactly one typed dispatch — the
1384    /// resolver's accept-set migrates as a unit on any future axis
1385    /// addition.
1386    ///
1387    /// First outer top-level [`Caixa`] `Copy`-return required-enum-
1388    /// discriminant accessor — opens the "outer [`Caixa`] `Copy`-return
1389    /// required-discriminant" projection pattern. Sibling in shape to
1390    /// the peer per-`:supervisor` [`crate::supervisor::SupervisorSpec::estrategia`]
1391    /// (eafb619), per-`:placement` [`crate::aplicacao::Placement::estrategia`]
1392    /// (921fe1b), and per-`:children` [`crate::supervisor::ChildSpec::restart`]
1393    /// (dfb4a81) `Copy`-return closed-set-enum discriminant accessors
1394    /// on the sibling nested-spec typed-slot discriminator axes,
1395    /// extended here to the outer top-level [`Caixa`] universal-axis
1396    /// surface. Named `kind()` to match the storage field's name;
1397    /// the accessor's identity maps onto the canonical CAIXA-SDLC §I
1398    /// vocabulary the slot's docstring already carries.
1399    #[must_use]
1400    pub fn kind(&self) -> CaixaKind {
1401        self.kind
1402    }
1403
1404    /// Substrate-canonical per-`Caixa` `:autores` universal-axis
1405    /// maintainer-name-list slice-accessor every consumer of the top-
1406    /// level manifest's maintainer axis keys off — returns the author-
1407    /// declared `:autores` list verbatim as a `&[String]` slice-view over
1408    /// the same backing buffer the raw `self.autores.as_slice()` field
1409    /// access borrows from. Empty-list-carrying (`:autores` is a default-
1410    /// empty axis every `defcaixa` form supplies with an empty `()` when
1411    /// unset; the [`Self::from_lisp`] derive folds an omitted `:autores`
1412    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1413    /// parse definitionally carries a `Vec<String>` slot — possibly
1414    /// empty — and the returned `&[String]` degenerates to an empty
1415    /// slice on that arm without any silent `None` collapse).
1416    ///
1417    /// The `:autores` slot carries the universal-axis maintainer-name
1418    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
1419    /// facing surface every `defcaixa` form supplies alongside `:nome` /
1420    /// `:versao` / `:kind`; the substrate-wide contact-carrying axis
1421    /// every downstream registry-facing artifact emits under) — the
1422    /// typed slot's `Vec<String>` accept-set (empty-per-entry rejected
1423    /// through [`ManifestError::AutorEmpty`], non-chart-maintainer-shape
1424    /// rejected through [`ManifestError::AutorInvalid`], cross-entry
1425    /// duplicate rejected through [`ManifestError::AutorDuplicate`]) maps
1426    /// onto every load-bearing downstream consumer the substrate carries
1427    /// — the [`Self::validate_autores`] universal-axis empty-per-entry +
1428    /// shape + duplicate gate at caixa-core/src/manifest.rs, the
1429    /// caixa-helm `build_chart_yaml` `maintainers:` fold at
1430    /// caixa-helm/src/lib.rs that walks each entry into a `Maintainer {
1431    /// name, email: None }` record, every future per-`Caixa` registry-
1432    /// facing renderer the CAIXA-SDLC §I roadmap acknowledges (the
1433    /// future `artifacthub.io/maintainers` `Chart.yaml` annotation the
1434    /// caixa-helm docstring alludes to at [`Self::validate_licenca`],
1435    /// the future per-cluster author-notification overlay the M4 CR
1436    /// materializer resolves per-CR).
1437    ///
1438    /// Prior to this lift the `.autores` field was accessed inline at
1439    /// two production sites — [`Self::validate_autores`]'s `for autor
1440    /// in &self.autores` walk that gates every entry through
1441    /// [`ManifestError::AutorEmpty`] / `AutorInvalid` / `AutorDuplicate`,
1442    /// and the caixa-helm `build_chart_yaml` `caixa.autores.iter().map(|a|
1443    /// Maintainer { name: a.clone(), email: None }).collect()` fold that
1444    /// materializes every entry into a `Chart.yaml` `maintainers:` row —
1445    /// two open-coded field-accesses that expressed no compile-time link
1446    /// back to the typed slot. A future extension of the `:autores` axis
1447    /// to a richer author surface — a per-`:autores` structured
1448    /// `Maintainer { name, email, url }` at the storage layer once the
1449    /// substrate absorbs `artifacthub.io/maintainers`' name+email+url
1450    /// tuple, a per-registry `:autores` allowlist the M4 CR materializer
1451    /// enforces per-CR (the "cluster policy demands every author declare
1452    /// an on-file `mailto:` contact" arm), a promotion of the plain
1453    /// `Vec<String>` byte-string list to a richer
1454    /// `Vec<ChartMaintainer>` newtype discriminated on the RFC-5322
1455    /// `<name> [<email>]` grammar the `is_chart_maintainer_name_shape`
1456    /// predicate already resolves through — would have had to be
1457    /// threaded through both open-coded copies in lockstep or the
1458    /// validate gate and the caixa-helm emit path would silently
1459    /// disagree on which authors a given [`Caixa`] resolves to (an
1460    /// author's `:autores ("alice" "bob")` would satisfy validate while
1461    /// the caixa-helm emit path silently rendered a drifted other
1462    /// maintainer list, or vice versa). Lifting the resolution to a
1463    /// typed method on the substrate primitive means every downstream
1464    /// consumer of the caixa's per-`Caixa` maintainer surface reaches
1465    /// for exactly one typed dispatch — the resolver's accept-set
1466    /// migrates as a unit on any future axis addition.
1467    ///
1468    /// First outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1469    /// opens the "outer [`Caixa`] `&[T]` slice" projection pattern the
1470    /// sibling per-`Caixa` `:etiquetas` / `:deps` / `:deps-dev` / `:exe`
1471    /// / `:bibliotecas` / `:servicos` / `:upgrade-from` / `:children`
1472    /// future lifts fold on. Sibling in shape to the peer per-`:supervisor`
1473    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce), per-`:placement`
1474    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7), per-`:membros`
1475    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36), per-`:contratos`
1476    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1477    /// per-`:upgrade-from :instructions` [`crate::upgrade::UpgradeFromEntry::instructions`]
1478    /// (0137e5a) `&[T]`-return slice accessors on the sibling per-M2 /
1479    /// per-M3 typed-slot list axes, extended here to the outer top-level
1480    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1481    /// `&Vec<String>`) because every downstream consumer of the author
1482    /// list treats it as a read-only sequence — the slice-view is the
1483    /// narrowest borrow that supports every present + roadmapped consumer
1484    /// (`.iter()`, `.len()`, `.is_empty()`) without leaking the backing
1485    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
1486    /// reaches for (the storage-side `Vec` remains reachable through the
1487    /// `pub autores` field for the mutation-carrying serde round-trip and
1488    /// per-test fixture-mutation paths). Named `autores()` to match the
1489    /// storage field's name; the accessor's identity maps onto the
1490    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1491    /// carries.
1492    #[must_use]
1493    pub fn autores(&self) -> &[String] {
1494        self.autores.as_slice()
1495    }
1496
1497    /// Substrate-canonical per-`Caixa` `:etiquetas` universal-axis
1498    /// registry-search-tag-list slice-accessor every consumer of the
1499    /// top-level manifest's topical-tag axis keys off — returns the
1500    /// author-declared `:etiquetas` list verbatim as a `&[String]`
1501    /// slice-view over the same backing buffer the raw
1502    /// `self.etiquetas.as_slice()` field access borrows from. Empty-
1503    /// list-carrying (`:etiquetas` is a default-empty axis every
1504    /// `defcaixa` form supplies with an empty `()` when unset; the
1505    /// [`Self::from_lisp`] derive folds an omitted `:etiquetas` through
1506    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1507    /// definitionally carries a `Vec<String>` slot — possibly empty —
1508    /// and the returned `&[String]` degenerates to an empty slice on
1509    /// that arm without any silent `None` collapse).
1510    ///
1511    /// The `:etiquetas` slot carries the universal-axis topical-tag
1512    /// list every kind of caixa emits under (CAIXA-SDLC §I — the
1513    /// author-facing surface every `defcaixa` form supplies alongside
1514    /// `:nome` / `:versao` / `:kind`; the substrate-wide registry-
1515    /// search-facing axis every downstream registry-facing artifact
1516    /// emits under) — the typed slot's `Vec<String>` accept-set
1517    /// (empty-per-entry rejected through [`ManifestError::EtiquetaEmpty`],
1518    /// non-chart-keyword-shape rejected through
1519    /// [`ManifestError::EtiquetaInvalid`], cross-entry duplicate
1520    /// rejected through [`ManifestError::EtiquetaDuplicate`]) maps onto
1521    /// every load-bearing downstream consumer the substrate carries —
1522    /// the [`Self::validate_etiquetas`] universal-axis empty-per-entry
1523    /// + shape + duplicate gate at caixa-core/src/manifest.rs, the
1524    /// caixa-helm `build_chart_yaml` `keywords:` fold at
1525    /// caixa-helm/src/lib.rs that walks each entry into the rendered
1526    /// `Chart.yaml` `keywords:` array (chained with the
1527    /// [`crate::LAREIRA_CHART_KEYWORDS`] substrate-wide floor set and
1528    /// dedup'd through a `BTreeSet` at emit time), every future per-
1529    /// `Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
1530    /// acknowledges (the future `artifacthub.io/keywords` `Chart.yaml`
1531    /// annotation, the future per-cluster tag-notification overlay the
1532    /// M4 CR materializer resolves per-CR).
1533    ///
1534    /// Prior to this lift the `.etiquetas` field was accessed inline at
1535    /// two production sites — [`Self::validate_etiquetas`]'s `for
1536    /// etiqueta in &self.etiquetas` walk that gates every entry through
1537    /// [`ManifestError::EtiquetaEmpty`] / `EtiquetaInvalid` /
1538    /// `EtiquetaDuplicate`, and the caixa-helm `build_chart_yaml`
1539    /// `caixa.etiquetas.iter().cloned().chain(...)` fold that
1540    /// materializes every entry into a `Chart.yaml` `keywords:` row —
1541    /// two open-coded field-accesses that expressed no compile-time
1542    /// link back to the typed slot. A future extension of the
1543    /// `:etiquetas` axis to a richer tag surface — a per-`:etiquetas`
1544    /// structured `ChartKeyword { name, uri, category }` at the storage
1545    /// layer once the substrate absorbs `artifacthub.io/keywords`
1546    /// richer tag tuple, a per-registry `:etiquetas` allowlist the M4
1547    /// CR materializer enforces per-CR (the "cluster policy demands
1548    /// every tag come from a substrate-approved taxonomy" arm), a
1549    /// promotion of the plain `Vec<String>` byte-string list to a
1550    /// richer `Vec<ChartKeyword>` newtype discriminated on the DNS-
1551    /// 1123-label-shaped grammar the `is_chart_keyword_shape` predicate
1552    /// already resolves through — would have had to be threaded through
1553    /// both open-coded copies in lockstep or the validate gate and the
1554    /// caixa-helm emit path would silently disagree on which tags a
1555    /// given [`Caixa`] resolves to (an author's `:etiquetas ("demo"
1556    /// "aplicacao")` would satisfy validate while the caixa-helm emit
1557    /// path silently rendered a drifted other keyword list, or vice
1558    /// versa). Lifting the resolution to a typed method on the
1559    /// substrate primitive means every downstream consumer of the
1560    /// caixa's per-`Caixa` topical-tag surface reaches for exactly one
1561    /// typed dispatch — the resolver's accept-set migrates as a unit
1562    /// on any future axis addition.
1563    ///
1564    /// Second outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1565    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1566    /// [`Self::autores`] (b5d813f) opened, sibling in shape and
1567    /// idiom. The remaining unlifted outer-`Caixa` slice-carrying axes
1568    /// (`:deps` / `:deps-dev` / `:exe` / `:bibliotecas` / `:servicos`
1569    /// / `:upgrade-from` / `:children` / `:membros` / `:contratos`)
1570    /// fold onto the same pattern in future lifts. Sibling in shape to
1571    /// the peer per-`:supervisor`
1572    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1573    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1574    /// (a6e18d7), per-`:membros`
1575    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1576    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1577    /// (0dcc926), and per-`:upgrade-from :instructions`
1578    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1579    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1580    /// typed-slot list axes, extended here to the outer top-level
1581    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1582    /// `&Vec<String>`) because every downstream consumer of the tag
1583    /// list treats it as a read-only sequence — the slice-view is the
1584    /// narrowest borrow that supports every present + roadmapped
1585    /// consumer (`.iter()`, `.len()`, `.is_empty()`) without leaking
1586    /// the backing `Vec`'s grow/push/reserve surface no consumer of
1587    /// the typed view reaches for (the storage-side `Vec` remains
1588    /// reachable through the `pub etiquetas` field for the mutation-
1589    /// carrying serde round-trip and per-test fixture-mutation paths).
1590    /// Named `etiquetas()` to match the storage field's name; the
1591    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1592    /// vocabulary the slot's docstring already carries.
1593    #[must_use]
1594    pub fn etiquetas(&self) -> &[String] {
1595        self.etiquetas.as_slice()
1596    }
1597
1598    /// Substrate-canonical per-`Caixa` `:bibliotecas` universal-axis
1599    /// library-source-path-list slice-accessor every consumer of the
1600    /// top-level manifest's Biblioteca-source axis keys off — returns
1601    /// the author-declared `:bibliotecas` list verbatim as a
1602    /// `&[String]` slice-view over the same backing buffer the raw
1603    /// `self.bibliotecas.as_slice()` field access borrows from. Empty-
1604    /// list-carrying (`:bibliotecas` is a default-empty axis every
1605    /// `defcaixa` form supplies with an empty `()` when unset; the
1606    /// [`Self::from_lisp`] derive folds an omitted `:bibliotecas`
1607    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1608    /// parse definitionally carries a `Vec<String>` slot — possibly
1609    /// empty — and the returned `&[String]` degenerates to an empty
1610    /// slice on that arm without any silent `None` collapse).
1611    ///
1612    /// The `:bibliotecas` slot carries the universal-axis lisp-library
1613    /// entry-path list every `:kind Biblioteca` caixa emits under
1614    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1615    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1616    /// substrate-wide library-carrier axis every downstream
1617    /// authoring-facing consumer keys off) — the typed slot's
1618    /// `Vec<String>` accept-set (empty-per-entry rejected through
1619    /// [`ManifestError::CodePathEmpty { slot: ":bibliotecas" }`],
1620    /// non-sandboxed-relative-shape rejected through
1621    /// [`ManifestError::CodePathShape`], non-`.lisp`-extension rejected
1622    /// through [`ManifestError::CodePathNonLispExtension`], cross-entry
1623    /// duplicate rejected through [`ManifestError::CodePathDuplicate`])
1624    /// maps onto every load-bearing downstream consumer the substrate
1625    /// carries — the [`crate::LayoutInvariants`] Biblioteca-arm
1626    /// empty-check + per-entry file-exists loop at
1627    /// caixa-core/src/layout.rs that gates each entry through
1628    /// [`crate::LayoutError::MissingLib`] / `MissingEntry`, the
1629    /// [`Self::validate_code_paths`] per-slot shape gate at
1630    /// caixa-core/src/manifest.rs that walks each entry through the
1631    /// sandbox-relative / `.lisp`-extension / cross-entry duplicate
1632    /// gates, the `feira build` per-entry `tatara_lisp::read` parse
1633    /// walk at caixa-feira/src/cmd/build.rs that phase-1-checks each
1634    /// declared library file for lexical / structural errors before
1635    /// downstream `importar` resolution, every future per-`Caixa`
1636    /// library-facing renderer the CAIXA-SDLC §I roadmap acknowledges
1637    /// (the future `tatara-lispc` compilation entry the docstring at
1638    /// caixa-feira/src/cmd/build.rs alludes to, the future per-cluster
1639    /// bytecode-caching overlay the M4 CR materializer resolves per-CR,
1640    /// the future `caixa-lsp` per-library semantic-token stream the
1641    /// caixa-lsp docstring roadmaps).
1642    ///
1643    /// Prior to this lift the `.bibliotecas` field was accessed inline
1644    /// at three production sites — [`crate::LayoutInvariants`]'s
1645    /// `caixa.bibliotecas.is_empty()` `MissingLib`-arm gate + `for p
1646    /// in &caixa.bibliotecas` `MissingEntry` walk that gates each
1647    /// declared library path through the on-disk-existence check,
1648    /// the compound-code-path `has_code = !caixa.bibliotecas.is_empty()
1649    /// || !caixa.exe.is_empty() || !caixa.servicos.is_empty()` OR-fold
1650    /// on the [`crate::LayoutError::SupervisorOwnsCode`] /
1651    /// `AplicacaoOwnsCode` kind-coherence gate, and the `feira build`
1652    /// per-entry `for entry in &caixa.bibliotecas` + `caixa.bibliotecas.
1653    /// len()` phase-1 tatara-lispc-precursor parse walk — three open-
1654    /// coded field-accesses that expressed no compile-time link back
1655    /// to the typed slot. A future extension of the `:bibliotecas`
1656    /// axis to a richer library surface — a per-`:bibliotecas`
1657    /// structured `BibliotecaEntry { path, edition, exports }` at the
1658    /// storage layer once the substrate absorbs the per-library
1659    /// language-edition + explicit-exports tuple the tatara-lisp
1660    /// module-system roadmap acknowledges, a per-registry
1661    /// `:bibliotecas` allowlist the M4 CR materializer enforces
1662    /// per-CR (the "cluster policy demands every biblioteca declare
1663    /// its own :edicao" arm), a promotion of the plain `Vec<String>`
1664    /// byte-string list to a richer `Vec<LibraryPath>` newtype
1665    /// discriminated on the `lib/<nome>.lisp`-shape grammar the
1666    /// [`crate::render::is_sandboxed_relative_path`] +
1667    /// [`crate::render::is_lisp_extension`] predicates already resolve
1668    /// through — would have had to be threaded through all three
1669    /// open-coded copies in lockstep or the layout gate, the shape
1670    /// validator, and the `feira build` phase-1 parse walk would
1671    /// silently disagree on which library paths a given [`Caixa`]
1672    /// resolves to (an author's `:bibliotecas ("lib/foo.lisp"
1673    /// "lib/bar.lisp")` would satisfy layout while `feira build`
1674    /// silently parsed a drifted other list, or vice versa). Lifting
1675    /// the resolution to a typed method on the substrate primitive
1676    /// means every downstream consumer of the caixa's per-`Caixa`
1677    /// library-source surface reaches for exactly one typed dispatch
1678    /// — the resolver's accept-set migrates as a unit on any future
1679    /// axis addition.
1680    ///
1681    /// Third outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1682    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1683    /// [`Self::autores`] (b5d813f) opened and [`Self::etiquetas`]
1684    /// (78c7d3c) folded on, sibling in shape and idiom. The remaining
1685    /// unlifted outer-`Caixa` slice-carrying axes (`:deps` /
1686    /// `:deps-dev` / `:exe` / `:servicos` / `:upgrade-from` /
1687    /// `:children` / `:membros` / `:contratos`) fold onto the same
1688    /// pattern in future lifts. Sibling in shape to the peer
1689    /// per-`:supervisor`
1690    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1691    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1692    /// (a6e18d7), per-`:membros`
1693    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1694    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1695    /// (0dcc926), and per-`:upgrade-from :instructions`
1696    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1697    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1698    /// typed-slot list axes, extended here to the outer top-level
1699    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1700    /// `&Vec<String>`) because every downstream consumer of the
1701    /// library-source list treats it as a read-only sequence — the
1702    /// slice-view is the narrowest borrow that supports every
1703    /// present + roadmapped consumer (`.iter()`, `.len()`,
1704    /// `.is_empty()`) without leaking the backing `Vec`'s
1705    /// grow/push/reserve surface no consumer of the typed view
1706    /// reaches for (the storage-side `Vec` remains reachable through
1707    /// the `pub bibliotecas` field for the mutation-carrying serde
1708    /// round-trip and per-test fixture-mutation paths). Named
1709    /// `bibliotecas()` to match the storage field's name; the
1710    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1711    /// vocabulary the slot's docstring already carries.
1712    #[must_use]
1713    pub fn bibliotecas(&self) -> &[String] {
1714        self.bibliotecas.as_slice()
1715    }
1716
1717    /// Substrate-canonical per-`Caixa` `:exe` universal-axis
1718    /// nix-built-executable-entry-path-list slice-accessor every consumer
1719    /// of the top-level manifest's Binario-executable axis keys off —
1720    /// returns the author-declared `:exe` list verbatim as a `&[String]`
1721    /// slice-view over the same backing buffer the raw
1722    /// `self.exe.as_slice()` field access borrows from. Empty-list-
1723    /// carrying (`:exe` is a default-empty axis every `defcaixa` form
1724    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
1725    /// derive folds an omitted `:exe` through `#[serde(default)]` to
1726    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
1727    /// `Vec<String>` slot — possibly empty — and the returned `&[String]`
1728    /// degenerates to an empty slice on that arm without any silent
1729    /// `None` collapse).
1730    ///
1731    /// The `:exe` slot carries the universal-axis nix-built executable
1732    /// entry-path list every `:kind Binario` caixa emits under
1733    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1734    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1735    /// substrate-wide `exe/`-directory-fenced entry-carrier axis every
1736    /// downstream flake-build-facing consumer keys off) — the typed
1737    /// slot's `Vec<String>` accept-set (empty-per-entry rejected
1738    /// through [`ManifestError::CodePathEmpty { slot: ":exe" }`],
1739    /// non-sandboxed-relative-shape rejected through
1740    /// [`ManifestError::CodePathShape`], cross-entry duplicate rejected
1741    /// through [`ManifestError::CodePathDuplicate`], out-of-`exe/`-
1742    /// directory paths rejected past the layout's
1743    /// [`crate::LayoutError::ExeOutsideDir`] `starts_with` fence) maps
1744    /// onto every load-bearing downstream consumer the substrate carries
1745    /// — the [`crate::LayoutInvariants`] Binario-arm empty-check +
1746    /// per-entry file-exists + `exe/`-directory-fence loop at
1747    /// caixa-core/src/layout.rs that gates each entry through
1748    /// [`crate::LayoutError::BinarioWithoutExe`] / `MissingEntry` /
1749    /// `ExeOutsideDir`, the compound `has_code` OR-fold on the
1750    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1751    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1752    /// that fences code-surface slots off from the two no-code kinds,
1753    /// [`Self::declared_foreign_code_slots`]'s `!self.exe.is_empty()`
1754    /// arm on the [`crate::LayoutError::ForeignCodeSlot`] gate that
1755    /// fences the `:exe` code surface off from every non-Binario code-
1756    /// running kind, [`Self::validate_code_paths`]'s per-slot shape gate
1757    /// that walks each entry through the sandbox-relative / cross-entry
1758    /// duplicate gates, every future per-`Caixa` executable-facing
1759    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1760    /// `caixa-flake` per-Binario `packages.<system>.<nome>` derivation
1761    /// entry the caixa-flake docstring roadmaps, the future per-cluster
1762    /// `nix-store` overlay the M4 CR materializer resolves per-CR, the
1763    /// future `feira nix` per-executable Binario-target emit path).
1764    ///
1765    /// Prior to this lift the `.exe` field was accessed inline at three
1766    /// production sites — the compound-code-path `has_code =
1767    /// !caixa.bibliotecas().is_empty() || !caixa.exe.is_empty() ||
1768    /// !caixa.servicos.is_empty()` OR-fold on the
1769    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1770    /// `AplicacaoOwnsCode` kind-coherence gate, the Binario-arm
1771    /// `caixa.exe.is_empty()` [`crate::LayoutError::BinarioWithoutExe`]
1772    /// gate, the per-entry `for p in &caixa.exe`
1773    /// `MissingEntry`/`ExeOutsideDir` walk, and the
1774    /// [`Self::declared_foreign_code_slots`]'s
1775    /// `!self.exe.is_empty()` arm on the `ForeignCodeSlot` gate — four
1776    /// open-coded field-accesses that expressed no compile-time link
1777    /// back to the typed slot. A future extension of the `:exe` axis
1778    /// to a richer executable surface — a per-`:exe` structured
1779    /// `BinarioEntry { path, wrapper, capabilities }` at the storage
1780    /// layer once the substrate absorbs the per-executable
1781    /// nix-wrapper + linux-capabilities tuple the CAIXA-SDLC §I
1782    /// executable roadmap acknowledges, a per-registry `:exe` allowlist
1783    /// the M4 CR materializer enforces per-CR (the "cluster policy
1784    /// demands every Binario declare an explicit `:wrapper`" arm), a
1785    /// promotion of the plain `Vec<String>` byte-string list to a
1786    /// richer `Vec<ExecutablePath>` newtype discriminated on the
1787    /// `exe/<nome>`-shape grammar the layout's `starts_with(exe_dir)`
1788    /// fence already resolves through — would have had to be threaded
1789    /// through all four open-coded copies in lockstep or the layout
1790    /// gate, the shape validator, and the `feira nix` emit path would
1791    /// silently disagree on which executable paths a given [`Caixa`]
1792    /// resolves to (an author's `:exe ("exe/cli" "exe/serve")` would
1793    /// satisfy layout while `feira nix` silently packaged a drifted
1794    /// other list, or vice versa). Lifting the resolution to a typed
1795    /// method on the substrate primitive means every downstream
1796    /// consumer of the caixa's per-`Caixa` executable-source surface
1797    /// reaches for exactly one typed dispatch — the resolver's accept-
1798    /// set migrates as a unit on any future axis addition.
1799    ///
1800    /// Fourth outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1801    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1802    /// [`Self::autores`] (b5d813f) opened, [`Self::etiquetas`]
1803    /// (78c7d3c) folded on, and [`Self::bibliotecas`] (8a36c23) closed
1804    /// the universal-axis text-tag family of. Opens the outer-`Caixa`
1805    /// foreign-code-slot `&[T]` sub-family the sibling `:servicos`
1806    /// future lift closes onto (per the trio of code-surface list slots
1807    /// the [`Self::validate_code_paths`] per-slot dispatch tuple
1808    /// already carries — `:bibliotecas` + `:exe` + `:servicos`, of which
1809    /// `:bibliotecas` landed at 8a36c23 and `:servicos` remains as the
1810    /// last unlifted code-surface slot). Sibling in shape to the peer
1811    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
1812    /// (bc92bce), per-`:placement`
1813    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
1814    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
1815    /// (6c77e36), per-`:contratos`
1816    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1817    /// per-`:upgrade-from :instructions`
1818    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1819    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1820    /// typed-slot list axes, extended here to the outer top-level
1821    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1822    /// `&Vec<String>`) because every downstream consumer of the
1823    /// executable-source list treats it as a read-only sequence — the
1824    /// slice-view is the narrowest borrow that supports every
1825    /// present + roadmapped consumer (`.iter()`, `.len()`,
1826    /// `.is_empty()`) without leaking the backing `Vec`'s
1827    /// grow/push/reserve surface no consumer of the typed view
1828    /// reaches for (the storage-side `Vec` remains reachable through
1829    /// the `pub exe` field for the mutation-carrying serde
1830    /// round-trip and per-test fixture-mutation paths). Named `exe()`
1831    /// to match the storage field's name; the accessor's identity
1832    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
1833    /// docstring already carries.
1834    #[must_use]
1835    pub fn exe(&self) -> &[String] {
1836        self.exe.as_slice()
1837    }
1838
1839    /// Substrate-canonical per-`Caixa` `:servicos` universal-axis
1840    /// ComputeUnit-CR-YAML-entry-path-list slice-accessor every consumer
1841    /// of the top-level manifest's Servico-component axis keys off —
1842    /// returns the author-declared `:servicos` list verbatim as a
1843    /// `&[String]` slice-view over the same backing buffer the raw
1844    /// `self.servicos.as_slice()` field access borrows from. Empty-list-
1845    /// carrying (`:servicos` is a default-empty axis every `defcaixa`
1846    /// form supplies with an empty `()` when unset; the
1847    /// [`Self::from_lisp`] derive folds an omitted `:servicos` through
1848    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1849    /// definitionally carries a `Vec<String>` slot — possibly empty —
1850    /// and the returned `&[String]` degenerates to an empty slice on
1851    /// that arm without any silent `None` collapse).
1852    ///
1853    /// The `:servicos` slot carries the universal-axis
1854    /// `.computeunit.yaml` ComputeUnit-CR entry-path list every
1855    /// `:kind Servico` caixa emits under (CAIXA-SDLC §I — the
1856    /// author-facing surface every `defcaixa` form supplies alongside
1857    /// `:nome` / `:versao` / `:kind`; the substrate-wide
1858    /// `servicos/`-directory-fenced entry-carrier axis every downstream
1859    /// Servico-facing renderer keys off) — the typed slot's
1860    /// `Vec<String>` accept-set (empty-per-entry rejected through
1861    /// [`ManifestError::CodePathEmpty { slot: ":servicos" }`],
1862    /// non-sandboxed-relative-shape rejected through
1863    /// [`ManifestError::CodePathShape`], non-`.computeunit.yaml`
1864    /// extension rejected through
1865    /// [`ManifestError::CodePathNonComputeUnitYamlExtension`], cross-
1866    /// entry duplicate rejected through
1867    /// [`ManifestError::CodePathDuplicate`], `len != 1` rejected by the
1868    /// V0 [`crate::ServicoCountMismatch`] gate on the per-Servico
1869    /// renderer entry-points, out-of-`servicos/`-directory paths
1870    /// rejected past the layout's [`crate::LayoutError::ServicoOutsideDir`]
1871    /// `starts_with` fence) maps onto every load-bearing downstream
1872    /// consumer the substrate carries — the [`crate::LayoutInvariants`]
1873    /// Servico-arm empty-check + per-entry file-exists + `servicos/`-
1874    /// directory-fence loop at caixa-core/src/layout.rs that gates each
1875    /// entry through [`crate::LayoutError::ServicoWithoutServicos`] /
1876    /// `MissingEntry` / `ServicoOutsideDir`, the compound `has_code`
1877    /// OR-fold on the [`crate::LayoutError::SupervisorOwnsCode`] /
1878    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1879    /// that fences code-surface slots off from the two no-code kinds,
1880    /// [`Self::declared_foreign_code_slots`]'s
1881    /// `!self.servicos.is_empty()` arm on the
1882    /// [`crate::LayoutError::ForeignCodeSlot`] gate that fences the
1883    /// `:servicos` code surface off from every non-Servico code-running
1884    /// kind, [`Self::validate_code_paths`]'s per-slot shape gate that
1885    /// walks each entry through the sandbox-relative / `.computeunit.
1886    /// yaml`-extension / cross-entry duplicate gates, the
1887    /// [`crate::require_single_servico`] V0 singularity gate every
1888    /// per-Servico renderer entry-point runs through
1889    /// [`crate::require_v0_servico_shape`], the `feira chart` /
1890    /// `feira deploy` per-verb `first_servico_path` walk at
1891    /// caixa-feira/src/cmd/chart.rs that resolves the singleton
1892    /// ComputeUnit-CR file, every future per-`Caixa` Servico-facing
1893    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1894    /// per-Servico OCI packager, the future M4
1895    /// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer, the future
1896    /// per-Servico OTel collector-config emit).
1897    ///
1898    /// Prior to this lift the `.servicos` field was accessed inline at
1899    /// five production sites — the compound-code-path `has_code =
1900    /// !caixa.bibliotecas().is_empty() || !caixa.exe().is_empty() ||
1901    /// !caixa.servicos.is_empty()` OR-fold on the
1902    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1903    /// `AplicacaoOwnsCode` kind-coherence gate, the Servico-arm
1904    /// `caixa.servicos.is_empty()`
1905    /// [`crate::LayoutError::ServicoWithoutServicos`] gate, the
1906    /// per-entry `for p in &caixa.servicos`
1907    /// `MissingEntry`/`ServicoOutsideDir` walk, the
1908    /// [`Self::declared_foreign_code_slots`]'s
1909    /// `!self.servicos.is_empty()` arm on the `ForeignCodeSlot` gate,
1910    /// and the [`crate::require_single_servico`] V0 count gate's
1911    /// `caixa.servicos.len() == 1` / `caixa.servicos.len()` count
1912    /// projection (both the accept-arm predicate and the
1913    /// diagnostic-carrying `ServicoCountMismatch { count }`
1914    /// projection) — five open-coded field-accesses across three
1915    /// crates that expressed no compile-time link back to the typed
1916    /// slot. A future extension of the `:servicos` axis to a richer
1917    /// component surface — a per-`:servicos` structured
1918    /// `ServicoEntry { path, world, capabilities }` at the storage
1919    /// layer once the substrate absorbs the per-component WIT-world +
1920    /// capability-set tuple the CAIXA-SDLC §I Servico roadmap
1921    /// acknowledges, a per-registry `:servicos` allowlist the M4 CR
1922    /// materializer enforces per-CR (the "cluster policy demands every
1923    /// Servico declare an explicit `:world`" arm), a promotion of the
1924    /// plain `Vec<String>` byte-string list to a richer
1925    /// `Vec<ComputeUnitPath>` newtype discriminated on the
1926    /// `servicos/<nome>.computeunit.yaml`-shape grammar the layout's
1927    /// `starts_with(servicos_dir)` fence and the
1928    /// [`crate::render::is_computeunit_yaml_extension`] predicate
1929    /// already resolve through, a promotion of the V0 singleton
1930    /// contract to a multi-component `Vec<ComputeUnitPath>` past the M5
1931    /// component-model multi-world boundary — would have had to be
1932    /// threaded through all five open-coded copies in lockstep or the
1933    /// layout gate, the shape validator, the V0 count gate, and the
1934    /// `feira chart` / `feira deploy` entry-point walks would silently
1935    /// disagree on which ComputeUnit-CR paths a given [`Caixa`]
1936    /// resolves to (an author's `:servicos ("servicos/foo.computeunit.
1937    /// yaml")` would satisfy layout while `feira chart` silently
1938    /// packaged a drifted other list, or vice versa). Lifting the
1939    /// resolution to a typed method on the substrate primitive means
1940    /// every downstream consumer of the caixa's per-`Caixa`
1941    /// ComputeUnit-CR-source surface reaches for exactly one typed
1942    /// dispatch — the resolver's accept-set migrates as a unit on any
1943    /// future axis addition.
1944    ///
1945    /// Fifth and final outer top-level [`Caixa`] `&[T]`-return slice-
1946    /// accessor — folds on the "outer [`Caixa`] `&[T]` slice"
1947    /// projection pattern [`Self::autores`] (b5d813f) opened,
1948    /// [`Self::etiquetas`] (78c7d3c) folded on, [`Self::bibliotecas`]
1949    /// (8a36c23) closed the universal-axis text-tag family of, and
1950    /// [`Self::exe`] (65d9527) opened the foreign-code-slot sub-family
1951    /// of. Closes the outer-`Caixa` foreign-code-slot `&[T]` sub-family
1952    /// — with `:bibliotecas`, `:exe`, and `:servicos` now each carrying
1953    /// a substrate-canonical slice accessor, the trio of code-surface
1954    /// list slots the [`Self::validate_code_paths`] per-slot dispatch
1955    /// tuple carries is complete on the typed dispatch surface (the
1956    /// internal `[(":bibliotecas", &self.bibliotecas, ..), (":exe",
1957    /// &self.exe, ..), (":servicos", &self.servicos, ..)]` per-slot
1958    /// dispatch tuple's homogeneous `&Vec<String>`-typed shape blocks a
1959    /// per-element accessor swap in isolation — a future companion lift
1960    /// promotes the tuple's element type to `&[String]` and threads the
1961    /// triple of typed dispatches through as a unit). Sibling in shape
1962    /// to the peer per-`:supervisor`
1963    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1964    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1965    /// (a6e18d7), per-`:membros`
1966    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1967    /// per-`:contratos`
1968    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1969    /// per-`:upgrade-from :instructions`
1970    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1971    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1972    /// typed-slot list axes, extended here to the outer top-level
1973    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1974    /// `&Vec<String>`) because every downstream consumer of the
1975    /// ComputeUnit-CR-source list treats it as a read-only sequence —
1976    /// the slice-view is the narrowest borrow that supports every
1977    /// present + roadmapped consumer (`.iter()`, `.len()`,
1978    /// `.is_empty()`, `.first()`) without leaking the backing `Vec`'s
1979    /// grow/push/reserve surface no consumer of the typed view reaches
1980    /// for (the storage-side `Vec` remains reachable through the
1981    /// `pub servicos` field for the mutation-carrying serde round-trip
1982    /// and per-test fixture-mutation paths, and for the
1983    /// [`Self::validate_code_paths`] per-slot dispatch tuple whose
1984    /// homogeneous-element-type shape carries the raw field access
1985    /// until the trio-closure lift promotes the tuple as a unit).
1986    /// Named `servicos()` to match the storage field's name; the
1987    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1988    /// vocabulary the slot's docstring already carries.
1989    #[must_use]
1990    pub fn servicos(&self) -> &[String] {
1991        self.servicos.as_slice()
1992    }
1993
1994    /// Substrate-canonical per-`Caixa` `:deps` universal-axis
1995    /// runtime-dependency-declaration-list slice-accessor every consumer
1996    /// of the top-level manifest's runtime-dep-graph axis keys off —
1997    /// returns the author-declared `:deps` list verbatim as a `&[Dep]`
1998    /// slice-view over the same backing buffer the raw
1999    /// `self.deps.as_slice()` field access borrows from. Empty-list-
2000    /// carrying (`:deps` is a default-empty axis every `defcaixa` form
2001    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
2002    /// derive folds an omitted `:deps` through `#[serde(default)]` to
2003    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
2004    /// `Vec<Dep>` slot — possibly empty — and the returned `&[Dep]`
2005    /// degenerates to an empty slice on that arm without any silent
2006    /// `None` collapse).
2007    ///
2008    /// The `:deps` slot carries the universal-axis runtime dependency
2009    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
2010    /// facing surface every `defcaixa` form supplies alongside `:nome` /
2011    /// `:versao` / `:kind`; the substrate-wide runtime-closure-input axis
2012    /// every downstream resolver-facing artifact emits under) — the
2013    /// typed slot's `Vec<Dep>` accept-set (empty-`:nome` rejected through
2014    /// [`DepError::NomeEmpty`], non-DNS-1123-label `:nome` rejected
2015    /// through [`DepError::NomeInvalid`], malformed `:versao` rejected
2016    /// through [`DepError::VersaoInvalid`], empty `:fonte.repo` rejected
2017    /// through [`DepError::FonteRepoEmpty`], within-list duplicate `:nome`
2018    /// rejected through [`DepError::DuplicateNome { list: ":deps" }`])
2019    /// maps onto every load-bearing downstream consumer the substrate
2020    /// carries — the [`Self::validate_deps`] per-entry
2021    /// [`Dep::validate`] + within-list dedup walk at
2022    /// caixa-core/src/manifest.rs, the [`crate::dep::validate_no_self_dep`]
2023    /// cross-list self-reference gate at caixa-core/src/layout.rs that
2024    /// checks each entry against the caixa's own `:nome`, the
2025    /// caixa-resolver `for dep in &root.deps` closure walk at
2026    /// caixa-resolver/src/resolve.rs that seeds every git-clone target
2027    /// through the resolver's [`crate::Dep`]-keyed pipeline, the
2028    /// caixa-crd `caixa.deps.iter().map(dep_into_ref).collect()` fold at
2029    /// caixa-crd/src/conversion.rs that materializes each entry into the
2030    /// K8s `Caixa` CR's `spec.deps` field, every future per-`Caixa`
2031    /// resolver-facing renderer the CAIXA-SDLC §I roadmap acknowledges
2032    /// (the future per-cluster runtime-closure-audit overlay the M4 CR
2033    /// materializer resolves per-CR, the future `lacre.lisp` BLAKE3-
2034    /// closure emit walk the caixa-resolver docstring roadmaps).
2035    ///
2036    /// First outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2037    /// opens the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2038    /// sibling `:deps-dev` future lift closes on. Peer of the closed
2039    /// outer-`Caixa` foreign-code-slot `&[String]` sub-family
2040    /// ([`Self::bibliotecas`] 8a36c23, [`Self::exe`] 65d9527,
2041    /// [`Self::servicos`] 611f78b) and the outer-`Caixa` universal-axis
2042    /// text-tag family ([`Self::autores`] b5d813f, [`Self::etiquetas`]
2043    /// 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice" projection
2044    /// pattern onto a novel element-type axis (`Dep` composite vs the
2045    /// prior sibling family's `String` scalar). Sibling in shape to the
2046    /// peer per-`:supervisor`
2047    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2048    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2049    /// (a6e18d7), per-`:membros`
2050    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2051    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
2052    /// (0dcc926), and per-`:upgrade-from :instructions`
2053    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2054    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2055    /// typed-slot list axes, extended here to the outer top-level
2056    /// [`Caixa`] universal-axis dep-graph surface. Returns `&[Dep]`
2057    /// (not `&Vec<Dep>`) because every downstream consumer of the
2058    /// runtime-dep list treats it as a read-only sequence — the slice-
2059    /// view is the narrowest borrow that supports every present +
2060    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2061    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2062    /// of the typed view reaches for (the storage-side `Vec` remains
2063    /// reachable through the `pub deps` field for the mutation-carrying
2064    /// serde round-trip and per-test fixture-mutation paths). Named
2065    /// `deps()` to match the storage field's name; the accessor's
2066    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
2067    /// slot's docstring already carries.
2068    #[must_use]
2069    pub fn deps(&self) -> &[Dep] {
2070        self.deps.as_slice()
2071    }
2072
2073    /// Substrate-canonical per-`Caixa` `:deps-dev` universal-axis
2074    /// development-only-dependency-declaration-list slice-accessor every
2075    /// consumer of the top-level manifest's dev-dep-graph axis keys off —
2076    /// returns the author-declared `:deps-dev` list verbatim as a `&[Dep]`
2077    /// slice-view over the same backing buffer the raw
2078    /// `self.deps_dev.as_slice()` field access borrows from. Empty-list-
2079    /// carrying (`:deps-dev` is a default-empty axis every `defcaixa`
2080    /// form supplies with an empty `()` when unset; the
2081    /// [`Self::from_lisp`] derive folds an omitted `:deps-dev` through
2082    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
2083    /// definitionally carries a `Vec<Dep>` slot — possibly empty — and
2084    /// the returned `&[Dep]` degenerates to an empty slice on that arm
2085    /// without any silent `None` collapse).
2086    ///
2087    /// The `:deps-dev` slot carries the universal-axis dev-only
2088    /// dependency list every kind of caixa emits under (CAIXA-SDLC §I —
2089    /// the author-facing sibling of `:deps` that every `defcaixa` form
2090    /// supplies to declare tests / lint / bench closures the runtime
2091    /// `:deps` axis does not carry; the substrate-wide dev-closure-input
2092    /// axis every downstream test-facing artifact emits under, matching
2093    /// Cargo's `[dev-dependencies]` table's dev-time-only visibility
2094    /// contract) — the typed slot's `Vec<Dep>` accept-set (empty-`:nome`
2095    /// rejected through [`DepError::NomeEmpty`], non-DNS-1123-label
2096    /// `:nome` rejected through [`DepError::NomeInvalid`], malformed
2097    /// `:versao` rejected through [`DepError::VersaoInvalid`], empty
2098    /// `:fonte.repo` rejected through [`DepError::FonteRepoEmpty`],
2099    /// within-list duplicate `:nome` rejected through
2100    /// [`DepError::DuplicateNome { list: ":deps-dev" }`]) maps onto every
2101    /// load-bearing downstream consumer the substrate carries — the
2102    /// [`Self::validate_deps`] per-entry [`Dep::validate`] + within-list
2103    /// dedup walk at caixa-core/src/manifest.rs, the
2104    /// [`crate::dep::validate_no_self_dep`] cross-list self-reference
2105    /// gate at caixa-core/src/layout.rs that checks each entry against
2106    /// the caixa's own `:nome`, the caixa-resolver
2107    /// `for dep in &root.deps_dev` closure walk at
2108    /// caixa-resolver/src/resolve.rs that seeds every dev-only git-clone
2109    /// target through the resolver's [`crate::Dep`]-keyed pipeline, and
2110    /// every future per-`Caixa` resolver-facing renderer the CAIXA-SDLC
2111    /// §I roadmap acknowledges (the future per-cluster dev-closure-audit
2112    /// overlay the M4 CR materializer resolves per-CR, the future
2113    /// `lacre.lisp` BLAKE3-closure emit walk the caixa-resolver docstring
2114    /// roadmaps).
2115    ///
2116    /// Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2117    /// closes the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2118    /// sibling [`Self::deps`] (ad34b4e) opened on. The two accessors
2119    /// jointly close the two-list dep-graph surface every downstream
2120    /// resolver-facing consumer keys off (runtime `:deps` +
2121    /// dev-only `:deps-dev`, the canonical Cargo-shaped dependency-table
2122    /// pair the [`Self::validate_deps`] gate already walks in canonical
2123    /// order). Peer of the closed outer-`Caixa` foreign-code-slot
2124    /// `&[String]` sub-family ([`Self::bibliotecas`] 8a36c23,
2125    /// [`Self::exe`] 65d9527, [`Self::servicos`] 611f78b) and the outer-
2126    /// `Caixa` universal-axis text-tag family ([`Self::autores`]
2127    /// b5d813f, [`Self::etiquetas`] 78c7d3c) — folds the "outer
2128    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
2129    /// dev-dep composite-element axis (`Dep` composite, matching the
2130    /// [`Self::deps`] element type). Sibling in shape to the peer
2131    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
2132    /// (bc92bce), per-`:placement`
2133    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
2134    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
2135    /// (6c77e36), per-`:contratos`
2136    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2137    /// per-`:upgrade-from :instructions`
2138    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2139    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2140    /// typed-slot list axes, folded here to the outer top-level
2141    /// [`Caixa`] universal-axis dev-dep-graph surface. Returns `&[Dep]`
2142    /// (not `&Vec<Dep>`) because every downstream consumer of the
2143    /// dev-dep list treats it as a read-only sequence — the slice-view
2144    /// is the narrowest borrow that supports every present +
2145    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2146    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2147    /// of the typed view reaches for (the storage-side `Vec` remains
2148    /// reachable through the `pub deps_dev` field for the mutation-
2149    /// carrying serde round-trip and per-test fixture-mutation paths).
2150    /// Named `deps_dev()` to match the storage field's `snake_case` name;
2151    /// the kebab-case author-surface tag `:deps-dev` is the same axis
2152    /// after tatara-lisp's kebab↔snake fold and the accessor's identity
2153    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
2154    /// docstring already carries.
2155    #[must_use]
2156    pub fn deps_dev(&self) -> &[Dep] {
2157        self.deps_dev.as_slice()
2158    }
2159
2160    /// Substrate-canonical per-[`Caixa`] typed-dispatch read accessor
2161    /// every consumer that walks one of the two dep-list axes keyed on a
2162    /// [`crate::dep::DepList`] discriminant reaches for — routes the
2163    /// `(list: DepList) -> &[Dep]` projection through one typed method on
2164    /// the substrate primitive rather than the prior open-coded
2165    /// `match list { Prod => caixa.deps(), Dev => caixa.deps_dev() }`
2166    /// inline dispatch every per-axis walker would otherwise carry.
2167    /// Returns the author-declared per-list `Vec<Dep>` verbatim as a
2168    /// `&[Dep]` slice-view over the same backing buffer the sibling
2169    /// [`Self::deps`] (`Prod`) / [`Self::deps_dev`] (`Dev`) per-slot
2170    /// accessors borrow from, preserving the empty-list-carrying invariant
2171    /// each per-slot accessor already establishes (`:deps` / `:deps-dev`
2172    /// are default-empty axes every `defcaixa` form supplies with an empty
2173    /// `()` when unset; the [`Self::from_lisp`] derive folds an omitted
2174    /// list through `#[serde(default)]` to `Vec::new()`, so both arms
2175    /// definitionally carry a `Vec<Dep>` slot — possibly empty — and the
2176    /// returned `&[Dep]` degenerates to an empty slice on either arm
2177    /// without any silent `None` collapse).
2178    ///
2179    /// The [`crate::dep::DepList`] closed-set typed enum is the
2180    /// substrate's canonical discriminator for the "runtime-closure
2181    /// `:deps` vs dev-only-closure `:deps-dev`" axis every dep-list
2182    /// consumer dispatches on — the compiler-checked exhaustiveness on
2183    /// the enum's `match` arms is the build-time guarantee that no future
2184    /// per-list read-site regresses to a bare-`bool`-flag inline dispatch
2185    /// that a future third dep-list axis (a `:deps-build` build-only
2186    /// closure once the substrate grows cross-artifact heterogeneous
2187    /// dep-graphs, per CAIXA-SDLC §I) would silently split at every
2188    /// consumer. Prior to this the read side carried two per-slot
2189    /// accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`]) and no
2190    /// typed dispatch that a per-axis walker could parametrise on, so
2191    /// every per-list walker (the [`Self::validate_deps`] per-list
2192    /// [`crate::render::insert_first_seen`] dedup walk, a future
2193    /// `feira app graph` per-list dep summary, a future M4 per-cluster
2194    /// dev-closure-audit overlay the CR materializer resolves per-CR)
2195    /// open-coded the same two-block "run over `:deps`, then run over
2196    /// `:deps-dev`" pattern — a silent duplication that a future third
2197    /// dep-list axis would have had to grow a third block at every site.
2198    ///
2199    /// Peer of the sibling [`Self::push_dep`] typed-mutation dispatch
2200    /// (359fba5) — closes the two-side dispatch symmetry on the outer
2201    /// [`Caixa`] two-list dep-graph surface: `push_dep` on the mutation
2202    /// side, `deps_of` on the read side, both keyed on the same
2203    /// [`crate::dep::DepList`] discriminator. Same "one typed dispatch on
2204    /// the substrate primitive, thin projections at each consumer"
2205    /// discipline the sibling per-slot read accessors ([`Self::nome`]
2206    /// e6b7d97, [`Self::versao`], [`Self::kind`]) carry — extended onto
2207    /// the outer-[`Caixa`] typed-dispatch read surface.
2208    #[must_use]
2209    pub fn deps_of(&self, list: crate::dep::DepList) -> &[Dep] {
2210        match list {
2211            crate::dep::DepList::Prod => self.deps(),
2212            crate::dep::DepList::Dev => self.deps_dev(),
2213        }
2214    }
2215
2216    /// Substrate-canonical per-[`Caixa`] typed-mutation dispatch every
2217    /// consumer that appends to one of the two dep-list axes keys off
2218    /// — routes the `(list: DepList, dep: Dep)` tuple through one typed
2219    /// method on the substrate primitive rather than the prior
2220    /// `feira add`-side open-coded `if self.dev { &mut caixa.deps_dev }
2221    /// else { &mut caixa.deps }` inline dispatch + open-coded
2222    /// `.iter().any(|d| d.nome == …)` dup-check cascade. Refuses the
2223    /// mutation with the canonical typed [`DepError::DuplicateNome`] on
2224    /// a within-list name collision — the same `list: &'static str`
2225    /// diagnostic shape [`Self::validate_deps`]'s per-list
2226    /// [`crate::render::insert_first_seen`] walk raises on the peer
2227    /// parse-time within-list dedup axis, so a future author reading a
2228    /// `feira add` refusal and a `feira build` refusal reaches for the
2229    /// same corrective surface without switching diagnostic idioms.
2230    ///
2231    /// The two-arm [`crate::dep::DepList`] enum is the substrate's
2232    /// closed-set typed carrier for the "runtime-closure `:deps` vs
2233    /// dev-only-closure `:deps-dev`" axis every dep-list consumer
2234    /// dispatches on — the compiler-checked exhaustiveness on the
2235    /// enum's `match` arms is the build-time guarantee that no future
2236    /// per-list mutation-site regresses to a bare-`bool`-flag
2237    /// (`is_dev: bool`) inline dispatch that a future third
2238    /// dep-list axis (a `:deps-build` build-only closure once the
2239    /// substrate grows cross-artifact heterogeneous dep-graphs, per
2240    /// CAIXA-SDLC §I) would silently split at every consumer.
2241    ///
2242    /// Same "one typed dispatch on the substrate primitive, thin
2243    /// projections at each consumer" discipline the sibling per-slot
2244    /// read accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`],
2245    /// [`Self::nome`] e6b7d97, [`Self::versao`], [`Self::kind`])
2246    /// carry — extended onto the outer-[`Caixa`] typed-mutation surface,
2247    /// the substrate's first typed-mutation dispatch on the top-level
2248    /// manifest. The prior `feira add` open-coded `&mut caixa.deps` /
2249    /// `&mut caixa.deps_dev` inline field-access + `bail!` string-
2250    /// diagnostic path routed no through-line back to the typed slot,
2251    /// so a future extension of either dep-list axis to a richer author
2252    /// surface (a per-cluster override the operator pins through a
2253    /// future `:placement`-scoped dep-list slot the CAIXA-SDLC §I
2254    /// roadmap acknowledges, an M4
2255    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
2256    /// admission-webhook that normalized the list at admission time)
2257    /// would have had to be threaded through the `feira add` mutation
2258    /// site in lockstep with every read consumer or one path would
2259    /// silently disagree with the other on which list a given dep lands
2260    /// in. Lifting the resolution rule to a typed method on the
2261    /// substrate primitive means every downstream dep-list-mutating
2262    /// consumer of the top-level manifest reaches for exactly one typed
2263    /// dispatch — the resolver's accept-set migrates as a unit on any
2264    /// future axis addition.
2265    ///
2266    /// # Errors
2267    ///
2268    /// Returns [`DepError::DuplicateNome`] with `list = list.as_str()`
2269    /// when another entry in the same list already carries the same
2270    /// `:nome` — the mutation is refused and the caller can surface the
2271    /// typed diagnostic to the author (the `feira add` verb routes the
2272    /// error through `anyhow::Error::from`, which preserves the
2273    /// canonical `#[error(...)]`-templated diagnostic body).
2274    pub fn push_dep(&mut self, list: crate::dep::DepList, dep: Dep) -> Result<(), DepError> {
2275        let target = match list {
2276            crate::dep::DepList::Prod => &mut self.deps,
2277            crate::dep::DepList::Dev => &mut self.deps_dev,
2278        };
2279        if target.iter().any(|d| d.nome() == dep.nome()) {
2280            return Err(DepError::DuplicateNome {
2281                nome: dep.nome().to_string(),
2282                list: list.as_str(),
2283            });
2284        }
2285        target.push(dep);
2286        Ok(())
2287    }
2288
2289    /// Substrate-canonical per-`Caixa` `:limits` M2 typed-slot outer-
2290    /// composite Lunatic-per-process wasm32-sandboxing-composite optional-
2291    /// composite-reference accessor every consumer of the top-level
2292    /// manifest's per-Servico [`LimitsSpec`] outer-composite reader keys
2293    /// off — returns the author-declared `:limits` typed composite
2294    /// verbatim as an `Option<&LimitsSpec>` reference over the same
2295    /// backing storage the raw `self.limits.as_ref()` field access
2296    /// borrows from, with `None` naming the "no `:limits` block
2297    /// authored — every per-axis Lunatic-sandbox cap defers to the
2298    /// wasm-engine-default arm named on the per-axis
2299    /// [`LimitsSpec::memory`] / [`LimitsSpec::fuel`] /
2300    /// [`LimitsSpec::wall_clock`] / [`LimitsSpec::cpu`] scalar-accessor
2301    /// docstrings" partition every downstream Servico-M2-overlay
2302    /// emitter treats as "emit nothing" and the sibling
2303    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate
2304    /// treats as "skip the per-axis
2305    /// [`crate::LimitsError::MemoryZero`] / `MemoryBelowWasm32Page` /
2306    /// `FuelZero` / `WallClockZero` / `CpuZero` refusal cascade".
2307    ///
2308    /// The outer `:limits` slot carries the M2 Servico-runtime typed
2309    /// composite — the load-bearing container of every Lunatic-shaped
2310    /// per-process wasm32-sandbox cap axis every long-running wasm
2311    /// component's runtime dispatches on (INSPIRATIONS §III.1 —
2312    /// Lunatic per-process linear-memory / fuel / wall-clock /
2313    /// millicore cap primitives translated onto pleme-io's typed
2314    /// `:limits :memory` / `:limits :fuel` / `:limits :wall-clock` /
2315    /// `:limits :cpu` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2316    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2317    /// chart both fan on). Every per-`:limits` axis threads through a
2318    /// lifted per-slot accessor on the [`LimitsSpec`] type: the
2319    /// [`LimitsSpec::memory`] wasm32 linear-memory byte-cap scalar
2320    /// accessor, the [`LimitsSpec::fuel`] wasmtime fuel-cap scalar
2321    /// accessor, the [`LimitsSpec::wall_clock`] per-call wall-clock
2322    /// deadline scalar accessor, and the [`LimitsSpec::cpu`]
2323    /// K8s-millicore soft-CPU-share scalar accessor. Every downstream
2324    /// consumer that reaches for a limits axis first passes through
2325    /// this outer accessor onto the composite and then dispatches
2326    /// onto the per-axis accessor — the two-level dispatch means
2327    /// every per-`:limits` reader now routes through a typed dispatch
2328    /// on the substrate primitive at both altitudes.
2329    ///
2330    /// Prior to this lift the `.limits` `Option<LimitsSpec>` composite
2331    /// was accessed inline at three production sites — the
2332    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate's
2333    /// `if let Some(l) = &caixa.limits { … }` traversal head
2334    /// (caixa-core/src/layout.rs:882, which drives the per-axis
2335    /// refusal cascade on the composite: the `LimitsError::MemoryZero`
2336    /// / `MemoryBelowWasm32Page` / `MemoryExceedsWasm32Max` /
2337    /// `FuelZero` / `FuelExceedsMax` / `WallClockZero` /
2338    /// `WallClockExceedsMax` / `CpuZero` / `CpuExceedsMax` refusals
2339    /// [`LimitsSpec::validate`] fans onto), the
2340    /// [`crate::render::servico_m2_overlay`] per-Servico M2 overlay
2341    /// emitter's `if let Some(limits) = &caixa.limits { … }` traversal
2342    /// head (caixa-core/src/render.rs:18504, which drives the
2343    /// `M2_KEY_LIMITS`-keyed `limits.is_empty()`-gated `serde_yaml`
2344    /// projection every `caixa-helm` / `caixa-flux` Servico values-
2345    /// block emitter fans on), and the
2346    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2347    /// set enumerator's `self.limits.is_some()` presence probe
2348    /// (caixa-core/src/manifest.rs:1788, which drives the
2349    /// `M2_AUTHOR_KEY_LIMITS` kebab-case author-label push every
2350    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2351    /// gate reads) — three open-coded outer-field accesses that
2352    /// expressed no compile-time link back to the typed slot at the
2353    /// [`Caixa`] altitude. A future extension of the `:limits` outer
2354    /// axis to a richer author surface (a multi-`:limits` list the M4
2355    /// CR materializer resolves per-CR at admission time so a Servico
2356    /// can expose a compute-heavy + IO-heavy limits pair, a per-
2357    /// cluster `:limits-overrides` slot the operator pins so a
2358    /// cluster-specific policy can tighten a caixa-declared cap
2359    /// without re-authoring the `caixa.lisp`, a promotion of the
2360    /// plain `Option<LimitsSpec>` to a richer
2361    /// `{static, dynamic}` partition once the wasm-engine's runtime-
2362    /// resolved dynamic-cap surface lands) would have had to be
2363    /// threaded through all three open-coded copies in lockstep or
2364    /// one consumer would silently disagree with the peers on which
2365    /// limits composite a given Caixa resolves to — the layout gate's
2366    /// per-axis bracket-dispatch seed reading the raw slot while the
2367    /// peer `servico_m2_overlay` emitter read an operator-resolved
2368    /// slot would silently split the build-time sandbox-shape gate
2369    /// from the runtime `ComputeUnit` CR emission gate, a three-
2370    /// consumer split at the layout gate, the M2 overlay emitter, and
2371    /// the declared-slot enumerator far from the source `caixa.lisp`
2372    /// with no field naming the limits-drift root cause. Lifting the
2373    /// resolution rule to a typed method on the substrate primitive
2374    /// means every downstream consumer of the caixa's per-`Caixa`
2375    /// Lunatic-sandboxing outer-composite surface reaches for exactly
2376    /// one typed dispatch — the resolver's accept-set migrates as a
2377    /// unit on any future axis addition.
2378    ///
2379    /// First outer top-level [`Caixa`] `Option<&Composite>`-return
2380    /// composite-reference accessor — opens the outer-`Caixa`
2381    /// `Option<&Composite>` composite-reference projection pattern the
2382    /// sibling per-`Caixa` `:behavior` [`crate::BehaviorSpec`] /
2383    /// `:politicas` [`crate::aplicacao::MeshPolicy`] / `:placement`
2384    /// [`crate::aplicacao::Placement`] / `:entrada`
2385    /// [`crate::aplicacao::Entrada`] future outer-composite lifts
2386    /// fold on. Peer of the M3 mesh-slot outer-composite family the
2387    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2388    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2389    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2390    /// accessors already close on the outer [`crate::AplicacaoSpec`]
2391    /// altitude — extends that "one typed dispatch on the substrate
2392    /// primitive, thin projections at each consumer" discipline onto
2393    /// the outer top-level [`Caixa`] altitude, opening the M2 Servico-
2394    /// runtime slot family's outer-composite axis. Returns
2395    /// `Option<&LimitsSpec>` (not the owning composite by copy or
2396    /// clone) because every downstream consumer of the limits
2397    /// composite treats it as a read-only per-axis dispatch source —
2398    /// the reference-view is the narrowest borrow that supports every
2399    /// present + roadmapped consumer (per-axis accessor dispatch,
2400    /// `.is_empty()`-gated overlay projection, presence-probe early
2401    /// return on the "author-omitted `:limits` ⇒ engine-default
2402    /// applies" partition) without cloning the composite through
2403    /// every consumer's fast path. The `Option` half of the return-
2404    /// type preserves the load-bearing "author-omitted `:limits` ⇒
2405    /// engine-default applies" partition (not a default composite the
2406    /// downstream must reject on emptiness) — the accessor projects
2407    /// the raw `Option<LimitsSpec>` slot's presence bit through the
2408    /// reference-return unchanged. Named `limits()` to match the
2409    /// storage field's name verbatim and the tatara-lisp author-
2410    /// surface term (`:limits`) the field's own docstring already
2411    /// carries.
2412    #[must_use]
2413    pub fn limits(&self) -> Option<&LimitsSpec> {
2414        self.limits.as_ref()
2415    }
2416
2417    /// Substrate-canonical per-`Caixa` `:behavior` M2 typed-slot outer-
2418    /// composite OTP-`gen_server`-shaped callback-table optional-
2419    /// composite-reference accessor every consumer of the top-level
2420    /// manifest's per-Servico [`BehaviorSpec`] outer-composite reader
2421    /// keys off — returns the author-declared `:behavior` typed
2422    /// composite verbatim as an `Option<&BehaviorSpec>` reference over
2423    /// the same backing storage the raw `self.behavior.as_ref()` field
2424    /// access borrows from, with `None` naming the "no `:behavior`
2425    /// block authored — every per-callback OTP-shaped hook defers to
2426    /// the wasm-engine's runtime default arm named on the per-axis
2427    /// [`BehaviorSpec::on_init`] / [`BehaviorSpec::on_call`] /
2428    /// [`BehaviorSpec::on_cast`] / [`BehaviorSpec::on_info`] /
2429    /// [`BehaviorSpec::on_state_change`] /
2430    /// [`BehaviorSpec::on_terminate`] scalar-accessor docstrings"
2431    /// partition every downstream Servico-M2-overlay emitter treats as
2432    /// "emit nothing" and the sibling [`crate::StandardLayout::verify`]
2433    /// per-`:behavior` shape gate treats as "skip the per-arm
2434    /// [`crate::behavior::BehaviorError`] refusal cascade + the
2435    /// per-callback on-disk `MissingEntry` existence check".
2436    ///
2437    /// The outer `:behavior` slot carries the M2 Servico-runtime typed
2438    /// composite — the load-bearing container of every OTP-shaped
2439    /// per-Servico lifecycle-callback path axis every long-running wasm
2440    /// component's runtime dispatches on (INSPIRATIONS §II.3 — Erlang/
2441    /// OTP `gen_server:init/1` / `handle_call/3` / `handle_cast/2` /
2442    /// `handle_info/2` / `code_change/3` / `terminate/2` primitives
2443    /// translated onto pleme-io's typed `:behavior :on-init` /
2444    /// `:on-call` / `:on-cast` / `:on-info` / `:on-state-change` /
2445    /// `:on-terminate` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2446    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2447    /// chart both fan on). Every per-`:behavior` axis threads through a
2448    /// lifted per-callback accessor on the [`BehaviorSpec`] type
2449    /// (9b4ecde / d66c702 / 156ddbe / 99616ac / 4846cef / 701add7).
2450    /// Every downstream consumer that reaches for a behavior axis
2451    /// first passes through this outer accessor onto the composite
2452    /// and then dispatches onto the per-callback accessor — the
2453    /// two-level dispatch means every per-`:behavior` reader now
2454    /// routes through a typed dispatch on the substrate primitive at
2455    /// both altitudes.
2456    ///
2457    /// Composes cross-slot with the M2 `:upgrade-from` gate: the
2458    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
2459    /// cross-slot composition gate at [`crate::StandardLayout::verify`]
2460    /// keys the "per-version `:state-change` instruction must have a
2461    /// `:on-state-change` callback" precondition off this accessor's
2462    /// composite (the callback-side counterpart to the
2463    /// `:upgrade-from :instructions :state-change :script` refusal at
2464    /// the appup-side). Threading that gate's traversal input through
2465    /// this accessor closes the cross-slot invariant on the substrate
2466    /// primitive, not on the raw field.
2467    ///
2468    /// Prior to this lift the `.behavior` `Option<BehaviorSpec>`
2469    /// composite was accessed inline at four production sites — the
2470    /// [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
2471    /// `if let Some(b) = &caixa.behavior { … }` traversal head
2472    /// (caixa-core/src/layout.rs:896, which drives the per-arm
2473    /// `BehaviorError` refusal cascade + the per-callback on-disk
2474    /// [`crate::LayoutError::MissingEntry`] existence check under
2475    /// [`crate::render::LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`]),
2476    /// the [`crate::upgrade::validate_upgrade_from_against_behavior`]
2477    /// cross-slot composition gate's `caixa.behavior.as_ref()`
2478    /// traversal-input feed (caixa-core/src/layout.rs:1008, which
2479    /// drives the `:state-change` ↔ `:on-state-change` precondition
2480    /// refusal), the [`crate::render::servico_m2_overlay`] per-Servico
2481    /// M2 overlay emitter's `if let Some(behavior) = &caixa.behavior
2482    /// { … }` traversal head (caixa-core/src/render.rs:18513, which
2483    /// drives the `M2_KEY_BEHAVIOR`-keyed `behavior.is_empty()`-gated
2484    /// `serde_yaml` projection every `caixa-helm` / `caixa-flux`
2485    /// Servico values-block emitter fans on), and the
2486    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2487    /// set enumerator's `self.behavior.is_some()` presence probe
2488    /// (caixa-core/src/manifest.rs:1919, which drives the
2489    /// `M2_AUTHOR_KEY_BEHAVIOR` kebab-case author-label push every
2490    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2491    /// gate reads) — four open-coded outer-field accesses that
2492    /// expressed no compile-time link back to the typed slot at the
2493    /// [`Caixa`] altitude. A future extension of the `:behavior`
2494    /// outer axis to a richer author surface (a per-callback overlay
2495    /// resolver the operator materializes at admission time so a
2496    /// cluster-specific policy can inject a per-callback tracing
2497    /// interceptor without re-authoring the `caixa.lisp`, a promotion
2498    /// of the plain `Option<BehaviorSpec>` to a richer `{static,
2499    /// dynamic}` partition once a runtime-resolved behavior-swap
2500    /// surface lands, the M4 per-callback middleware chain the
2501    /// caixa-operator's per-Servico admission webhook keys off) would
2502    /// have had to be threaded through all four open-coded copies in
2503    /// lockstep or one consumer would silently disagree with the
2504    /// peers on which behavior composite a given Caixa resolves to —
2505    /// the layout gate's per-callback existence-check seed reading
2506    /// the raw slot while the peer `servico_m2_overlay` emitter read
2507    /// an operator-resolved slot would silently split the build-time
2508    /// callback-shape gate from the runtime `ComputeUnit` CR emission
2509    /// gate from the cross-slot `:state-change` composition gate from
2510    /// the M2 declared-slot enumerator, a four-consumer split far
2511    /// from the source `caixa.lisp` with no field naming the
2512    /// behavior-drift root cause. Lifting the resolution rule to a
2513    /// typed method on the substrate primitive means every downstream
2514    /// consumer of the caixa's per-`Caixa` OTP-callback-table outer-
2515    /// composite surface reaches for exactly one typed dispatch — the
2516    /// resolver's accept-set migrates as a unit on any future axis
2517    /// addition.
2518    ///
2519    /// Second outer top-level [`Caixa`] `Option<&Composite>`-return
2520    /// composite-reference accessor — sibling to the opening
2521    /// [`Self::limits`] (b2bd9d7) accessor on the outer-`Caixa`
2522    /// `Option<&Composite>` composite-reference sub-family, extends
2523    /// the "one typed dispatch on the substrate primitive, thin
2524    /// projections at each consumer" discipline onto the second of
2525    /// the three M2 Servico-runtime slots. The remaining
2526    /// `Option<&Composite>` axes at the outer top-level [`Caixa`]
2527    /// altitude — the M3 mesh-slot family (`:politicas`,
2528    /// `:placement`, `:entrada` — already closed on the inner
2529    /// [`crate::AplicacaoSpec`] altitude via 534dc21 / 9abb8f0 /
2530    /// d32111c) — remain the future sibling lifts on the outer
2531    /// top-level projection. Returns `Option<&BehaviorSpec>` (not
2532    /// the owning composite by copy or clone) because every
2533    /// downstream consumer of the behavior composite treats it as a
2534    /// read-only per-callback dispatch source — the reference-view is
2535    /// the narrowest borrow that supports every present + roadmapped
2536    /// consumer (per-callback accessor dispatch, `.is_empty()`-gated
2537    /// overlay projection, presence-probe early return on the
2538    /// "author-omitted `:behavior` ⇒ runtime-default applies"
2539    /// partition, cross-slot `:state-change` composition input)
2540    /// without cloning the composite through every consumer's fast
2541    /// path. The `Option` half of the return-type preserves the
2542    /// load-bearing "author-omitted `:behavior` ⇒ runtime-default
2543    /// applies" partition (not a default composite the downstream
2544    /// must reject on emptiness) — the accessor projects the raw
2545    /// `Option<BehaviorSpec>` slot's presence bit through the
2546    /// reference-return unchanged. Named `behavior()` to match the
2547    /// storage field's name verbatim and the tatara-lisp author-
2548    /// surface term (`:behavior`) the field's own docstring already
2549    /// carries.
2550    #[must_use]
2551    pub fn behavior(&self) -> Option<&crate::BehaviorSpec> {
2552        self.behavior.as_ref()
2553    }
2554
2555    /// Substrate-canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
2556    /// composite MESH-COMPOSITION-shaped mesh-policy optional-composite-
2557    /// reference accessor every consumer of the top-level manifest's
2558    /// per-Aplicacao [`crate::aplicacao::MeshPolicy`] outer-composite
2559    /// reader keys off — returns the author-declared `:politicas` typed
2560    /// composite verbatim as an `Option<&MeshPolicy>` reference over the
2561    /// same backing storage the raw `self.politicas.as_ref()` field
2562    /// access borrows from, with `None` naming the "no `:politicas`
2563    /// block authored — every per-axis mesh-policy scalar defers to the
2564    /// cluster-default arm named on the per-axis
2565    /// [`crate::aplicacao::MeshPolicy::timeout`] /
2566    /// [`crate::aplicacao::MeshPolicy::retries`] /
2567    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] /
2568    /// [`crate::aplicacao::MeshPolicy::mtls_required`] /
2569    /// [`crate::aplicacao::MeshPolicy::rate_limit`] scalar-accessor
2570    /// docstrings" partition every downstream caixa-mesh /
2571    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2572    /// "emit no per-`:politicas` overlay" and the sibling
2573    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2574    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2575    /// arm.
2576    ///
2577    /// The outer `:politicas` slot carries the M3 mesh-slot per-
2578    /// Aplicacao typed composite — the load-bearing container of every
2579    /// mesh-level policy axis every Cilium NetworkPolicy / Gateway API
2580    /// v1.x HTTPRoute / future M4 per-edge policy overlay emitter fans
2581    /// on (MESH-COMPOSITION §III.2 — the Aplicacao's typed mesh-policy
2582    /// composite; §V — the "no infinite blocking" per-call deadline +
2583    /// "sandboxing-by-default" mTLS-enforcement CSE invariants; §III.3
2584    /// — the typed inter-Servico contrato-edge overlay the per-`(:de,
2585    /// :para)` mesh renderer keys off). Every per-`:politicas` axis
2586    /// threads through a lifted per-slot accessor on the
2587    /// [`crate::aplicacao::MeshPolicy`] type: the
2588    /// [`crate::aplicacao::MeshPolicy::mtls_required`] (c0110f1) Cilium
2589    /// mTLS-enforcement toggle, the
2590    /// [`crate::aplicacao::MeshPolicy::retries`] (bdfb399) transient-
2591    /// failure retry budget, the [`crate::aplicacao::MeshPolicy::timeout`]
2592    /// (7073d0f) Gateway-API per-call deadline, the
2593    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] (b0e741a)
2594    /// Envoy-outlier-detection composite. Every downstream consumer
2595    /// that reaches for a mesh-policy axis first passes through this
2596    /// outer accessor onto the composite and then dispatches onto the
2597    /// per-axis accessor — the two-level dispatch means every per-
2598    /// `:politicas` reader now routes through a typed dispatch on the
2599    /// substrate primitive at both altitudes.
2600    ///
2601    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2602    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2603    /// author-omitted arm onto the [`crate::aplicacao::MeshPolicy::default`]
2604    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::politicas`]
2605    /// (534dc21) `&MeshPolicy`-return accessor observes a typed
2606    /// composite whether or not the author declared the outer slot.
2607    /// The outer accessor preserves the "author-omitted vs authored-
2608    /// empty" partition the inner accessor's `is_empty()`-gated
2609    /// renderer overlay collapses — routing the presence bit through
2610    /// this accessor keeps the [`Self::declared_mesh_slots`] M3 kind-
2611    /// coherence enumerator's `M3_AUTHOR_KEY_POLITICAS` push separate
2612    /// from the inner `MeshPolicy::is_empty()`-gated overlay elision.
2613    ///
2614    /// Prior to this lift the `.politicas` `Option<MeshPolicy>`
2615    /// composite was accessed inline at two production sites — the
2616    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2617    /// `self.politicas.clone().unwrap_or_default()` traversal head
2618    /// (caixa-core/src/manifest.rs:1899, which drives the fold onto
2619    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2620    /// arm the inner [`crate::AplicacaoSpec::politicas`] accessor
2621    /// then observes), and the [`Self::declared_mesh_slots`] M3
2622    /// declared-slot-set enumerator's `self.politicas.is_some()`
2623    /// presence probe (caixa-core/src/manifest.rs:1961, which drives
2624    /// the `M3_AUTHOR_KEY_POLITICAS` kebab-case author-label push
2625    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2626    /// coherence gate reads) — two open-coded outer-field accesses
2627    /// that expressed no compile-time link back to the typed slot at
2628    /// the [`Caixa`] altitude. A future extension of the `:politicas`
2629    /// outer axis to a richer author surface (a per-cluster
2630    /// `:politicas-overrides` slot the operator materializes at
2631    /// admission time so a cluster-specific policy can tighten the
2632    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2633    /// promotion of the plain `Option<MeshPolicy>` to a richer
2634    /// `{static, dynamic}` partition once the M4 per-edge
2635    /// contrato-scoped policy-override surface lands, the M5 traffic-
2636    /// shaping composition the caixa-operator's per-Aplicacao mesh
2637    /// admission webhook keys off) would have had to be threaded
2638    /// through both open-coded copies in lockstep or the Aplicacao-
2639    /// composition seed's default-fold arm would silently disagree
2640    /// with the M3 declared-slot enumerator on which policy composite
2641    /// a given Caixa resolves to — the seed reading an operator-
2642    /// resolved slot while the enumerator's presence probe read the
2643    /// raw slot would silently split the build-time mesh-artifact
2644    /// emission gate from the M3 declared-slot enumerator's kind-
2645    /// coherence gate, a two-consumer split far from the source
2646    /// `caixa.lisp` with no field naming the policy-drift root cause.
2647    /// Lifting the resolution rule to a typed method on the substrate
2648    /// primitive means every downstream consumer of the caixa's per-
2649    /// `Caixa` MESH-COMPOSITION mesh-policy outer-composite surface
2650    /// reaches for exactly one typed dispatch — the resolver's
2651    /// accept-set migrates as a unit on any future axis addition.
2652    ///
2653    /// Third outer top-level [`Caixa`] `Option<&Composite>`-return
2654    /// composite-reference accessor — sibling to the opening
2655    /// [`Self::limits`] (b2bd9d7) and [`Self::behavior`] (35d8b52)
2656    /// accessors on the outer-`Caixa` `Option<&Composite>` composite-
2657    /// reference sub-family, extends the "one typed dispatch on the
2658    /// substrate primitive, thin projections at each consumer"
2659    /// discipline onto the first of the three M3 mesh-slot axes.
2660    /// Peer of the closed inner mesh-slot outer-composite family the
2661    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2662    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2663    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2664    /// accessor pins already close on the inner [`crate::AplicacaoSpec`]
2665    /// altitude — opens the outer top-level [`Caixa`] altitude's M3
2666    /// mesh-slot arm of the composite-reference family the remaining
2667    /// two axes (`:placement`, `:entrada`) fold onto in future
2668    /// sibling lifts. Returns `Option<&MeshPolicy>` (not the owning
2669    /// composite by copy or clone) because every downstream consumer
2670    /// of the mesh-policy composite treats it as a read-only per-axis
2671    /// dispatch source — the reference-view is the narrowest borrow
2672    /// that supports every present + roadmapped consumer (per-axis
2673    /// accessor dispatch, `.is_empty()`-gated overlay projection,
2674    /// presence-probe early return on the "author-omitted `:politicas`
2675    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2676    /// seed's default-fold arm) without cloning the composite through
2677    /// every consumer's fast path. The `Option` half of the return-
2678    /// type preserves the load-bearing "author-omitted `:politicas` ⇒
2679    /// cluster-default applies" partition (not a default composite
2680    /// the downstream must reject on emptiness) — the accessor
2681    /// projects the raw `Option<MeshPolicy>` slot's presence bit
2682    /// through the reference-return unchanged. Named `politicas()` to
2683    /// match the storage field's name verbatim and the tatara-lisp
2684    /// author-surface term (`:politicas`) the field's own docstring
2685    /// already carries.
2686    #[must_use]
2687    pub fn politicas(&self) -> Option<&crate::aplicacao::MeshPolicy> {
2688        self.politicas.as_ref()
2689    }
2690
2691    /// Substrate-canonical per-`Caixa` `:placement` M3 mesh-slot outer-
2692    /// composite MESH-COMPOSITION-shaped distribution optional-composite-
2693    /// reference accessor every consumer of the top-level manifest's
2694    /// per-Aplicacao [`crate::aplicacao::Placement`] outer-composite
2695    /// reader keys off — returns the author-declared `:placement` typed
2696    /// composite verbatim as an `Option<&Placement>` reference over the
2697    /// same backing storage the raw `self.placement.as_ref()` field
2698    /// access borrows from, with `None` naming the "no `:placement`
2699    /// block authored — every per-axis placement scalar defers to the
2700    /// cluster-default arm named on the per-axis
2701    /// [`crate::aplicacao::Placement::estrategia`] /
2702    /// [`crate::aplicacao::Placement::clusters`] /
2703    /// [`crate::aplicacao::Placement::affinity`] /
2704    /// [`crate::aplicacao::Placement::shard_key`] scalar-accessor
2705    /// docstrings" partition every downstream caixa-mesh /
2706    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2707    /// "emit no per-`:placement` overlay" and the sibling
2708    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2709    /// the [`crate::aplicacao::Placement::default`] cluster-default arm.
2710    ///
2711    /// The outer `:placement` slot carries the M3 mesh-slot per-
2712    /// Aplicacao typed distribution composite — the load-bearing
2713    /// container of every where-does-this-Aplicacao-run axis every
2714    /// caixa-mesh programs.yaml per-cluster distribution overlay /
2715    /// caixa-flux per-Aplicacao GitRepository/HelmRelease fan-out /
2716    /// future M4 per-Aplicacao Akka-style cluster-sharding entity-id
2717    /// resolver emitter fans on (MESH-COMPOSITION §II.4 — the
2718    /// Aplicacao's typed distribution composite; §V CSE invariants —
2719    /// "distribution is a first-class typed composite, not a runtime
2720    /// scheduler hint" the per-axis scalars enforce; §III.3 — the
2721    /// typed inter-Servico contrato-edge overlay the per-cluster
2722    /// mesh renderer keys off). Every per-`:placement` axis threads
2723    /// through a lifted per-slot accessor on the
2724    /// [`crate::aplicacao::Placement`] type: the
2725    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
2726    /// MESH-COMPOSITION distribution-strategy scalar, the
2727    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7) per-cluster
2728    /// distribution-target slice, the [`crate::aplicacao::Placement::affinity`]
2729    /// M3-Adaptive-compression-hint optional-scalar, and the
2730    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) Akka-cluster-
2731    /// sharding extractor-expression optional-scalar. Every downstream
2732    /// consumer that reaches for a placement axis first passes through
2733    /// this outer accessor onto the composite and then dispatches onto
2734    /// the per-axis accessor — the two-level dispatch means every per-
2735    /// `:placement` reader now routes through a typed dispatch on the
2736    /// substrate primitive at both altitudes.
2737    ///
2738    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2739    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2740    /// author-omitted arm onto the [`crate::aplicacao::Placement::default`]
2741    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::placement`]
2742    /// (9abb8f0) `&Placement`-return accessor observes a typed composite
2743    /// whether or not the author declared the outer slot. The outer
2744    /// accessor preserves the "author-omitted vs authored-empty" partition
2745    /// the inner accessor collapses at the cluster-default fold —
2746    /// routing the presence bit through this accessor keeps the
2747    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2748    /// `M3_AUTHOR_KEY_PLACEMENT` push separate from the inner
2749    /// [`crate::AplicacaoSpec::validate_placement`]-gated overlay
2750    /// dispatch.
2751    ///
2752    /// Prior to this lift the `.placement` `Option<Placement>`
2753    /// composite was accessed inline at two production sites — the
2754    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2755    /// `self.placement.clone().unwrap_or_default()` traversal head
2756    /// (caixa-core/src/manifest.rs:2036, which drives the fold onto
2757    /// the [`crate::aplicacao::Placement::default`] cluster-default
2758    /// arm the inner [`crate::AplicacaoSpec::placement`] accessor
2759    /// then observes), and the [`Self::declared_mesh_slots`] M3
2760    /// declared-slot-set enumerator's `self.placement.is_some()`
2761    /// presence probe (caixa-core/src/manifest.rs:2100, which drives
2762    /// the `M3_AUTHOR_KEY_PLACEMENT` kebab-case author-label push
2763    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2764    /// coherence gate reads) — two open-coded outer-field accesses
2765    /// that expressed no compile-time link back to the typed slot at
2766    /// the [`Caixa`] altitude. A future extension of the `:placement`
2767    /// outer axis to a richer author surface (a per-cluster
2768    /// `:placement-overrides` slot the operator materializes at
2769    /// admission time so a cluster-specific placement can tighten the
2770    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2771    /// per-tenant placement-alias table the M4
2772    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer resolves
2773    /// per-CR at admission time, a promotion of the plain
2774    /// `Option<Placement>` to a richer `{static, dynamic}` partition
2775    /// once Orleans-style virtual-actor dynamic placement comes into
2776    /// typed scope) would have had to be threaded through both open-
2777    /// coded copies in lockstep or the Aplicacao-composition seed's
2778    /// default-fold arm would silently disagree with the M3 declared-
2779    /// slot enumerator on which distribution composite a given Caixa
2780    /// resolves to — the seed reading an operator-resolved slot while
2781    /// the enumerator's presence probe read the raw slot would
2782    /// silently split the build-time distribution-artifact emission
2783    /// gate from the M3 declared-slot enumerator's kind-coherence
2784    /// gate, a two-consumer split far from the source `caixa.lisp`
2785    /// with no field naming the distribution-drift root cause.
2786    /// Lifting the resolution rule to a typed method on the substrate
2787    /// primitive means every downstream consumer of the caixa's per-
2788    /// `Caixa` MESH-COMPOSITION distribution outer-composite surface
2789    /// reaches for exactly one typed dispatch — the resolver's
2790    /// accept-set migrates as a unit on any future axis addition.
2791    ///
2792    /// Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
2793    /// composite-reference accessor — sibling to the opening
2794    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) M2-
2795    /// Servico-runtime pair and the peer [`Self::politicas`] (5d23d29)
2796    /// M3-mesh-slot arm on the outer-`Caixa` `Option<&Composite>`
2797    /// composite-reference sub-family, folds on the "one typed
2798    /// dispatch on the substrate primitive, thin projections at each
2799    /// consumer" discipline extended onto the second of the three M3
2800    /// mesh-slot axes. Peer of the closed inner mesh-slot outer-
2801    /// composite family the sibling
2802    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2803    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2804    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2805    /// accessor pins already close on the inner
2806    /// [`crate::AplicacaoSpec`] altitude — folds on the outer top-
2807    /// level [`Caixa`] altitude's M3 mesh-slot arm the sibling
2808    /// [`Self::politicas`] opened, extending the discipline onto the
2809    /// second of the three M3 mesh-slot axes. The remaining M3
2810    /// mesh-slot axis (`:entrada`) folds onto this accessor's
2811    /// discipline in the final sibling lift, closing the outer top-
2812    /// level [`Caixa`] `Option<&Composite>` M3 mesh-slot sub-family.
2813    /// Returns `Option<&Placement>` (not the owning composite by copy
2814    /// or clone) because every downstream consumer of the placement
2815    /// composite treats it as a read-only per-axis dispatch source —
2816    /// the reference-view is the narrowest borrow that supports every
2817    /// present + roadmapped consumer (per-axis accessor dispatch,
2818    /// serde composite-serialization on the programs.yaml overlay,
2819    /// presence-probe early return on the "author-omitted `:placement`
2820    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2821    /// seed's default-fold arm) without cloning the composite through
2822    /// every consumer's fast path. The `Option` half of the return-
2823    /// type preserves the load-bearing "author-omitted `:placement` ⇒
2824    /// cluster-default applies" partition (not a default composite
2825    /// the downstream must reject on emptiness) — the accessor
2826    /// projects the raw `Option<Placement>` slot's presence bit
2827    /// through the reference-return unchanged. Named `placement()` to
2828    /// match the storage field's name verbatim and the tatara-lisp
2829    /// author-surface term (`:placement`) the field's own docstring
2830    /// already carries.
2831    #[must_use]
2832    pub fn placement(&self) -> Option<&crate::aplicacao::Placement> {
2833        self.placement.as_ref()
2834    }
2835
2836    /// Substrate-canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
2837    /// composite MESH-COMPOSITION-shaped external-gateway optional-
2838    /// composite-reference accessor every consumer of the top-level
2839    /// manifest's per-Aplicacao [`crate::aplicacao::Entrada`] outer-
2840    /// composite reader keys off — returns the author-declared
2841    /// `:entrada` typed composite verbatim as an `Option<&Entrada>`
2842    /// reference over the same backing storage the raw
2843    /// `self.entrada.as_ref()` field access borrows from, with `None`
2844    /// naming the "no `:entrada` block authored — this Aplicacao is
2845    /// cluster-internal, no `Gateway`/`HTTPRoute` fan-out emitted"
2846    /// partition every downstream caixa-mesh Gateway-API artifact
2847    /// emitter treats as "emit no gateway-listener + no `HTTPRoute`
2848    /// backend for this Aplicacao" and the sibling
2849    /// [`Self::aplicacao_view`] Aplicacao-composition seed forwards
2850    /// verbatim (unlike the peer `:politicas` / `:placement` arms,
2851    /// `:entrada` has no cluster-default fold — an omitted `:entrada`
2852    /// stays `None` on the projected [`crate::AplicacaoSpec`] and the
2853    /// peer inner [`crate::AplicacaoSpec::entrada`] accessor observes
2854    /// the same `Option<&Entrada>` presence bit unchanged).
2855    ///
2856    /// The outer `:entrada` slot carries the M3 mesh-slot per-
2857    /// Aplicacao typed external-gateway composite — the load-bearing
2858    /// container of every how-does-the-outside-world-reach-this-
2859    /// Aplicacao axis every caixa-mesh `Gateway`/`HTTPRoute` fan-out
2860    /// emitter fans on (MESH-COMPOSITION §II.5 — the Aplicacao's typed
2861    /// external-entry composite; §V CSE invariants — "the external
2862    /// gateway is a first-class typed composite, not a per-Servico
2863    /// ingress annotation" the per-axis scalars enforce; §III.4 — the
2864    /// typed hostname + backend-Servico pair the per-cluster Gateway-
2865    /// API renderer keys off). Every per-`:entrada` axis threads
2866    /// through a lifted per-slot accessor on the
2867    /// [`crate::aplicacao::Entrada`] type: the
2868    /// [`crate::aplicacao::Entrada::host`] Gateway-API `Listener.hostname`
2869    /// scalar, the [`crate::aplicacao::Entrada::para`] backend-Servico
2870    /// caixa-name scalar, the [`crate::aplicacao::Entrada::paths`]
2871    /// per-rule `HTTPPathMatch` list, the [`crate::aplicacao::Entrada::port`]
2872    /// backend `trigger.service.port` scalar, and the
2873    /// [`crate::aplicacao::Entrada::resolved_paths`] URL-path fallback
2874    /// resolver every HTTPRoute-aware renderer consumes. Every
2875    /// downstream consumer that reaches for an entry axis first passes
2876    /// through this outer accessor onto the composite and then
2877    /// dispatches onto the per-axis accessor — the two-level dispatch
2878    /// means every per-`:entrada` reader now routes through a typed
2879    /// dispatch on the substrate primitive at both altitudes.
2880    ///
2881    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2882    /// seed: the Aplicacao-view builder forwards the outer `Option`
2883    /// arm verbatim (no default fold — `:entrada` is inherently
2884    /// optional; a cluster-internal Aplicacao has no external gateway
2885    /// at all, not "an external gateway that defaults to nothing"), so
2886    /// the peer inner [`crate::AplicacaoSpec::entrada`] (d32111c)
2887    /// `Option<&Entrada>`-return accessor observes the same presence
2888    /// bit whether or not the author declared the outer slot. Routing
2889    /// the presence bit through this accessor keeps the
2890    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2891    /// `M3_AUTHOR_KEY_ENTRADA` push separate from the inner
2892    /// [`crate::AplicacaoSpec::validate_entrada`]-gated
2893    /// hostname/backend/path emission dispatch.
2894    ///
2895    /// Prior to this lift the `.entrada` `Option<Entrada>` composite
2896    /// was accessed inline at two production sites — the
2897    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2898    /// `self.entrada.clone()` traversal head (caixa-core/src/manifest.rs:2182,
2899    /// which drives the forward onto the peer inner
2900    /// [`crate::AplicacaoSpec::entrada`] accessor the caixa-mesh
2901    /// Gateway-API fan-out then observes), and the
2902    /// [`Self::declared_mesh_slots`] M3 declared-slot-set enumerator's
2903    /// `self.entrada.is_some()` presence probe (caixa-core/src/manifest.rs:2248,
2904    /// which drives the `M3_AUTHOR_KEY_ENTRADA` kebab-case author-
2905    /// label push every [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
2906    /// kind-coherence gate reads) — two open-coded outer-field
2907    /// accesses that expressed no compile-time link back to the typed
2908    /// slot at the [`Caixa`] altitude. A future extension of the
2909    /// `:entrada` outer axis to a richer author surface (a per-cluster
2910    /// `:entrada-overrides` slot the operator materializes at admission
2911    /// time so a cluster-specific hostname can pin the caixa-declared
2912    /// bound without re-authoring the `caixa.lisp`, a per-tenant
2913    /// gateway-alias table the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
2914    /// CR materializer resolves per-CR at admission time, a promotion
2915    /// of the plain `Option<Entrada>` to a richer
2916    /// `{public, private, internal}` partition once Cilium-identity-
2917    /// scoped internal gateways come into typed scope) would have had
2918    /// to be threaded through both open-coded copies in lockstep or the
2919    /// Aplicacao-composition seed's forward arm would silently
2920    /// disagree with the M3 declared-slot enumerator on which external-
2921    /// gateway composite a given Caixa resolves to — the seed reading
2922    /// an operator-resolved slot while the enumerator's presence probe
2923    /// read the raw slot would silently split the build-time gateway-
2924    /// artifact emission gate from the M3 declared-slot enumerator's
2925    /// kind-coherence gate, a two-consumer split far from the source
2926    /// `caixa.lisp` with no field naming the entry-drift root cause.
2927    /// Lifting the resolution rule to a typed method on the substrate
2928    /// primitive means every downstream consumer of the caixa's per-
2929    /// `Caixa` MESH-COMPOSITION external-gateway outer-composite
2930    /// surface reaches for exactly one typed dispatch — the resolver's
2931    /// accept-set migrates as a unit on any future axis addition.
2932    ///
2933    /// Fifth and final outer top-level [`Caixa`] `Option<&Composite>`-
2934    /// return composite-reference accessor — closes the outer-`Caixa`
2935    /// `Option<&Composite>` composite-reference sub-family opened by
2936    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) on the
2937    /// M2 Servico-runtime arm and extended onto the M3 mesh-slot arm
2938    /// by [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074),
2939    /// folds on the "one typed dispatch on the substrate primitive,
2940    /// thin projections at each consumer" discipline extended onto the
2941    /// third and final M3 mesh-slot axis. Peer of the closed inner
2942    /// mesh-slot outer-composite family the sibling
2943    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2944    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2945    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2946    /// accessor pins already close on the inner
2947    /// [`crate::AplicacaoSpec`] altitude — this lift closes the mirror
2948    /// sub-family on the outer top-level [`Caixa`] altitude, so both
2949    /// altitudes of the outer-composite reference-return discipline
2950    /// (per-`Caixa` outer-slot presence + per-`AplicacaoSpec` inner-
2951    /// slot presence) now carry the full five-arm accept-set behind a
2952    /// typed dispatch on the substrate primitive. Returns
2953    /// `Option<&Entrada>` (not the owning composite by copy or clone)
2954    /// because every downstream consumer of the entrada composite
2955    /// treats it as a read-only per-axis dispatch source — the
2956    /// reference-view is the narrowest borrow that supports every
2957    /// present + roadmapped consumer (per-axis accessor dispatch,
2958    /// serde composite-serialization on the programs.yaml overlay,
2959    /// presence-probe early return on the "author-omitted `:entrada`
2960    /// ⇒ cluster-internal Aplicacao" partition, `Aplicacao`-composition
2961    /// seed's forward arm) without cloning the composite through every
2962    /// consumer's fast path. The `Option` half of the return-type
2963    /// preserves the load-bearing "author-omitted `:entrada` ⇒
2964    /// cluster-internal Aplicacao" partition (not a default composite
2965    /// the downstream must reject on emptiness — a cluster-internal
2966    /// Aplicacao has no external gateway at all, not "a default gateway
2967    /// that emits nothing"); the accessor projects the raw
2968    /// `Option<Entrada>` slot's presence bit through the reference-
2969    /// return unchanged. Named `entrada()` to match the storage field's
2970    /// name verbatim and the tatara-lisp author-surface term
2971    /// (`:entrada`) the field's own docstring already carries.
2972    #[must_use]
2973    pub fn entrada(&self) -> Option<&crate::aplicacao::Entrada> {
2974        self.entrada.as_ref()
2975    }
2976
2977    /// Substrate-canonical per-`Caixa` `:ci` slot accessor — returns the
2978    /// author-declared typed CI run (`canteiro_types::CiRun`) verbatim as
2979    /// an `Option<&CiRun>`, borrowed from the typed slot's own
2980    /// `Option<CiRun>` storage. `None` when the slot is absent (every
2981    /// non-`Acao` kind, and an `Acao` caixa that hasn't declared `:ci`
2982    /// yet — the latter is caught by [`crate::LayoutError::MissingCi`],
2983    /// not silently accepted).
2984    ///
2985    /// Named `ci()` to match the storage field's name and the
2986    /// tatara-lisp author surface (`:ci`); mirrors the sibling
2987    /// `Option<&Composite>` accessors on this same `Caixa` altitude
2988    /// ([`Self::limits`], [`Self::behavior`], [`Self::politicas`],
2989    /// [`Self::placement`], [`Self::entrada`]) — one typed dispatch on
2990    /// the substrate primitive rather than an open-coded `self.ci.as_ref()`
2991    /// at every consumer.
2992    #[must_use]
2993    pub fn ci(&self) -> Option<&canteiro_types::CiRun> {
2994        self.ci.as_ref()
2995    }
2996
2997    /// Substrate-canonical per-`Caixa` `:estrategia` M2 supervisor-tree-
2998    /// slot flat-spread OTP-shaped sibling-restart-strategy discriminant
2999    /// accessor every consumer of the top-level manifest's per-Supervisor
3000    /// restart-strategy axis keys off — returns the author-declared
3001    /// `:estrategia` variant verbatim as an `Option<RestartStrategy>`,
3002    /// `Copy`-projected from the typed slot's own
3003    /// `Option<crate::supervisor::RestartStrategy>` storage. Optional
3004    /// (`:estrategia` is a flat-spread supervisor-only slot every
3005    /// non-`Supervisor`-kind `defcaixa` carries as `None` by
3006    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3007    /// still omit to defer to [`RestartStrategy::default`] —
3008    /// [`RestartStrategy::OneForOne`] — through the [`Self::supervisor_view`]
3009    /// `unwrap_or_default()` fold; a returned `None` degenerates to the
3010    /// [`SupervisorSpec::default`]-inherited strategy without any silent
3011    /// promotion to a fresh explicit variant at the accessor boundary).
3012    ///
3013    /// The `:estrategia` slot carries the M2 typed OTP-shaped sibling-
3014    /// restart-strategy discriminant every substrate-side per-Supervisor
3015    /// dispatch fans on (INSPIRATIONS §II.2 — OTP `supervisor:strategy`
3016    /// closed-set `one_for_one | one_for_all | rest_for_one |
3017    /// simple_one_for_one` algebra translated onto pleme-io's typed
3018    /// [`RestartStrategy`] enum; CAIXA-SDLC §II — the M2 supervisor-tree
3019    /// slot algebra the operator's hierarchical reconciliation scheduler
3020    /// fans on). The slot is *flat-spread* on the outer top-level `Caixa`
3021    /// (per the field-shape docstring at caixa-core/src/manifest.rs — "The
3022    /// supervisor slots are flat on Caixa (vs nested under a
3023    /// `SupervisorSpec` sub-form) to keep tatara-lisp authoring at one
3024    /// level of nesting"), so the accessor's altitude is the outer
3025    /// [`Caixa`] surface rather than the composed [`SupervisorSpec`]
3026    /// altitude the sibling [`crate::supervisor::SupervisorSpec::estrategia`]
3027    /// (eafb619) accessor keys off. The two typed axes — the outer
3028    /// author-surface `Option<RestartStrategy>` on the [`Caixa`] altitude
3029    /// (author-omitted arm carried as `None`) and the inner post-
3030    /// composition `RestartStrategy` on the [`SupervisorSpec`] altitude
3031    /// (`Option` collapsed through the [`Self::supervisor_view`]
3032    /// `unwrap_or_default()` fold) — now share one accessor discipline for
3033    /// the shared substrate concept "the author-declared OTP-shaped
3034    /// sibling-restart-strategy variant that partitions the downstream
3035    /// per-Supervisor renderer's per-arm fan-out"; the outer-altitude
3036    /// `None` arm is the pre-composition presence bit every declared-slot
3037    /// enumerator ([`Self::declared_supervisor_slots`]) reads, and the
3038    /// inner-altitude non-`Option` `RestartStrategy` is the post-
3039    /// composition partition-dispatch input every strategy-arm consumer
3040    /// ([`SupervisorSpec::validate`], the future wasm-operator's per-
3041    /// Supervisor sibling-restart branch, the future M4
3042    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
3043    /// webhook) fans on.
3044    ///
3045    /// Prior to this lift the `.estrategia` field was accessed inline at
3046    /// two production sites in `caixa-core/src/manifest.rs` — the
3047    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`
3048    /// presence-probe arm at `if self.estrategia.is_some()` (which drives
3049    /// the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3050    /// coherence gate's per-slot label push) and the [`Self::supervisor_view`]
3051    /// `SupervisorSpec` construction site at `estrategia:
3052    /// self.estrategia.unwrap_or_default()` (which composes the flat-
3053    /// spread outer author-surface `Option<RestartStrategy>` onto the
3054    /// inner post-composition [`SupervisorSpec`] `RestartStrategy` field
3055    /// the [`SupervisorSpec::estrategia`] accessor keys off) — two open-
3056    /// coded field-accesses that expressed no compile-time link back to
3057    /// the typed slot. A future extension of the outer `:estrategia` axis
3058    /// to a richer author surface (a per-cluster strategy override the
3059    /// operator pins through a future `:estrategia-overrides` overlay the
3060    /// MESH-COMPOSITION §III.2 supervision-canary roadmap acknowledges,
3061    /// a per-tenant strategy-alias table the M4 CR materializer resolves
3062    /// per-CR, a per-Supervisor dynamic strategy derivation the future
3063    /// adaptive-supervision engine computes from child-failure-history
3064    /// topology, a per-child-cohort strategy split the future
3065    /// `RestForCohort` extension the INSPIRATIONS.md §II.2 Erlang/OTP
3066    /// absorption roadmap acknowledges, a promotion of the plain
3067    /// `Option<RestartStrategy>` to a richer
3068    /// `AuthorDeclaredStrategy { declared, overlay }` newtype once the
3069    /// operator-resolved overlay lands) would have had to be threaded
3070    /// through both open-coded copies in lockstep or the enumerator's
3071    /// presence probe and the composition site's `unwrap_or_default()`
3072    /// fold would silently disagree on which strategy a given [`Caixa`]
3073    /// resolves to (an author's `:estrategia OneForAll` would satisfy
3074    /// the enumerator's presence probe while the composition site
3075    /// silently rendered a stale `OneForOne`, or vice versa). Lifting
3076    /// the resolution rule to a typed method on the substrate primitive
3077    /// means every downstream consumer of the caixa's per-`Caixa` outer-
3078    /// altitude sibling-restart-strategy surface reaches for exactly one
3079    /// typed dispatch — the resolver's accept-set migrates as a unit on
3080    /// any future axis addition.
3081    ///
3082    /// First outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3083    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3084    /// axes — opens the outer-`Caixa` `Option<Copy>` flat-spread
3085    /// projection pattern the sibling per-`Caixa` `:max-restarts`
3086    /// `Option<u32>` and (through the future duration-newtype landing)
3087    /// `:restart-window` `Option<Duration>` future outer-scalar lifts
3088    /// fold on. Peer of the inner-altitude [`crate::supervisor::SupervisorSpec::estrategia`]
3089    /// (eafb619) `Copy`-return sibling-restart-strategy scalar accessor on
3090    /// the post-composition [`SupervisorSpec`] altitude — same "one
3091    /// typed dispatch on the substrate primitive, thin projections at
3092    /// each consumer" discipline extended onto the pre-composition outer
3093    /// author-surface [`Caixa`] altitude for the same OTP-shaped
3094    /// sibling-restart-strategy axis. Peer of the closed outer-`Caixa`
3095    /// `Option<&Composite>` composite-reference family the sibling
3096    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3097    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3098    /// [`Self::entrada`] (e4128e4) accessor pins already carry on the
3099    /// outer `Option<&Composite>` altitude — extends the outer-`Caixa`
3100    /// typed-slot accessor discipline onto the flat-spread M2 supervisor-
3101    /// tree `Option<Copy>`-discriminant sub-family the sibling M3
3102    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
3103    /// `PlacementStrategy` `Copy`-composite-enum scalar accessor already
3104    /// pins on the inner-altitude per-`:placement` composite. Named
3105    /// `estrategia()` to match the storage field's name and the
3106    /// per-[`SupervisorSpec`] peer [`crate::supervisor::SupervisorSpec::estrategia`]
3107    /// / per-[`crate::aplicacao::Placement`] peer
3108    /// [`crate::aplicacao::Placement::estrategia`] method-name discipline
3109    /// verbatim; the accessor's identity name maps onto the canonical
3110    /// OTP-shape supervision vocabulary the [`RestartStrategy`] enum's
3111    /// docstring already carries.
3112    #[must_use]
3113    pub fn estrategia(&self) -> Option<crate::supervisor::RestartStrategy> {
3114        self.estrategia
3115    }
3116
3117    /// Substrate-canonical per-`Caixa` `:max-restarts` M2 supervisor-tree-
3118    /// slot flat-spread OTP-`MaxIntensity`-shaped restart-budget-count
3119    /// scalar accessor every consumer of the top-level manifest's per-
3120    /// Supervisor `:max-restarts` restart-budget-count axis keys off —
3121    /// returns the author-declared `:max-restarts` typed `Option<u32>`
3122    /// verbatim, `Copy`-projected from the typed slot's own `Option<u32>`
3123    /// storage (`u32` is `Copy`, so `Option<u32>` is `Copy` and the
3124    /// accessor returns by value; no borrow of `&self` past the call).
3125    /// Optional (`:max-restarts` is a flat-spread supervisor-only slot
3126    /// every non-`Supervisor`-kind `defcaixa` carries as `None` by
3127    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3128    /// still omit to defer to the [`Self::supervisor_view`]
3129    /// `unwrap_or(5)` fold's OTP-canonical `{intensity, 5, 60}` default).
3130    ///
3131    /// The `:max-restarts` slot carries the M2 typed Erlang/OTP-shaped
3132    /// `MaxIntensity` restart-budget count that pairs with the sibling
3133    /// `:restart-window` `Period` to form the `MaxIntensity / Period`
3134    /// restart-intensity ratio the supervisor trips its own escalation on
3135    /// (INSPIRATIONS §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}`
3136    /// worker-supervisor default; RUNTIME-PATTERNS §II.2; CAIXA-SDLC §II
3137    /// — the M2 supervisor-tree slot algebra the operator's hierarchical
3138    /// reconciliation scheduler fans on). The slot is *flat-spread* on
3139    /// the outer top-level `Caixa` (per the field-shape docstring at
3140    /// caixa-core/src/manifest.rs — "The supervisor slots are flat on
3141    /// Caixa (vs nested under a `SupervisorSpec` sub-form)"), so the
3142    /// accessor's altitude is the outer [`Caixa`] surface rather than the
3143    /// composed [`SupervisorSpec`] altitude the sibling
3144    /// [`crate::supervisor::SupervisorSpec::max_restarts`] accessor keys
3145    /// off. The two typed axes — the outer author-surface `Option<u32>`
3146    /// on the [`Caixa`] altitude (author-omitted arm carried as `None`)
3147    /// and the inner post-composition `u32` on the [`SupervisorSpec`]
3148    /// altitude (`Option` collapsed through the [`Self::supervisor_view`]
3149    /// `unwrap_or(5)` fold) — now share one accessor discipline for the
3150    /// shared substrate concept "the author-declared OTP-shaped
3151    /// restart-budget count every downstream per-Supervisor consumer's
3152    /// restart-intensity budget-vs-count comparator fans on".
3153    ///
3154    /// Prior to this lift the `.max_restarts` field was accessed inline
3155    /// at two production sites in `caixa-core/src/manifest.rs` — the
3156    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`
3157    /// presence-probe arm at `if self.max_restarts.is_some()` (which
3158    /// drives the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3159    /// kind-coherence gate's per-slot label push) and the
3160    /// [`Self::supervisor_view`] `SupervisorSpec` construction site at
3161    /// `max_restarts: self.max_restarts.unwrap_or(5)` (which composes the
3162    /// flat-spread outer author-surface `Option<u32>` onto the inner
3163    /// post-composition [`SupervisorSpec`] `u32` field the
3164    /// [`SupervisorSpec::max_restarts`] accessor keys off) — two open-
3165    /// coded field-accesses that expressed no compile-time link back to
3166    /// the typed slot. A future extension of the outer `:max-restarts`
3167    /// axis to a richer author surface (a per-cluster restart-budget
3168    /// override the operator pins through a future `:max-restarts-overrides`
3169    /// overlay the MESH-COMPOSITION §III.2 supervision-canary roadmap
3170    /// acknowledges, a per-tenant restart-budget-alias table the M4 CR
3171    /// materializer resolves per-CR, a per-Supervisor dynamic restart-
3172    /// budget derivation the future adaptive-supervision engine computes
3173    /// from child-failure-history topology, a promotion of the plain
3174    /// `Option<u32>` count to a richer `{MaxR, MaxT}` per-child-cohort
3175    /// restart-budget-partition once the INSPIRATIONS §II.2 Erlang/OTP
3176    /// per-child-cohort roadmap lands) would have had to be threaded
3177    /// through both open-coded copies in lockstep or the enumerator's
3178    /// presence probe and the composition site's `unwrap_or(5)` fold
3179    /// would silently disagree on which restart-budget a given [`Caixa`]
3180    /// resolves to (an author's `:max-restarts 10` would satisfy the
3181    /// enumerator's presence probe while the composition site silently
3182    /// composed the OTP-canonical `5`, or vice versa). Lifting the
3183    /// resolution rule to a typed method on the substrate primitive means
3184    /// every downstream consumer of the caixa's per-`Caixa` outer-altitude
3185    /// restart-budget-count surface reaches for exactly one typed dispatch
3186    /// — the resolver's accept-set migrates as a unit on any future axis
3187    /// addition.
3188    ///
3189    /// Second outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3190    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3191    /// axes — folds on the outer-`Caixa` `Option<Copy>` flat-spread
3192    /// projection pattern the sibling per-`Caixa`
3193    /// [`Self::estrategia`] (ed04d3c) accessor opened, extends the
3194    /// sub-family onto the sibling `Option<u32>` restart-budget-count arm.
3195    /// Peer of the inner-altitude
3196    /// [`crate::supervisor::SupervisorSpec::max_restarts`] `u32` accessor
3197    /// on the post-composition [`SupervisorSpec`] altitude — same "one
3198    /// typed dispatch on the substrate primitive, thin projections at
3199    /// each consumer" discipline extended onto the pre-composition outer
3200    /// author-surface [`Caixa`] altitude for the same OTP-`MaxIntensity`-
3201    /// shaped restart-budget-count axis. Named `max_restarts()` to match
3202    /// the storage field's name and the per-[`SupervisorSpec`] peer
3203    /// [`crate::supervisor::SupervisorSpec::max_restarts`] method-name
3204    /// discipline verbatim; the accessor's identity maps onto the
3205    /// canonical OTP-shape supervision vocabulary the `:max-restarts`
3206    /// field's docstring already carries.
3207    #[must_use]
3208    pub const fn max_restarts(&self) -> Option<u32> {
3209        self.max_restarts
3210    }
3211
3212    /// Substrate-canonical per-`Caixa` `:restart-window` M2 supervisor-
3213    /// tree-slot flat-spread OTP-`Period`-shaped restart-intensity-
3214    /// denominator raw-duration-string scalar accessor every consumer of
3215    /// the top-level manifest's per-Supervisor `:restart-window` sliding-
3216    /// window axis keys off — returns the author-declared `:restart-window`
3217    /// typed `Option<String>` verbatim as an `Option<&str>`, borrowed
3218    /// from the typed slot's own `Option<String>` storage. `None` when
3219    /// the slot is absent (the canonical "never reset — every restart
3220    /// across the supervisor's lifetime counts against the sibling
3221    /// `:max-restarts` budget" sentinel every non-`Supervisor`-kind
3222    /// `defcaixa` carries by `#[serde(default)]` and every
3223    /// `Supervisor`-kind `defcaixa` may still omit to defer to the
3224    /// [`Self::supervisor_view`] `restart_window: None` composition
3225    /// through the [`crate::supervisor::duration_codec::parse`] soft-
3226    /// swallow `.and_then(|s| … .ok())` fold).
3227    ///
3228    /// The `:restart-window` slot carries the raw M2 typed Erlang/OTP-
3229    /// shaped `Period` sliding-observation-interval duration string that
3230    /// pairs with the sibling `:max-restarts` `MaxIntensity` restart-
3231    /// budget count to form the `MaxIntensity / Period` restart-intensity
3232    /// ratio the supervisor trips its own escalation on (INSPIRATIONS
3233    /// §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}` worker-
3234    /// supervisor default; RUNTIME-PATTERNS §II.2). The outer-`Caixa`
3235    /// slot stores the raw duration string (`"60s"`, `"5m"`, `"500ms"`)
3236    /// authored under `:restart-window` — the typed [`SupervisorSpec`]
3237    /// holds an `Option<Duration>` routed through the shared
3238    /// [`crate::supervisor::duration_codec`] via `with = "duration_codec"`
3239    /// — so the outer altitude's accessor returns `Option<&str>` (raw
3240    /// authoring surface) while the inner altitude's
3241    /// [`crate::supervisor::SupervisorSpec::restart_window`] returns
3242    /// `Option<Duration>` (parsed typed surface). The parse-refusal arm
3243    /// is closed by the sibling [`Self::validate_restart_window`] gate
3244    /// that surfaces [`ManifestError::RestartWindowMalformed`] naming
3245    /// the offending value; the view-construction path
3246    /// [`Self::supervisor_view`] soft-swallows the same parse error to
3247    /// `None` to keep the view best-effort.
3248    ///
3249    /// Prior to this lift the `.restart_window` field was accessed inline
3250    /// at three production sites in `caixa-core/src/manifest.rs` — the
3251    /// [`Self::declared_supervisor_slots`]
3252    /// `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` presence-probe arm at
3253    /// `if self.restart_window.is_some()` (which drives the
3254    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3255    /// coherence gate's per-slot label push), the
3256    /// [`Self::validate_restart_window`] `let Some(s) =
3257    /// self.restart_window.as_deref()` empty-and-shape gate binding
3258    /// (which folds the raw string through the shared
3259    /// [`crate::supervisor::duration_codec::parse`] to surface
3260    /// [`ManifestError::RestartWindowMalformed`] naming the offending
3261    /// value), and the [`Self::supervisor_view`] `self.restart_window
3262    /// .as_deref().and_then(…)` view-construction fold (which composes
3263    /// the flat-spread outer author-surface `Option<String>` onto the
3264    /// inner post-composition [`SupervisorSpec`] `Option<Duration>`
3265    /// field the [`SupervisorSpec::restart_window`] accessor keys off) —
3266    /// three open-coded field-accesses that expressed no compile-time
3267    /// link back to the typed slot. A future extension of the outer
3268    /// `:restart-window` axis to a richer author surface (a per-cluster
3269    /// window override, a per-tenant window-alias table, a per-Supervisor
3270    /// dynamic window derivation the future adaptive-supervision engine
3271    /// computes from child-failure-history topology, a promotion of the
3272    /// plain `Option<String>` raw duration to a typed `Option<Duration>`
3273    /// once the future author-surface parser lands at the [`Caixa`]
3274    /// altitude and the raw-string form is retired) would have had to be
3275    /// threaded through every open-coded copy in lockstep or the three
3276    /// consumers would silently disagree on which raw string a given
3277    /// [`Caixa`] resolves to. Lifting the resolution rule to a typed
3278    /// method on the substrate primitive means every downstream consumer
3279    /// of the caixa's per-`Caixa` outer-altitude restart-window raw-
3280    /// string surface reaches for exactly one typed dispatch — the
3281    /// resolver's accept-set migrates as a unit on any future axis
3282    /// addition.
3283    ///
3284    /// Third outer top-level [`Caixa`] supervisor-tree-slot flat-spread
3285    /// accessor — folds on the outer-`Caixa` M2 supervisor-tree flat-
3286    /// spread projection pattern the sibling per-`Caixa`
3287    /// [`Self::estrategia`] (ed04d3c) `Option<Copy>` and
3288    /// [`Self::max_restarts`] `Option<Copy>` accessors opened, extends
3289    /// the sub-family onto the sibling `Option<&str>` raw-duration-
3290    /// string arm (the outer altitude's raw-string form; the inner
3291    /// altitude's parsed [`Duration`] form is the peer
3292    /// [`crate::supervisor::SupervisorSpec::restart_window`] accessor).
3293    /// Peer of the sibling per-`Caixa` `Option<&str>`-return scalar
3294    /// accessors ([`Self::licenca`] / [`Self::repositorio`] /
3295    /// [`Self::descricao`] / [`Self::edicao`]) on the universal-axis
3296    /// outer scalar-projection family the outer-`Caixa` `Option<&str>`
3297    /// sub-family already carries — same "one typed dispatch on the
3298    /// substrate primitive, thin projections at each consumer"
3299    /// discipline extended onto the M2 supervisor-tree flat-spread
3300    /// `Option<&str>` raw-duration-string arm. Named `restart_window()`
3301    /// to match the storage field's name and the per-[`SupervisorSpec`]
3302    /// peer [`crate::supervisor::SupervisorSpec::restart_window`]
3303    /// method-name discipline verbatim; the accessor's identity maps
3304    /// onto the canonical OTP-shape supervision vocabulary the
3305    /// `:restart-window` field's docstring already carries.
3306    #[must_use]
3307    pub fn restart_window(&self) -> Option<&str> {
3308        self.restart_window.as_deref()
3309    }
3310
3311    /// Substrate-canonical per-`Caixa` `:upgrade-from` M2 typed-slot
3312    /// outer-composite OTP-appup-shaped per-prior-version migration-
3313    /// entry-list slice accessor every consumer of the top-level
3314    /// manifest's per-Servico hot-upgrade-block `&[UpgradeFromEntry]`
3315    /// slice-view keys off — returns the author-declared `:upgrade-from`
3316    /// typed `Vec<UpgradeFromEntry>` verbatim as a
3317    /// `&[UpgradeFromEntry]` slice-view over the same backing buffer
3318    /// the raw `self.upgrade_from.as_slice()` field access borrows
3319    /// from. Empty-slice-carrying (the "no hot-upgrade path declared"
3320    /// arm every `defcaixa` without an `:upgrade-from` block carries;
3321    /// the [`Self::from_lisp`] derive folds an omitted `:upgrade-from`
3322    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
3323    /// parse definitionally carries a `Vec<UpgradeFromEntry>` slot —
3324    /// possibly empty — and the returned `&[UpgradeFromEntry]`
3325    /// degenerates to an empty slice on that arm without any silent
3326    /// `None` collapse).
3327    ///
3328    /// The outer `:upgrade-from` slot carries the M2 typed OTP-appup
3329    /// migration block — the load-bearing container of every per-
3330    /// prior-`:versao` migration-instruction list the wasm-operator
3331    /// dispatches on at hot-upgrade time (INSPIRATIONS §II.4 — OTP
3332    /// `.appup` per-prior-version `LoadModule | StateChange |
3333    /// SoftPurge | Purge | Restart` instruction algebra translated
3334    /// onto pleme-io's typed `:upgrade-from :from` + `:instructions`
3335    /// entry list; CAIXA-SDLC §II — the typed-M2 slot algebra the
3336    /// operator's hot-upgrade dispatch fans on). Every per-entry axis
3337    /// threads through a lifted per-entry accessor on the
3338    /// [`UpgradeFromEntry`] type: the
3339    /// [`UpgradeFromEntry::prior_versao`] SemVer-shaped previous-
3340    /// version scalar accessor and the
3341    /// [`UpgradeFromEntry::instructions`] `&[UpgradeInstruction]`-
3342    /// return per-entry instruction-list accessor (0137e5a). Every
3343    /// downstream consumer of the hot-upgrade path first passes
3344    /// through this outer accessor onto the slice and then dispatches
3345    /// per-entry through the inner accessors — the two-level dispatch
3346    /// means every per-`:upgrade-from` reader now routes through a
3347    /// typed dispatch on the substrate primitive at both altitudes.
3348    ///
3349    /// Prior to this lift the `.upgrade_from` `Vec<UpgradeFromEntry>`
3350    /// slot was accessed inline at production sites across three
3351    /// files — the [`Self::declared_servico_slots`] M2 declared-slot
3352    /// enumerator's `self.upgrade_from.is_empty()` presence probe
3353    /// (caixa-core/src/manifest.rs, which drives the
3354    /// `M2_AUTHOR_KEY_UPGRADE_FROM` kebab-case author-label push every
3355    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
3356    /// gate reads), the [`crate::StandardLayout::verify`] per-
3357    /// `:upgrade-from` three-stage validation pass (caixa-core/src/
3358    /// layout.rs, which fans onto the
3359    /// [`crate::upgrade::validate_upgrade_from`] per-entry shape +
3360    /// cross-entry duplicate gate, the
3361    /// [`crate::upgrade::validate_upgrade_from_against_versao`]
3362    /// SemVer-precedence cross-slot gate, the
3363    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
3364    /// `:state-change` ↔ `:on-state-change` cross-slot composition
3365    /// gate, and the per-instruction script-path existence-probe walk
3366    /// that reads each entry's [`UpgradeFromEntry::instructions`] to
3367    /// resolve every declared migration script against the layout
3368    /// root), and the [`crate::render::servico_m2_overlay`] per-
3369    /// Servico M2 overlay emitter's `!caixa.upgrade_from.is_empty()`
3370    /// presence gate + `serde_yaml::to_value(&caixa.upgrade_from)`
3371    /// projection (caixa-core/src/render.rs, which drives the
3372    /// `M2_KEY_UPGRADE_FROM`-keyed `serde_yaml` projection every
3373    /// `caixa-helm` / `caixa-flux` Servico values-block emitter fans
3374    /// on and lands as the ComputeUnit CR's `spec.upgradeFrom` field).
3375    /// A future extension of the outer `:upgrade-from` axis (a per-
3376    /// cluster `:upgrade-overrides` overlay the wasm-engine operator
3377    /// resolves at admission time so a cluster-specific migration
3378    /// policy can tighten a caixa-declared step without re-authoring
3379    /// the `caixa.lisp`, promotion of the plain
3380    /// `Vec<UpgradeFromEntry>` to a richer `{static, dynamic}`
3381    /// partition once runtime-resolved hot-upgrade instructions land,
3382    /// per-entry priority annotation once multi-strategy fan-out
3383    /// lands) would have had to be threaded through all six open-
3384    /// coded copies in lockstep or one consumer would silently
3385    /// disagree with the peers on which upgrade slice a given Caixa
3386    /// resolves to — a six-consumer split at the enumerator, the
3387    /// three-stage validate pass, the script-path probe walk, and the
3388    /// M2 overlay emitter, far from the source `caixa.lisp` with no
3389    /// field naming the upgrade-drift root cause. Lifting the
3390    /// resolution rule to a typed method on the substrate primitive
3391    /// means every downstream consumer of the caixa's per-`Caixa`
3392    /// OTP-appup outer-slice surface reaches for exactly one typed
3393    /// dispatch — the resolver's accept-set migrates as a unit on any
3394    /// future axis addition.
3395    ///
3396    /// First outer top-level [`Caixa`] `&[Composite]`-return slice
3397    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the
3398    /// outer-`Caixa` `&[Composite]` composite-slice projection
3399    /// pattern the sibling `:children`
3400    /// [`crate::supervisor::ChildSpec`] / `:membros`
3401    /// [`crate::aplicacao::Membro`] / `:contratos`
3402    /// [`crate::aplicacao::WitContract`] future outer-composite-slice
3403    /// lifts fold on. Peer of the closed outer-`Caixa` scalar
3404    /// `Option<&Composite>` composite-reference family the sibling
3405    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3406    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3407    /// [`Self::entrada`] (e4128e4) accessors closed on the outer
3408    /// `Option<&Composite>` altitude, extended here to the outer-
3409    /// `Caixa` `&[Composite]` vec-carry altitude. Peer at the inner
3410    /// altitude of [`crate::upgrade::UpgradeFromEntry::instructions`]
3411    /// (0137e5a) — same "one typed dispatch on the substrate
3412    /// primitive, thin projections at each consumer" discipline
3413    /// folded onto the outer top-level [`Caixa`] altitude, opening the
3414    /// M2 vec-carry slot family's outer-composite-slice axis. Sibling
3415    /// in shape to the peer outer-`Caixa` `&[Dep]`-return
3416    /// [`Self::deps`] (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and
3417    /// `&[String]`-return [`Self::autores`] (b5d813f) /
3418    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`]
3419    /// (8a36c23) / [`Self::exe`] (65d9527) / [`Self::servicos`]
3420    /// (611f78b) slice-accessors on the sibling outer-`Caixa` scalar-
3421    /// element vec-carry axes — folds the "outer [`Caixa`] `&[T]`
3422    /// slice" projection pattern onto the sibling M2 typed-composite-
3423    /// element axis (`UpgradeFromEntry` composite, matching the
3424    /// per-inner [`UpgradeFromEntry::instructions`] element type at a
3425    /// different altitude).
3426    ///
3427    /// Returns `&[UpgradeFromEntry]` (not `&Vec<UpgradeFromEntry>`)
3428    /// because every downstream consumer of the hot-upgrade list
3429    /// treats it as a read-only sequence — the slice-view is the
3430    /// narrowest borrow that supports every present + roadmapped
3431    /// consumer (`.iter()`, `.len()`, `.is_empty()`, `serde` slice-
3432    /// serialization through
3433    /// `serde_yaml::to_value(&[UpgradeFromEntry])`) without leaking
3434    /// the backing `Vec`'s grow/push/reserve surface no consumer of
3435    /// the typed view reaches for (the storage-side `Vec` remains
3436    /// reachable through the `pub upgrade_from` field for the
3437    /// mutation-carrying serde round-trip and per-test fixture-
3438    /// mutation paths). Named `upgrade_from()` to match the storage
3439    /// field's `snake_case` name; the kebab-case author-surface tag
3440    /// `:upgrade-from` is the same axis after tatara-lisp's
3441    /// kebab↔snake fold and the accessor's identity maps onto the
3442    /// canonical CAIXA-SDLC §II vocabulary the slot's docstring
3443    /// already carries.
3444    #[must_use]
3445    pub fn upgrade_from(&self) -> &[UpgradeFromEntry] {
3446        self.upgrade_from.as_slice()
3447    }
3448
3449    /// Substrate-canonical per-`Caixa` `:children` M2 supervisor-tree-
3450    /// slot outer-composite OTP-shaped per-supervisor static-child-list
3451    /// slice accessor every consumer of the top-level manifest's per-
3452    /// Supervisor `&[ChildSpec]` slice-view keys off — returns the
3453    /// author-declared `:children` typed `Vec<crate::supervisor::ChildSpec>`
3454    /// verbatim as a `&[crate::supervisor::ChildSpec]` slice-view over
3455    /// the same backing buffer the raw `self.children.as_slice()` field
3456    /// access borrows from. Empty-slice-carrying (the "no static children
3457    /// declared" arm every non-`Supervisor`-kind `defcaixa` carries by
3458    /// #[serde(default)] and every `SimpleOneForOne` supervisor carries
3459    /// by [`crate::supervisor::SupervisorError::SimpleOneForOneWithStaticChildren`]
3460    /// gate; the returned `&[ChildSpec]` degenerates to an empty slice
3461    /// on those arms without any silent `None` collapse).
3462    ///
3463    /// The outer `:children` slot carries the M2 typed OTP-supervisor
3464    /// static-child list — the load-bearing container of every per-
3465    /// child `{caixa, versao, restart}` triple the wasm-operator's
3466    /// hierarchical reconciler dispatches on at supervisor-tree
3467    /// materialization time (INSPIRATIONS §II.2 — OTP `supervisor:init/1`
3468    /// static-child list translated onto pleme-io's typed
3469    /// [`crate::supervisor::ChildSpec`] entry list; CAIXA-SDLC §II —
3470    /// the typed-M2 slot algebra the operator's per-supervisor fan-out
3471    /// dispatch fans on). Every per-child axis threads through a lifted
3472    /// per-entry accessor on the [`crate::supervisor::ChildSpec`] type:
3473    /// the [`crate::supervisor::ChildSpec::nome`] DNS-1123-label
3474    /// child-caixa-identity scalar accessor, the peer versao SemVer-2
3475    /// version-requirement scalar accessor, and the
3476    /// [`crate::supervisor::ChildSpec::restart`] `Copy`-composite-enum
3477    /// per-child post-exit restart-decision-policy discriminant
3478    /// accessor (dfb4a81). Every downstream consumer of the supervisor-
3479    /// tree path first passes through this outer accessor onto the
3480    /// slice and then dispatches per-child through the inner accessors
3481    /// — the two-level dispatch means every per-`:children` reader now
3482    /// routes through a typed dispatch on the substrate primitive at
3483    /// both altitudes.
3484    ///
3485    /// Prior to this lift the `.children` `Vec<ChildSpec>` slot was
3486    /// accessed inline at three production sites across two files —
3487    /// the [`Self::declared_supervisor_slots`] supervisor-tree
3488    /// declared-slot enumerator's `!self.children.is_empty()` presence
3489    /// probe (caixa-core/src/manifest.rs, which drives the
3490    /// `SUPERVISOR_AUTHOR_KEY_CHILDREN` kebab-case author-label push
3491    /// every [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3492    /// kind-coherence gate reads), the [`Self::supervisor_view`]
3493    /// per-supervisor typed-view composer's `self.children.clone()`
3494    /// per-child fold-in path (caixa-core/src/manifest.rs, which
3495    /// materializes the typed [`crate::supervisor::SupervisorSpec`]
3496    /// view every [`crate::StandardLayout::verify`] Supervisor-arm gate
3497    /// dispatches on), and the [`crate::StandardLayout::verify`] per-
3498    /// `:children :caixa` self-parent refusal probe's
3499    /// `&caixa.children`-borrowed
3500    /// [`crate::supervisor::validate_no_self_supervision`] input
3501    /// (caixa-core/src/layout.rs, which pins the "no child names the
3502    /// supervisor's own `:nome`" cross-slot coherence gate). A future
3503    /// extension of the outer `:children` axis (a per-cluster
3504    /// `:children-overrides` overlay the wasm-engine operator resolves
3505    /// at admission time so a cluster-specific child-set can tighten
3506    /// a caixa-declared list without re-authoring the `caixa.lisp`,
3507    /// promotion of the plain `Vec<ChildSpec>` to a richer
3508    /// `{static, dynamic}` partition once Erlang/OTP's
3509    /// `simple_one_for_one`-shaped dynamic-child slot lands as a typed
3510    /// axis, per-child priority annotation once multi-strategy fan-out
3511    /// lands) would have had to be threaded through all three open-
3512    /// coded copies in lockstep or one consumer would silently
3513    /// disagree with the peers on which child slice a given Caixa
3514    /// resolves to — the enumerator's presence probe reading the raw
3515    /// slot while the peer view-composer's fold-in path read an
3516    /// operator-resolved slot would silently split the paired
3517    /// declared-slot enumerator and typed-view composition, and the
3518    /// [`crate::supervisor::validate_no_self_supervision`] self-parent
3519    /// refusal probe reading a third borrow would silently drift the
3520    /// cross-slot coherence gate's traversal input from the two peers,
3521    /// a three-consumer split at the enumerator, the view composer,
3522    /// and the self-parent gate far from the source `caixa.lisp` with
3523    /// no field naming the child-set-drift root cause. Lifting the
3524    /// resolution rule to a typed method on the substrate primitive
3525    /// means every downstream consumer of the caixa's per-`Caixa`
3526    /// OTP-supervisor outer-slice surface reaches for exactly one
3527    /// typed dispatch — the resolver's accept-set migrates as a unit
3528    /// on any future axis addition.
3529    ///
3530    /// Second outer top-level [`Caixa`] `&[Composite]`-return slice
3531    /// accessor for M2 / M3 typed-slot vec-carry axes — folds on the
3532    /// outer-`Caixa` `&[Composite]` composite-slice sub-family the
3533    /// sibling [`Self::upgrade_from`] (2a1f907) accessor opened, peer
3534    /// at the outer altitude of the closed inner-`SupervisorSpec`
3535    /// [`crate::SupervisorSpec::children`] (bc92bce) accessor on the
3536    /// same OTP-supervisor static-child-list axis — same "byte-equal,
3537    /// borrow-shared" outer-accessor discipline extended onto the
3538    /// second outer-`Caixa` `&[Composite]` vec-carry axis. Sibling in
3539    /// shape to the peer outer-`Caixa` `&[Dep]`-return [`Self::deps`]
3540    /// (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and `&[String]`-return
3541    /// [`Self::autores`] (b5d813f) / [`Self::etiquetas`] (78c7d3c) /
3542    /// [`Self::bibliotecas`] (8a36c23) / [`Self::exe`] (65d9527) /
3543    /// [`Self::servicos`] (611f78b) slice-accessors on the sibling
3544    /// outer-`Caixa` scalar-element vec-carry axes — folds the "outer
3545    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
3546    /// M2 typed-composite-element axis
3547    /// ([`crate::supervisor::ChildSpec`] composite, matching the
3548    /// per-inner [`crate::SupervisorSpec::children`] element type at a
3549    /// different altitude).
3550    ///
3551    /// Returns `&[crate::supervisor::ChildSpec]` (not
3552    /// `&Vec<ChildSpec>`) because every downstream consumer of the
3553    /// child list treats it as a read-only sequence — the slice-view
3554    /// is the narrowest borrow that supports every present +
3555    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`, the
3556    /// [`crate::supervisor::validate_no_self_supervision`] `&[ChildSpec]`
3557    /// input, `serde` slice-serialization) without leaking the backing
3558    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3559    /// reaches for (the storage-side `Vec` remains reachable through
3560    /// the `pub children` field for the mutation-carrying serde round-
3561    /// trip and per-test fixture-mutation paths, including the
3562    /// [`Self::supervisor_view`] fold-in path that clones the slot
3563    /// into the typed view). Named `children()` to match the storage
3564    /// field's name verbatim and the tatara-lisp author-surface term
3565    /// (`:children`) the field's own docstring already carries; the
3566    /// accessor's identity maps onto the canonical OTP supervision
3567    /// vocabulary the [`Caixa::children`] field's docstring already
3568    /// reaches for ("Static children of a supervisor").
3569    #[must_use]
3570    pub fn children(&self) -> &[crate::supervisor::ChildSpec] {
3571        self.children.as_slice()
3572    }
3573
3574    /// Substrate-canonical per-`Caixa` `:membros` M3 mesh-slot outer-
3575    /// composite MESH-COMPOSITION-shaped per-Aplicacao member-list slice
3576    /// accessor every consumer of the top-level manifest's per-Aplicacao
3577    /// `&[crate::aplicacao::Membro]` slice-view keys off — returns the
3578    /// author-declared `:membros` typed `Vec<crate::aplicacao::Membro>`
3579    /// verbatim as a `&[crate::aplicacao::Membro]` slice-view over the
3580    /// same backing buffer the raw `self.membros.as_slice()` field access
3581    /// borrows from. Empty-slice-carrying (the "no members declared" arm
3582    /// every non-`Aplicacao`-kind `defcaixa` carries by `#[serde(default)]`
3583    /// and every partially-authored Aplicacao carries before the
3584    /// [`crate::AplicacaoError::MembrosEmpty`] gate fires; the returned
3585    /// `&[Membro]` degenerates to an empty slice on those arms without any
3586    /// silent `None` collapse).
3587    ///
3588    /// The outer `:membros` slot carries the M3 typed MESH-COMPOSITION
3589    /// per-Aplicacao member list — the load-bearing container of every
3590    /// per-member `{caixa, versao}` pair the caixa-mesh renderer's
3591    /// per-Aplicacao program-emission dispatch fans on at mesh-artifact
3592    /// materialization time (MESH-COMPOSITION §III.1 — the typed graph's
3593    /// vertex set the `:contratos` `:de`/`:para` edges resolve against and
3594    /// the `:entrada :para` external-gateway destination validates
3595    /// against; CAIXA-SDLC §II — the typed-M3 slot algebra the operator's
3596    /// per-Aplicacao fan-out dispatch fans on). Every per-member axis
3597    /// threads through a lifted per-entry accessor on the
3598    /// [`crate::aplicacao::Membro`] type: the
3599    /// [`crate::aplicacao::Membro::nome`] DNS-1123-label member-caixa-
3600    /// identity scalar accessor (4a32abf) and the peer
3601    /// [`crate::aplicacao::Membro::versao_requirement`] SemVer-2
3602    /// version-requirement scalar accessor (a40b0e3). Every downstream
3603    /// consumer of the mesh-graph path first passes through this outer
3604    /// accessor onto the slice and then dispatches per-member through
3605    /// the inner accessors — the two-level dispatch means every per-
3606    /// `:membros` reader now routes through a typed dispatch on the
3607    /// substrate primitive at both altitudes.
3608    ///
3609    /// Prior to this lift the `.membros` `Vec<Membro>` slot was accessed
3610    /// inline at three production sites across two files — the
3611    /// [`Self::declared_mesh_slots`] mesh-slot declared-slot
3612    /// enumerator's `!self.membros.is_empty()` presence probe
3613    /// (caixa-core/src/manifest.rs, which drives the
3614    /// `M3_AUTHOR_KEY_MEMBROS` kebab-case author-label push every
3615    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3616    /// gate reads), the [`Self::aplicacao_view`] per-Aplicacao typed-view
3617    /// composer's `self.membros.clone()` per-member fold-in path
3618    /// (caixa-core/src/manifest.rs, which materializes the typed
3619    /// [`crate::aplicacao::AplicacaoSpec`] view every
3620    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate dispatches
3621    /// on), and the [`crate::StandardLayout::verify`] per-`:membros
3622    /// :caixa` self-membership refusal probe's `&caixa.membros`-borrowed
3623    /// [`crate::aplicacao::validate_no_self_membership`] input
3624    /// (caixa-core/src/layout.rs, which pins the "no member names the
3625    /// Aplicacao's own `:nome`" cross-slot coherence gate). A future
3626    /// extension of the outer `:membros` axis (a per-cluster
3627    /// `:membros-overrides` overlay the wasm-engine operator resolves at
3628    /// admission time so a cluster-specific member-set can tighten a
3629    /// caixa-declared list without re-authoring the `caixa.lisp`,
3630    /// promotion of the plain `Vec<Membro>` to a richer
3631    /// `{static, dynamic}` partition once runtime-resolved Aplicacao
3632    /// members land as a typed axis, per-member priority annotation once
3633    /// multi-strategy fan-out lands) would have had to be threaded
3634    /// through all three open-coded copies in lockstep or one consumer
3635    /// would silently disagree with the peers on which member slice a
3636    /// given Caixa resolves to — the enumerator's presence probe reading
3637    /// the raw slot while the peer view-composer's fold-in path read an
3638    /// operator-resolved slot would silently split the paired
3639    /// declared-slot enumerator and typed-view composition, and the
3640    /// [`crate::aplicacao::validate_no_self_membership`] self-membership
3641    /// refusal probe reading a third borrow would silently drift the
3642    /// cross-slot coherence gate's traversal input from the two peers, a
3643    /// three-consumer split at the enumerator, the view composer, and
3644    /// the self-membership gate far from the source `caixa.lisp` with no
3645    /// field naming the member-set-drift root cause. Lifting the
3646    /// resolution rule to a typed method on the substrate primitive
3647    /// means every downstream consumer of the caixa's per-`Caixa`
3648    /// MESH-COMPOSITION outer-slice surface reaches for exactly one
3649    /// typed dispatch — the resolver's accept-set migrates as a unit on
3650    /// any future axis addition.
3651    ///
3652    /// Third outer top-level [`Caixa`] `&[Composite]`-return slice
3653    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the outer-
3654    /// `Caixa` M3 mesh-slot arm of the `&[Composite]` composite-slice
3655    /// sub-family the sibling M2 [`Self::upgrade_from`] (2a1f907) /
3656    /// [`Self::children`] (c17b51e) accessors opened for the M2 vec-carry
3657    /// altitude. Peer at the outer altitude of the closed inner-
3658    /// [`crate::AplicacaoSpec::membros`] (6c77e36) accessor on the same
3659    /// MESH-COMPOSITION per-Aplicacao member-list axis — the two
3660    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3661    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3662    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3663    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3664    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3665    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3666    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3667    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3668    /// pattern onto the sibling M3 typed-composite-element axis
3669    /// ([`crate::aplicacao::Membro`] composite, matching the per-inner
3670    /// [`crate::AplicacaoSpec::membros`] element type at a different
3671    /// altitude).
3672    ///
3673    /// Returns `&[crate::aplicacao::Membro]` (not `&Vec<Membro>`)
3674    /// because every downstream consumer of the member list treats it
3675    /// as a read-only sequence — the slice-view is the narrowest borrow
3676    /// that supports every present + roadmapped consumer (`.iter()`,
3677    /// `.len()`, `.is_empty()`, the
3678    /// [`crate::aplicacao::validate_no_self_membership`] `&[Membro]`
3679    /// input, `serde` slice-serialization) without leaking the backing
3680    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3681    /// reaches for (the storage-side `Vec` remains reachable through the
3682    /// `pub membros` field for the mutation-carrying serde round-trip
3683    /// and per-test fixture-mutation paths, including the
3684    /// [`Self::aplicacao_view`] fold-in path that clones the slot into
3685    /// the typed view). Named `membros()` to match the storage field's
3686    /// name verbatim and the tatara-lisp author-surface term
3687    /// (`:membros`) the field's own docstring already carries; the
3688    /// accessor's identity maps onto the canonical MESH-COMPOSITION
3689    /// vocabulary the [`Caixa::membros`] field's docstring already
3690    /// reaches for ("Member Servicos that make up this Aplicacao").
3691    #[must_use]
3692    pub fn membros(&self) -> &[crate::aplicacao::Membro] {
3693        self.membros.as_slice()
3694    }
3695
3696    /// Substrate-canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
3697    /// composite MESH-COMPOSITION-shaped per-Aplicacao WIT-typed
3698    /// inter-Servico contract-list slice accessor every consumer of the
3699    /// top-level manifest's per-Aplicacao `&[crate::aplicacao::WitContract]`
3700    /// slice-view keys off — returns the author-declared `:contratos`
3701    /// typed `Vec<crate::aplicacao::WitContract>` verbatim as a
3702    /// `&[crate::aplicacao::WitContract]` slice-view over the same
3703    /// backing buffer the raw `self.contratos.as_slice()` field access
3704    /// borrows from. Empty-slice-carrying (the "no contracts declared"
3705    /// arm every non-`Aplicacao`-kind `defcaixa` carries by
3706    /// `#[serde(default)]` and every leaf Aplicacao carrying only a
3707    /// single member with no inter-Servico edge carries; the returned
3708    /// `&[WitContract]` degenerates to an empty slice on those arms
3709    /// without any silent `None` collapse).
3710    ///
3711    /// The outer `:contratos` slot carries the M3 typed MESH-COMPOSITION
3712    /// per-Aplicacao WIT-typed inter-Servico edge list — the load-bearing
3713    /// container of every per-edge `{de, para, wit, endpoint | subject |
3714    /// slot}` quadruple the caixa-mesh renderer's per-Aplicacao
3715    /// `CiliumNetworkPolicy` fan-out (one L7 policy per edge —
3716    /// MESH-COMPOSITION §III.2 point 2) and per-`(:de, :para)`
3717    /// adjacency-list seed dispatch on at mesh-artifact materialization
3718    /// time (MESH-COMPOSITION §III.1 — the typed graph's edge set the
3719    /// `:membros` vertex set resolves against, closed by the
3720    /// [`crate::AplicacaoError::ContractoUnknownMember`] / cycle-refusal
3721    /// gates in §III.3; CAIXA-SDLC §II — the typed-M3 slot algebra the
3722    /// operator's per-Aplicacao fan-out dispatch fans on). Every
3723    /// per-edge axis threads through a lifted per-entry accessor on the
3724    /// [`crate::aplicacao::WitContract`] type: the peer `de` / `para`
3725    /// DNS-1123-label member-caixa-name endpoint scalar accessors, the
3726    /// [`crate::aplicacao::WitContract::endpoint`] (7020470) HTTP-shape
3727    /// / [`crate::aplicacao::WitContract::subject`] (90de675)
3728    /// NATS-pub-sub-shape / [`crate::aplicacao::WitContract::slot`]
3729    /// (ed22b66) `wasi:keyvalue/store`-shape payload-carrier accessors,
3730    /// and the WIT-world discriminant. Every downstream consumer of the
3731    /// mesh-graph edge path first passes through this outer accessor
3732    /// onto the slice and then dispatches per-contract through the
3733    /// inner accessors — the two-level dispatch means every
3734    /// per-`:contratos` reader now routes through a typed dispatch on
3735    /// the substrate primitive at both altitudes.
3736    ///
3737    /// Prior to this lift the `.contratos` `Vec<WitContract>` slot was
3738    /// accessed inline at two production sites in
3739    /// caixa-core/src/manifest.rs — the [`Self::declared_mesh_slots`]
3740    /// mesh-slot declared-slot enumerator's
3741    /// `!self.contratos.is_empty()` presence probe (which drives the
3742    /// `M3_AUTHOR_KEY_CONTRATOS` kebab-case author-label push every
3743    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3744    /// gate reads) and the [`Self::aplicacao_view`] per-Aplicacao
3745    /// typed-view composer's `self.contratos.clone()` per-contract
3746    /// fold-in path (which materializes the typed
3747    /// [`crate::aplicacao::AplicacaoSpec`] view every
3748    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate and every
3749    /// downstream `caixa-mesh` renderer dispatches on). A future
3750    /// extension of the outer `:contratos` axis (a per-cluster
3751    /// `:contratos-overrides` overlay the wasm-engine operator resolves
3752    /// at admission time so a cluster-specific edge-set can tighten a
3753    /// caixa-declared list without re-authoring the `caixa.lisp`,
3754    /// promotion of the plain `Vec<WitContract>` to a richer
3755    /// `{static, dynamic}` partition once runtime-resolved contract
3756    /// edges land, per-edge policy annotation once the M4 per-edge
3757    /// policy overlay axis lands) would have had to be threaded through
3758    /// both open-coded copies in lockstep or one consumer would
3759    /// silently disagree with the peer on which edge slice a given
3760    /// Caixa resolves to — the enumerator's presence probe reading the
3761    /// raw slot while the peer view-composer's fold-in path read an
3762    /// operator-resolved slot would silently split the paired
3763    /// declared-slot enumerator and typed-view composition, a
3764    /// two-consumer split at the enumerator and the view composer far
3765    /// from the source `caixa.lisp` with no field naming the edge-set-
3766    /// drift root cause. Lifting the resolution rule to a typed method
3767    /// on the substrate primitive means every downstream consumer of
3768    /// the caixa's per-`Caixa` MESH-COMPOSITION outer-slice surface
3769    /// reaches for exactly one typed dispatch — the resolver's
3770    /// accept-set migrates as a unit on any future axis addition.
3771    ///
3772    /// Fourth and final outer top-level [`Caixa`] `&[Composite]`-return
3773    /// slice accessor for M2 / M3 typed-slot vec-carry axes — closes
3774    /// the outer-`Caixa` `&[Composite]` composite-slice sub-family the
3775    /// sibling M2 [`Self::upgrade_from`] (2a1f907) / [`Self::children`]
3776    /// (c17b51e) accessors opened and the M3 [`Self::membros`]
3777    /// (0f26987) accessor folded on, and closes the outer-`Caixa` M3
3778    /// mesh-slot arm of the composite-slice sub-family the sibling
3779    /// [`Self::membros`] accessor opened for the M3 vec-carry altitude.
3780    /// Peer at the outer altitude of the closed inner-
3781    /// [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
3782    /// same MESH-COMPOSITION per-Aplicacao contract-list axis — the two
3783    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3784    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3785    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3786    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3787    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3788    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3789    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3790    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3791    /// pattern onto the sibling M3 typed-composite-element axis
3792    /// ([`crate::aplicacao::WitContract`] composite, matching the
3793    /// per-inner [`crate::AplicacaoSpec::contratos`] element type at a
3794    /// different altitude).
3795    ///
3796    /// Returns `&[crate::aplicacao::WitContract]` (not
3797    /// `&Vec<WitContract>`) because every downstream consumer of the
3798    /// contract list treats it as a read-only sequence — the slice-view
3799    /// is the narrowest borrow that supports every present + roadmapped
3800    /// consumer (`.iter()`, `.len()`, `.is_empty()`, per-edge WIT-world
3801    /// discriminant dispatch, `serde` slice-serialization) without
3802    /// leaking the backing `Vec`'s grow/push/reserve surface no
3803    /// consumer of the typed view reaches for (the storage-side `Vec`
3804    /// remains reachable through the `pub contratos` field for the
3805    /// mutation-carrying serde round-trip and per-test fixture-mutation
3806    /// paths, including the [`Self::aplicacao_view`] fold-in path that
3807    /// clones the slot into the typed view). Named `contratos()` to
3808    /// match the storage field's name verbatim and the tatara-lisp
3809    /// author-surface term (`:contratos`) the field's own docstring
3810    /// already carries; the accessor's identity maps onto the canonical
3811    /// MESH-COMPOSITION vocabulary the [`Caixa::contratos`] field's
3812    /// docstring already reaches for ("WIT-typed inter-Servico
3813    /// contracts").
3814    #[must_use]
3815    pub fn contratos(&self) -> &[crate::aplicacao::WitContract] {
3816        self.contratos.as_slice()
3817    }
3818
3819    /// Compose the Aplicacao-related flat slots into a single typed
3820    /// [`crate::aplicacao::AplicacaoSpec`] for validation +
3821    /// downstream renderer consumption. Returns `None` when the
3822    /// caixa isn't a `:kind Aplicacao`.
3823    #[must_use]
3824    pub fn aplicacao_view(&self) -> Option<crate::aplicacao::AplicacaoSpec> {
3825        if !self.kind().is_aplicacao() {
3826            return None;
3827        }
3828        Some(crate::aplicacao::AplicacaoSpec {
3829            membros: self.membros().to_vec(),
3830            contratos: self.contratos().to_vec(),
3831            politicas: self.politicas().cloned().unwrap_or_default(),
3832            placement: self.placement().cloned().unwrap_or_default(),
3833            entrada: self.entrada().cloned(),
3834        })
3835    }
3836
3837    /// The kebab-case `:slot` tags of every M3 mesh slot this caixa
3838    /// *declares* a value on, in canonical declaration order
3839    /// (`:membros` → `:contratos` → `:politicas` → `:placement` →
3840    /// `:entrada`). A slot counts as declared when its backing field
3841    /// carries a value — a non-empty `Vec`, or a `Some(...)`.
3842    ///
3843    /// The M3 mesh slots compose the typed graph of a `:kind Aplicacao`
3844    /// (MESH-COMPOSITION §III.1). [`Self::aplicacao_view`] only folds
3845    /// them into a validatable [`crate::aplicacao::AplicacaoSpec`] when
3846    /// the kind matches (returns `None` otherwise), and the caixa-mesh /
3847    /// caixa-flux / caixa-helm renderers only emit them for an
3848    /// Aplicacao. On any *other* kind a declared mesh slot is the
3849    /// manifest field's documented "ignored otherwise" (see the
3850    /// `:membros` … `:entrada` field docs): it silently passes
3851    /// [`Caixa::from_lisp`] and then vanishes — never validated, never
3852    /// rendered — far from the source caixa.lisp.
3853    /// [`crate::StandardLayout::verify`] consults this to reject that
3854    /// silent-drop at caixa-build time
3855    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]), mirroring the
3856    /// `SupervisorOwnsCode` / `AplicacaoOwnsCode` kind-coherence gates:
3857    /// a slot foreign to the kind is a build error, not a silent drop.
3858    ///
3859    /// Lifted as a typed method (rather than an inline disjunction at
3860    /// the verify call site) so the mesh-slot set lives in one place —
3861    /// a future M4 axis added to the Aplicacao surface (per-edge policy
3862    /// overlay, distributed-app takeover config) is one push here, and
3863    /// every consumer reaching for "which mesh slots are set" (the
3864    /// verify gate, a future `feira lint` kind-coherence advisory)
3865    /// inherits the canonical order without rolling its own.
3866    ///
3867    /// Each per-arm kebab-case label is routed through the peer
3868    /// [`crate::M3_AUTHOR_KEY_MEMBROS`] /
3869    /// [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
3870    /// [`crate::M3_AUTHOR_KEY_POLITICAS`] /
3871    /// [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
3872    /// [`crate::M3_AUTHOR_KEY_ENTRADA`] consts declared next to the
3873    /// [`crate::M3_KEY_PLACEMENT`] renderer-side wire-key peer, so both
3874    /// halves of every M3 top-level mesh slot's dual axis (author-facing
3875    /// kebab-case label + renderer-side artifact key) route through one
3876    /// canonical declaration per arm — same discipline the peer
3877    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`]
3878    /// / [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot consts
3879    /// (f49c8b0) establish on the sibling per-Servico M2 top-level slot
3880    /// axis, extended here to close the M3 mesh-slot author-facing-label
3881    /// axis so both altitudes of the typed-slot algebra
3882    /// (per-Servico M2 + per-Aplicacao M3) share the same
3883    /// "one canonical byte-string per arm, next to the axis" discipline.
3884    #[must_use]
3885    pub fn declared_mesh_slots(&self) -> Vec<&'static str> {
3886        let mut slots = Vec::new();
3887        if !self.membros().is_empty() {
3888            slots.push(crate::render::M3_AUTHOR_KEY_MEMBROS);
3889        }
3890        if !self.contratos().is_empty() {
3891            slots.push(crate::render::M3_AUTHOR_KEY_CONTRATOS);
3892        }
3893        if self.politicas().is_some() {
3894            slots.push(crate::render::M3_AUTHOR_KEY_POLITICAS);
3895        }
3896        if self.placement().is_some() {
3897            slots.push(crate::render::M3_AUTHOR_KEY_PLACEMENT);
3898        }
3899        if self.entrada().is_some() {
3900            slots.push(crate::render::M3_AUTHOR_KEY_ENTRADA);
3901        }
3902        slots
3903    }
3904
3905    /// The kebab-case `:slot` tags of every supervisor-tree slot this
3906    /// caixa *declares* a value on, in canonical declaration order
3907    /// (`:estrategia` → `:max-restarts` → `:restart-window` →
3908    /// `:children`). A slot counts as declared when its backing field
3909    /// carries a value — a `Some(...)`, or a non-empty `Vec`.
3910    ///
3911    /// The supervisor-tree slots compose the typed OTP supervisor of a
3912    /// `:kind Supervisor` (INSPIRATIONS §II.2; the `:estrategia` +
3913    /// `:children` field docs above). [`Self::supervisor_view`] only
3914    /// folds them into a validatable [`SupervisorSpec`] when the kind
3915    /// matches (returns `None` otherwise), and the wasm-operator's
3916    /// hierarchical reconciler only consumes them for a Supervisor. On
3917    /// any *other* kind a declared supervisor slot is the manifest
3918    /// field's documented "ignored otherwise" (see the `:estrategia` …
3919    /// `:children` field docs): it silently passes [`Caixa::from_lisp`]
3920    /// and then vanishes — never validated, never reconciled — far from
3921    /// the source caixa.lisp. [`crate::StandardLayout::verify`] consults
3922    /// this to reject that silent-drop at caixa-build time
3923    /// ([`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]), the
3924    /// exact mirror of the [`Self::declared_mesh_slots`] /
3925    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] gate on the
3926    /// Aplicacao-only slot set: a slot foreign to the kind is a build
3927    /// error, not a silent drop.
3928    #[must_use]
3929    pub fn declared_supervisor_slots(&self) -> Vec<&'static str> {
3930        let mut slots = Vec::new();
3931        if self.estrategia().is_some() {
3932            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA);
3933        }
3934        if self.max_restarts().is_some() {
3935            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS);
3936        }
3937        if self.restart_window().is_some() {
3938            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW);
3939        }
3940        if !self.children().is_empty() {
3941            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN);
3942        }
3943        slots
3944    }
3945
3946    /// The kebab-case `:slot` tags of every M2 Servico-runtime slot this
3947    /// caixa *declares* a value on, in canonical declaration order
3948    /// (`:limits` → `:behavior` → `:upgrade-from`). A slot counts as
3949    /// declared when its backing field carries a value — a `Some(...)`,
3950    /// or a non-empty `Vec`.
3951    ///
3952    /// The M2 slots configure the runtime of a long-running wasm
3953    /// component, i.e. a `:kind Servico`: `:limits` is Lunatic
3954    /// per-process sandboxing (INSPIRATIONS §III.1), `:behavior` is the
3955    /// OTP `gen_server` callback set (§II.3), `:upgrade-from` is the OTP
3956    /// appup hot-code-reload table (§II.4). The caixa-helm / caixa-flux
3957    /// renderers gate on [`crate::require_kind`]`(_, Servico)` and only
3958    /// emit these slots for a Servico; on any *other* kind a declared M2
3959    /// slot is the manifest field's documented "ignored otherwise": its
3960    /// well-formedness is checked by [`crate::StandardLayout::verify`]
3961    /// but the value is never rendered into a chart / programs.yaml entry
3962    /// — it silently passes [`Caixa::from_lisp`] + `feira build` and then
3963    /// vanishes, far from the source caixa.lisp.
3964    /// [`crate::StandardLayout::verify`] consults this to reject that
3965    /// silent-drop at caixa-build time
3966    /// ([`crate::LayoutError::ServicoSlotsOnNonServico`]), the exact
3967    /// mirror of the [`Self::declared_mesh_slots`] /
3968    /// [`Self::declared_supervisor_slots`] gates on the peer
3969    /// kind-exclusive slot sets: a slot foreign to the kind is a build
3970    /// error, not a silent drop.
3971    ///
3972    /// Each per-arm kebab-case label is routed through the peer
3973    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
3974    /// [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts declared next to the
3975    /// [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
3976    /// [`crate::M2_KEY_UPGRADE_FROM`] renderer-side wire-key peers, so
3977    /// both halves of the M2 top-level slot's dual axis (author-facing
3978    /// kebab-case label + renderer-side camelCase overlay-container wire
3979    /// key) route through one canonical declaration per arm — same
3980    /// discipline the peer [`crate::M2_BEHAVIOR_AUTHOR_KEY_ON_*`] sub-slot
3981    /// author-label consts (889dc18) establish on the sibling
3982    /// per-callback axis inside the `:behavior` overlay block.
3983    #[must_use]
3984    pub fn declared_servico_slots(&self) -> Vec<&'static str> {
3985        let mut slots = Vec::new();
3986        if self.limits().is_some() {
3987            slots.push(crate::render::M2_AUTHOR_KEY_LIMITS);
3988        }
3989        if self.behavior().is_some() {
3990            slots.push(crate::render::M2_AUTHOR_KEY_BEHAVIOR);
3991        }
3992        if !self.upgrade_from().is_empty() {
3993            slots.push(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM);
3994        }
3995        slots
3996    }
3997
3998    /// The kebab-case `:slot` tags of every code-surface slot this caixa
3999    /// declares a value on that its [`CaixaKind`] doesn't natively own,
4000    /// in canonical declaration order (`:exe` → `:servicos`). A
4001    /// code-surface slot is owned by exactly one kind: `:exe` by
4002    /// [`CaixaKind::Binario`] (the nix-built executable surface), and
4003    /// `:servicos` by [`CaixaKind::Servico`] (the wasm component +
4004    /// `ComputeUnit` daemon surface).
4005    ///
4006    /// Each is silently ignored when declared on the wrong kind: the
4007    /// caixa-helm / caixa-flux / caixa-flake renderers gate on
4008    /// [`crate::require_kind`]`(_, <owning-kind>)`, so on any *other*
4009    /// code-running kind a declared `:exe` / `:servicos` is the manifest
4010    /// field's documented "ignored otherwise" — its path is checked for
4011    /// existence by the layout's `bibliotecas`/`exe`/`servicos` loops
4012    /// (which run after [`Caixa::from_lisp`]), but the value is never
4013    /// rendered into a build target or programs.yaml entry. It silently
4014    /// passes [`Caixa::from_lisp`] + `feira build`, far from the source
4015    /// caixa.lisp, with no field naming which slot is foreign.
4016    ///
4017    /// [`crate::StandardLayout::verify`] consults this to reject that
4018    /// silent-drop at caixa-build time
4019    /// ([`crate::LayoutError::ForeignCodeSlot`]), beside the M2
4020    /// servico-runtime, supervisor-tree, and M3 mesh kind-coherence
4021    /// gates ([`Self::declared_servico_slots`] /
4022    /// [`Self::declared_supervisor_slots`] /
4023    /// [`Self::declared_mesh_slots`]): the fourth kind ↔ slot algebra
4024    /// axis to be closed on the typed surface. The Supervisor /
4025    /// Aplicacao "no code at all" cases ([`crate::LayoutError::SupervisorOwnsCode`]
4026    /// / [`crate::LayoutError::AplicacaoOwnsCode`]) keep their dedicated
4027    /// diagnostics — they fire ahead of this gate on the same `verify`
4028    /// pass, so for Supervisor / Aplicacao the `OwnCode` arm always wins
4029    /// and this method is moot. For Biblioteca / Binario / Servico, this
4030    /// gate fires when a code-running kind declares another code-running
4031    /// kind's exclusive code surface.
4032    ///
4033    /// `:bibliotecas` is deliberately excluded — a Binario or Servico
4034    /// may legitimately ship a `lib/` helper that the underlying
4035    /// substrate (the nix flake for Binario, the wasm component build
4036    /// for Servico) bundles into its build, so the slot's
4037    /// declared-on-wrong-kind cardinality isn't a structural error on
4038    /// either code-running kind. A Biblioteca declaring `:bibliotecas`
4039    /// is the native case (the slot's owning kind). Supervisor /
4040    /// Aplicacao declaring `:bibliotecas` is gated upstream by
4041    /// [`crate::LayoutError::SupervisorOwnsCode`] /
4042    /// [`crate::LayoutError::AplicacaoOwnsCode`].
4043    ///
4044    /// Lifted as a typed method (rather than an inline disjunction at
4045    /// the verify call site) so the foreign-code-slot set lives in one
4046    /// place — a future kind that gains its own code-surface slot is
4047    /// one push here, and every consumer reaching for "which code
4048    /// surfaces are foreign to this kind" (the verify gate, a future
4049    /// `feira lint` kind-coherence advisory, the future `app-operator`'s
4050    /// per-caixa build-target classifier) inherits the canonical order
4051    /// without rolling its own.
4052    #[must_use]
4053    pub fn declared_foreign_code_slots(&self) -> Vec<&'static str> {
4054        let mut slots = Vec::new();
4055        if !self.exe().is_empty() && !self.kind().requires_exe() {
4056            slots.push(":exe");
4057        }
4058        if !self.servicos().is_empty() && !self.kind().requires_servicos() {
4059            slots.push(":servicos");
4060        }
4061        slots
4062    }
4063
4064    /// Validate every entry of `:deps` and `:deps-dev` through
4065    /// [`Dep::validate`] — closing the parity loop with the per-axis
4066    /// `:versao` gates already wired into the typed-graph
4067    /// ([`crate::AplicacaoSpec::validate_membros`] for `:membros`,
4068    /// 9888b13) and typed supervisor tree
4069    /// ([`crate::SupervisorSpec::validate`] for `:children`, b38ff3a).
4070    ///
4071    /// Until this gate landed `:deps :versao` and `:deps-dev :versao`
4072    /// were the only `:versao` axes still untyped past
4073    /// [`Caixa::from_lisp`]: the derive macro stored the requirement
4074    /// as a String without parsing it, so a malformed-but-non-empty
4075    /// requirement (`"^bad-version"`, `"^^0.1"`, `"v0.1"`, `"not-a-req"`)
4076    /// silently passed parse and the `semver::Error` surfaced at
4077    /// lacre-resolve time, far from the source caixa.lisp, with no
4078    /// field naming which `:deps` entry carried the typo. Lifting the
4079    /// gate here makes the four `:versao` typed surfaces (`:deps`,
4080    /// `:deps-dev`, `:membros`, `:children`) structurally equivalent —
4081    /// every requirement string past `validate_deps` is round-trippable
4082    /// through [`crate::parse_requirement`] without re-checking at the
4083    /// resolver layer.
4084    ///
4085    /// Both lists run through the same per-entry validator so a typo
4086    /// in `:deps-dev` surfaces with the same diagnostic as one in
4087    /// `:deps` — neither axis is a second-class citizen of the typed
4088    /// surface.
4089    ///
4090    /// Within each list, [`DepError::DuplicateNome`] closes the
4091    /// set-not-multiset discipline on the `:nome` axis: two entries
4092    /// naming the same caixa carry two `:versao` / `:fonte` / feature
4093    /// triples that the caixa-resolver's lacre pipeline collapses to one
4094    /// via its `HashMap`-keyed-by-`:nome` consumption — the second entry
4095    /// silently overwrites the first at `concrete_versao`-resolve time
4096    /// (the same "second wins / one silently overwrites the other"
4097    /// shape the peer typed-graph duplicate gates already close on every
4098    /// other Vec-shaped authoring surface that keys by name). The
4099    /// duplicate check fires per-list and runs *after* each per-entry
4100    /// [`Dep::validate`] call so a malformed-and-duplicated entry
4101    /// surfaces its narrower per-entry diagnostic
4102    /// ([`DepError::NomeInvalid`], [`DepError::VersaoInvalid`],
4103    /// [`DepError::FonteRepoEmpty`], …) before the cross-entry duplicate
4104    /// diagnostic — the canonical "per-entry shape before cross-entry
4105    /// uniqueness" precedence the peer `:children :caixa`
4106    /// ([`crate::SupervisorSpec::validate`]), `:membros :caixa`
4107    /// ([`crate::AplicacaoSpec::validate_membros`]), `:contratos`
4108    /// ([`crate::AplicacaoSpec::validate`]), `:placement :clusters`
4109    /// ([`crate::AplicacaoSpec::validate_placement`]),
4110    /// `:entrada :paths` ([`crate::AplicacaoSpec::validate`]),
4111    /// `:upgrade-from :from` ([`crate::upgrade::validate_upgrade_from`]),
4112    /// and the within-`:upgrade-from`-entry per-instruction-class
4113    /// singularity gates ([`crate::UpgradeError::DuplicateLoadModule`],
4114    /// [`crate::UpgradeError::DuplicateStateChange`],
4115    /// [`crate::UpgradeError::DuplicateCleanup`]) all establish.
4116    ///
4117    /// Cross-list (`:deps` ↔ `:deps-dev`) coincidence is *not* gated
4118    /// here: Cargo's `[dependencies]` + `[dev-dependencies]` accept the
4119    /// same name in both tables (the dev table's pin overrides the
4120    /// runtime table's pin in test/dev contexts), and caixa's surface
4121    /// mirrors that convention until a deliberate choice retires the
4122    /// override pattern. Only within-list duplicates are structurally
4123    /// incoherent — those are what this gate closes.
4124    pub fn validate_deps(&self) -> Result<(), DepError> {
4125        for &list in crate::dep::DepList::ALL {
4126            let mut seen = std::collections::HashSet::new();
4127            for dep in self.deps_of(list) {
4128                dep.validate()?;
4129                crate::render::insert_first_seen(&mut seen, dep.nome(), || {
4130                    DepError::DuplicateNome {
4131                        nome: dep.nome().to_string(),
4132                        list: list.as_str(),
4133                    }
4134                })?;
4135            }
4136        }
4137        Ok(())
4138    }
4139
4140    /// Reject `:nome` values the K8s apiserver would refuse at admission
4141    /// time. The top-level Caixa identity flows directly into every
4142    /// substrate-side artifact's `metadata.name` axis: the
4143    /// `lareira-<nome>` Helm chart name ([`caixa-helm::lib::chart_name`]),
4144    /// the programs.yaml `name:` entry the `lareira-fleet-programs`
4145    /// aggregator keys ComputeUnit derivation off
4146    /// ([`caixa-flux::lib::programs_yaml_entry`]), the
4147    /// `LABEL_APLICACAO` label value carried on every Aplicacao-owned
4148    /// pod and the per-`:contratos` CiliumNetworkPolicy `metadata.name`
4149    /// (`<aplicacao>-<de>-to-<para>`) and the per-`:entrada`
4150    /// `<aplicacao>-<para>` HTTPRoute `metadata.name`
4151    /// ([`caixa-mesh::lib::cilium_network_policies`],
4152    /// [`caixa-mesh::lib::gateway_routes`]), and the default
4153    /// `lib/<nome>.lisp` / `exe/<nome>` layout paths
4154    /// ([`crate::StandardLayout::verify`]). Each K8s apiserver-side
4155    /// schema enforces the DNS-1123 label rule on admission; a
4156    /// structurally invalid `:nome` (`"MyApp"` — the canonical
4157    /// "I copied the display name verbatim" footgun, `"my_app"` — the
4158    /// Python-/Postgres-leak, `"team.app"` — `:nome` is a single label
4159    /// not a subdomain, `"-app"` / `"app-"` — DNS-1123 boundary
4160    /// violations, `"my app"` — the paste-from-doc footgun, `"café"` —
4161    /// IDN must be pre-encoded as Punycode, the 64-byte UUID-shaped
4162    /// over-cap slug) silently passed [`Caixa::from_lisp`] and the
4163    /// failure surfaced at `kubectl apply` time as a `metadata.name:
4164    /// Invalid value` rejection on whichever derived artifact admitted
4165    /// first, far from the source `caixa.lisp` and without any field
4166    /// naming the offending `:nome`.
4167    ///
4168    /// Thin wrapper around [`crate::render::is_dns_1123_label`] (the
4169    /// substrate-side predicate the per-axis name gates already share:
4170    /// `:membros :caixa` 3f9d7a0, `:placement :clusters` 6cbb900,
4171    /// `:children :caixa` 31bfa43) that maps the shared parser-shaped
4172    /// reason into the [`ManifestError::NomeInvalid`] variant, so the
4173    /// diagnostic is self-locating (the offending `:nome` is named
4174    /// verbatim) and the author can grep their `caixa.lisp` for
4175    /// `:nome "<value>"` and fix it in one edit. Same diagnostic shape
4176    /// every per-axis sibling gate already exposes
4177    /// ([`crate::AplicacaoError::MembroCaixaInvalid`],
4178    /// [`crate::AplicacaoError::PlacementClusterInvalid`],
4179    /// [`crate::SupervisorError::ChildCaixaInvalid`]).
4180    ///
4181    /// Empty `:nome` (which [`Caixa::from_lisp`] does not reject — the
4182    /// derive macro stores the raw String) is gated by the narrower
4183    /// [`ManifestError::NomeEmpty`] arm before the predicate is
4184    /// consulted, mirroring the empty-first cascade every per-axis
4185    /// name gate already uses (e.g. `MembroCaixaEmpty` before
4186    /// `MembroCaixaInvalid`, `EmptyChildName` before `ChildCaixaInvalid`).
4187    pub fn validate_nome(&self) -> Result<(), ManifestError> {
4188        // Routes through the shared
4189        // [`crate::render::require_valid_dns_1123_label`] gate the peer
4190        // name axes each land on so drift between the eight axes'
4191        // accepted DNS-1123-label sets is structurally impossible.
4192        let nome = self.nome();
4193        crate::render::require_valid_dns_1123_label(
4194            nome,
4195            || ManifestError::NomeEmpty,
4196            |reason| ManifestError::NomeInvalid {
4197                nome: nome.to_string(),
4198                reason,
4199            },
4200        )
4201    }
4202
4203    /// Reject `:nome` values whose joint length with the canonical
4204    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] (`"lareira-"`) overflows
4205    /// the K8s DNS-1123 label cap [`crate::DNS_1123_LABEL_MAX_LEN`]
4206    /// (63 bytes). Every per-Servico / per-Aplicacao renderer the
4207    /// substrate carries materializes the caixa's `:nome` through the
4208    /// canonical [`crate::lareira_chart_name`] helper (f7320d7) into a
4209    /// `lareira-<nome>` artifact that lands as a K8s `metadata.name` /
4210    /// Helm chart name / `HelmRelease` `release_name`: `caixa-helm`'s
4211    /// `ChartDir.name` + `Chart.yaml::name`
4212    /// (caixa-helm/src/lib.rs:207), `caixa-flux`'s `cluster_bundle`
4213    /// `HelmRelease` `chart:` slot (caixa-flux/src/lib.rs:329),
4214    /// `caixa-tatara`'s `process_for_aplicacao` `release_name` +
4215    /// `oci://<registry>/lareira-<nome>` chart ref
4216    /// (caixa-tatara/src/lib.rs:124,178). Helm's own `Chart.yaml::name`
4217    /// admission rule strict-parses against DNS-1123-label, the Helm
4218    /// operator's tracking-secret name is derived from `release_name`
4219    /// and is itself DNS-1123-label-bounded, and the rendered chart's
4220    /// K8s object `metadata.name` axes embed the chart name as a
4221    /// prefix — every one fails admission on a > 63-byte chart name.
4222    ///
4223    /// The per-axis [`Self::validate_nome`] gate (6c992f8) already
4224    /// caps `:nome` itself at 63 bytes via [`is_dns_1123_label`], so a
4225    /// `:nome` of 56–63 bytes silently passed validate (the inner
4226    /// DNS-1123 check accepts the bare `:nome`) but produced a
4227    /// `lareira-<nome>` of 64–71 bytes that the apiserver / `helm lint`
4228    /// rejected at admission — far from the source `caixa.lisp`, with
4229    /// no field naming the overflow root cause. The
4230    /// [`lareira_chart_name`] helper's own doc comment
4231    /// (caixa-core/src/render.rs:3198) explicitly deferred the fix:
4232    /// "the M4 admission webhook will pin the joint-length invariant
4233    /// when it lands". This gate lands the invariant at the
4234    /// manifest-validate layer rather than waiting for the apiserver
4235    /// — the same fail-at-the-source posture every peer per-axis
4236    /// value-shape gate (DNS-1123 on `:nome`, SemVer-2 on `:versao`,
4237    /// SPDX-expression-shape on `:licenca`, 4-digit decimal year on
4238    /// `:edicao`, etc.) takes.
4239    ///
4240    /// Thin wrapper around
4241    /// [`crate::render::is_lareira_chart_name_shape`] (the
4242    /// substrate-side predicate that composes [`lareira_chart_name`] +
4243    /// [`is_dns_1123_label`] via the lifted
4244    /// [`crate::LAREIRA_CHART_NAME_NOME_MAX_LEN`] budget); maps the
4245    /// shared parser-shaped reason into the
4246    /// [`ManifestError::NomeChartNameBudgetExceeded`] variant so the
4247    /// diagnostic is self-locating (the offending `:nome` is named
4248    /// verbatim alongside the rendered chart name and the budget) and
4249    /// the author can shorten in one edit. The gate runs across every
4250    /// `:kind` — `:nome` is the substrate-wide identity axis any
4251    /// future renderer the substrate adds can derive a
4252    /// `lareira-<nome>` artifact from, and uniform enforcement closes
4253    /// the drift footgun where a future kind grows a chart-emitting
4254    /// render path while the validate cascade doesn't catch it.
4255    ///
4256    /// Runs *after* [`Self::validate_nome`] so the narrower
4257    /// `NomeEmpty` / `NomeInvalid` shape diagnostics fire first — a
4258    /// structurally-malformed `:nome` (empty, uppercase, underscore,
4259    /// dot, leading/trailing hyphen, Unicode, > 63 bytes) surfaces its
4260    /// specific shape error rather than the chart-name-budget error,
4261    /// preserving the legitimate "well-shaped `:nome` that happens to
4262    /// overflow the joint cap" arm for this gate.
4263    pub fn validate_nome_chart_name_budget(&self) -> Result<(), ManifestError> {
4264        let nome = self.nome();
4265        crate::render::is_lareira_chart_name_shape(nome).map_err(|reason| {
4266            ManifestError::NomeChartNameBudgetExceeded {
4267                nome: nome.to_string(),
4268                reason,
4269            }
4270        })
4271    }
4272
4273    /// Reject `:versao` values that don't parse as [`semver::Version`].
4274    /// The top-level Caixa version flows directly into every
4275    /// substrate-side artifact that carries a "this is which version of
4276    /// the caixa" axis: the `lareira-<nome>` Helm chart's `Chart.yaml`
4277    /// `version:` + `appVersion:` axes ([`caixa-helm::lib`] —
4278    /// SemVer-2-strict at `helm template` / `helm install` time per
4279    /// https://helm.sh/docs/topics/charts/#charts-and-versioning), the
4280    /// `feira publish` Zig-style `v<versao>` git tag
4281    /// ([`caixa-flux::lib::programs_yaml_entry`] / the
4282    /// `caixa-publish.yml` reusable workflow), the programs.yaml entry's
4283    /// `versao:` value the `lareira-fleet-programs` aggregator carries
4284    /// onto each rendered ComputeUnit, the OCI image's `:v<versao>` /
4285    /// `:latest` tags the substrate's `wasi-service-flake` builds with
4286    /// `skopeo push`, the lacre closure's pinned versions
4287    /// ([`caixa-resolver`] keys `concrete_versao`), and the
4288    /// `:upgrade-from :from` references peers in this exact `versao`
4289    /// shape (`semver::Version`, not `VersionReq`). Each consumer
4290    /// expects a strict three-part `MAJOR.MINOR.PATCH` (optionally
4291    /// `-prerelease` and/or `+build`); a structurally invalid `:versao`
4292    /// (`"0.1"` — missing patch, the canonical "I shortened it" footgun;
4293    /// `"v0.1.0"` — the git-tag-shape-leaking-into-versao typo;
4294    /// `"latest"` / `"main"` — the "I confused it with a docker tag"
4295    /// footgun; `"^0.1"` / `"~0.1.2"` — the requirement-shape leaking
4296    /// into the version field a peer `:deps :versao` accepts;
4297    /// `"0.1.0.0"` — the four-part Java/Microsoft convention DNS
4298    /// SemVer-2 forbids) silently passed [`Caixa::from_lisp`] (the
4299    /// derive macro stores the raw String) and the failure surfaced at
4300    /// the *first* downstream consumer that strict-parses it: at
4301    /// `helm install` time as a chart-version rejection, at
4302    /// `feira publish` time as a malformed git tag, at lacre-resolve
4303    /// time as a `semver::Error` not naming the offending caixa, at
4304    /// `feira upgrade --to <versao>` time as an unresolvable
4305    /// `:upgrade-from :from` match — far from the source `caixa.lisp`
4306    /// and without any field naming the offending `:versao`.
4307    ///
4308    /// Thin wrapper around [`semver::Version::parse`] — the same parser
4309    /// [`crate::CaixaVersion::parse`] (the typed `:versao` accessor)
4310    /// and [`crate::UpgradeFromEntry::validate`] (the peer
4311    /// `:upgrade-from :from` axis, 26da2c7) consume. Maps the
4312    /// `semver::Error` reason into the [`ManifestError::VersaoInvalid`]
4313    /// variant, carrying the offending `:versao` verbatim + a
4314    /// parser-shaped reason naming the specific violation, so the
4315    /// diagnostic is self-locating (the author can grep their
4316    /// `caixa.lisp` for `:versao "<value>"` and fix it in one edit).
4317    /// Same diagnostic shape as [`ManifestError::NomeInvalid`]
4318    /// (6c992f8) and [`crate::UpgradeError::FromInvalid`]
4319    /// (b0c8389) on the peer axes. With this gate, the typed `:versao`
4320    /// surfaces — top-level `:versao`, `:upgrade-from :from` — are
4321    /// now structurally equivalent (every value past validate is
4322    /// round-trippable through [`semver::Version::parse`] without
4323    /// re-checking at the renderer, resolver, or operator hot-upgrade
4324    /// layer), peer with the four `:versao` requirement axes (`:deps`,
4325    /// `:deps-dev`, `:membros`, `:children`) the prior commits
4326    /// (2420c44, 9888b13, b38ff3a) wired through `parse_requirement`.
4327    ///
4328    /// Empty `:versao` (which [`Caixa::from_lisp`] does not reject —
4329    /// the derive macro stores the raw String) is gated by the
4330    /// narrower [`ManifestError::VersaoEmpty`] arm before the parser is
4331    /// consulted, mirroring the empty-first cascade every per-axis
4332    /// version gate already uses (e.g. `MembroVersaoEmpty` before
4333    /// `MembroVersaoInvalid`, `EmptyChildVersion` before
4334    /// `ChildVersaoInvalid`, `NomeEmpty` before `NomeInvalid`).
4335    pub fn validate_versao(&self) -> Result<(), ManifestError> {
4336        let versao = self.versao();
4337        if versao.is_empty() {
4338            return Err(ManifestError::VersaoEmpty);
4339        }
4340        semver::Version::parse(versao).map_err(|e| ManifestError::VersaoInvalid {
4341            versao: versao.to_string(),
4342            reason: e.to_string(),
4343        })?;
4344        Ok(())
4345    }
4346
4347    /// Reject `:restart-window` values the shared
4348    /// [`crate::supervisor::duration_codec::parse`] refuses. The flat
4349    /// `restart_window: Option<String>` slot on [`Caixa`] is stored
4350    /// raw by the derive macro (the typed [`SupervisorSpec`] holds an
4351    /// `Option<Duration>` routed through the shared codec via `with =
4352    /// "duration_codec"`); the inline `Caixa → SupervisorSpec`
4353    /// view-construction path ([`Self::supervisor_view`]) folds the
4354    /// raw string through the same shared codec and soft-swallows the
4355    /// parse error as `None` to keep the view best-effort. Without
4356    /// this gate a malformed `:restart-window` (`"1.5s"` — the
4357    /// fractional-seconds drift class; `"1.0s"` — the decimal-shaped
4358    /// integer drift; `"0.5m"` — the unit-fraction drift; `"+30s"` /
4359    /// `"-30s"` — the leading-sign drift; `"30x"` — the unknown-unit
4360    /// footgun; `"abc"` — pure garbage; `""` — the empty-after-trim
4361    /// edge case) silently produced a `SupervisorSpec` with
4362    /// `restart_window: None`, indistinguishable from the canonical
4363    /// "omit the slot to express no reset" authoring shape — Erlang/OTP's
4364    /// `MaxIntensity / Period` invariant turns into a never-reset
4365    /// supervisor far from the source `caixa.lisp`, with no field
4366    /// naming the offending `:restart-window`. Lifting the gate to a
4367    /// Caixa-level validator mirrors the trajectory of the peer
4368    /// per-axis identity gates ([`Self::validate_nome`] 6c992f8,
4369    /// [`Self::validate_versao`] 1fdaa02, [`Self::validate_deps`]
4370    /// a7f0d8c) and the ABSORPTION-ROADMAP.md M2.2 test pin
4371    /// (line 196: "reject invalid `:restart-window` (non-duration)").
4372    ///
4373    /// Thin wrapper around [`crate::supervisor::duration_codec::parse`]
4374    /// (the shared codec backing `:supervisor :restart-window` as
4375    /// serde-routed on [`SupervisorSpec`], `:politicas :timeout`, and
4376    /// `:politicas :circuit-breaker :window` — all three covered by
4377    /// the integer-magnitude gate 1c55a2a). Maps the codec's parse
4378    /// error verbatim into the [`ManifestError::RestartWindowMalformed`]
4379    /// variant, carrying the offending raw string + a parser-shaped
4380    /// reason naming the canonical authoring form, so the diagnostic
4381    /// is self-locating (the author can grep their `caixa.lisp` for
4382    /// `:restart-window "<value>"` and fix it in one edit) and
4383    /// uniform with every other manifest-level validate diagnostic.
4384    /// With this gate the four `:restart-window`-shaped surfaces (the
4385    /// flat raw string on [`Caixa`], the typed `Option<Duration>` on
4386    /// [`SupervisorSpec`], the two `MeshPolicy` peer durations) are
4387    /// now structurally equivalent — every value past the codec is in
4388    /// one accepted set, by construction.
4389    ///
4390    /// `None` (the canonical "omit the slot to express no reset"
4391    /// shape) is accepted trivially — the gate is a no-op when the
4392    /// author didn't author a window. The empty string is rejected by
4393    /// the shared codec (its digit-only gate refuses an empty
4394    /// magnitude), surfacing the same `RestartWindowMalformed`
4395    /// diagnostic as every other rejected non-canonical shape.
4396    pub fn validate_restart_window(&self) -> Result<(), ManifestError> {
4397        let Some(s) = self.restart_window() else {
4398            return Ok(());
4399        };
4400        crate::supervisor::duration_codec::parse(s)
4401            .map(|_| ())
4402            .map_err(|reason| ManifestError::RestartWindowMalformed {
4403                restart_window: s.to_string(),
4404                reason,
4405            })
4406    }
4407
4408    /// Reject per-entry values on the three Caixa-level code-surface
4409    /// path lists (`:bibliotecas`, `:exe`, `:servicos`) that the
4410    /// layout checker's `root.join(p)` sandbox would silently subvert.
4411    /// Same three structural footguns the peer
4412    /// [`BehaviorSpec::validate`] (b0c8389) and
4413    /// [`crate::UpgradeInstruction::validate`] `StateChange` arm
4414    /// (26da2c7) already close on the M2 `:behavior :on-*` and
4415    /// `:upgrade-from :state-change :script` axes, here lifted onto
4416    /// the three top-level code-path axes through the shared
4417    /// [`is_sandboxed_relative_path`] predicate:
4418    ///
4419    ///   - empty entry (`(:bibliotecas (""))` / `(:exe (""))` /
4420    ///     `(:servicos (""))`): `PathBuf::new()` round-trips through
4421    ///     [`Path::join`] as the base itself — `root.join("")` ==
4422    ///     `root`, so the existence check (`self.exists(&root)`)
4423    ///     trivially passes (the project root exists), and the layout
4424    ///     silently treats the project root as a biblioteca / exe /
4425    ///     servico entry. The `:bibliotecas` loop then hands the root
4426    ///     to `tatara_lisp::read` at `feira build` time as if the root
4427    ///     directory itself were a Lisp source file — a parse error
4428    ///     far from the source `caixa.lisp` with no field naming the
4429    ///     offending entry.
4430    ///   - absolute path (`(:bibliotecas ("/etc/passwd"))`):
4431    ///     [`Path::join`] *replaces* the base when the right-hand side
4432    ///     is absolute, so `root.join("/etc/passwd")` resolves to
4433    ///     `"/etc/passwd"` and escapes the project sandbox entirely.
4434    ///     The existence check then silently consults whatever the
4435    ///     escaped path resolves to — for `:bibliotecas`, the layout
4436    ///     has no `starts_with`-fence (only `:exe` is fenced under
4437    ///     `exe/` and `:servicos` under `servicos/`), so an absolute
4438    ///     `:bibliotecas` entry that happens to resolve on disk
4439    ///     silently passes. For `:exe` / `:servicos` the fence catches
4440    ///     the absolute case downstream as `ExeOutsideDir` /
4441    ///     `ServicoOutsideDir` (or `MissingEntry` if the absolute path
4442    ///     doesn't exist), but with a downstream-shaped diagnostic
4443    ///     that names the resolved escape path rather than the
4444    ///     authoring footgun at the source.
4445    ///   - parent-escape (`(:bibliotecas ("../sibling/x.lisp"))` /
4446    ///     `(:exe ("exe/../../escape.lisp"))`): a [`PathBuf`] with any
4447    ///     [`std::path::Component::ParentDir`] anywhere round-trips
4448    ///     through [`Path::join`] as a traversal above the caixa root.
4449    ///     The `:exe` / `:servicos` `starts_with(<dir>)` fence is
4450    ///     *component-aware* (not canonical-path-aware), so
4451    ///     `root.join("exe/../../escape.lisp")` `starts_with(exe_dir)`
4452    ///     is **true** even though the canonical resolution
4453    ///     `{parent of root}/escape.lisp` lives outside the caixa root
4454    ///     — the fence silently lets the parent-escape through, and
4455    ///     the existence check passes if that escape-target happens
4456    ///     to exist. Caught regardless of where the `..` sits
4457    ///     (leading, mid-path, trailing) so the gate matches the peer
4458    ///     predicate's full coverage.
4459    ///
4460    /// Same `Empty` → `Absolute` → `ParentEscape` arm-ordering every peer
4461    /// `is_sandboxed_relative_path` consumer follows (b0c8389 / 26da2c7);
4462    /// same per-slot diagnostic shape every peer per-axis path-gate
4463    /// exposes (`*Empty { slot }` / `*Absolute { slot, path }` /
4464    /// `*ParentEscape { slot, path }`). Cross-slot precedence is
4465    /// `:bibliotecas` → `:exe` → `:servicos` — the same declaration
4466    /// order [`Caixa::declared_foreign_code_slots`] uses for its
4467    /// canonical foreign-code-slot diagnostic, so a manifest with
4468    /// multiple malformed slots surfaces the lexicographically-earliest
4469    /// slot's diagnostic deterministically.
4470    ///
4471    /// Lifted to the typed surface as a Caixa-level validator (peer
4472    /// of [`Self::validate_nome`] / [`Self::validate_versao`] /
4473    /// [`Self::validate_deps`] / [`Self::validate_restart_window`])
4474    /// and wired into [`crate::StandardLayout::verify`] before the
4475    /// existence-check loops so the diagnostic names the offending
4476    /// slot at the source caixa.lisp rather than reporting a
4477    /// downstream `MissingEntry` / `ExeOutsideDir` /
4478    /// `ServicoOutsideDir` against the resolved sandbox-escape path.
4479    /// The fourth typed code-path surface — every author-supplied
4480    /// path on the manifest — is now structurally accept-shaped
4481    /// past validate, peer with `:behavior :on-*` and
4482    /// `:upgrade-from :state-change :script`.
4483    pub fn validate_code_paths(&self) -> Result<(), ManifestError> {
4484        /// Per-slot file-type contract for the three Caixa-level
4485        /// code-path surfaces (`:bibliotecas`, `:exe`, `:servicos`).
4486        /// Each variant names the predicate the per-entry file-type
4487        /// gate consults; [`Self::None`] opts the slot out of any
4488        /// file-type contract. Lifted as a typed local enum so the
4489        /// per-slot dispatch is exhaustive at the `match` — adding a
4490        /// future axis to the typed-substrate `:` slot set (the
4491        /// future `:assets` resource axis the M5 roadmap names, the
4492        /// future `:nix-flake` derivation axis the caixa-flake
4493        /// emitter consults) lands as one variant + one `match` arm,
4494        /// not a coordinated rewrite of every per-slot bool flag.
4495        ///
4496        /// Peer of the typed-substrate per-slot variant disciplines
4497        /// already established on this surface
4498        /// ([`crate::supervisor::RestartStrategy`] +
4499        /// [`crate::supervisor::RestartPolicy`] on the OTP-shape
4500        /// supervision-tree axis,
4501        /// [`crate::aplicacao::PlacementStrategy`] on the §III.1
4502        /// placement axis, [`crate::aplicacao::WitTarget`] on the
4503        /// `:contratos` payload-target axis): the typed `enum` is
4504        /// the substrate's single source of truth for the per-axis
4505        /// dispatch, and every consumer (the per-arm body here, the
4506        /// future feira-lint per-slot diagnostic renderer, the M4
4507        /// per-axis admission webhook) reaches for the same typed
4508        /// surface rather than re-deriving the partition from inline
4509        /// flag combinations.
4510        enum CodePathFileType {
4511            /// `:exe` — nix-build derivation output, no terminating-
4512            /// extension contract (the canonical `"exe/<name>"`
4513            /// fixtures the layout's `ExeOutsideDir` error message
4514            /// documents carry no extension by convention).
4515            None,
4516            /// `:bibliotecas` — tatara-lisp source files the
4517            /// `feira build` loop reads through `tatara_lisp::read`
4518            /// at parse time. Routes to [`is_lisp_extension`].
4519            LispSource,
4520            /// `:servicos` — ComputeUnit-CR YAML files the
4521            /// caixa-helm / caixa-flux renderers consume through
4522            /// `serde_yaml::from_str`. Routes to
4523            /// [`is_computeunit_yaml_extension`].
4524            ComputeUnitYaml,
4525        }
4526
4527        // The per-slot [`CodePathFileType`] selects which axes carry the
4528        // lifted file-type predicate. `:bibliotecas` is the tatara-lisp
4529        // source axis (the `feira build` loop at
4530        // `caixa-feira/src/cmd/build.rs:33` reads each entry through
4531        // `tatara_lisp::read` at parse time) — the lifted
4532        // [`is_lisp_extension`] predicate gates the `.lisp` extension.
4533        // `:exe` is the nix-built executable surface (per the canonical
4534        // `"exe/<name>"`-shaped fixtures the layout's `ExeOutsideDir`
4535        // error message documents and every in-tree
4536        // `caixa_with_code_paths` positive control uses) — its file-type
4537        // contract is "nix-build derivation output", not a typed source
4538        // file, so [`CodePathFileType::None`] opts the slot out of any
4539        // file-type gate. `:servicos` is the `.computeunit.yaml`
4540        // ComputeUnit-CR axis (the peer caixa-helm / caixa-flux
4541        // renderers consume each entry through `serde_yaml::from_str` as
4542        // a typed `ComputeUnit` CR) — the lifted
4543        // [`is_computeunit_yaml_extension`] predicate gates the compound
4544        // `.computeunit.yaml` suffix. All three axes are surfaced through
4545        // the same iteration so the sandbox-shape + duplicate gates
4546        // apply uniformly; the typed file-type dispatch fires per-slot
4547        // exactly where the downstream consumer's accepted set demands
4548        // it. The third file-type variant ([`ComputeUnitYaml`]) is the
4549        // compounding lift on the peer 64772a9 `:bibliotecas`
4550        // `.lisp`-gate trajectory — the second of the three code-path
4551        // axes to land on a typed compound-suffix gate, with the same
4552        // self-locating per-slot diagnostic shape every peer per-axis
4553        // file-type lift uses (`*NonLispExtension { slot, path }` /
4554        // `*NonComputeUnitYamlExtension { slot, path }`).
4555        for (slot, list, file_type) in [
4556            (
4557                ":bibliotecas",
4558                &self.bibliotecas,
4559                CodePathFileType::LispSource,
4560            ),
4561            (":exe", &self.exe, CodePathFileType::None),
4562            (
4563                ":servicos",
4564                &self.servicos,
4565                CodePathFileType::ComputeUnitYaml,
4566            ),
4567        ] {
4568            // Per-slot set-not-multiset gate on the typed code-path axis.
4569            // Every peer Vec-shaped author-supplied list past validate is
4570            // a set, not a multiset: `:membros :caixa`
4571            // ([`crate::AplicacaoError::MembroDuplicate`]), `:placement
4572            // :clusters` ([`crate::AplicacaoError::PlacementClusterDuplicate`]),
4573            // `:entrada :paths` ([`crate::AplicacaoError::EntradaPathDuplicate`]),
4574            // `:contratos` ([`crate::AplicacaoError::ContratoDuplicate`]),
4575            // `:children :caixa` ([`crate::SupervisorError::DuplicateChild`]),
4576            // `:deps` / `:deps-dev` `:nome` ([`crate::DepError::DuplicateNome`]
4577            // per 359fba5), `:upgrade-from :from` ([`crate::UpgradeError::DuplicateFrom`]),
4578            // `:etiquetas` ([`ManifestError::EtiquetaDuplicate`] per 360a499),
4579            // `:autores` ([`ManifestError::AutorDuplicate`] per 86c769b) —
4580            // the three code-path lists are the last Vec-shaped author-
4581            // supplied slots on the typed Caixa surface still admitting a
4582            // duplicate entry silently. Scope is per-list (`:bibliotecas`
4583            // duplicates are flagged within `:bibliotecas`, not across
4584            // `:bibliotecas` ↔ `:exe`) — the same per-list scope `:deps`
4585            // ↔ `:deps-dev` use (a `:nome` present in both lists is a
4586            // legitimate dev-vs-runtime shape on the dep axis, fenced
4587            // separately by [`crate::dep::validate_no_self_dep`]). On the
4588            // code-path axis a cross-slot collision is structurally
4589            // impossible by the layout's `starts_with(<exe|servicos>_dir)`
4590            // fence — `:exe` and `:servicos` entries are confined to their
4591            // own directory trees, so the only way a string could appear
4592            // on two code-path lists is the (rare, structurally invalid)
4593            // case where `:bibliotecas` carries an `"exe/<x>"` or
4594            // `"servicos/<x>.yaml"`-shaped path.
4595            //
4596            // Without the gate three authoring footguns silently passed:
4597            //
4598            //   - `:bibliotecas ("lib/foo.lisp" "lib/foo.lisp")` — the
4599            //     canonical copy-paste-the-wrong-file footgun. `feira
4600            //     build` (`caixa-feira/src/cmd/build.rs:33`) walks the
4601            //     list and re-parses the same file twice, wasting work
4602            //     and silently masking the author's intent to declare a
4603            //     *second* biblioteca.
4604            //   - `:exe ("exe/cli" "exe/cli")` — the same footgun on the
4605            //     Binario surface. The future `caixa-flake` `nix flake`
4606            //     emitter that materializes each `:exe` entry as a flake
4607            //     `packages.<exe-name>` derivation would collide on the
4608            //     duplicate package name and surface a flake-eval error
4609            //     far from the source `caixa.lisp`.
4610            //   - `:servicos ("servicos/x.computeunit.yaml"
4611            //     "servicos/x.computeunit.yaml")` — the same footgun on
4612            //     the Servico surface. The peer `caixa-helm` / `caixa-flux`
4613            //     renderers already refuse `:servicos.len() != 1` with
4614            //     the narrower [`UnsupportedServicoCount`] diagnostic, but
4615            //     that diagnostic surfaces "too many servicos" without
4616            //     naming "duplicate entry" — the typed self-locating
4617            //     "which entry is the duplicate" framing only lands at
4618            //     this gate.
4619            //
4620            // Same `seen.insert(entry.as_str())` shape every peer per-list
4621            // duplicate gate uses (`:etiquetas` 360a499, `:autores`
4622            // 86c769b, `:deps` 359fba5) and the same "structural shape
4623            // checks fire before the duplicate check on the same entry"
4624            // ordering (a `(:bibliotecas ("" "lib/x.lisp" "lib/x.lisp"))`
4625            // shape surfaces the narrower [`Self::CodePathEmpty`] for the
4626            // empty entry first, not the duplicate on the later pair).
4627            let mut seen = std::collections::HashSet::new();
4628            for entry in list {
4629                let path = Path::new(entry);
4630                match is_sandboxed_relative_path(path) {
4631                    Ok(()) => {}
4632                    Err(PathShapeViolation::Empty) => {
4633                        return Err(ManifestError::CodePathEmpty { slot });
4634                    }
4635                    Err(PathShapeViolation::Absolute) => {
4636                        return Err(ManifestError::CodePathAbsolute {
4637                            slot,
4638                            path: path.to_path_buf(),
4639                        });
4640                    }
4641                    Err(PathShapeViolation::ParentEscape) => {
4642                        return Err(ManifestError::CodePathParentEscape {
4643                            slot,
4644                            path: path.to_path_buf(),
4645                        });
4646                    }
4647                }
4648                // The per-slot file-type gate dispatched through the
4649                // typed [`CodePathFileType`] selector above. Each variant
4650                // routes to the lifted predicate the downstream consumer
4651                // demands:
4652                //
4653                //   - [`LispSource`] → [`is_lisp_extension`] for
4654                //     `:bibliotecas` (the `feira build` loop's
4655                //     `tatara_lisp::read` consumer);
4656                //   - [`ComputeUnitYaml`] → [`is_computeunit_yaml_extension`]
4657                //     for `:servicos` (the caixa-helm / caixa-flux
4658                //     `serde_yaml::from_str` consumer's `ComputeUnit` CR
4659                //     accepted set);
4660                //   - [`None`] for `:exe` — the nix-build derivation-
4661                //     output axis has no terminating-extension contract.
4662                //
4663                // Fires after the sandbox-shape arms so a path that is
4664                // *both* sandbox-escaping and wrong-extension surfaces
4665                // the more fundamental sandbox-shape diagnostic first
4666                // (mirrors the peer `EmptyPath` → `AbsolutePath` →
4667                // `ParentEscape` → `NonLispExtension` arm-ordering on
4668                // `:behavior :on-*` c97815a, and `EmptyScript` →
4669                // `AbsoluteScript` → `ParentEscapeScript` →
4670                // `NonLispExtensionScript` on
4671                // `:upgrade-from :state-change :script` 33cc830), and
4672                // before the duplicate gate so the narrower per-entry
4673                // file-type shape dominates the cross-entry uniqueness
4674                // diagnostic (a
4675                // `("servicos/x.yaml" "servicos/x.yaml")` shape on
4676                // `:servicos` surfaces
4677                // `CodePathNonComputeUnitYamlExtension` on the first
4678                // entry rather than `CodePathDuplicate` on the pair —
4679                // peer with the 64772a9 `:bibliotecas`
4680                // `("lib/x.txt" "lib/x.txt")` ordering).
4681                match file_type {
4682                    CodePathFileType::None => {}
4683                    CodePathFileType::LispSource => {
4684                        if !is_lisp_extension(path) {
4685                            return Err(ManifestError::CodePathNonLispExtension {
4686                                slot,
4687                                path: path.to_path_buf(),
4688                            });
4689                        }
4690                    }
4691                    CodePathFileType::ComputeUnitYaml => {
4692                        if !is_computeunit_yaml_extension(path) {
4693                            return Err(ManifestError::CodePathNonComputeUnitYamlExtension {
4694                                slot,
4695                                path: path.to_path_buf(),
4696                            });
4697                        }
4698                    }
4699                }
4700                crate::render::insert_first_seen(&mut seen, entry.as_str(), || {
4701                    ManifestError::CodePathDuplicate {
4702                        slot,
4703                        path: path.to_path_buf(),
4704                    }
4705                })?;
4706            }
4707        }
4708        Ok(())
4709    }
4710
4711    /// Reject `:etiquetas` lists with an empty entry or with two entries
4712    /// agreeing on the same string. `:etiquetas` is the universal
4713    /// registry-search-tag axis on [`Caixa`] (every kind carries the
4714    /// `Vec<String>` slot) and lands verbatim as the Helm chart
4715    /// `Chart.yaml` `keywords:` array on every Servico (caixa-helm's
4716    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:236` folds it through
4717    /// a [`std::collections::BTreeSet`] alongside the four substrate-
4718    /// fixed tags `lareira` / `wasm` / `tatara-lisp` / `caixa-servico`).
4719    /// Two authoring footguns silently passed validate without this gate:
4720    ///
4721    ///   - Empty entry (`(:etiquetas (""))` — the canonical paste-from-
4722    ///     blank-doc footgun) rendered as `keywords: ["", "caixa-servico",
4723    ///     "lareira", "tatara-lisp", "wasm"]` in `Chart.yaml`. Helm's
4724    ///     `chart.metadata.keywords` admits the value without a strict
4725    ///     parser-side gate, but the empty keyword has no operational
4726    ///     meaning — it indexes nothing in the future caixa-registry
4727    ///     search axis and clutters the rendered chart with a no-op tag.
4728    ///   - Duplicate entries (`(:etiquetas ("demo" "demo"))` — the
4729    ///     copy-paste-the-wrong-tag footgun) silently passed validate
4730    ///     and were silently dedup'd by caixa-helm's `BTreeSet` collect
4731    ///     at chart render — a "second wins / one silently disappears"
4732    ///     shape divergent from every peer typed-graph set gate
4733    ///     ([`crate::AplicacaoError::MembroDuplicate`] on `:membros`,
4734    ///     [`crate::AplicacaoError::PlacementClusterDuplicate`] on
4735    ///     `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
4736    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
4737    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
4738    ///     `:deps` / `:deps-dev` per 359fba5, [`crate::UpgradeError::DuplicateFrom`]
4739    ///     on `:upgrade-from`, the per-instruction-class singularity
4740    ///     gates [`crate::UpgradeError::DuplicateLoadModule`] /
4741    ///     [`crate::UpgradeError::DuplicateStateChange`] /
4742    ///     [`crate::UpgradeError::DuplicateCleanup`]). The typed-graph
4743    ///     discipline is uniform: every Vec-shaped author-supplied list
4744    ///     past validate is set-not-multiset, by construction.
4745    ///
4746    /// Past the empty arm the gate enforces the chart-keyword shape
4747    /// predicate via [`crate::render::is_chart_keyword_shape`]: Cargo's
4748    /// crates.io `[package] keywords` grammar — 1..=20 bytes, starts
4749    /// with an ASCII letter, ASCII alphanumeric / `_` / `-`
4750    /// continuation. Closes the canonical paste-from-doc footguns the
4751    /// bare empty + duplicate arms left open: paste-from-aligned-doc
4752    /// whitespace (`" mesh"`, `"mesh "`), paste-from-multiline-doc
4753    /// newline (`"mesh\nhttp"` — the author pasted a multi-tag block
4754    /// into one entry instead of splitting), paste-from-Windows-CRLF-doc
4755    /// carriage return, CSV-list-separator confusion (`"mesh,http,grpc"`
4756    /// — the author meant three separate list entries), path-separator
4757    /// confusion (`"caixa/servico"`), namespace-suffix (`"http.1"`),
4758    /// leading-digit (`"1foo"`), kebab-leak (`"-foo"`), snake-leak
4759    /// (`"_foo"`), non-ASCII (`"café"`), and paste-from-binary-blob
4760    /// control bytes that would silently land as malformed search tags
4761    /// in the rendered Chart.yaml `keywords:` array and break the
4762    /// Artifact Hub keyword index lookup far from the source caixa.lisp.
4763    /// Mirrors the [`Self::validate_autores`] shape-predicate cascade
4764    /// established on the sibling universal-axis `Vec<String>` surface
4765    /// — the second universal-axis Vec<String> surface to land the
4766    /// empty-first-then-shape-then-duplicate per-entry cascade.
4767    ///
4768    /// Same empty-first cascade discipline every peer per-axis gate
4769    /// uses: the per-entry empty arm fires before the per-entry shape
4770    /// arm fires before the cross-entry duplicate arm, so an
4771    /// `("" "mesh" "mesh")` authoring shape surfaces the narrower
4772    /// [`ManifestError::EtiquetaEmpty`] (the structural "this entry
4773    /// has no value" defect) before either the shape or the duplicate
4774    /// diagnostic. Walks the list in declaration order so the
4775    /// first-collision diagnostic surfaces the lexicographically-
4776    /// earliest offending position, peer with every other duplicate
4777    /// gate on this surface.
4778    ///
4779    /// Universal-axis (every kind carries `:etiquetas`), so wired at the
4780    /// caixa-build gate alongside the peer universal gates
4781    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
4782    /// [`Self::validate_deps`] / [`Self::validate_code_paths`] — before
4783    /// the kind-coherence gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]
4784    /// / [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
4785    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
4786    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
4787    /// slot sets. The future caixa-registry search axis can reach for
4788    /// `caixa.etiquetas` knowing every entry is a non-empty distinct
4789    /// chart-keyword-shaped string without re-deriving the precondition.
4790    pub fn validate_etiquetas(&self) -> Result<(), ManifestError> {
4791        let mut seen = std::collections::HashSet::new();
4792        for etiqueta in self.etiquetas() {
4793            if etiqueta.is_empty() {
4794                return Err(ManifestError::EtiquetaEmpty);
4795            }
4796            crate::render::is_chart_keyword_shape(etiqueta).map_err(|reason| {
4797                ManifestError::EtiquetaInvalid {
4798                    etiqueta: etiqueta.clone(),
4799                    reason,
4800                }
4801            })?;
4802            crate::render::insert_first_seen(&mut seen, etiqueta.as_str(), || {
4803                ManifestError::EtiquetaDuplicate {
4804                    etiqueta: etiqueta.clone(),
4805                }
4806            })?;
4807        }
4808        Ok(())
4809    }
4810
4811    /// Reject `:autores` lists with an empty entry or with two entries
4812    /// agreeing on the same string. `:autores` is the universal
4813    /// maintainer-axis on [`Caixa`] (every kind carries the
4814    /// `Vec<String>` slot) and lands verbatim as the Helm chart
4815    /// `Chart.yaml` `maintainers:` array on every Servico (caixa-helm's
4816    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:251` maps each entry
4817    /// to a `Maintainer { name, email: None }` without dedup). Two
4818    /// authoring footguns silently passed validate without this gate:
4819    ///
4820    ///   - Empty entry (`(:autores (""))` — the canonical paste-from-
4821    ///     blank-doc footgun) rendered as
4822    ///     `maintainers: [{name: "", email: null}]` in `Chart.yaml`. The
4823    ///     empty maintainer name has no operational meaning — it
4824    ///     identifies no one in the substrate's authorship index and
4825    ///     clutters the rendered chart with a no-op maintainer.
4826    ///   - Duplicate entries (`(:autores ("pleme-io" "pleme-io"))` —
4827    ///     the copy-paste-the-wrong-author footgun) silently passed
4828    ///     validate and rendered as two identical maintainer entries.
4829    ///     Unlike the [`Self::validate_etiquetas`] peer (caixa-helm's
4830    ///     `BTreeSet`-collect on `:etiquetas` silently dedups the
4831    ///     rendered `keywords:` array at chart-render time), the
4832    ///     `maintainers:` rendering has *no* dedup — duplicate `:autores`
4833    ///     entries stack verbatim in the chart, divergent from every
4834    ///     peer typed-graph set gate ([`crate::AplicacaoError::MembroDuplicate`]
4835    ///     on `:membros`, [`crate::AplicacaoError::PlacementClusterDuplicate`]
4836    ///     on `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
4837    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
4838    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
4839    ///     `:deps` / `:deps-dev`, [`crate::UpgradeError::DuplicateFrom`]
4840    ///     on `:upgrade-from`, [`ManifestError::EtiquetaDuplicate`] on
4841    ///     `:etiquetas`).
4842    ///
4843    /// Past the empty arm the gate enforces the chart-maintainer-name
4844    /// shape predicate via [`crate::render::is_chart_maintainer_name_shape`]:
4845    /// the structural single-line printable-UTF-8 floor every realistic
4846    /// Helm chart maintainer name carries — 1..=128 bytes, no leading
4847    /// or trailing whitespace, no ASCII control characters anywhere,
4848    /// Unicode bytes accepted. Closes the canonical paste-from-doc
4849    /// footguns the bare empty + duplicate arms left open:
4850    /// paste-from-aligned-doc whitespace (`" pleme-io"`, `"pleme-io "`),
4851    /// paste-from-multiline-doc newline (`"alice\nbob"` — the author
4852    /// pasted a multi-line block of author records into one `:autores`
4853    /// entry instead of splitting into one entry per author),
4854    /// paste-from-Windows-CRLF-doc carriage return, tab-from-aligned-doc,
4855    /// and the paste-from-binary-blob control bytes that would silently
4856    /// land as YAML-illegal byte sequences in the rendered Chart.yaml
4857    /// `maintainers:` array. Mirrors the shape-predicate cascade
4858    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
4859    /// [`Self::validate_edicao`] / [`Self::validate_repositorio`]
4860    /// establish past their own empty arms on the sibling universal-axis
4861    /// `Option<String>` surfaces — the first universal-axis Vec<String>
4862    /// surface to land the empty-first-then-shape-then-duplicate per-entry
4863    /// cascade.
4864    ///
4865    /// Same empty-first cascade discipline every peer per-axis gate
4866    /// uses: the per-entry empty arm fires before the per-entry shape
4867    /// arm before the cross-entry duplicate arm. Walks the list in
4868    /// declaration order so the first-collision diagnostic surfaces the
4869    /// lexicographically-earliest offending position, peer with every
4870    /// other duplicate gate on this surface.
4871    ///
4872    /// Universal-axis (every kind carries `:autores`), so wired at the
4873    /// caixa-build gate alongside the peer universal gates
4874    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
4875    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
4876    /// [`Self::validate_code_paths`] — before the kind-coherence gates
4877    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
4878    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
4879    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
4880    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
4881    /// slot sets.
4882    pub fn validate_autores(&self) -> Result<(), ManifestError> {
4883        let mut seen = std::collections::HashSet::new();
4884        for autor in self.autores() {
4885            if autor.is_empty() {
4886                return Err(ManifestError::AutorEmpty);
4887            }
4888            crate::render::is_chart_maintainer_name_shape(autor).map_err(|reason| {
4889                ManifestError::AutorInvalid {
4890                    autor: autor.clone(),
4891                    reason,
4892                }
4893            })?;
4894            crate::render::insert_first_seen(&mut seen, autor.as_str(), || {
4895                ManifestError::AutorDuplicate {
4896                    autor: autor.clone(),
4897                }
4898            })?;
4899        }
4900        Ok(())
4901    }
4902
4903    /// Reject `:repositorio` values whose shape the shared
4904    /// [`crate::render::is_git_repo_url`] predicate refuses. The flat
4905    /// `repositorio: Option<String>` slot on [`Caixa`] is the
4906    /// universal git-shaped homepage axis every kind carries — the
4907    /// substrate routes the same string through two load-bearing
4908    /// consumers:
4909    ///
4910    ///   - [`caixa-helm`] folds it verbatim into the rendered
4911    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `home:` field
4912    ///     (`build_chart_yaml` at `caixa-helm/src/lib.rs:268`) and into
4913    ///     the chart `README.md` `repo = …` interpolation
4914    ///     (`caixa-helm/src/lib.rs:359`).
4915    ///   - [`caixa-flux`] folds it verbatim into the standalone
4916    ///     `ClusterBundleOpts::for_caixa` `git_url:` field
4917    ///     (`caixa-flux/src/lib.rs:293`), which becomes the `FluxCD`
4918    ///     `GitRepository.spec.url` the cluster's source-controller
4919    ///     polls — the load-bearing deploy-time axis.
4920    ///
4921    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
4922    /// substitute a placeholder when the slot is absent (`None` → the
4923    /// fallback fires); a `Some("")` *skips the fallback* and silently
4924    /// passes the empty string through to `Chart.yaml home: ""` /
4925    /// `GitRepository url: ""` — Helm's chart lint and `FluxCD`'s source
4926    /// controller both reject the empty URL far from the source
4927    /// `caixa.lisp`, with no field naming the offending `:repositorio`.
4928    /// Similarly a malformed `:repositorio` (whitespace, control char,
4929    /// missing `:` separator, leading `-`) silently lands in the
4930    /// rendered artifacts and breaks at `git clone` / `helm template`
4931    /// / `flux reconcile` time.
4932    ///
4933    /// Thin wrapper around [`crate::render::is_git_repo_url`] — the
4934    /// same shared predicate the peer [`crate::DepSource::validate`]
4935    /// routes the `:fonte (:tipo git :repo …)` axis through. With this
4936    /// gate the two `git URL`-shaped surfaces on the typed Caixa
4937    /// (`:repositorio` here, `:deps :fonte :repo` peer) are
4938    /// structurally equivalent: every value past validate is
4939    /// guaranteed-acceptable by the predicate's union of constraints
4940    /// (non-empty, length-bounded, no leading `-`, no whitespace, no
4941    /// control chars, ASCII only, no leading `:`, contains a `:`
4942    /// separator). The predicate accepts every documented authoring
4943    /// shape — `github:org/repo` shorthand, `https://host/path`,
4944    /// `ssh://[user@]host/path`, `git://host/path`, `git@host:path`
4945    /// scp-style SSH, `file:///path` — and refuses the canonical
4946    /// paste-from-blank-doc / paste-from-multiline-doc / CLI-arg-
4947    /// injection footguns at validate time. Maps the predicate's
4948    /// `String` reason verbatim into the
4949    /// [`ManifestError::RepositorioInvalid`] variant, carrying the
4950    /// offending value + parser-shaped reason so the diagnostic is
4951    /// self-locating (the author can grep their `caixa.lisp` for
4952    /// `:repositorio "<value>"` and fix it in one edit).
4953    ///
4954    /// `None` (the canonical "omit the slot to express no published
4955    /// homepage" shape) is accepted trivially — the gate is a no-op
4956    /// when the author didn't declare a value. `Some("")` is gated by
4957    /// the narrower [`ManifestError::RepositorioEmpty`] arm before the
4958    /// shape predicate is consulted, mirroring the empty-first cascade
4959    /// every peer per-axis identity gate uses
4960    /// ([`ManifestError::NomeEmpty`] → [`ManifestError::NomeInvalid`],
4961    /// [`ManifestError::VersaoEmpty`] → [`ManifestError::VersaoInvalid`],
4962    /// [`crate::DepError::FonteRepoEmpty`] →
4963    /// [`crate::DepError::FonteRepoInvalid`]).
4964    ///
4965    /// Universal-axis (every kind carries `:repositorio`), so wired at
4966    /// the caixa-build gate alongside the peer universal gates
4967    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
4968    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
4969    /// [`Self::validate_autores`] / [`Self::validate_code_paths`] —
4970    /// before the kind-coherence gates
4971    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
4972    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
4973    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
4974    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
4975    /// specific slot sets.
4976    pub fn validate_repositorio(&self) -> Result<(), ManifestError> {
4977        let Some(s) = self.repositorio() else {
4978            return Ok(());
4979        };
4980        if s.is_empty() {
4981            return Err(ManifestError::RepositorioEmpty);
4982        }
4983        is_git_repo_url(s).map_err(|reason| ManifestError::RepositorioInvalid {
4984            repositorio: s.to_string(),
4985            reason,
4986        })
4987    }
4988
4989    /// Reject `:descricao` values that are the empty string. The flat
4990    /// `descricao: Option<String>` slot on [`Caixa`] is the universal
4991    /// free-form-prose homepage axis every kind carries — the
4992    /// substrate routes the same string through two load-bearing
4993    /// consumers in the [`caixa-helm`] renderer:
4994    ///
4995    ///   - `build_chart_yaml` folds it verbatim into the rendered
4996    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `description:`
4997    ///     field (`caixa-helm/src/lib.rs:232-235`).
4998    ///   - `build_readme` folds it verbatim into the rendered chart
4999    ///     `README.md` header (`caixa-helm/src/lib.rs:333-336`).
5000    ///
5001    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
5002    /// substitute a `caixa.nome`-derived placeholder when the slot is
5003    /// absent (`None` → the fallback fires); a `Some("")` *skips the
5004    /// fallback* and silently passes the empty string through to
5005    /// `Chart.yaml description: ""` / a blank chart `README.md`
5006    /// header. Helm's chart spec requires a non-empty `description:`
5007    /// field on `apiVersion: v2` charts (`helm lint` surfaces it as
5008    /// `WARNING [chart.metadata.description]: description is required`),
5009    /// so the empty `Some("")` silently lands in the rendered
5010    /// artifacts and breaks at `helm lint` / `helm install` time far
5011    /// from the source `caixa.lisp`, with no field naming the
5012    /// offending `:descricao`.
5013    ///
5014    /// `None` (the canonical "omit the slot to defer to the renderer's
5015    /// `caixa.nome`-derived fallback" shape) is accepted trivially —
5016    /// the gate is a no-op when the author didn't declare a value.
5017    /// `Some("")` is gated by the narrower
5018    /// [`ManifestError::DescricaoEmpty`] arm, mirroring the empty-arm
5019    /// shape every peer per-axis empty gate uses
5020    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
5021    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
5022    /// [`ManifestError::RepositorioEmpty`]).
5023    ///
5024    /// Universal-axis (every kind carries `:descricao`), so wired at
5025    /// the caixa-build gate alongside the peer universal gates
5026    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5027    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5028    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
5029    /// [`Self::validate_code_paths`] — before the kind-coherence
5030    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5031    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5032    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5033    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5034    /// specific slot sets.
5035    ///
5036    /// Past the empty arm the gate enforces the chart-description
5037    /// shape predicate via [`crate::render::is_chart_description_shape`]:
5038    /// the structural single-line UTF-8 floor every realistic chart
5039    /// description in the wild matches — 1..=512 bytes, no leading
5040    /// or trailing whitespace, no ASCII control characters anywhere
5041    /// (`0x00..=0x1F` plus `0x7F` DEL — banning tab, newline,
5042    /// carriage return, and every other control byte), Unicode
5043    /// continuation bytes accepted (the canonical fixtures carry
5044    /// `→` and `—`). Closes the canonical paste-from-doc footguns
5045    /// the bare empty-arm gate left open: paste-from-aligned-doc
5046    /// leading / trailing whitespace (`" Checkout flow."`,
5047    /// `"Checkout flow. "`), paste-from-multiline-doc newline
5048    /// (`"Checkout\nflow."`), paste-from-Windows-CRLF-doc CR
5049    /// (`"Checkout\rflow."`), tab-from-aligned-doc
5050    /// (`"Checkout\tflow."`), and paste-from-binary-blob NUL / BEL /
5051    /// ESC / DEL bytes. Mirrors the shape-predicate cascade
5052    /// [`Self::validate_repositorio`] / [`Self::validate_licenca`] /
5053    /// [`Self::validate_edicao`] establish past their own empty arms
5054    /// on the sibling universal-axis `Option<String>` Caixa-level
5055    /// value-shape surfaces.
5056    ///
5057    /// The empty-first cascade discipline mirrors every peer per-axis
5058    /// identity gate: [`ManifestError::DescricaoEmpty`] runs before
5059    /// [`ManifestError::DescricaoInvalid`], so the narrower empty
5060    /// diagnostic surfaces on `Some("")` rather than the broader
5061    /// shape-predicate diagnostic — peer with how
5062    /// [`ManifestError::LicencaEmpty`] runs before
5063    /// [`ManifestError::LicencaInvalid`],
5064    /// [`ManifestError::EdicaoEmpty`] runs before
5065    /// [`ManifestError::EdicaoInvalid`],
5066    /// [`ManifestError::RepositorioEmpty`] runs before
5067    /// [`ManifestError::RepositorioInvalid`].
5068    pub fn validate_descricao(&self) -> Result<(), ManifestError> {
5069        let Some(s) = self.descricao() else {
5070            return Ok(());
5071        };
5072        if s.is_empty() {
5073            return Err(ManifestError::DescricaoEmpty);
5074        }
5075        crate::render::is_chart_description_shape(s).map_err(|reason| {
5076            ManifestError::DescricaoInvalid {
5077                descricao: s.to_string(),
5078                reason,
5079            }
5080        })?;
5081        Ok(())
5082    }
5083
5084    /// Reject `:licenca` values that are the empty string. The flat
5085    /// `licenca: Option<String>` slot on [`Caixa`] is the universal
5086    /// SPDX-shaped license-expression axis every kind carries — the
5087    /// substrate routes the same string through the [`caixa-helm`]
5088    /// renderer's `build_readme` which folds it verbatim into the
5089    /// rendered `lareira-<nome>` Helm chart's `README.md` `## License`
5090    /// section (`caixa-helm/src/lib.rs:361`) via
5091    /// `caixa.licenca.clone().unwrap_or_else(|| "MIT".into())`. The
5092    /// fallback only fires on `None`; a `Some("")` *skips the
5093    /// fallback* and silently passes the empty string through to a
5094    /// chart `README.md` whose `License` section renders as the bare
5095    /// trailing period (`.\n`) — peer footgun with the
5096    /// `Some("")`-skips-`unwrap_or_else` shape the
5097    /// [`Self::validate_descricao`] and [`Self::validate_repositorio`]
5098    /// gates close on the sibling free-form-prose and git-URL axes.
5099    ///
5100    /// `None` (the canonical "omit the slot to defer to the
5101    /// renderer's `MIT` fallback" shape every existing fixture
5102    /// carries) is accepted trivially — the gate is a no-op when the
5103    /// author didn't declare a value. `Some("")` is gated by the
5104    /// narrower [`ManifestError::LicencaEmpty`] arm, mirroring the
5105    /// empty-arm shape every peer per-axis empty gate uses
5106    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
5107    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
5108    /// [`ManifestError::RepositorioEmpty`],
5109    /// [`ManifestError::DescricaoEmpty`]).
5110    ///
5111    /// Universal-axis (every kind carries `:licenca`), so wired at
5112    /// the caixa-build gate alongside the peer universal gates
5113    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5114    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5115    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
5116    /// [`Self::validate_descricao`] / [`Self::validate_code_paths`]
5117    /// — before the kind-coherence gates
5118    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5119    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5120    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5121    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5122    /// specific slot sets.
5123    ///
5124    /// Past the empty arm the gate enforces the SPDX-expression shape
5125    /// predicate via [`crate::render::is_spdx_expression_shape`]: the
5126    /// structural alphabet floor every realistic SPDX expression in
5127    /// the wild uses — ASCII alphanumeric plus `.`, `-`, `+`, `(`,
5128    /// `)`, `:` (the `DocumentRef-…:LicenseRef-…` separator), and a
5129    /// single ASCII space (token separator). Closes the canonical
5130    /// paste-from-doc footguns the bare empty-arm gate left open:
5131    /// paste-from-doc whitespace (`"MIT "`, `" MIT"`), paste-from-
5132    /// multiline-doc CRLF (`"MIT\n"`), tab-from-aligned-doc
5133    /// (`"MIT\tOR Apache-2.0"`), non-ASCII smart-quote paste,
5134    /// underscore-instead-of-hyphen typo (`"Apache_2.0"`),
5135    /// comma-instead-of-`OR`-keyword colloquial idiom (`"MIT,
5136    /// Apache-2.0"`), slash-dual-license colloquial idiom (`"MIT/
5137    /// Apache-2.0"`), and semicolon-list-separator confusion
5138    /// (`"MIT; Apache-2.0"`). Mirrors the shape-predicate cascade
5139    /// [`Self::validate_repositorio`] / [`Self::validate_edicao`]
5140    /// establish past their own empty arms.
5141    ///
5142    /// The empty-first cascade discipline mirrors every peer per-axis
5143    /// identity gate: [`ManifestError::LicencaEmpty`] runs before
5144    /// [`ManifestError::LicencaInvalid`], so the narrower empty
5145    /// diagnostic surfaces on `Some("")` rather than the broader
5146    /// shape-predicate diagnostic — peer with how
5147    /// [`ManifestError::EdicaoEmpty`] runs before
5148    /// [`ManifestError::EdicaoInvalid`],
5149    /// [`ManifestError::RepositorioEmpty`] runs before
5150    /// [`ManifestError::RepositorioInvalid`].
5151    ///
5152    /// A future tightening on this axis can extend the alphabet
5153    /// floor into a full SPDX expression parser + license-id
5154    /// allowlist (rejecting alphabet-valid values that don't name a
5155    /// real SPDX license identifier — e.g., `"NotAReal"` is
5156    /// alphabet-valid but no `NotAReal` license-id exists). That
5157    /// parser only becomes meaningful past a real SPDX-spec
5158    /// dependency; this gate establishes the structural floor by
5159    /// refusing every non-SPDX-alphabet value at validate time.
5160    pub fn validate_licenca(&self) -> Result<(), ManifestError> {
5161        let Some(s) = self.licenca() else {
5162            return Ok(());
5163        };
5164        if s.is_empty() {
5165            return Err(ManifestError::LicencaEmpty);
5166        }
5167        crate::render::is_spdx_expression_shape(s).map_err(|reason| {
5168            ManifestError::LicencaInvalid {
5169                licenca: s.to_string(),
5170                reason,
5171            }
5172        })?;
5173        Ok(())
5174    }
5175
5176    /// Reject `:edicao` values that are the empty string. The flat
5177    /// `edicao: Option<String>` slot on [`Caixa`] is the universal
5178    /// language-edition axis every kind carries — it determines the
5179    /// tatara-lisp macro surface + compatibility flags the substrate
5180    /// applies when building a caixa, and lands verbatim in the
5181    /// `Caixa::template` author-time scaffold (the canonical
5182    /// `:edicao "2026"` line every `feira init` emits via
5183    /// [`Caixa::template`] at `caixa-core/src/manifest.rs:1193`) and
5184    /// in every renderer-side fixture (`caixa-helm/src/lib.rs:375`,
5185    /// `caixa-flux/src/lib.rs:445`, `caixa-mesh/src/lib.rs:629`,
5186    /// `caixa-core/src/render.rs:2510`) via
5187    /// `edicao: Some("2026".into())`.
5188    ///
5189    /// `None` (the canonical "omit the slot to defer to the
5190    /// substrate's default edition" shape every existing
5191    /// [`caixa-resolver`] integration test fixture carries via
5192    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
5193    /// is accepted trivially — the gate is a no-op when the author
5194    /// didn't declare a value. `Some("")` is gated by the narrower
5195    /// [`ManifestError::EdicaoEmpty`] arm, mirroring the empty-arm
5196    /// shape every peer per-axis empty gate uses
5197    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
5198    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
5199    /// [`ManifestError::RepositorioEmpty`],
5200    /// [`ManifestError::DescricaoEmpty`], [`ManifestError::LicencaEmpty`]).
5201    ///
5202    /// Universal-axis (every kind carries `:edicao`), so wired at
5203    /// the caixa-build gate alongside the peer universal gates
5204    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
5205    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
5206    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
5207    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
5208    /// [`Self::validate_code_paths`] — before the kind-coherence
5209    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5210    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5211    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
5212    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
5213    /// specific slot sets.
5214    ///
5215    /// Past the empty arm the gate enforces the canonical year-shape
5216    /// predicate: every documented tatara-lisp edition is a 4-digit
5217    /// ASCII decimal year (`"2026"` is the only edition currently
5218    /// minted; future-introduced siblings will follow the same
5219    /// shape, peer with Cargo's `[package] edition` grammar which
5220    /// every value Cargo has ever accepted matches — `"2015"`,
5221    /// `"2018"`, `"2021"`, `"2024"`). Any value that's not exactly
5222    /// 4 ASCII decimal bytes is rejected with the narrower
5223    /// [`ManifestError::EdicaoInvalid`] arm, mirroring the
5224    /// shape-predicate cascade [`Self::validate_repositorio`]
5225    /// establishes past its own empty arm
5226    /// ([`ManifestError::RepositorioEmpty`] →
5227    /// [`ManifestError::RepositorioInvalid`]). Closes the canonical
5228    /// paste-from-doc footguns the bare empty-arm gate left open:
5229    ///
5230    ///   - leading / trailing whitespace from a paste-from-doc
5231    ///     (`"2026 "`, `" 2026"`)
5232    ///   - control characters / CRLF from a paste-from-multiline-doc
5233    ///     (`"2026\n"`)
5234    ///   - non-ASCII look-alikes from a fullwidth keyboard
5235    ///     (`"2026"`) which would silently land as a non-ASCII
5236    ///     string in the rendered caixa.lisp
5237    ///   - free-form non-year values (`"x"`, `"latest"`,
5238    ///     `"nightly"`) that have no operational meaning on the
5239    ///     substrate's build-time edition selector
5240    ///   - leading non-digit prefixes (`"v2026"`, `"e2026"`,
5241    ///     `"r2026"`) — common version-tag idioms that don't apply
5242    ///     to the year-shaped edition axis
5243    ///   - decimal-shaped values (`"2026.1"`, `"2026.0"`) — every
5244    ///     edition is a year, not a fractional version
5245    ///   - wrong-length numeric values (`"26"`, `"202"`, `"20260"`,
5246    ///     `"00026"`) that don't name a year
5247    ///
5248    /// `None` (the canonical "omit the slot to defer to the
5249    /// substrate's default edition" shape every existing
5250    /// [`caixa-resolver`] integration test fixture carries via
5251    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
5252    /// is accepted trivially — the gate is a no-op when the author
5253    /// didn't declare a value. The empty-first cascade discipline
5254    /// mirrors every peer per-axis identity gate:
5255    /// [`ManifestError::EdicaoEmpty`] runs before
5256    /// [`ManifestError::EdicaoInvalid`], so the narrower empty
5257    /// diagnostic surfaces on `Some("")` rather than the broader
5258    /// shape-predicate diagnostic — peer with how
5259    /// [`ManifestError::NomeEmpty`] runs before
5260    /// [`ManifestError::NomeInvalid`],
5261    /// [`ManifestError::VersaoEmpty`] runs before
5262    /// [`ManifestError::VersaoInvalid`],
5263    /// [`ManifestError::RepositorioEmpty`] runs before
5264    /// [`ManifestError::RepositorioInvalid`].
5265    ///
5266    /// A future tightening on this axis can extend the shape
5267    /// predicate into a known-edition allowlist (rejecting
5268    /// year-shaped values that don't name a tatara-lisp edition
5269    /// the substrate actually understands — e.g., `"1999"` is
5270    /// year-shaped but no `1999` edition exists). That allowlist
5271    /// only becomes meaningful past the introduction of a sibling
5272    /// edition to `"2026"`; this gate establishes the structural
5273    /// floor by refusing every non-year-shaped value at validate
5274    /// time.
5275    pub fn validate_edicao(&self) -> Result<(), ManifestError> {
5276        let Some(s) = self.edicao() else {
5277            return Ok(());
5278        };
5279        if s.is_empty() {
5280            return Err(ManifestError::EdicaoEmpty);
5281        }
5282        if s.len() != 4 || !s.bytes().all(|b| b.is_ascii_digit()) {
5283            return Err(ManifestError::EdicaoInvalid {
5284                edicao: s.to_string(),
5285                reason: "must be a 4-digit ASCII decimal year (canonical \"2026\")".to_string(),
5286            });
5287        }
5288        Ok(())
5289    }
5290
5291    /// Compose the supervisor-related flat slots into a single
5292    /// [`SupervisorSpec`] for validation. Returns `None` when the
5293    /// caixa isn't a `:kind Supervisor`.
5294    ///
5295    /// The flat representation in [`Caixa`] keeps tatara-lisp authoring
5296    /// simple (one form, no nested `:supervisor (…)` block); this view
5297    /// is the "typed shape" the operator + supervisor reconciler
5298    /// consume.
5299    #[must_use]
5300    pub fn supervisor_view(&self) -> Option<SupervisorSpec> {
5301        if !self.kind().is_supervisor() {
5302            return None;
5303        }
5304        // Fold through the shared `supervisor::duration_codec::parse`
5305        // — the same parser the serde-routed `with = "duration_codec"`
5306        // on `SupervisorSpec::restart_window`, the `:politicas
5307        // :timeout` codec, and the `:politicas :circuit-breaker
5308        // :window` codec all consume. The prior inline f64-shaped
5309        // duplicate (`parse_window_inline`) admitted every magnitude
5310        // the integer-magnitude gate (1c55a2a) rejects on the three
5311        // serde-routed siblings — `"1.5s"`, `"1.0s"`, `"0.5m"`,
5312        // `"+30s"`, `"-30s"` — and silently dropped malformed input as
5313        // `None` (i.e. "no reset"), divergent from the shared codec's
5314        // integer-magnitude discipline by construction. The fold
5315        // closes the divergence: every value the typed
5316        // `SupervisorSpec` carries past `supervisor_view` is in the
5317        // shared codec's accepted set. The `.ok()` here preserves the
5318        // existing soft-swallow shape on this view-construction path;
5319        // the new [`Caixa::validate_restart_window`] (sibling of
5320        // [`Self::validate_nome`] / [`Self::validate_versao`]) names
5321        // the offending raw string at build time so authoring tools
5322        // (`feira lint`, the future layout-side wire-up) surface a
5323        // self-locating diagnostic instead of a silently dropped
5324        // window.
5325        let restart_window = self
5326            .restart_window()
5327            .and_then(|s| crate::supervisor::duration_codec::parse(s).ok());
5328        Some(SupervisorSpec {
5329            // Route the author-omitted `:estrategia` arm through the
5330            // substrate-canonical
5331            // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
5332            // `pub const` rather than the transitively-derived
5333            // [`RestartStrategy::default`] route the prior
5334            // `.unwrap_or_default()` fold reached for — one source of
5335            // truth for the Erlang/OTP `one_for_one` half of Learn You
5336            // Some Erlang's `{one_for_one, intensity, 5, 60}` worker-
5337            // supervisor canonical default that also backs the
5338            // [`crate::supervisor::Default for RestartStrategy`] impl
5339            // and the [`crate::supervisor::Default for SupervisorSpec`]
5340            // impl's struct-literal `estrategia` field, all now routed
5341            // through the same lifted constant. Prior to the lift the
5342            // composition site carried `.unwrap_or_default()` with no
5343            // compile-time link back to the shared OTP-canonical
5344            // default that the peer paired
5345            // `.unwrap_or(SUPERVISOR_MAX_RESTARTS_DEFAULT)` (b698ec0)
5346            // arm on the sibling `:max-restarts` axis routes through —
5347            // so a future rebrand of the OTP-canonical strategy default
5348            // (a widening to `rest_for_one` once the substrate
5349            // discovers startup-order-coupled child cohorts as the more
5350            // common shape, a per-cluster overlay the operator pins
5351            // through the MESH-COMPOSITION §III.2 supervision-canary
5352            // `:estrategia-overrides` roadmap slot) would have had to
5353            // migrate the paired `MaxIntensity` + `Period` halves
5354            // through the lifted constants and the `one_for_one` half
5355            // through a `RestartStrategy::default()` route in lockstep
5356            // or the three halves of the same OTP-canonical default
5357            // would silently drift out of pairing. Byte-parity against
5358            // the lifted constant closes the split. Pinned by
5359            // [`supervisor_view_estrategia_fallback_routes_through_lifted_default`]
5360            // in the tests module.
5361            estrategia: self
5362                .estrategia()
5363                .unwrap_or(crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT),
5364            // Route the author-omitted `:max-restarts` arm through the
5365            // substrate-canonical [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`]
5366            // typed `pub const` rather than the raw `5` literal — one
5367            // source of truth for the Erlang/OTP-canonical
5368            // `{intensity, 5, 60}` `MaxIntensity` default that also
5369            // backs the serde-side wire-format author-omitted arm on
5370            // [`crate::supervisor::SupervisorSpec::max_restarts`] via
5371            // `#[serde(default = "default_max_restarts")]` and the
5372            // [`Default for SupervisorSpec`] impl's struct-literal
5373            // default field. Prior to the lift the composition site
5374            // carried a raw `5` with no compile-time link back to the
5375            // serde-side default, so a future rebrand of the OTP-
5376            // canonical default (a tightening to Elixir's `3`, a
5377            // widening to a per-cluster overlay the operator pins
5378            // through the MESH-COMPOSITION §III.2 supervision-canary
5379            // `:supervisor :max-restarts-overrides` roadmap slot)
5380            // would have had to be threaded through both open-coded
5381            // copies in lockstep or the wire-format author-omitted arm
5382            // and this view-construction author-omitted arm would
5383            // silently disagree on which restart-budget an omitted
5384            // `:max-restarts` resolves to. Pinned by
5385            // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
5386            // in the tests module.
5387            max_restarts: self
5388                .max_restarts()
5389                .unwrap_or(crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT),
5390            restart_window,
5391            children: self.children().to_vec(),
5392        })
5393    }
5394
5395    /// A minimal starter manifest emitted by `feira init`.
5396    #[must_use]
5397    pub fn template(nome: &str) -> String {
5398        format!(
5399            "(defcaixa\n  \
5400               :nome        {nome:?}\n  \
5401               :versao      \"0.1.0\"\n  \
5402               :kind        Biblioteca\n  \
5403               :edicao      \"2026\"\n  \
5404               :descricao   \"FIXME — describe this caixa\"\n  \
5405               :autores     ()\n  \
5406               :etiquetas   ()\n  \
5407               :deps        ()\n  \
5408               :deps-dev    ()\n  \
5409               :bibliotecas (\"lib/{nome}.lisp\"))\n"
5410        )
5411    }
5412
5413    /// Serialize to a canonical `caixa.lisp` source — suitable for writing
5414    /// back after mutation (e.g. `feira add`).
5415    ///
5416    /// Goes through serde JSON → canonical Sexp → per-field pretty print.
5417    /// The derive-macro `compile_from_sexp` path is the inverse, so any
5418    /// `Caixa` round-trips through `to_lisp` + `from_lisp`.
5419    #[must_use]
5420    pub fn to_lisp(&self) -> String {
5421        let json = serde_json::to_value(self).expect("Caixa serialize");
5422        let sexp = tatara_lisp::domain::json_to_sexp(&json);
5423        let tatara_lisp::Sexp::List(items) = sexp else {
5424            return format!("(defcaixa {sexp})\n");
5425        };
5426        let mut out = String::from("(defcaixa");
5427        let mut i = 0;
5428        while i + 1 < items.len() {
5429            out.push_str("\n  ");
5430            out.push_str(&items[i].to_string());
5431            out.push(' ');
5432            out.push_str(&items[i + 1].to_string());
5433            i += 2;
5434        }
5435        out.push_str(")\n");
5436        out
5437    }
5438}
5439
5440/// Errors raised by top-level [`Caixa`] validators that don't fit
5441/// the per-axis [`DepError`] / [`crate::AplicacaoError`] /
5442/// [`crate::SupervisorError`] / [`crate::LayoutError`] families —
5443/// the Caixa's own identity axes (`:nome`, `:versao`) that flow
5444/// through every substrate-side artifact's `metadata.name` /
5445/// version derivation.
5446///
5447/// A future top-level sum (the M4 `CaixaError` the [`DepError`]
5448/// doc-comment anticipates) can hold one of each per-axis error
5449/// family without reshaping individual diagnostics; this enum is
5450/// the first such per-Caixa-identity family.
5451#[derive(Debug, Error, PartialEq, Eq)]
5452pub enum ManifestError {
5453    #[error(
5454        ":nome is empty (every caixa must name itself; the value flows \
5455         into every K8s artifact's `metadata.name` derivation and into \
5456         the default `lib/<nome>.lisp` / `exe/<nome>` layout paths)"
5457    )]
5458    NomeEmpty,
5459    #[error(
5460        ":nome {nome:?} is not a valid DNS-1123 label: {reason} (the K8s \
5461         apiserver enforces this rule on every `metadata.name` the \
5462         caixa's substrate-side renderers derive from `:nome` — the \
5463         `lareira-<nome>` Helm chart name, the programs.yaml entry \
5464         name, the `LABEL_APLICACAO` label value, the `<aplicacao>-<de>-to-<para>` \
5465         CiliumNetworkPolicy name, the `<aplicacao>-<para>` HTTPRoute \
5466         name; use a lowercase alphanumeric + hyphen identifier like \
5467         `\"checkout\"` or `\"cart-v2\"`)"
5468    )]
5469    NomeInvalid { nome: String, reason: String },
5470    #[error(
5471        ":nome {nome:?} overflows the joint-length budget on the canonical \
5472         `lareira-<nome>` chart-name shape: {reason} (every per-Servico / \
5473         per-Aplicacao renderer the substrate carries — `caixa-helm`'s \
5474         `Chart.yaml::name`, `caixa-flux`'s `cluster_bundle` HelmRelease \
5475         `chart:` slot, `caixa-tatara`'s `release_name` + \
5476         `oci://<registry>/lareira-<nome>` chart ref — derives the same \
5477         joint name through the canonical `lareira_chart_name` helper, and \
5478         Helm's `Chart.yaml::name` admission rule + the K8s apiserver's \
5479         DNS-1123 label cap on every chart-name-derived `metadata.name` \
5480         reject any joint name exceeding 63 bytes; the narrower \
5481         `:nome` shape (`NomeInvalid`) gates the bare-`:nome` budget, this \
5482         arm gates the chart-name budget downstream renderers inherit)"
5483    )]
5484    NomeChartNameBudgetExceeded { nome: String, reason: String },
5485    #[error(
5486        ":versao is empty (every caixa must pin its own version; the value flows \
5487         into the `lareira-<nome>` Helm chart's `Chart.yaml` version + appVersion, \
5488         the `feira publish` `v<versao>` git tag, the OCI image's `:v<versao>` / \
5489         `:latest` tags, the lacre closure's `concrete_versao`, and the \
5490         `:upgrade-from :from` peers — use a SemVer-2 literal like `\"0.1.0\"`)"
5491    )]
5492    VersaoEmpty,
5493    #[error(
5494        ":versao {versao:?} is not a valid SemVer-2 version: {reason} (the substrate \
5495         consumes this string as `semver::Version` — three-part `MAJOR.MINOR.PATCH` \
5496         with optional `-prerelease` and `+build` — across every artifact derived \
5497         from `:versao`: the `lareira-<nome>` Helm chart's `Chart.yaml` version + \
5498         appVersion (Helm SemVer-2-strict), the `feira publish` `v<versao>` git tag, \
5499         the OCI image's `:v<versao>` tag, the lacre closure's `concrete_versao`, \
5500         and the `:upgrade-from :from` peers that match against this exact shape; \
5501         use a literal like `\"0.1.0\"`, `\"0.2.0-rc.1\"`, or `\"1.0.0+build.42\"` — \
5502         not a git-tag-shape like `\"v0.1.0\"`, a docker-tag-shape like `\"latest\"`, \
5503         a requirement-shape like `\"^0.1\"`, or a four-part `\"0.1.0.0\"`)"
5504    )]
5505    VersaoInvalid { versao: String, reason: String },
5506    #[error(
5507        ":restart-window {restart_window:?} is not a valid duration: {reason} (the \
5508         substrate consumes this string through the shared \
5509         `supervisor::duration_codec` — the same parser routed via `with = \
5510         \"duration_codec\"` onto the typed `SupervisorSpec::restart_window`, \
5511         `:politicas :timeout`, and `:politicas :circuit-breaker :window` slots; \
5512         the canonical authoring form is `<integer><unit>` where the unit is one \
5513         of `ms` / `s` / `m` / `h` and the magnitude has no decimal point and no \
5514         leading `+` / `-` sign — e.g. `\"60s\"`, `\"5m\"`, `\"1h\"`, `\"500ms\"`. \
5515         Without this gate a malformed `:restart-window` silently produced a \
5516         supervisor with `restart_window: None` (\"never reset\"), turning OTP's \
5517         `MaxIntensity / Period` invariant into a never-reset supervisor far from \
5518         the source `caixa.lisp`; the gate moves the diagnostic to the manifest \
5519         layer with the offending value named verbatim. Omit the slot entirely to \
5520         express \"no reset\"; carry a positive integer duration to express the \
5521         sliding window)"
5522    )]
5523    RestartWindowMalformed {
5524        restart_window: String,
5525        reason: String,
5526    },
5527    #[error(
5528        "{slot} entry is an empty path string — every {slot} entry must name \
5529         a file relative to the caixa root; omit the entry to omit the file \
5530         (the layout checker's `root.join(\"\")` resolves to the caixa root \
5531         itself, so an empty entry silently aliases the project root as a \
5532         declared {slot} file, then fails downstream at parse / existence \
5533         time with a diagnostic that names the root rather than the offending \
5534         entry)"
5535    )]
5536    CodePathEmpty { slot: &'static str },
5537    #[error(
5538        "{slot} entry {} is an absolute path — entries must be relative to \
5539         the caixa root, since `Path::join` replaces the base with an absolute \
5540         right-hand side and `root.join(\"/abs/...\")` resolves to \"/abs/...\" \
5541         outside the caixa root sandbox; rewrite the entry as a relative path \
5542         under the caixa root (e.g. `\"lib/<name>.lisp\"`, `\"exe/<name>\"`, \
5543         `\"servicos/<name>.computeunit.yaml\"`)",
5544        path.display()
5545    )]
5546    CodePathAbsolute { slot: &'static str, path: PathBuf },
5547    #[error(
5548        "{slot} entry {} contains a `..` component — entries must not traverse \
5549         above the caixa root (the layout's `starts_with(<dir>)` fence on \
5550         `:exe` / `:servicos` is component-aware, not canonical-path-aware, \
5551         so a mid-path `..` silently traverses the sandbox; `:bibliotecas` \
5552         has no such fence, so a leading `..` escapes unconditionally if the \
5553         resolved target happens to exist)",
5554        path.display()
5555    )]
5556    CodePathParentEscape { slot: &'static str, path: PathBuf },
5557    #[error(
5558        "{slot} entry {} does not terminate in the `.lisp` extension — every \
5559         `:bibliotecas` entry is a tatara-lisp source file the `feira build` \
5560         loop reads through `tatara_lisp::read` at parse time, so any other \
5561         extension (`.rs`, `.txt`, `.lisp.bak`) or no-extension shape is \
5562         structurally a parser error far from the source caixa.lisp, with \
5563         no field naming the offending `:bibliotecas` entry. Pin a relative \
5564         path under the caixa root whose terminating extension is \
5565         lowercase-`.lisp` (e.g. `\"lib/<name>.lisp\"`, \
5566         `\"lib/handlers.lisp\"`) — the same file-type contract the peer \
5567         `:behavior :on-*` (c97815a) and `:upgrade-from :state-change :script` \
5568         (33cc830) axes already carry through the same lifted \
5569         `is_lisp_extension` predicate",
5570        path.display()
5571    )]
5572    CodePathNonLispExtension { slot: &'static str, path: PathBuf },
5573    #[error(
5574        "{slot} entry {} does not terminate in the `.computeunit.yaml` \
5575         compound suffix — every `:servicos` entry is a typed `ComputeUnit` \
5576         CR YAML file the peer caixa-helm / caixa-flux renderers consume \
5577         through `serde_yaml::from_str` at chart / FluxCD bundle render \
5578         time, so any other extension (`.yaml`, `.yml`, `.json`, the \
5579         off-by-one-segment `.computeunit-yaml`, the editor-backup \
5580         `.computeunit.yaml.bak`) or no-extension shape is structurally a \
5581         YAML-parser error / `ComputeUnit` schema-mismatch far from the \
5582         source caixa.lisp, with no field naming the offending `:servicos` \
5583         entry. Pin a relative path under the caixa root whose terminating \
5584         compound suffix is lowercase-`.computeunit.yaml` (e.g. \
5585         `\"servicos/<name>.computeunit.yaml\"`, \
5586         `\"servicos/hello-rio.computeunit.yaml\"`) — the same file-type \
5587         contract the sibling `:bibliotecas` axis (64772a9) already carries \
5588         on the tatara-lisp-source axis through the peer lifted \
5589         `is_lisp_extension` predicate, here on the compound-suffix axis \
5590         `Path::extension` can't express on its own through the lifted \
5591         `is_computeunit_yaml_extension` predicate",
5592        path.display()
5593    )]
5594    CodePathNonComputeUnitYamlExtension { slot: &'static str, path: PathBuf },
5595    #[error(
5596        "{slot} entry {} appears more than once (the code-path list is \
5597         a set, not a multiset; every peer Vec-shaped author-supplied \
5598         list past validate is set-not-multiset — `:membros :caixa`, \
5599         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
5600         `:children :caixa`, `:deps` / `:deps-dev` `:nome`, \
5601         `:upgrade-from :from`, `:etiquetas`, `:autores` — and the three \
5602         code-path lists are the last Vec-shaped author-supplied slots on \
5603         the typed Caixa surface still admitting a duplicate entry. \
5604         `:bibliotecas` duplicates re-parse the same file at \
5605         `feira build` time and silently mask the author's intent to \
5606         declare a *second* biblioteca; `:exe` duplicates collide on the \
5607         flake `packages.<name>` derivation key at the future \
5608         `caixa-flake` materializer; `:servicos` duplicates surface as the \
5609         narrower [`caixa-helm`] / [`caixa-flux`] `UnsupportedServicoCount` \
5610         rejection far from the source `caixa.lisp`. Drop the duplicate \
5611         or rename it to the actual second file intended)",
5612        path.display()
5613    )]
5614    CodePathDuplicate { slot: &'static str, path: PathBuf },
5615    #[error(
5616        ":etiquetas entry is empty (every tag must carry a non-empty \
5617         registry-search identifier; the empty entry has no operational \
5618         meaning — it indexes nothing in the future caixa-registry search \
5619         axis and clutters the rendered Helm `Chart.yaml` `keywords:` array \
5620         with a no-op tag; omit the entry to express \"no tag on this \
5621         position\")"
5622    )]
5623    EtiquetaEmpty,
5624    #[error(
5625        ":etiquetas entry {etiqueta:?} appears more than once (the \
5626         registry-search tag set is a set, not a multiset; duplicate \
5627         entries are silently dedup'd by caixa-helm's `BTreeSet` collect \
5628         at chart render — a \"second wins / one silently disappears\" \
5629         shape divergent from every peer typed-graph set gate \
5630         (`:membros :caixa`, `:placement :clusters`, `:entrada :paths`, \
5631         `:contratos`, `:deps :nome`, `:upgrade-from :from`); drop the \
5632         duplicate or rename it to the actual tag intended)"
5633    )]
5634    EtiquetaDuplicate { etiqueta: String },
5635    #[error(
5636        ":etiquetas entry {etiqueta:?} is not a valid chart-keyword shape: \
5637         {reason} (the substrate consumes this string through the shared \
5638         `crate::render::is_chart_keyword_shape` predicate — the same \
5639         Cargo crates.io `[package] keywords` grammar entry shape: 1..=20 \
5640         bytes, starts with an ASCII letter, ASCII alphanumeric / `_` / `-` \
5641         continuation. The canonical authoring shapes are short kebab-case \
5642         identifiers like `\"mesh\"`, `\"wasm\"`, `\"tatara-lisp\"`, \
5643         `\"hello-world\"`, `\"caixa-servico\"`, `\"infrastructure\"`. \
5644         Without this gate a malformed `:etiquetas` entry (paste-from-doc \
5645         leading / trailing whitespace `\" mesh\"` / `\"mesh \"`; \
5646         paste-from-multiline-doc newline `\"mesh\\nhttp\"`; \
5647         paste-from-Windows-CRLF-doc CR; CSV-list-separator confusion \
5648         `\"mesh,http,grpc\"` — the author meant to author three separate \
5649         list entries; path-separator confusion `\"caixa/servico\"`; \
5650         namespace-suffix `\"http.1\"`; leading-digit `\"1foo\"`; \
5651         kebab-leak `\"-foo\"`; snake-leak `\"_foo\"`; non-ASCII \
5652         `\"café\"` — every legitimate search tag is strict ASCII; \
5653         paste-from-binary-blob NUL / BEL / ESC / DEL byte) silently \
5654         passed `from_lisp` + `validate_etiquetas` + \
5655         `StandardLayout::verify` and landed in the rendered \
5656         `lareira-<nome>` Helm chart's `Chart.yaml keywords:` array as a \
5657         malformed search tag — Artifact Hub's keyword index + the future \
5658         caixa-registry's keyword index would either silently drop the \
5659         tag or fail to index it far from the source caixa.lisp; the gate \
5660         moves the diagnostic to the manifest layer with the offending \
5661         value named verbatim)"
5662    )]
5663    EtiquetaInvalid { etiqueta: String, reason: String },
5664    #[error(
5665        ":autores entry is empty (every maintainer must carry a non-empty \
5666         identifier; the empty entry has no operational meaning — it \
5667         identifies no one in the substrate's authorship index and renders \
5668         as `maintainers: [{{name: \"\", email: null}}]` in the Helm chart's \
5669         `Chart.yaml`, a no-op maintainer the substrate cannot route to; \
5670         omit the entry to express \"no maintainer on this position\")"
5671    )]
5672    AutorEmpty,
5673    #[error(
5674        ":autores entry {autor:?} appears more than once (the maintainer \
5675         set is a set, not a multiset; unlike `:etiquetas`, caixa-helm's \
5676         `maintainers:` rendering does *no* dedup — duplicate entries \
5677         stack verbatim in `Chart.yaml` as two identical \
5678         `Maintainer {{ name, email: None }}` records, divergent from every \
5679         peer typed-graph set gate (`:etiquetas`, `:membros :caixa`, \
5680         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
5681         `:deps :nome`, `:upgrade-from :from`); drop the duplicate or \
5682         rename it to the actual author intended)"
5683    )]
5684    AutorDuplicate { autor: String },
5685    #[error(
5686        ":autores entry {autor:?} is not a valid chart-maintainer-name shape: \
5687         {reason} (the substrate consumes this string through the shared \
5688         `crate::render::is_chart_maintainer_name_shape` predicate — the same \
5689         single-line-UTF-8 floor every realistic chart maintainer name carries: \
5690         1..=128 bytes, no leading or trailing whitespace, no ASCII control \
5691         characters anywhere, Unicode bytes accepted. The canonical authoring \
5692         shapes are short single-line identifiers like `\"pleme-io\"`, \
5693         `\"Pleme Contributors\"`, `\"alice <alice@example.com>\"`, \
5694         `\"François Dupont\"`. Without this gate a malformed `:autores` entry \
5695         (paste-from-aligned-doc leading whitespace `\" pleme-io\"` / trailing \
5696         whitespace `\"pleme-io \"`; paste-from-multiline-doc newline \
5697         `\"alice\\nbob\"` — the author pasted a multi-line block of author \
5698         records into one entry instead of splitting into one entry per author; \
5699         paste-from-Windows-CRLF-doc carriage return `\"alice\\rbob\"`; \
5700         tab-from-aligned-doc `\"Pleme\\tContributors\"`; paste-from-binary-blob \
5701         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
5702         `validate_autores` + `StandardLayout::verify` and landed in the \
5703         rendered `lareira-<nome>` Helm chart's `Chart.yaml maintainers:` array \
5704         as a YAML-illegal multi-line scalar or a silently-trimmed whitespace \
5705         round-trip — every chart-aware UI (`helm list`, `helm search`, \
5706         Artifact Hub maintainer index) would render the maintainer name in a \
5707         single-line column far from the source caixa.lisp; the gate moves the \
5708         diagnostic to the manifest layer with the offending value named \
5709         verbatim)"
5710    )]
5711    AutorInvalid { autor: String, reason: String },
5712    #[error(
5713        ":repositorio is the empty string (every published caixa names its \
5714         git source via a non-empty `:repositorio` locator — the value \
5715         flows verbatim into the rendered `lareira-<nome>` Helm chart's \
5716         `Chart.yaml` `home:` field via `caixa-helm` and into the FluxCD \
5717         `GitRepository.spec.url` via `caixa-flux`'s \
5718         `ClusterBundleOpts::for_caixa`; both consumers' \
5719         `Option::unwrap_or_else` fallbacks only fire when the slot is \
5720         `None`, so an empty `Some(\"\")` silently lands as `home: \"\"` / \
5721         `url: \"\"` in the rendered artifacts and breaks at `helm \
5722         template` / FluxCD source-controller reconcile time far from the \
5723         source caixa.lisp; omit the slot entirely to defer to the \
5724         renderer's `https://github.com/pleme-io/<nome>` / \
5725         `caixa.nome`-derived fallback, or carry a canonical authoring \
5726         shape like `\"github:org/repo\"`, `\"https://host/path\"`, \
5727         `\"ssh://[user@]host/path\"`, `\"git@host:path\"`, or \
5728         `\"file:///path\"`)"
5729    )]
5730    RepositorioEmpty,
5731    #[error(
5732        ":repositorio {repositorio:?} is not a valid git repo URL: {reason} \
5733         (the substrate consumes this string through the shared \
5734         `crate::render::is_git_repo_url` predicate — the same parser the \
5735         peer `:deps :fonte (:tipo git :repo …)` axis routes its `:repo` \
5736         value through via `DepSource::validate`; the canonical authoring \
5737         shapes are `\"github:org/repo\"` shorthand, `\"https://host/path\"` \
5738         / `\"ssh://[user@]host/path\"` / `\"git://host/path\"` / \
5739         `\"file:///path\"` URL schemes, or the `\"git@host:path\"` \
5740         scp-style SSH form. Without this gate a malformed `:repositorio` \
5741         (whitespace from a paste-from-doc; control characters / CRLF \
5742         from a paste-from-multiline-doc; a leading `-` from a \
5743         CLI-argument-injection footgun; a missing `:` separator from a \
5744         bare `org/repo` shape git treats as a relative filesystem path) \
5745         silently landed in the rendered `Chart.yaml home:` and the \
5746         FluxCD `GitRepository.spec.url` and broke at `git clone` / \
5747         FluxCD reconcile time far from the source caixa.lisp; the gate \
5748         moves the diagnostic to the manifest layer with the offending \
5749         value named verbatim)"
5750    )]
5751    RepositorioInvalid { repositorio: String, reason: String },
5752    #[error(
5753        ":descricao is the empty string (every published caixa names \
5754         its purpose via a non-empty `:descricao` summary — the value \
5755         flows verbatim into the rendered `lareira-<nome>` Helm \
5756         chart's `Chart.yaml` `description:` field via `caixa-helm`'s \
5757         `build_chart_yaml` and into the chart `README.md` header via \
5758         `build_readme`; both consumers' `Option::unwrap_or_else` \
5759         `caixa.nome`-derived fallbacks only fire when the slot is \
5760         `None`, so an empty `Some(\"\")` silently lands as \
5761         `description: \"\"` / a blank `README.md` header in the \
5762         rendered artifacts and breaks at `helm lint` time \
5763         (`WARNING [chart.metadata.description]: description is \
5764         required` on `apiVersion: v2` charts) far from the source \
5765         caixa.lisp; omit the slot entirely to defer to the \
5766         renderer's `\"Generated chart for caixa Servico <nome>\"` / \
5767         `\"caixa Servico <nome>\"` fallbacks, or carry a non-empty \
5768         summary like `\"Canonical Rust→wasm32-wasip2 caixa \
5769         Servico.\"`)"
5770    )]
5771    DescricaoEmpty,
5772    #[error(
5773        ":descricao {descricao:?} is not a valid chart-description shape: \
5774         {reason} (the substrate consumes this string through the shared \
5775         `crate::render::is_chart_description_shape` predicate — the same \
5776         single-line-UTF-8 floor every realistic chart description carries: \
5777         1..=512 bytes, no leading or trailing whitespace, no ASCII control \
5778         characters anywhere, Unicode prose bytes accepted. The canonical \
5779         authoring shapes are short single-line summaries like `\"Canonical \
5780         Rust→wasm32-wasip2 caixa Servico.\"`, `\"Checkout flow.\"`, \
5781         `\"AWS provider caixa for tatara-lisp\"`. Without this gate a \
5782         malformed `:descricao` (paste-from-aligned-doc leading whitespace \
5783         `\" Checkout flow.\"` / trailing whitespace `\"Checkout flow. \"`; \
5784         paste-from-multiline-doc newline `\"Checkout\\nflow.\"`; \
5785         paste-from-Windows-CRLF-doc carriage return `\"Checkout\\rflow.\"`; \
5786         tab-from-aligned-doc `\"Checkout\\tflow.\"`; paste-from-binary-blob \
5787         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
5788         `validate_descricao` + `StandardLayout::verify` and landed in the \
5789         rendered `lareira-<nome>` Helm chart's `Chart.yaml description:` \
5790         field + `README.md` header paragraph as a YAML-illegal multi-line \
5791         scalar or a silently-trimmed whitespace round-trip — every \
5792         chart-aware UI (`helm list`, `helm search`, Artifact Hub) would \
5793         render the description in a single-line column far from the source \
5794         caixa.lisp; the gate moves the diagnostic to the manifest layer \
5795         with the offending value named verbatim)"
5796    )]
5797    DescricaoInvalid { descricao: String, reason: String },
5798    #[error(
5799        ":licenca is the empty string (every published caixa names \
5800         its license via a non-empty `:licenca` SPDX expression — the \
5801         value flows verbatim into the rendered `lareira-<nome>` Helm \
5802         chart's `README.md` `## License` section via `caixa-helm`'s \
5803         `build_readme` at `caixa-helm/src/lib.rs:361`; the consumer's \
5804         `Option::unwrap_or_else(|| \"MIT\".into())` `MIT` fallback \
5805         only fires when the slot is `None`, so an empty `Some(\"\")` \
5806         silently lands as a bare trailing period in the rendered \
5807         chart `README.md` `License` section far from the source \
5808         caixa.lisp; omit the slot entirely to defer to the \
5809         renderer's `MIT` fallback, or carry a canonical SPDX \
5810         expression like `\"MIT\"`, `\"Apache-2.0\"`, \
5811         `\"Apache-2.0 OR MIT\"`)"
5812    )]
5813    LicencaEmpty,
5814    #[error(
5815        ":licenca {licenca:?} is not a valid SPDX expression shape: {reason} \
5816         (the substrate consumes this string through the shared \
5817         `crate::render::is_spdx_expression_shape` predicate — the same \
5818         alphabet-floor parser every peer per-axis value-shape gate routes \
5819         its value through; the canonical authoring shapes are single \
5820         license identifiers like `\"MIT\"`, `\"Apache-2.0\"`, `\"BSD-3-Clause\"`, \
5821         compound expressions like `\"Apache-2.0 OR MIT\"`, \
5822         `\"MIT AND BSD-3-Clause\"`, `\"(MIT OR Apache-2.0) AND ISC\"`, \
5823         license-with-exception forms like `\"Apache-2.0 WITH LLVM-exception\"`, \
5824         `+`-suffix variants like `\"GPL-2.0+\"`, and user-defined references \
5825         like `\"LicenseRef-MyLicense\"` / \
5826         `\"DocumentRef-doc:LicenseRef-MyLicense\"`. Without this gate a \
5827         malformed `:licenca` (paste-from-doc whitespace `\"MIT \"` / \
5828         `\" MIT\"`; paste-from-multiline-doc CRLF `\"MIT\\n\"`; \
5829         tab-from-aligned-doc `\"MIT\\tOR Apache-2.0\"`; non-ASCII byte from \
5830         a smart-quote paste; underscore-instead-of-hyphen typo \
5831         `\"Apache_2.0\"`; comma-instead-of-`OR`-keyword colloquial idiom \
5832         `\"MIT, Apache-2.0\"`; slash-dual-license colloquial idiom \
5833         `\"MIT/Apache-2.0\"`; semicolon-list-separator confusion \
5834         `\"MIT; Apache-2.0\"`) silently landed in the rendered chart \
5835         `README.md` `## License` section + a future SPDX-aware \
5836         `Chart.yaml license:` emitter would refuse the value at \
5837         `helm lint` time far from the source caixa.lisp; the gate moves \
5838         the diagnostic to the manifest layer with the offending value \
5839         named verbatim)"
5840    )]
5841    LicencaInvalid { licenca: String, reason: String },
5842    #[error(
5843        ":edicao is the empty string (every published caixa names \
5844         its language edition via a non-empty `:edicao` value — the \
5845         edition determines the tatara-lisp macro surface + \
5846         compatibility flags the substrate applies when building \
5847         the caixa; the canonical `Caixa::template` scaffold every \
5848         `feira init` emits carries `:edicao \"2026\"` verbatim and \
5849         every renderer-side fixture (`caixa-helm`, `caixa-flux`, \
5850         `caixa-mesh`) carries `edicao: Some(\"2026\".into())` by \
5851         construction, so an empty `Some(\"\")` silently lands as a \
5852         bare `(:edicao \"\")` line in the rendered `caixa.lisp` and \
5853         a future renderer-side consumer that folds it through \
5854         `Option::unwrap_or_else` will skip the fallback and pass the \
5855         empty edition through to the substrate's build-time edition \
5856         selector far from the source caixa.lisp; omit the slot \
5857         entirely to defer to the substrate's default edition, or \
5858         carry a canonical edition like `\"2026\"`)"
5859    )]
5860    EdicaoEmpty,
5861    #[error(
5862        ":edicao {edicao:?} is not a valid edition: {reason} (every \
5863         documented tatara-lisp edition is a 4-digit ASCII decimal \
5864         year — `\"2026\"` is the only edition currently minted; \
5865         future-introduced siblings will follow the same shape, peer \
5866         with Cargo's `[package] edition` grammar which every value \
5867         Cargo has ever accepted matches: `\"2015\"`, `\"2018\"`, \
5868         `\"2021\"`, `\"2024\"`. Without this gate the canonical \
5869         paste-from-doc footguns silently passed: a trailing space \
5870         (`\"2026 \"`) from a paste-from-doc, a CRLF (`\"2026\\n\"`) \
5871         from a paste-from-multiline-doc, a fullwidth-keyboard \
5872         look-alike (`\"2026\"`), a free-form non-year value \
5873         (`\"x\"`, `\"latest\"`, `\"nightly\"`), a leading non-digit \
5874         version-tag prefix (`\"v2026\"`, `\"e2026\"`), a \
5875         decimal-shaped pseudo-version (`\"2026.1\"`), or a \
5876         wrong-length numeric value (`\"26\"`, `\"202\"`, \
5877         `\"20260\"`) all landed as `(:edicao \"<garbage>\")` in the \
5878         rendered caixa.lisp and broke at the substrate's \
5879         build-time edition selector far from the source caixa.lisp; \
5880         omit the slot entirely to defer to the substrate's default \
5881         edition, or carry a canonical 4-digit ASCII decimal year \
5882         like `\"2026\"`)"
5883    )]
5884    EdicaoInvalid { edicao: String, reason: String },
5885}
5886
5887#[cfg(test)]
5888mod tests {
5889    use super::*;
5890
5891    #[test]
5892    fn template_round_trips() {
5893        let src = Caixa::template("demo");
5894        let c = Caixa::from_lisp(&src).expect("template must parse");
5895        assert_eq!(c.nome, "demo");
5896        assert_eq!(c.versao, "0.1.0");
5897        assert_eq!(c.kind, CaixaKind::Biblioteca);
5898        assert_eq!(c.bibliotecas, vec!["lib/demo.lisp".to_string()]);
5899        assert!(c.deps.is_empty());
5900        assert!(c.deps_dev.is_empty());
5901    }
5902
5903    #[test]
5904    fn register_populates_registry() {
5905        Caixa::register().expect("first register call in this test process must succeed");
5906        let kws = tatara_lisp::domain::registered_keywords();
5907        assert!(kws.contains(&"defcaixa"));
5908    }
5909
5910    #[test]
5911    fn to_lisp_round_trips() {
5912        let src = Caixa::template("demo");
5913        let c1 = Caixa::from_lisp(&src).unwrap();
5914        let emitted = c1.to_lisp();
5915        let c2 = Caixa::from_lisp(&emitted).expect("emitted lisp parses back");
5916        assert_eq!(c1, c2);
5917    }
5918
5919    // ── DialetoEstrangeiro carries a single typed axis ────────────────────
5920    //
5921    // The compounding pin: the variant stores only the typed
5922    // [`crate::dialeto::CaixaDialeto`], and every user-facing byte-string
5923    // (canonical keyword, description, consumer) routes through the enum's
5924    // own accessors at Display time. Prior to that closure the variant
5925    // carried each accessor's return value as a stored `&'static str`
5926    // snapshot alongside `dialeto`; a caller could construct the variant
5927    // with a snapshot that drifted from what `dialeto`'s accessors would
5928    // return, and every downstream user-facing projection would silently
5929    // disagree with the classification. Storing only the axis makes the
5930    // drift structurally impossible.
5931
5932    #[test]
5933    fn dialeto_estrangeiro_variant_carries_only_the_typed_dialeto_axis() {
5934        // Single-field construction is the whole compounding shape — a
5935        // future re-introduction of a snapshot field (a `palavra_canonica:
5936        // &'static str`, a stored `descricao:`, a stored `consumidor:`)
5937        // would re-open the drift surface and this construction would fail
5938        // to compile with "missing field" until every snapshot was seeded
5939        // at the call site again. The compile-time guarantee is the
5940        // invariant; the assertion below only witnesses that the
5941        // construction is well-formed after the closure.
5942        let err = LeituraError::DialetoEstrangeiro {
5943            dialeto: crate::dialeto::CaixaDialeto::Molde,
5944        };
5945        assert!(matches!(
5946            err,
5947            LeituraError::DialetoEstrangeiro {
5948                dialeto: crate::dialeto::CaixaDialeto::Molde,
5949            }
5950        ));
5951    }
5952
5953    #[test]
5954    fn dialeto_estrangeiro_display_routes_through_typed_dialeto_accessors() {
5955        // For every foreign-dialect classification the variant surfaces —
5956        // [`crate::dialeto::CaixaDialeto::Molde`] and
5957        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two
5958        // variants [`Caixa::from_lisp`] raises this error for — the
5959        // rendered [`std::fmt::Display`] byte-string must interpolate each
5960        // typed accessor's return verbatim. A future re-introduction of a
5961        // stored `&'static str` snapshot alongside `dialeto` that Display
5962        // read instead of the accessor would fail this pin as soon as the
5963        // two disagreed; a future accessor rebrand (a per-dialect
5964        // consumer rename, a canonical-keyword shift once the substrate
5965        // migration named in [`crate::dialeto`] completes) reaches every
5966        // consumer through one typed dispatch and this pin verifies the
5967        // display path is one of them.
5968        for d in [
5969            crate::dialeto::CaixaDialeto::Molde,
5970            crate::dialeto::CaixaDialeto::MoldePosicional,
5971        ] {
5972            let rendered = LeituraError::DialetoEstrangeiro { dialeto: d }.to_string();
5973            assert!(
5974                rendered.contains(d.palavra_canonica()),
5975                "Display must interpolate `dialeto.palavra_canonica()` \
5976                 verbatim — a stored snapshot would silently drift from \
5977                 the typed accessor. dialect: {d}, rendered: {rendered:?}"
5978            );
5979            assert!(
5980                rendered.contains(d.descricao()),
5981                "Display must interpolate `dialeto.descricao()` verbatim. \
5982                 dialect: {d}, rendered: {rendered:?}"
5983            );
5984            assert!(
5985                rendered.contains(d.consumidor()),
5986                "Display must interpolate `dialeto.consumidor()` verbatim. \
5987                 dialect: {d}, rendered: {rendered:?}"
5988            );
5989        }
5990    }
5991
5992    #[test]
5993    fn from_lisp_rejects_molde_dialect_via_typed_variant() {
5994        // The end-to-end pin the compounding closure defends: a
5995        // Molde-dialect source lands as [`LeituraError::DialetoEstrangeiro`]
5996        // carrying [`crate::dialeto::CaixaDialeto::Molde`], and the
5997        // rendered Display byte-string names the Molde accessors'
5998        // returns verbatim. Any future path that constructed the variant
5999        // with a mismatched snapshot (a stored `palavra_canonica:
6000        // "defcaixa"` on a `Molde` classification) would land Display
6001        // pointing at `defcaixa` while the typed axis said `Molde` — the
6002        // exact drift the closure removes.
6003        let src = r#"
6004          (defcaixa
6005            :name "x"
6006            :kind :Biblioteca
6007            :ecosystem :rust-single-crate
6008            :package {:name "x" :version "0.1.0"})
6009        "#;
6010        let err = Caixa::from_lisp(src).expect_err("Molde dialect must not parse as Pacote");
6011        match err {
6012            LeituraError::DialetoEstrangeiro { dialeto } => {
6013                assert_eq!(dialeto, crate::dialeto::CaixaDialeto::Molde);
6014                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
6015                assert!(rendered.contains(dialeto.palavra_canonica()));
6016                assert!(rendered.contains(dialeto.consumidor()));
6017                assert!(rendered.contains(dialeto.descricao()));
6018            }
6019            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
6020        }
6021    }
6022
6023    #[test]
6024    fn from_lisp_rejects_molde_posicional_dialect_via_typed_variant() {
6025        // Coverage pin for the [`crate::dialeto::CaixaDialeto::MoldePosicional`]
6026        // arm of the [`Caixa::from_lisp`] foreign-dialect gate — the
6027        // positional-arity `defmolde` form written under a `(defcaixa …)`
6028        // head (`(defcaixa todoku-go :kind :Biblioteca :ecosystem :go
6029        // …)`). Pre-lift this arm rode the same `foreign =>` wildcard
6030        // the [`crate::dialeto::CaixaDialeto::Molde`] sibling arm rode,
6031        // so no test exercised the positional-arity path through
6032        // `Caixa::from_lisp` specifically; the sibling
6033        // [`from_lisp_rejects_molde_dialect_via_typed_variant`] only
6034        // covered [`crate::dialeto::CaixaDialeto::Molde`]. Post-lift the
6035        // two arms route through the lifted
6036        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
6037        // typed predicate — the same predicate the pre-lift `foreign =>`
6038        // wildcard resolved to today — and this pin makes the
6039        // positional-arity arm's byte-shape at the gate explicit rather
6040        // than implied by wildcard-absorption. A future regression that
6041        // silently reordered [`crate::dialeto::CaixaDialeto::is_molde_family`]'s
6042        // arm-set (dropped [`crate::dialeto::CaixaDialeto::MoldePosicional`]
6043        // from the two-arity closure) would fail this pin at caixa-core
6044        // test time rather than surfacing far from the change as a
6045        // `caixa.lisp` carrying a `(defcaixa todoku-go :ecosystem :go
6046        // …)` silently parsing past the derive.
6047        let src = r#"
6048          (defcaixa todoku-go
6049            :kind :Biblioteca
6050            :ecosystem :go
6051            :package {:name "todoku-go" :version "0.3.0"})
6052        "#;
6053        let err =
6054            Caixa::from_lisp(src).expect_err("MoldePosicional dialect must not parse as Pacote");
6055        match err {
6056            LeituraError::DialetoEstrangeiro { dialeto } => {
6057                assert_eq!(
6058                    dialeto,
6059                    crate::dialeto::CaixaDialeto::MoldePosicional,
6060                    "DialetoEstrangeiro must carry the MoldePosicional \
6061                     variant verbatim — the positional-arity `defmolde` \
6062                     form under a `(defcaixa …)` head is the \
6063                     `MoldePosicional` arm's canonical byte-shape"
6064                );
6065                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
6066                assert!(
6067                    rendered.contains(dialeto.palavra_canonica()),
6068                    "Display must interpolate `dialeto.palavra_canonica()` \
6069                     verbatim on the MoldePosicional arm; rendered: \
6070                     {rendered:?}"
6071                );
6072                assert!(
6073                    rendered.contains(dialeto.consumidor()),
6074                    "Display must interpolate `dialeto.consumidor()` \
6075                     verbatim on the MoldePosicional arm; rendered: \
6076                     {rendered:?}"
6077                );
6078                assert!(
6079                    rendered.contains(dialeto.descricao()),
6080                    "Display must interpolate `dialeto.descricao()` \
6081                     verbatim on the MoldePosicional arm; rendered: \
6082                     {rendered:?}"
6083                );
6084            }
6085            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
6086        }
6087    }
6088
6089    #[test]
6090    fn from_lisp_dialect_gate_dispatches_through_caixa_dialeto_is_molde_family_predicate() {
6091        // Load-bearing byte-parity pin: for every arm in
6092        // [`crate::dialeto::CaixaDialeto::ALL`], the
6093        // [`Caixa::from_lisp`] foreign-dialect gate's DialetoEstrangeiro
6094        // partition must agree with the lifted
6095        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
6096        // typed predicate — i.e. from_lisp raises
6097        // [`LeituraError::DialetoEstrangeiro`] carrying `d` iff
6098        // `d.is_molde_family()` returns `true`, and does NOT raise
6099        // [`LeituraError::DialetoEstrangeiro`] on any arm where the
6100        // predicate returns `false` (the arm's source falls through to
6101        // the derive — parses cleanly on
6102        // [`crate::dialeto::CaixaDialeto::Pacote`], surfaces a
6103        // [`LeituraError::Leitura`] on
6104        // [`crate::dialeto::CaixaDialeto::Desconhecido`]).
6105        //
6106        // Pre-lift the gate hand-rolled a three-arm match
6107        // (`Pacote => {}`, `Desconhecido => {}`, `foreign => Err(…)`)
6108        // whose `foreign =>` wildcard expressed no compile-time link
6109        // back to the substrate primitive's arm-family; a future fifth
6110        // dialect the [`crate::dialeto`] module doc's "third dialect"
6111        // hazard actualises would fall silently onto the wildcard
6112        // regardless of whether it belonged to the `defmolde` family or
6113        // to a distinct `defcaixa`-family. Post-lift the partition
6114        // resolves through
6115        // [`crate::dialeto::CaixaDialeto::is_molde_family`]'s single
6116        // typed dispatch, and this pin refuses any future regression
6117        // that silently split the from_lisp partition from the typed
6118        // predicate — the two paths now migrate as one on any future
6119        // arm addition.
6120        //
6121        // Sibling in shape to the peer
6122        // [`crate::dialeto::tests::caixa_dialeto_is_molde_family_agrees_with_palavra_canonica_defmolde_projection`]
6123        // (e9d2315) that pins the same byte-parity between
6124        // [`crate::dialeto::CaixaDialeto::is_molde_family`] and the
6125        // sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
6126        // `== "defmolde"` classifier — extends the discipline from the
6127        // two paths within the [`crate::dialeto`] primitive onto the
6128        // third external consumer of the `defmolde`-family partition
6129        // (the [`Caixa::from_lisp`] gate that raises
6130        // [`LeituraError::DialetoEstrangeiro`]).
6131        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
6132            (
6133                crate::dialeto::CaixaDialeto::Pacote,
6134                r#"
6135                  (defcaixa
6136                    :nome   "checkout"
6137                    :versao "0.1.0"
6138                    :kind   Biblioteca
6139                    :edicao "2026"
6140                    :descricao "canonical Pacote source"
6141                    :autores ()
6142                    :etiquetas ()
6143                    :deps ()
6144                    :deps-dev ()
6145                    :bibliotecas ("lib/checkout.lisp"))
6146                "#,
6147            ),
6148            (
6149                crate::dialeto::CaixaDialeto::Molde,
6150                r#"
6151                  (defcaixa
6152                    :name "base64"
6153                    :kind :Biblioteca
6154                    :ecosystem :rust-single-crate
6155                    :package {:name "base64" :version "0.22.1"}
6156                    :workflows [:auto-release])
6157                "#,
6158            ),
6159            (
6160                crate::dialeto::CaixaDialeto::MoldePosicional,
6161                r#"
6162                  (defcaixa todoku-go
6163                    :kind :Biblioteca
6164                    :ecosystem :go
6165                    :package {:name "todoku-go" :version "0.3.0"})
6166                "#,
6167            ),
6168            (
6169                crate::dialeto::CaixaDialeto::Desconhecido,
6170                r#"(defcaixa :licenca "MIT")"#,
6171            ),
6172        ];
6173
6174        // Coverage: every arm in [`crate::dialeto::CaixaDialeto::ALL`]
6175        // must appear in the fixture table so the pin's arm-set stays
6176        // synchronised with the enum's arm-set. Fails at test time if a
6177        // future fifth arm added to [`crate::dialeto::CaixaDialeto`]
6178        // (with a corresponding `is_molde_family` return) forgot to
6179        // extend this fixture table with a canonical source for the new
6180        // arm — the pin cannot cover an arm it has no source for.
6181        for &expected in crate::dialeto::CaixaDialeto::ALL {
6182            assert!(
6183                fixtures.iter().any(|(d, _)| *d == expected),
6184                "fixture table must carry a canonical source for every \
6185                 CaixaDialeto arm; missing: {expected:?}"
6186            );
6187        }
6188
6189        for &(expected_dialect, src) in fixtures {
6190            let classified = crate::dialeto::classify(src.trim()).unwrap_or_else(|err| {
6191                panic!(
6192                    "fixture source for {expected_dialect:?} must classify \
6193                     cleanly, got err: {err:?}"
6194                )
6195            });
6196            assert_eq!(
6197                classified, expected_dialect,
6198                "fixture source for {expected_dialect:?} must classify as \
6199                 {expected_dialect:?} (drift here defeats the byte-parity \
6200                 pin below — a source labelled for one arm but classifying \
6201                 as another would silently satisfy or violate the pin for \
6202                 the wrong reason)"
6203            );
6204
6205            let outcome = Caixa::from_lisp(src);
6206            match (expected_dialect.is_molde_family(), &outcome) {
6207                (true, Err(LeituraError::DialetoEstrangeiro { dialeto })) => {
6208                    assert_eq!(
6209                        *dialeto, expected_dialect,
6210                        "DialetoEstrangeiro must carry the same typed arm \
6211                         the classifier returned — a drift here would let \
6212                         from_lisp raise the error while pointing at the \
6213                         wrong dialect (e.g. rejecting a \
6214                         MoldePosicional source as Molde). arm: \
6215                         {expected_dialect:?}"
6216                    );
6217                }
6218                (true, other) => panic!(
6219                    "arm {expected_dialect:?} has is_molde_family() = true \
6220                     so from_lisp must raise DialetoEstrangeiro carrying \
6221                     {expected_dialect:?}; got: {other:?}"
6222                ),
6223                (false, Err(LeituraError::DialetoEstrangeiro { dialeto })) => panic!(
6224                    "arm {expected_dialect:?} has is_molde_family() = false \
6225                     so from_lisp must NOT raise DialetoEstrangeiro; got \
6226                     one carrying: {dialeto:?}. This means the typed \
6227                     predicate and the from_lisp partition disagree on \
6228                     this arm — exactly the drift this pin refuses."
6229                ),
6230                (false, _) => {
6231                    // A non-molde arm's source falls through to the
6232                    // derive: Pacote sources parse to Ok(_); Desconhecido
6233                    // sources surface as LeituraError::Leitura from the
6234                    // derive's own unknown-keyword rejection. Either
6235                    // shape is acceptable here — the pin's promise is
6236                    // narrower: "no DialetoEstrangeiro on
6237                    // is_molde_family() == false".
6238                }
6239            }
6240        }
6241    }
6242
6243    // ── M2 typed-substrate slot tests (limits, behavior, upgrade-from, supervisor) ──
6244
6245    #[test]
6246    fn limits_round_trip_via_json() {
6247        use crate::LimitsSpec;
6248        use std::time::Duration;
6249        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6250        c.limits = Some(LimitsSpec {
6251            memory: Some(64 * 1024 * 1024),
6252            fuel: Some(1_000_000),
6253            wall_clock: Some(Duration::from_secs(30)),
6254            cpu: Some(500),
6255        });
6256        let json = serde_json::to_string(&c).unwrap();
6257        assert!(json.contains("\"limits\""));
6258        assert!(json.contains("\"64MiB\""));
6259        assert!(json.contains("\"30s\""));
6260        assert!(json.contains("\"500m\""));
6261        let back: Caixa = serde_json::from_str(&json).unwrap();
6262        assert_eq!(c.limits, back.limits);
6263    }
6264
6265    #[test]
6266    fn behavior_round_trip_via_json() {
6267        use crate::BehaviorSpec;
6268        use std::path::PathBuf;
6269        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6270        c.behavior = Some(BehaviorSpec {
6271            on_init: Some(PathBuf::from("lib/init.lisp")),
6272            on_call: Some(PathBuf::from("lib/handlers.lisp")),
6273            ..Default::default()
6274        });
6275        let json = serde_json::to_string(&c).unwrap();
6276        let back: Caixa = serde_json::from_str(&json).unwrap();
6277        assert_eq!(c.behavior, back.behavior);
6278    }
6279
6280    #[test]
6281    fn upgrade_from_round_trip_via_json() {
6282        use crate::{UpgradeFromEntry, UpgradeInstruction};
6283        use std::path::PathBuf;
6284        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6285        c.upgrade_from = vec![UpgradeFromEntry {
6286            from: "0.1.0".into(),
6287            instructions: vec![
6288                UpgradeInstruction::LoadModule {
6289                    module: "demo".into(),
6290                },
6291                UpgradeInstruction::StateChange {
6292                    script: PathBuf::from("lib/migrations/v01-to-v02.lisp"),
6293                },
6294                UpgradeInstruction::SoftPurge {
6295                    module: "demo-old".into(),
6296                },
6297            ],
6298        }];
6299        let json = serde_json::to_string(&c).unwrap();
6300        let back: Caixa = serde_json::from_str(&json).unwrap();
6301        assert_eq!(c.upgrade_from, back.upgrade_from);
6302    }
6303
6304    #[test]
6305    fn supervisor_view_returns_typed_shape() {
6306        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
6307        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
6308        c.kind = CaixaKind::Supervisor;
6309        c.bibliotecas.clear();
6310        c.estrategia = Some(RestartStrategy::OneForOne);
6311        c.max_restarts = Some(5);
6312        c.restart_window = Some("60s".into());
6313        c.children = vec![ChildSpec {
6314            caixa: "worker".into(),
6315            versao: "^0.1".into(),
6316            restart: RestartPolicy::Permanent,
6317        }];
6318        let view = c.supervisor_view().expect("Supervisor kind has a view");
6319        assert_eq!(view.estrategia, RestartStrategy::OneForOne);
6320        assert_eq!(view.max_restarts, 5);
6321        assert_eq!(
6322            view.restart_window,
6323            Some(std::time::Duration::from_secs(60))
6324        );
6325        assert_eq!(view.children.len(), 1);
6326        view.validate().unwrap();
6327    }
6328
6329    #[test]
6330    fn supervisor_view_none_for_non_supervisor_kinds() {
6331        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6332        assert!(c.supervisor_view().is_none());
6333    }
6334
6335    #[test]
6336    fn declared_mesh_slots_empty_for_bare_caixa() {
6337        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6338        assert!(c.declared_mesh_slots().is_empty());
6339    }
6340
6341    #[test]
6342    fn declared_mesh_slots_reports_only_set_slots_in_canonical_order() {
6343        use crate::{Entrada, Membro};
6344        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6345        // Set a non-adjacent pair (:membros + :entrada) to pin that the
6346        // canonical declaration order is preserved regardless of which
6347        // subset is populated.
6348        c.membros = vec![Membro {
6349            caixa: "a".into(),
6350            versao: "^0.1".into(),
6351        }];
6352        c.entrada = Some(Entrada {
6353            host: "x.example.com".into(),
6354            para: "a".into(),
6355            paths: vec![],
6356            port: 8080,
6357        });
6358        assert_eq!(
6359            c.declared_mesh_slots(),
6360            vec![
6361                crate::render::M3_AUTHOR_KEY_MEMBROS,
6362                crate::render::M3_AUTHOR_KEY_ENTRADA,
6363            ]
6364        );
6365    }
6366
6367    #[test]
6368    fn m3_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
6369        // Scalar-value pin: the five author-facing kebab-case labels the
6370        // `(defcaixa … :<slot> (…))` surface admits on the M3 top-level
6371        // mesh slot axis, one arm per typed slot. Mirrors the peer
6372        // scalar-value pin the sibling
6373        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
6374        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
6375        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] M2 top-level slot consts
6376        // carry (f49c8b0), so both altitudes of the typed-slot algebra
6377        // (per-Servico M2 + per-Aplicacao M3) share the same
6378        // "one canonical byte-string per arm" discipline. A future
6379        // rebrand (`:membros` → `:members`, `:contratos` → `:contracts`,
6380        // `:politicas` → `:policies`, `:placement` → `:distribution`,
6381        // `:entrada` → `:ingress`) lands as an edit to exactly one const,
6382        // and every consumer that reaches for the label picks it up at
6383        // build time rather than at runtime as a downstream mismatch.
6384        assert_eq!(crate::render::M3_AUTHOR_KEY_MEMBROS, ":membros");
6385        assert_eq!(crate::render::M3_AUTHOR_KEY_CONTRATOS, ":contratos");
6386        assert_eq!(crate::render::M3_AUTHOR_KEY_POLITICAS, ":politicas");
6387        assert_eq!(crate::render::M3_AUTHOR_KEY_PLACEMENT, ":placement");
6388        assert_eq!(crate::render::M3_AUTHOR_KEY_ENTRADA, ":entrada");
6389    }
6390
6391    #[test]
6392    fn declared_mesh_slots_route_through_lifted_m3_author_key_consts() {
6393        // Production-through-const pin: the five per-arm labels the
6394        // [`Caixa::declared_mesh_slots`] tagger pushes onto its return
6395        // `Vec` route through the lifted
6396        // [`crate::M3_AUTHOR_KEY_MEMBROS`] /
6397        // [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
6398        // [`crate::M3_AUTHOR_KEY_POLITICAS`] /
6399        // [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
6400        // [`crate::M3_AUTHOR_KEY_ENTRADA`] consts, in canonical
6401        // declaration order. A future re-order or drift at the tagger
6402        // (a rename that reaches the tagger but not the const, or vice
6403        // versa) surfaces here at build time rather than at runtime as
6404        // a [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
6405        // `slots: <stale-kebab-case>` diagnostic far from the rename's
6406        // commit. Mirror of the peer
6407        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
6408        // pin (f49c8b0) on the sibling per-Servico M2 top-level slot
6409        // axis.
6410        use crate::{Entrada, Membro, MeshPolicy, Placement, PlacementStrategy, WitContract};
6411        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6412        c.membros = vec![Membro {
6413            caixa: "a".into(),
6414            versao: "^0.1".into(),
6415        }];
6416        c.contratos = vec![WitContract {
6417            de: "a".into(),
6418            para: "a".into(),
6419            wit: "wasi:http/proxy".into(),
6420            endpoint: Some("/x".into()),
6421            subject: None,
6422            slot: None,
6423        }];
6424        c.politicas = Some(MeshPolicy::default());
6425        c.placement = Some(Placement {
6426            estrategia: PlacementStrategy::Replicated,
6427            clusters: vec!["rio".into()],
6428            affinity: None,
6429            shard_key: None,
6430        });
6431        c.entrada = Some(Entrada {
6432            host: "x.example.com".into(),
6433            para: "a".into(),
6434            paths: vec![],
6435            port: 8080,
6436        });
6437        assert_eq!(
6438            c.declared_mesh_slots(),
6439            vec![
6440                crate::render::M3_AUTHOR_KEY_MEMBROS,
6441                crate::render::M3_AUTHOR_KEY_CONTRATOS,
6442                crate::render::M3_AUTHOR_KEY_POLITICAS,
6443                crate::render::M3_AUTHOR_KEY_PLACEMENT,
6444                crate::render::M3_AUTHOR_KEY_ENTRADA,
6445            ]
6446        );
6447    }
6448
6449    #[test]
6450    fn declared_supervisor_slots_empty_for_bare_caixa() {
6451        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6452        assert!(c.declared_supervisor_slots().is_empty());
6453    }
6454
6455    #[test]
6456    fn declared_supervisor_slots_reports_only_set_slots_in_canonical_order() {
6457        use crate::RestartStrategy;
6458        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6459        // Set a non-adjacent pair (:estrategia + :restart-window) to pin
6460        // that the canonical declaration order is preserved regardless
6461        // of which subset is populated.
6462        c.estrategia = Some(RestartStrategy::OneForOne);
6463        c.restart_window = Some("60s".into());
6464        assert_eq!(
6465            c.declared_supervisor_slots(),
6466            vec![
6467                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
6468                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
6469            ]
6470        );
6471    }
6472
6473    #[test]
6474    fn supervisor_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
6475        // Scalar-value pin: the four author-facing kebab-case labels the
6476        // `(defcaixa … :<slot> (…))` surface admits on the Supervisor
6477        // supervision-tree slot axis, one arm per typed slot. Mirrors the
6478        // peer scalar-value pins the sibling
6479        // [`crate::render::M2_AUTHOR_KEY_LIMITS`] /
6480        // [`crate::render::M2_AUTHOR_KEY_BEHAVIOR`] /
6481        // [`crate::render::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot
6482        // consts and [`crate::render::M3_AUTHOR_KEY_MEMBROS`] etc.
6483        // top-level M3 slot consts carry, so all three kind-scoped
6484        // typed-slot-family author-facing-label axes route through one
6485        // canonical per-arm declaration. A future rebrand
6486        // (`:estrategia` → `:strategy` for English uniformity,
6487        // `:max-restarts` → `:max-intensity` matching Erlang/OTP's
6488        // `MaxIntensity` name, `:restart-window` → `:period` matching
6489        // OTP's `Period` name, `:children` → `:workers` matching Elixir
6490        // idiom) lands as an edit to exactly one const, and every
6491        // consumer that reaches for the label picks it up at build time
6492        // rather than at runtime as a downstream mismatch.
6493        assert_eq!(
6494            crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
6495            ":estrategia"
6496        );
6497        assert_eq!(
6498            crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
6499            ":max-restarts"
6500        );
6501        assert_eq!(
6502            crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
6503            ":restart-window"
6504        );
6505        assert_eq!(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN, ":children");
6506    }
6507
6508    #[test]
6509    fn declared_supervisor_slots_route_through_lifted_supervisor_author_key_consts() {
6510        // Production-through-const pin: the four per-arm labels the
6511        // [`Caixa::declared_supervisor_slots`] tagger pushes onto its
6512        // return `Vec` route through the lifted
6513        // [`crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] /
6514        // [`crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`] /
6515        // [`crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW`] /
6516        // [`crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN`] consts, in
6517        // canonical declaration order. A future re-order or drift at the
6518        // tagger (a rename that reaches the tagger but not the const, or
6519        // vice versa) surfaces here at build time rather than at runtime
6520        // as a [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
6521        // `slots: <stale-kebab-case>` diagnostic far from the rename's
6522        // commit. Mirror of the peer
6523        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
6524        // (f49c8b0) and
6525        // [`declared_mesh_slots_route_through_lifted_m3_author_key_consts`]
6526        // (882f498) pins on the sibling M2 / M3 top-level slot axes.
6527        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
6528        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6529        c.estrategia = Some(RestartStrategy::OneForOne);
6530        c.max_restarts = Some(5);
6531        c.restart_window = Some("60s".into());
6532        c.children = vec![ChildSpec {
6533            caixa: "worker".into(),
6534            versao: "^0.1".into(),
6535            restart: RestartPolicy::Permanent,
6536        }];
6537        assert_eq!(
6538            c.declared_supervisor_slots(),
6539            vec![
6540                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
6541                crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
6542                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
6543                crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN,
6544            ]
6545        );
6546    }
6547
6548    #[test]
6549    fn declared_servico_slots_empty_for_bare_caixa() {
6550        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6551        assert!(c.declared_servico_slots().is_empty());
6552    }
6553
6554    #[test]
6555    fn declared_servico_slots_reports_only_set_slots_in_canonical_order() {
6556        use crate::{UpgradeFromEntry, UpgradeInstruction};
6557        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6558        // Set a non-adjacent pair (:limits + :upgrade-from) to pin that
6559        // the canonical declaration order is preserved regardless of
6560        // which subset is populated.
6561        c.limits = Some(crate::LimitsSpec {
6562            fuel: Some(1_000_000),
6563            ..Default::default()
6564        });
6565        c.upgrade_from = vec![UpgradeFromEntry {
6566            from: "0.1.0".into(),
6567            instructions: vec![UpgradeInstruction::Restart],
6568        }];
6569        assert_eq!(
6570            c.declared_servico_slots(),
6571            vec![
6572                crate::render::M2_AUTHOR_KEY_LIMITS,
6573                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
6574            ]
6575        );
6576    }
6577
6578    #[test]
6579    fn m2_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
6580        // Scalar-value pin: the three author-facing kebab-case labels
6581        // the `(defcaixa … :<slot> (…))` surface admits on the M2
6582        // top-level slot axis, one arm per typed slot. Mirrors the peer
6583        // scalar-value pin the sibling renderer-side
6584        // [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
6585        // [`crate::M2_KEY_UPGRADE_FROM`] camelCase overlay-container
6586        // consts carry, so both halves of the M2 top-level slot dual
6587        // axis (author-facing kebab-case label + renderer-side
6588        // camelCase overlay-container wire key) route through one
6589        // canonical per-arm declaration. A future rebrand
6590        // (`:limits` → `:sandbox` matching Lunatic per-process
6591        // terminology INSPIRATIONS §III.1, `:behavior` → `:gen-server`
6592        // matching Erlang's verbatim name, `:upgrade-from` → `:appup`
6593        // matching Erlang's verbatim appup name) lands as an edit to
6594        // exactly one const, and every consumer that reaches for the
6595        // label picks it up at build time rather than at runtime as a
6596        // downstream mismatch.
6597        assert_eq!(crate::render::M2_AUTHOR_KEY_LIMITS, ":limits");
6598        assert_eq!(crate::render::M2_AUTHOR_KEY_BEHAVIOR, ":behavior");
6599        assert_eq!(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM, ":upgrade-from");
6600    }
6601
6602    #[test]
6603    fn declared_servico_slots_route_through_lifted_m2_author_key_consts() {
6604        // Production-through-const pin: the three per-arm labels the
6605        // [`Caixa::declared_servico_slots`] tagger pushes onto its
6606        // return `Vec` route through the lifted
6607        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
6608        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
6609        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts, in canonical
6610        // declaration order. A future re-order or drift at the tagger
6611        // (a rename that reaches the tagger but not the const, or vice
6612        // versa) surfaces here at build time rather than at runtime as
6613        // a [`crate::LayoutError::ServicoSlotsOnNonServico`]
6614        // `slots: <stale-kebab-case>` diagnostic far from the rename's
6615        // commit. Mirror of the peer
6616        // [`crate::behavior::BehaviorSpec::declared_slots`] production
6617        // tagger pin (889dc18) on the sibling per-callback axis.
6618        use crate::{BehaviorSpec, UpgradeFromEntry, UpgradeInstruction};
6619        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6620        c.limits = Some(crate::LimitsSpec {
6621            fuel: Some(1_000_000),
6622            ..Default::default()
6623        });
6624        c.behavior = Some(BehaviorSpec {
6625            on_init: Some(PathBuf::from("lib/init.lisp")),
6626            ..Default::default()
6627        });
6628        c.upgrade_from = vec![UpgradeFromEntry {
6629            from: "0.1.0".into(),
6630            instructions: vec![UpgradeInstruction::Restart],
6631        }];
6632        assert_eq!(
6633            c.declared_servico_slots(),
6634            vec![
6635                crate::render::M2_AUTHOR_KEY_LIMITS,
6636                crate::render::M2_AUTHOR_KEY_BEHAVIOR,
6637                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
6638            ]
6639        );
6640    }
6641
6642    #[test]
6643    fn existing_manifests_unaffected_by_new_optional_slots() {
6644        // Regression test: a caixa.lisp authored before M2 typed slots
6645        // should still parse + serialize cleanly. The bare `defcaixa`
6646        // emitted by `Caixa::template` has none of the new fields.
6647        let src = Caixa::template("legacy");
6648        let c = Caixa::from_lisp(&src).unwrap();
6649        assert!(c.limits.is_none());
6650        assert!(c.behavior.is_none());
6651        assert!(c.upgrade_from.is_empty());
6652        assert!(c.estrategia.is_none());
6653        assert!(c.children.is_empty());
6654
6655        // And to_lisp emits a manifest with the new slots in the
6656        // empty/default state — round-trippable.
6657        let emitted = c.to_lisp();
6658        let back = Caixa::from_lisp(&emitted).unwrap();
6659        assert_eq!(c, back);
6660    }
6661
6662    #[test]
6663    fn validate_deps_accepts_canonical_caixa() {
6664        // Positive control: the bare template — zero deps, zero
6665        // deps_dev — passes the gate trivially. A future axis added to
6666        // `Dep::validate` mustn't regress an empty-deps caixa to a
6667        // build error.
6668        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6669        c.validate_deps().unwrap();
6670    }
6671
6672    #[test]
6673    fn validate_deps_rejects_invalid_versao_in_deps() {
6674        // Fail-before-pass-after pin: a malformed `:deps :versao`
6675        // surfaces at validate_deps() time, not at lacre-resolve time.
6676        // Mirrors `rejects_invalid_membro_versao_requirement` and
6677        // `validate_rejects_invalid_child_versao_requirement` on the
6678        // other two `:versao` axes.
6679        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6680        c.deps = vec![Dep::simple("caixa-teia", "^bad-version")];
6681        let err = c.validate_deps().unwrap_err();
6682        assert!(
6683            matches!(
6684                err,
6685                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
6686                    if nome == "caixa-teia" && versao == "^bad-version"
6687            ),
6688            "got {err:?}"
6689        );
6690    }
6691
6692    #[test]
6693    fn validate_deps_rejects_invalid_versao_in_deps_dev() {
6694        // Parity pin: `:deps-dev` must run through the same per-entry
6695        // validator as `:deps` — a typo in either axis surfaces the
6696        // same diagnostic. Without this leg, `:deps-dev` would be a
6697        // second-class citizen of the typed surface and an author
6698        // could land a build that passes validate_deps but fails at
6699        // `feira lock`-time when the dev-dep is resolved for a test
6700        // build.
6701        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6702        c.deps_dev = vec![Dep::simple("tatara-check", "^^0.1")];
6703        let err = c.validate_deps().unwrap_err();
6704        assert!(
6705            matches!(
6706                err,
6707                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
6708                    if nome == "tatara-check" && versao == "^^0.1"
6709            ),
6710            "got {err:?}"
6711        );
6712    }
6713
6714    #[test]
6715    fn validate_deps_runs_deps_before_deps_dev() {
6716        // Order pin: when both lists carry typos, the `:deps`
6717        // diagnostic surfaces first. The author's mental model is
6718        // "runtime deps are load-bearing; dev deps are scaffolding";
6719        // surfacing the runtime axis first matches that hierarchy.
6720        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6721        c.deps = vec![Dep::simple("runtime-dep", "^bad-runtime")];
6722        c.deps_dev = vec![Dep::simple("dev-dep", "^bad-dev")];
6723        let err = c.validate_deps().unwrap_err();
6724        assert!(
6725            matches!(
6726                err,
6727                crate::dep::DepError::VersaoInvalid { ref nome, .. }
6728                    if nome == "runtime-dep"
6729            ),
6730            "expected `:deps` typo to surface first, got {err:?}"
6731        );
6732    }
6733
6734    #[test]
6735    fn validate_deps_accepts_canonical_versao_forms_in_both_lists() {
6736        // Positive control sweep across both lists. Pin every
6737        // canonical Cargo-shaped form so a future tightening of the
6738        // accepted set surfaces here as a test failure (parity with
6739        // `accepts_canonical_membro_versao_forms` and
6740        // `validate_accepts_canonical_child_versao_forms`).
6741        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6742        c.deps = vec![
6743            Dep::simple("caret", "^0.1"),
6744            Dep::simple("tilde", "~0.1.2"),
6745            Dep::simple("exact", "0.1.0"),
6746            Dep::simple("wildcard", "*"),
6747            Dep::simple("multi-range", ">=0.1, <2"),
6748        ];
6749        c.deps_dev = vec![
6750            Dep::simple("dev-caret", "^0.1"),
6751            Dep::simple("dev-wildcard", "*"),
6752        ];
6753        c.validate_deps().unwrap();
6754    }
6755
6756    #[test]
6757    fn validate_deps_diagnostic_carries_offending_dep() {
6758        // Diagnostic-shape pin: the error names the offending entry's
6759        // `:nome` + `:versao` verbatim and carries a non-empty
6760        // `reason` from `semver::VersionReq::parse`, so a `feira lint`
6761        // run can render the diagnostic without re-parsing.
6762        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6763        c.deps = vec![Dep::simple("caixa-teia", "not-a-req")];
6764        let err = c.validate_deps().unwrap_err();
6765        let crate::dep::DepError::VersaoInvalid {
6766            nome,
6767            versao,
6768            reason,
6769        } = err
6770        else {
6771            panic!("expected VersaoInvalid, got other variant");
6772        };
6773        assert_eq!(nome, "caixa-teia");
6774        assert_eq!(versao, "not-a-req");
6775        assert!(
6776            !reason.is_empty(),
6777            "VersaoInvalid `reason` must carry the parser's wording verbatim"
6778        );
6779    }
6780
6781    #[test]
6782    fn validate_deps_rejects_ambiguous_fonte_in_deps_dev() {
6783        // Cross-axis pin: `validate_deps` walks both :deps and
6784        // :deps-dev through `Dep::validate`, and the new fonte gate
6785        // (`:tag` + `:branch` both set — the canonical "pin drift"
6786        // footgun) must surface from the :deps-dev arm with the
6787        // offending entry's :nome named. Pin the :deps-dev arm
6788        // explicitly so a future shortcut that only walks :deps
6789        // surfaces here as a regression.
6790        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6791        c.deps_dev = vec![Dep {
6792            nome: "dev-only".into(),
6793            versao: "^0.1".into(),
6794            fonte: Some(crate::DepSource::Git {
6795                repo: "github:p/x".into(),
6796                tag: Some("v1".into()),
6797                rev: None,
6798                branch: Some("main".into()),
6799            }),
6800            opcional: false,
6801            caracteristicas: vec![],
6802        }];
6803        let err = c.validate_deps().unwrap_err();
6804        let crate::dep::DepError::FontePinAmbiguous { nome, pins } = err else {
6805            panic!("expected FontePinAmbiguous from :deps-dev walk");
6806        };
6807        assert_eq!(nome, "dev-only");
6808        assert!(pins.contains(":tag") && pins.contains(":branch"));
6809    }
6810
6811    #[test]
6812    fn validate_deps_rejects_empty_repo_in_deps() {
6813        // Parity pin on the :deps arm: an empty :repo on the runtime
6814        // deps list surfaces the same FonteRepoEmpty diagnostic the
6815        // dep.rs per-entry tests pin, naming the offending entry.
6816        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6817        c.deps = vec![Dep {
6818            nome: "runtime".into(),
6819            versao: "^0.1".into(),
6820            fonte: Some(crate::DepSource::Git {
6821                repo: String::new(),
6822                tag: Some("v1".into()),
6823                rev: None,
6824                branch: None,
6825            }),
6826            opcional: false,
6827            caracteristicas: vec![],
6828        }];
6829        let err = c.validate_deps().unwrap_err();
6830        assert!(
6831            matches!(
6832                err,
6833                crate::dep::DepError::FonteRepoEmpty { ref nome }
6834                    if nome == "runtime"
6835            ),
6836            "got {err:?}"
6837        );
6838    }
6839
6840    // ── validate_deps: within-list :nome set-not-multiset gate ─────────
6841
6842    #[test]
6843    fn validate_deps_rejects_duplicate_nome_in_deps() {
6844        // Fail-before-pass-after pin: two `:deps` entries naming the same
6845        // caixa carry two `:versao` / `:fonte` / feature triples that the
6846        // caixa-resolver's lacre pipeline collapses (the second silently
6847        // overwrites the first at `concrete_versao`-resolve time). The
6848        // gate surfaces the duplicate at validate-time, naming the
6849        // offending caixa + the list, before the resolver-side silent
6850        // drop. Mirrors the peer typed-graph duplicate gates
6851        // (`DuplicateChildCaixa`, `MembroDuplicate`, `DuplicateFrom`, …).
6852        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6853        c.deps = vec![
6854            Dep::simple("caixa-teia", "^0.1"),
6855            Dep::simple("caixa-teia", "^0.2"),
6856        ];
6857        let err = c.validate_deps().unwrap_err();
6858        assert!(
6859            matches!(
6860                err,
6861                crate::dep::DepError::DuplicateNome { ref nome, list }
6862                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
6863            ),
6864            "got {err:?}"
6865        );
6866    }
6867
6868    #[test]
6869    fn validate_deps_rejects_duplicate_nome_in_deps_dev() {
6870        // Parity pin: `:deps-dev` runs through the same per-list
6871        // duplicate check as `:deps` — neither axis is a second-class
6872        // citizen of the set-not-multiset discipline.
6873        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6874        c.deps_dev = vec![
6875            Dep::simple("tatara-check", "*"),
6876            Dep::simple("tatara-check", "^0.1"),
6877        ];
6878        let err = c.validate_deps().unwrap_err();
6879        assert!(
6880            matches!(
6881                err,
6882                crate::dep::DepError::DuplicateNome { ref nome, list }
6883                    if nome == "tatara-check" && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
6884            ),
6885            "got {err:?}"
6886        );
6887    }
6888
6889    #[test]
6890    fn validate_deps_accepts_cross_list_same_nome() {
6891        // The Cargo `[dependencies]` + `[dev-dependencies]` override
6892        // convention is preserved: a name appearing in *both* lists is
6893        // valid (the dev-pin overrides at test/dev time). Only
6894        // within-list duplicates are structurally incoherent — pin the
6895        // permissive cross-list semantics so a future shortcut that
6896        // collapses the two seen-sets into one surfaces here as a test
6897        // failure.
6898        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6899        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
6900        c.deps_dev = vec![Dep::simple("caixa-teia", "^0.2")];
6901        c.validate_deps().unwrap();
6902    }
6903
6904    #[test]
6905    fn validate_deps_accepts_distinct_nome_in_both_lists() {
6906        // Positive control: distinct names within each list pass — the
6907        // gate's identity element on the canonical authoring shape.
6908        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6909        c.deps = vec![
6910            Dep::simple("caixa-teia", "^0.1"),
6911            Dep::simple("pleme-mesh", "*"),
6912        ];
6913        c.deps_dev = vec![
6914            Dep::simple("tatara-check", "*"),
6915            Dep::simple("dev-shim", "^0.1"),
6916        ];
6917        c.validate_deps().unwrap();
6918    }
6919
6920    #[test]
6921    fn validate_deps_per_entry_validate_fires_before_duplicate_in_deps() {
6922        // Diagnostic-precedence pin: a malformed `:versao` on the
6923        // duplicating entry surfaces its narrower `VersaoInvalid`
6924        // diagnostic first, before the cross-entry duplicate gate fires
6925        // — the canonical "per-entry shape before cross-entry uniqueness"
6926        // precedence every peer set-not-multiset gate establishes
6927        // (`*_invalid_fires_before_duplicate_check` pins on
6928        // `SupervisorSpec::validate`, `AplicacaoSpec::validate_membros`,
6929        // `validate_upgrade_from`).
6930        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6931        c.deps = vec![
6932            Dep::simple("caixa-teia", "^0.1"),
6933            Dep::simple("caixa-teia", "^bad-version"),
6934        ];
6935        let err = c.validate_deps().unwrap_err();
6936        assert!(
6937            matches!(
6938                err,
6939                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
6940                    if nome == "caixa-teia" && versao == "^bad-version"
6941            ),
6942            "expected VersaoInvalid to surface before DuplicateNome, got {err:?}"
6943        );
6944    }
6945
6946    #[test]
6947    fn validate_deps_duplicate_diagnostic_names_first_collision() {
6948        // First-collision determinism pin: with three entries naming the
6949        // same caixa, the first colliding pair surfaces — not the last.
6950        // Mirrors the peer first-collision posture on every
6951        // duplicate-target gate
6952        // (`validate_upgrade_from_duplicate_diagnostic_names_second_collision`
6953        // — the second entry is the first collision; this gate uses the
6954        // same shape: the second entry's `:nome` lands in the diagnostic
6955        // because `seen.insert(first.nome)` already populated the set).
6956        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6957        c.deps = vec![
6958            Dep::simple("caixa-teia", "^0.1"),
6959            Dep::simple("caixa-teia", "^0.2"),
6960            Dep::simple("caixa-teia", "^0.3"),
6961        ];
6962        let err = c.validate_deps().unwrap_err();
6963        // The diagnostic carries the offending caixa name; the
6964        // implementation surfaces on the *second* entry (the first
6965        // collision), so the test pins the `:nome` value.
6966        assert!(
6967            matches!(
6968                err,
6969                crate::dep::DepError::DuplicateNome { ref nome, list }
6970                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
6971            ),
6972            "got {err:?}"
6973        );
6974    }
6975
6976    #[test]
6977    fn validate_deps_duplicate_in_deps_fires_before_duplicate_in_deps_dev() {
6978        // Cross-list precedence pin: when both lists carry duplicates,
6979        // the `:deps` diagnostic surfaces first — same author-mental-
6980        // model ordering the `validate_deps_runs_deps_before_deps_dev`
6981        // pin establishes for malformed `:versao` (runtime axis before
6982        // dev axis).
6983        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
6984        c.deps = vec![
6985            Dep::simple("runtime-dep", "^0.1"),
6986            Dep::simple("runtime-dep", "^0.2"),
6987        ];
6988        c.deps_dev = vec![Dep::simple("dev-dep", "*"), Dep::simple("dev-dep", "^0.1")];
6989        let err = c.validate_deps().unwrap_err();
6990        assert!(
6991            matches!(
6992                err,
6993                crate::dep::DepError::DuplicateNome { ref nome, list }
6994                    if nome == "runtime-dep" && list == crate::render::DEP_AUTHOR_KEY_DEPS
6995            ),
6996            "expected :deps duplicate to surface before :deps-dev duplicate, got {err:?}"
6997        );
6998    }
6999
7000    #[test]
7001    fn validate_deps_empty_lists_pass_duplicate_gate() {
7002        // Empty-set identity pin: the bare template (zero deps, zero
7003        // deps_dev) passes the duplicate gate as the gate's identity
7004        // element. A future tighten that conflates "empty" with
7005        // "missing" would regress this baseline.
7006        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7007        c.validate_deps().unwrap();
7008    }
7009
7010    #[test]
7011    fn validate_deps_duplicate_diagnostic_carries_list_tag() {
7012        // Diagnostic-shape pin: the `list:` field tags which list the
7013        // duplicate landed in (`:deps` vs `:deps-dev`) verbatim, so a
7014        // `feira lint` run can route the author to the right block in
7015        // their caixa.lisp without re-deriving the list from context.
7016        // Same self-locating shape every peer per-axis diagnostic
7017        // already exposes.
7018        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7019        c.deps_dev = vec![
7020            Dep::simple("dev-thing", "*"),
7021            Dep::simple("dev-thing", "^0.1"),
7022        ];
7023        let err = c.validate_deps().unwrap_err();
7024        let crate::dep::DepError::DuplicateNome { nome, list } = err else {
7025            panic!("expected DuplicateNome from :deps-dev walk");
7026        };
7027        assert_eq!(nome, "dev-thing");
7028        assert_eq!(list, crate::render::DEP_AUTHOR_KEY_DEPS_DEV);
7029    }
7030
7031    // ── validate_deps: per-entry :caracteristicas set-discipline gate ──
7032
7033    #[test]
7034    fn validate_deps_surfaces_caracteristicas_duplicate_in_deps_list() {
7035        // Thread-through pin on `:deps`: the per-entry
7036        // `Dep::validate_caracteristicas` gate fires inside
7037        // `Caixa::validate_deps`'s linear walk, so a malformed feature
7038        // list on any `:deps` entry surfaces as a `DepError` from
7039        // `validate_deps` — the same reachability shape every per-entry
7040        // `Dep::validate` arm threads through. Without this pin a future
7041        // shortcut that skips the per-entry `Dep::validate` call on the
7042        // cross-entry-uniqueness path would mask the within-entry
7043        // `:caracteristicas` gates.
7044        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7045        c.deps = vec![Dep {
7046            nome: "caixa-teia".into(),
7047            versao: "^0.1".into(),
7048            fonte: None,
7049            opcional: false,
7050            caracteristicas: vec!["http".into(), "http".into()],
7051        }];
7052        let err = c.validate_deps().unwrap_err();
7053        let crate::dep::DepError::CaracteristicaDuplicate {
7054            nome,
7055            caracteristica,
7056        } = err
7057        else {
7058            panic!("expected CaracteristicaDuplicate from :deps walk, got {err:?}");
7059        };
7060        assert_eq!(nome, "caixa-teia");
7061        assert_eq!(caracteristica, "http");
7062    }
7063
7064    #[test]
7065    fn validate_deps_surfaces_caracteristicas_empty_in_deps_dev_list() {
7066        // Peer thread-through pin on `:deps-dev`: same reachability as
7067        // the `:deps` arm above, on the dev-only authoring axis. Pins
7068        // that the `validate_deps` walk visits both lists' per-entry
7069        // gates uniformly. The empty-feature arm carries here so both
7070        // new `:caracteristicas` arms are surfaced via at least one
7071        // `validate_deps` thread-through.
7072        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7073        c.deps_dev = vec![Dep {
7074            nome: "caixa-teia".into(),
7075            versao: "^0.1".into(),
7076            fonte: None,
7077            opcional: false,
7078            caracteristicas: vec![String::new()],
7079        }];
7080        let err = c.validate_deps().unwrap_err();
7081        let crate::dep::DepError::CaracteristicaEmpty { nome } = err else {
7082            panic!("expected CaracteristicaEmpty from :deps-dev walk, got {err:?}");
7083        };
7084        assert_eq!(nome, "caixa-teia");
7085    }
7086
7087    #[test]
7088    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_list() {
7089        // Thread-through pin on `:deps`: the per-entry
7090        // `Dep::validate_caracteristicas` value-shape gate (lifted via
7091        // `crate::render::is_cargo_feature_name`) fires inside
7092        // `Caixa::validate_deps`'s linear walk on the `:deps` list, so
7093        // a structurally invalid feature name on any `:deps` entry
7094        // surfaces as `DepError::CaracteristicaInvalid` from
7095        // `validate_deps` — the same reachability shape every per-entry
7096        // `Dep::validate` arm threads through. Without this pin a
7097        // future shortcut that skips the per-entry `Dep::validate` call
7098        // on the cross-entry-uniqueness path would mask the within-
7099        // entry `:caracteristicas` value-shape gate.
7100        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7101        c.deps = vec![Dep {
7102            nome: "caixa-teia".into(),
7103            versao: "^0.1".into(),
7104            fonte: None,
7105            opcional: false,
7106            caracteristicas: vec!["+http".into()],
7107        }];
7108        let err = c.validate_deps().unwrap_err();
7109        let crate::dep::DepError::CaracteristicaInvalid {
7110            nome,
7111            caracteristica,
7112            ..
7113        } = err
7114        else {
7115            panic!("expected CaracteristicaInvalid from :deps walk, got {err:?}");
7116        };
7117        assert_eq!(nome, "caixa-teia");
7118        assert_eq!(caracteristica, "+http");
7119    }
7120
7121    #[test]
7122    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_dev_list() {
7123        // Peer thread-through pin on `:deps-dev`: same reachability as
7124        // the `:deps` arm above, on the dev-only authoring axis. The
7125        // `http/json` shape carries here so the segment-separator
7126        // diagnostic (the canonical Cargo `dep/feat` namespaced-dep
7127        // confusion footgun) is surfaced via the cross-entry walk too —
7128        // pinning that the `:deps-dev` list visits the same per-entry
7129        // value-shape gate as the `:deps` list.
7130        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7131        c.deps_dev = vec![Dep {
7132            nome: "caixa-teia".into(),
7133            versao: "^0.1".into(),
7134            fonte: None,
7135            opcional: false,
7136            caracteristicas: vec!["http/json".into()],
7137        }];
7138        let err = c.validate_deps().unwrap_err();
7139        let crate::dep::DepError::CaracteristicaInvalid {
7140            nome,
7141            caracteristica,
7142            ..
7143        } = err
7144        else {
7145            panic!("expected CaracteristicaInvalid from :deps-dev walk, got {err:?}");
7146        };
7147        assert_eq!(nome, "caixa-teia");
7148        assert_eq!(caracteristica, "http/json");
7149    }
7150
7151    #[test]
7152    fn to_lisp_preserves_deps() {
7153        let src = r#"
7154(defcaixa
7155  :nome "x"
7156  :versao "0.1.0"
7157  :kind Biblioteca
7158  :deps ((:nome "a" :versao "^0.1")
7159         (:nome "b" :versao "*" :fonte (:tipo git :repo "github:o/b" :tag "v1"))))
7160"#;
7161        let c1 = Caixa::from_lisp(src).unwrap();
7162        let emitted = c1.to_lisp();
7163        let c2 = Caixa::from_lisp(&emitted).expect("round trip");
7164        assert_eq!(c1.deps, c2.deps);
7165    }
7166
7167    // ── Caixa::validate_nome — top-level :nome value-shape gate ─────────
7168
7169    fn caixa_with_nome(nome: &str) -> Caixa {
7170        let mut c = Caixa::from_lisp(&Caixa::template("placeholder")).unwrap();
7171        c.nome = nome.to_string();
7172        c
7173    }
7174
7175    #[test]
7176    fn validate_nome_accepts_canonical_template() {
7177        // Positive control: the bare `feira init`-style template's
7178        // `:nome` ("demo") is a canonical DNS-1123 label; the gate must
7179        // not regress this baseline shape. A future tightening of the
7180        // accepted set surfaces here as a test failure first.
7181        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7182        c.validate_nome().unwrap();
7183    }
7184
7185    #[test]
7186    fn validate_nome_accepts_canonical_forms() {
7187        // Positive-set sweep: each realistic caixa-name shape the K8s
7188        // apiserver accepts as a `metadata.name` label must pass —
7189        // single-word, hyphen-joined, version-suffixed, single-char,
7190        // two-char, digit-start (DNS-1123 allows this; the stricter
7191        // DNS-1035 Service-name rule doesn't), version-suffix-bearing.
7192        // Mirrors `accepts_canonical_membro_caixa_forms` (3f9d7a0) on
7193        // the peer member-name axis.
7194        for nome in [
7195            "checkout",
7196            "cart-v2",
7197            "a",
7198            "db",
7199            "3rd-party-shim",
7200            "payment-retry",
7201            "0",
7202        ] {
7203            caixa_with_nome(nome)
7204                .validate_nome()
7205                .unwrap_or_else(|e| panic!("canonical :nome {nome:?} must validate, got {e:?}"));
7206        }
7207    }
7208
7209    #[test]
7210    fn validate_nome_rejects_empty() {
7211        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
7212        // an empty `:nome` (the derive macro stores the raw String);
7213        // the gate's empty arm names the offending axis with a narrower
7214        // diagnostic than the `NomeInvalid` parse arm would emit.
7215        let c = caixa_with_nome("");
7216        let err = c.validate_nome().unwrap_err();
7217        assert_eq!(err, ManifestError::NomeEmpty);
7218    }
7219
7220    #[test]
7221    fn validate_nome_rejects_uppercase() {
7222        // The canonical "I copied the TitleCase display name verbatim"
7223        // footgun. The K8s apiserver rejects `metadata.name: MyApp` at
7224        // admission on every derived artifact (Helm chart, ComputeUnit,
7225        // CNP, HTTPRoute, label values); the gate moves the diagnostic
7226        // to the source `caixa.lisp` and the reason suggests the
7227        // lowercased fix verbatim.
7228        let c = caixa_with_nome("MyApp");
7229        let err = c.validate_nome().unwrap_err();
7230        let ManifestError::NomeInvalid { nome, reason } = err else {
7231            panic!("expected NomeInvalid for uppercase :nome");
7232        };
7233        assert_eq!(nome, "MyApp");
7234        assert!(
7235            reason.contains("uppercase") && reason.contains("myapp"),
7236            "diagnostic must name the violation + the lowercased fix, got {reason:?}"
7237        );
7238    }
7239
7240    #[test]
7241    fn validate_nome_rejects_underscore() {
7242        // The Python-/Postgres-style `snake_case` leak. DNS-1123 forbids
7243        // `_`; the apiserver rejects on admission across every derived
7244        // artifact. Same fixture pinned for `:membros :caixa` (3f9d7a0)
7245        // and `:children :caixa` (31bfa43).
7246        let c = caixa_with_nome("my_app");
7247        let err = c.validate_nome().unwrap_err();
7248        assert!(
7249            matches!(
7250                err,
7251                ManifestError::NomeInvalid { ref nome, ref reason }
7252                    if nome == "my_app" && reason.contains('_')
7253            ),
7254            "got {err:?}"
7255        );
7256    }
7257
7258    #[test]
7259    fn validate_nome_rejects_dot() {
7260        // A `:nome` is a single DNS-1123 label, not a subdomain. The
7261        // "I want to namespace with `.`" footgun the gate redirects to
7262        // `-` via the shared predicate's reason wording.
7263        let c = caixa_with_nome("team.app");
7264        let err = c.validate_nome().unwrap_err();
7265        assert!(
7266            matches!(
7267                err,
7268                ManifestError::NomeInvalid { ref nome, ref reason }
7269                    if nome == "team.app" && reason.contains('.')
7270            ),
7271            "got {err:?}"
7272        );
7273    }
7274
7275    #[test]
7276    fn validate_nome_rejects_leading_hyphen() {
7277        // DNS-1123 boundary rule: the label must start with an ASCII
7278        // alphanumeric. Pin the leading-`-` arm explicitly.
7279        let c = caixa_with_nome("-app");
7280        let err = c.validate_nome().unwrap_err();
7281        assert!(
7282            matches!(
7283                err,
7284                ManifestError::NomeInvalid { ref nome, .. } if nome == "-app"
7285            ),
7286            "got {err:?}"
7287        );
7288    }
7289
7290    #[test]
7291    fn validate_nome_rejects_trailing_hyphen() {
7292        // Symmetric arm of the boundary rule, pinned separately so a
7293        // future relaxation that only checks the leading position
7294        // surfaces here. Mirrors `rejects_membro_caixa_with_trailing_hyphen`
7295        // and `_with_trailing_hyphen` on the supervisor / aplicacao
7296        // axes.
7297        let c = caixa_with_nome("app-");
7298        let err = c.validate_nome().unwrap_err();
7299        assert!(
7300            matches!(
7301                err,
7302                ManifestError::NomeInvalid { ref nome, .. } if nome == "app-"
7303            ),
7304            "got {err:?}"
7305        );
7306    }
7307
7308    #[test]
7309    fn validate_nome_rejects_unicode() {
7310        // IDN must be pre-encoded as Punycode (`xn--…`); raw Unicode
7311        // bytes are rejected by the K8s apiserver on every name axis.
7312        let c = caixa_with_nome("café");
7313        let err = c.validate_nome().unwrap_err();
7314        assert!(
7315            matches!(
7316                err,
7317                ManifestError::NomeInvalid { ref nome, .. } if nome == "café"
7318            ),
7319            "got {err:?}"
7320        );
7321    }
7322
7323    #[test]
7324    fn validate_nome_rejects_whitespace() {
7325        // The paste-from-sketch / paste-from-spec footgun. Internal
7326        // whitespace is rejected by every K8s name axis.
7327        let c = caixa_with_nome("my app");
7328        let err = c.validate_nome().unwrap_err();
7329        assert!(
7330            matches!(
7331                err,
7332                ManifestError::NomeInvalid { ref nome, .. } if nome == "my app"
7333            ),
7334            "got {err:?}"
7335        );
7336    }
7337
7338    #[test]
7339    fn validate_nome_rejects_too_long() {
7340        // 64-byte boundary pin: the K8s apiserver rejects any
7341        // `metadata.name` over 63 bytes at admission; the diagnostic
7342        // names both the 63-byte cap and the actual length so the
7343        // author can shorten in one edit. Mirrors `_too_long` on the
7344        // peer member-/cluster-/child-name axes.
7345        let over = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN + 1);
7346        let c = caixa_with_nome(&over);
7347        let err = c.validate_nome().unwrap_err();
7348        let ManifestError::NomeInvalid { nome, reason } = err else {
7349            panic!("expected NomeInvalid for over-cap :nome");
7350        };
7351        assert_eq!(nome.len(), crate::DNS_1123_LABEL_MAX_LEN + 1);
7352        assert!(
7353            reason.contains("63") && reason.contains("64"),
7354            "diagnostic must name the cap + actual length, got {reason:?}"
7355        );
7356    }
7357
7358    #[test]
7359    fn nome_max_length_validates() {
7360        // The 63-byte cap exactly — the boundary-accepting case pinned
7361        // alongside `validate_nome_rejects_too_long` so a future cap
7362        // shift surfaces both arms simultaneously. Mirrors
7363        // `membro_caixa_max_length_validates`,
7364        // `placement_cluster_max_length_validates`,
7365        // `child_caixa_max_length_validates`.
7366        let at_cap = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
7367        caixa_with_nome(&at_cap).validate_nome().unwrap();
7368    }
7369
7370    #[test]
7371    fn nome_empty_takes_precedence_over_invalid() {
7372        // Order pin: the empty arm fires before the predicate is
7373        // consulted. Empty < invalid in self-locating-ness — the
7374        // narrower `NomeEmpty` diagnostic doesn't carry a useless
7375        // `nome: ""` reference into the parser-shaped reason. Mirrors
7376        // `membro_caixa_empty_takes_precedence_over_invalid` on the
7377        // peer axis (3f9d7a0).
7378        let c = caixa_with_nome("");
7379        assert_eq!(c.validate_nome().unwrap_err(), ManifestError::NomeEmpty);
7380    }
7381
7382    #[test]
7383    fn nome_invalid_diagnostic_carries_offending_nome() {
7384        // Diagnostic-shape pin: the error names the offending `:nome`
7385        // verbatim with a non-empty parser-shaped reason, so a `feira
7386        // lint` run can render the diagnostic without re-parsing.
7387        // Mirrors `membro_caixa_invalid_diagnostic_carries_offending_caixa`.
7388        let c = caixa_with_nome("MyApp");
7389        let err = c.validate_nome().unwrap_err();
7390        let ManifestError::NomeInvalid { nome, reason } = err else {
7391            panic!("expected NomeInvalid variant");
7392        };
7393        assert_eq!(nome, "MyApp");
7394        assert!(
7395            !reason.is_empty(),
7396            "NomeInvalid `reason` must carry the predicate's wording verbatim"
7397        );
7398    }
7399
7400    // ── Caixa::validate_nome_chart_name_budget — joint-length on `:nome` ──
7401    //
7402    // The bare-`:nome` axis [`Caixa::validate_nome`] caps at 63 bytes
7403    // via DNS-1123; this second-axis gate caps the joint
7404    // `lareira-<nome>` chart name at the same 63-byte ceiling. The
7405    // canonical [`crate::lareira_chart_name`] helper's doc comment
7406    // (f7320d7, caixa-core/src/render.rs:3198) explicitly deferred:
7407    // "the M4 admission webhook will pin the joint-length invariant
7408    // when it lands". These tests pin it at the manifest-validate
7409    // layer instead, fail-before-pass-after on the 56-byte boundary.
7410
7411    #[test]
7412    fn validate_nome_chart_name_budget_accepts_canonical_template() {
7413        // Positive control: the bare `feira init`-style template's
7414        // `:nome` ("demo") sits far below the cap; the gate must not
7415        // regress this baseline. Same shape every peer
7416        // value-shape-gate baseline pin uses.
7417        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7418        c.validate_nome_chart_name_budget().unwrap();
7419    }
7420
7421    #[test]
7422    fn validate_nome_chart_name_budget_accepts_canonical_fixtures() {
7423        // Positive-set sweep across the canonical author surface every
7424        // in-tree fixture uses (`hello-rio`, `cart`, `checkout`,
7425        // `worker`, the `checkout-aplicacao` example members, the
7426        // `akeyless-attest` caixa-tatara fixture). Every value sits
7427        // far below the 55-byte per-`:nome` budget. Same shape every
7428        // peer per-axis baseline pin uses.
7429        for nome in [
7430            "hello-rio",
7431            "cart",
7432            "checkout",
7433            "worker",
7434            "akeyless-attest",
7435            "demo",
7436            "a",
7437        ] {
7438            caixa_with_nome(nome)
7439                .validate_nome_chart_name_budget()
7440                .unwrap_or_else(|e| {
7441                    panic!("canonical :nome {nome:?} must pass chart-name budget, got {e:?}")
7442                });
7443        }
7444    }
7445
7446    #[test]
7447    fn validate_nome_chart_name_budget_accepts_nome_at_cap() {
7448        // Boundary-accepting case at the 55-byte per-`:nome` budget —
7449        // the joint chart name is exactly 63 bytes, the DNS-1123 label
7450        // cap. Pinned alongside the rejecting-arm test so a future cap
7451        // shift surfaces both arms simultaneously. Mirrors
7452        // `nome_max_length_validates` on the peer bare-`:nome` axis.
7453        let at_cap = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN);
7454        caixa_with_nome(&at_cap)
7455            .validate_nome_chart_name_budget()
7456            .unwrap();
7457    }
7458
7459    #[test]
7460    fn validate_nome_chart_name_budget_rejects_nome_one_over_cap() {
7461        // Fail-before-pass-after pin on the 56-byte boundary: the
7462        // smallest `:nome` length that overflows the joint chart-name
7463        // cap. The inner [`is_dns_1123_label`] gate
7464        // (`Caixa::validate_nome`) accepts it (56 ≤ 63), so prior to
7465        // this gate it silently passed the manifest-validate cascade
7466        // and surfaced as a `helm lint` / apiserver rejection on the
7467        // rendered chart name far from the source `caixa.lisp`, with
7468        // no field naming the overflow. With this gate the diagnostic
7469        // names the offending `:nome` verbatim alongside the rendered
7470        // chart name and the budget, so the author can shorten in one
7471        // edit. Mirrors `validate_nome_rejects_too_long` on the peer
7472        // bare-`:nome` axis.
7473        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
7474        let c = caixa_with_nome(&over);
7475        let err = c.validate_nome_chart_name_budget().unwrap_err();
7476        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
7477            panic!("expected NomeChartNameBudgetExceeded for over-budget :nome");
7478        };
7479        assert_eq!(nome.len(), crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
7480        assert_eq!(nome, over);
7481        assert!(
7482            reason.contains("63") && reason.contains("64") && reason.contains("55"),
7483            "diagnostic must name the DNS-1123 cap (63), the actual chart-name length (64), \
7484             and the per-`:nome` budget (55), got {reason:?}"
7485        );
7486    }
7487
7488    #[test]
7489    fn validate_nome_chart_name_budget_rejects_nome_at_bare_dns_cap() {
7490        // The 63-byte `:nome` boundary — passes the bare-`:nome`
7491        // [`is_dns_1123_label`] cap exactly, but produces a 71-byte
7492        // joint chart name that overflows the DNS-1123 label cap
7493        // structurally. The most stringent fail-before-pass-after
7494        // surface: every `:nome` in the 56..=63-byte range passed the
7495        // prior cascade and broke at admission.
7496        let bare_max = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
7497        let c = caixa_with_nome(&bare_max);
7498        // The bare-`:nome` gate accepts the 63-byte length.
7499        c.validate_nome().unwrap();
7500        // The new joint-length gate rejects it.
7501        let err = c.validate_nome_chart_name_budget().unwrap_err();
7502        assert!(
7503            matches!(
7504                err,
7505                ManifestError::NomeChartNameBudgetExceeded { ref nome, .. }
7506                    if nome.len() == crate::DNS_1123_LABEL_MAX_LEN
7507            ),
7508            "got {err:?}"
7509        );
7510    }
7511
7512    #[test]
7513    fn validate_nome_chart_name_budget_diagnostic_carries_offending_chart_name() {
7514        // Diagnostic-shape pin: the rendered `lareira-<nome>` chart
7515        // name appears verbatim in the diagnostic so the author sees
7516        // exactly the string the apiserver / `helm lint` would have
7517        // rejected — no re-derivation required to grep the source.
7518        // Peer with `nome_invalid_diagnostic_carries_offending_nome`
7519        // on the bare-`:nome` axis.
7520        let over = "x".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 5);
7521        let c = caixa_with_nome(&over);
7522        let err = c.validate_nome_chart_name_budget().unwrap_err();
7523        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
7524            panic!("expected NomeChartNameBudgetExceeded variant");
7525        };
7526        assert_eq!(nome, over);
7527        let expected_chart = crate::lareira_chart_name(&over);
7528        assert!(
7529            reason.contains(&expected_chart),
7530            "diagnostic must carry the rendered chart name {expected_chart:?} verbatim, \
7531             got {reason:?}"
7532        );
7533        assert!(
7534            reason.contains("lareira-"),
7535            "diagnostic must name the canonical chart-name prefix verbatim, got {reason:?}"
7536        );
7537    }
7538
7539    #[test]
7540    fn validate_nome_chart_name_budget_runs_after_nome_shape_via_layout_verify() {
7541        // Order pin on the layout cascade: the narrower
7542        // `NomeInvalid` (bare-DNS-1123 shape) fires before the
7543        // joint-length budget. A structurally-malformed `:nome` (here:
7544        // uppercase) surfaces its specific shape error rather than
7545        // the chart-name-budget error, even when the joint length
7546        // would also overflow — the narrower diagnostic is more
7547        // self-locating. Mirrors the cascade-precedence pins peer
7548        // gates already use (e.g. `EntradaParaEmpty` before
7549        // `EntradaParaInvalid`).
7550        let over = "A".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
7551        let c = caixa_with_nome(&over);
7552        // The bare-shape gate fires first.
7553        let err = c.validate_nome().unwrap_err();
7554        assert!(
7555            matches!(err, ManifestError::NomeInvalid { .. }),
7556            "bare-shape gate must fire before chart-name-budget gate; got {err:?}"
7557        );
7558        // And the layout verify cascade surfaces that diagnostic, not
7559        // the budget arm. Inject a path-exists oracle so the cascade
7560        // gets past the manifest-presence check and into the
7561        // value-shape gates.
7562        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
7563        let err = crate::LayoutInvariants::verify(
7564            &layout,
7565            &c,
7566            std::path::Path::new("/tmp/caixa-test-fake-root"),
7567        )
7568        .unwrap_err();
7569        let issue = err.to_string();
7570        assert!(
7571            issue.contains("DNS-1123") || issue.contains("uppercase"),
7572            "layout cascade must surface the bare-DNS-1123 diagnostic on a \
7573             structurally-malformed :nome, not the chart-name-budget diagnostic; got {issue:?}"
7574        );
7575    }
7576
7577    #[test]
7578    fn layout_verify_routes_chart_name_budget_through_nome_violation() {
7579        // Cross-axis envelope pin: the layout cascade wraps both
7580        // bare-`:nome` and joint-length-`:nome` failures through the
7581        // same [`LayoutError::NomeViolation`] envelope, since both
7582        // arms are on the `:nome` axis. The user's diagnostic stays
7583        // self-locating ("which axis"), and a future consumer that
7584        // dispatches on the layout-error variant (e.g. a `feira lint`
7585        // exit-code mapping) sees a single per-axis envelope. The
7586        // wrapped `issue:` carries the full inner diagnostic.
7587        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
7588        let c = caixa_with_nome(&over);
7589        // The bare-shape gate accepts.
7590        c.validate_nome().unwrap();
7591        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
7592        let err = crate::LayoutInvariants::verify(
7593            &layout,
7594            &c,
7595            std::path::Path::new("/tmp/caixa-test-fake-root"),
7596        )
7597        .unwrap_err();
7598        let crate::LayoutError::NomeViolation { caixa, issue } = err else {
7599            panic!("expected LayoutError::NomeViolation, got {err:?}");
7600        };
7601        assert_eq!(caixa, over);
7602        assert!(
7603            issue.contains("lareira-") && issue.contains("63") && issue.contains("55"),
7604            "wrapped issue must carry the joint-length diagnostic verbatim, got {issue:?}"
7605        );
7606    }
7607
7608    // ── Caixa::validate_versao — top-level :versao value-shape gate ─────
7609
7610    fn caixa_with_versao(versao: &str) -> Caixa {
7611        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7612        c.versao = versao.to_string();
7613        c
7614    }
7615
7616    #[test]
7617    fn validate_versao_accepts_canonical_template() {
7618        // Positive control: the bare `feira init`-style template's
7619        // `:versao` ("0.1.0") is a canonical SemVer-2 literal; the gate
7620        // must not regress this baseline shape. A future tightening of
7621        // the accepted set surfaces here as a test failure first.
7622        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
7623        c.validate_versao().unwrap();
7624    }
7625
7626    #[test]
7627    fn validate_versao_accepts_canonical_forms() {
7628        // Positive-set sweep: each realistic SemVer-2 shape the
7629        // substrate's downstream consumers accept must pass — bare
7630        // MAJOR.MINOR.PATCH, pre-release tags (`-rc.1`, `-alpha.0`),
7631        // build metadata (`+build.42`), the combined form, and the
7632        // `0.0.0` boundary case. Mirrors `accepts_canonical_forms` on
7633        // the peer `:nome` axis (6c992f8).
7634        for versao in [
7635            "0.1.0",
7636            "0.0.0",
7637            "1.0.0",
7638            "0.2.0-rc.1",
7639            "1.0.0-alpha.0",
7640            "1.0.0+build.42",
7641            "1.0.0-rc.1+build.42",
7642            "10.20.30",
7643        ] {
7644            caixa_with_versao(versao)
7645                .validate_versao()
7646                .unwrap_or_else(|e| {
7647                    panic!("canonical :versao {versao:?} must validate, got {e:?}")
7648                });
7649        }
7650    }
7651
7652    #[test]
7653    fn validate_versao_rejects_empty() {
7654        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
7655        // an empty `:versao` (the derive macro stores the raw String);
7656        // the gate's empty arm names the offending axis with a narrower
7657        // diagnostic than the `VersaoInvalid` parse arm would emit.
7658        // Mirrors `validate_nome_rejects_empty` (6c992f8).
7659        let c = caixa_with_versao("");
7660        let err = c.validate_versao().unwrap_err();
7661        assert_eq!(err, ManifestError::VersaoEmpty);
7662    }
7663
7664    #[test]
7665    fn validate_versao_rejects_git_tag_shape() {
7666        // The canonical "I copied the git tag verbatim" footgun —
7667        // `feira publish` *emits* `v<versao>` git tags, so a leaked
7668        // `v0.1.0` in `:versao` would render as `vv0.1.0` and silently
7669        // shift every downstream consumer's version axis. `semver`
7670        // rejects the leading `v` at parse time; the gate moves the
7671        // diagnostic to the source `caixa.lisp`.
7672        let c = caixa_with_versao("v0.1.0");
7673        let err = c.validate_versao().unwrap_err();
7674        let ManifestError::VersaoInvalid { versao, reason } = err else {
7675            panic!("expected VersaoInvalid for git-tag-shape :versao");
7676        };
7677        assert_eq!(versao, "v0.1.0");
7678        assert!(
7679            !reason.is_empty(),
7680            "VersaoInvalid `reason` must carry the parser's wording, got {reason:?}"
7681        );
7682    }
7683
7684    #[test]
7685    fn validate_versao_rejects_missing_patch() {
7686        // The canonical "I shortened it" footgun — SemVer-2 requires
7687        // three parts. Cargo's `version =` field accepts the shortened
7688        // form as a requirement, conflating the two leaks across the
7689        // typed `:deps :versao` vs top-level `:versao` axes; the gate
7690        // pins the top-level axis to the strict three-part shape.
7691        let c = caixa_with_versao("0.1");
7692        let err = c.validate_versao().unwrap_err();
7693        assert!(
7694            matches!(
7695                err,
7696                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1"
7697            ),
7698            "got {err:?}"
7699        );
7700    }
7701
7702    #[test]
7703    fn validate_versao_rejects_requirement_shape() {
7704        // The canonical "I leaked a requirement into a version" footgun —
7705        // the typed `:deps :versao` / `:membros :versao` axes accept
7706        // `^0.1` (a `VersionReq`); the top-level `:versao` requires a
7707        // concrete `Version`. Without this gate the two typed surfaces
7708        // would silently overlap, and a top-level `^0.1` would surface
7709        // at `helm install` time as a Chart.yaml version rejection far
7710        // from the source `caixa.lisp`.
7711        let c = caixa_with_versao("^0.1");
7712        let err = c.validate_versao().unwrap_err();
7713        assert!(
7714            matches!(
7715                err,
7716                ManifestError::VersaoInvalid { ref versao, .. } if versao == "^0.1"
7717            ),
7718            "got {err:?}"
7719        );
7720    }
7721
7722    #[test]
7723    fn validate_versao_rejects_docker_tag_shape() {
7724        // The "I confused it with a docker tag" footgun — `latest`,
7725        // `main`, `stable` parse as identifiers, not SemVer-2 versions.
7726        // SemVer rejects at parse time; the gate moves the diagnostic
7727        // to the source `caixa.lisp`.
7728        for bad in ["latest", "main", "stable"] {
7729            let c = caixa_with_versao(bad);
7730            let err = c.validate_versao().unwrap_err();
7731            assert!(
7732                matches!(
7733                    err,
7734                    ManifestError::VersaoInvalid { ref versao, .. } if versao == bad
7735                ),
7736                "got {err:?} for {bad:?}"
7737            );
7738        }
7739    }
7740
7741    #[test]
7742    fn validate_versao_rejects_four_part_form() {
7743        // The Java/Microsoft "MAJOR.MINOR.PATCH.BUILD" convention
7744        // SemVer-2 forbids. A leak from a non-SemVer ecosystem; the
7745        // semver crate rejects the extra `.0` at parse time.
7746        let c = caixa_with_versao("0.1.0.0");
7747        let err = c.validate_versao().unwrap_err();
7748        assert!(
7749            matches!(
7750                err,
7751                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1.0.0"
7752            ),
7753            "got {err:?}"
7754        );
7755    }
7756
7757    #[test]
7758    fn versao_empty_takes_precedence_over_invalid() {
7759        // Order pin: the empty arm fires before the parser is consulted.
7760        // Empty < invalid in self-locating-ness — the narrower
7761        // `VersaoEmpty` diagnostic doesn't carry a useless `versao: ""`
7762        // reference into the parser-shaped reason. Mirrors
7763        // `nome_empty_takes_precedence_over_invalid` (6c992f8) on the
7764        // peer axis.
7765        let c = caixa_with_versao("");
7766        assert_eq!(c.validate_versao().unwrap_err(), ManifestError::VersaoEmpty);
7767    }
7768
7769    #[test]
7770    fn versao_invalid_diagnostic_carries_offending_versao() {
7771        // Diagnostic-shape pin: the error names the offending `:versao`
7772        // verbatim with a non-empty parser-shaped reason, so a `feira
7773        // lint` run can render the diagnostic without re-parsing.
7774        // Mirrors `nome_invalid_diagnostic_carries_offending_nome`.
7775        let c = caixa_with_versao("v0.1.0");
7776        let err = c.validate_versao().unwrap_err();
7777        let ManifestError::VersaoInvalid { versao, reason } = err else {
7778            panic!("expected VersaoInvalid variant");
7779        };
7780        assert_eq!(versao, "v0.1.0");
7781        assert!(
7782            !reason.is_empty(),
7783            "VersaoInvalid `reason` must carry the parser's wording verbatim"
7784        );
7785    }
7786
7787    #[test]
7788    fn validate_versao_accepts_what_upgrade_from_from_accepts() {
7789        // Parity pin: every shape `UpgradeFromEntry::validate` accepts
7790        // for `:upgrade-from :from` must also pass `validate_versao` —
7791        // the two `:versao`-typed surfaces (top-level `:versao`,
7792        // `:upgrade-from :from`) consume the *same* `semver::Version`
7793        // parser, so they must agree on the accepted set. Without this
7794        // pin, a future tightening of one axis could silently diverge
7795        // from the other. Mirrors the `:versao` requirement-axis
7796        // parity (`:deps`/`:deps-dev`/`:membros`/`:children`) the prior
7797        // commits established.
7798        for versao in ["0.1.0", "0.2.0-rc.1", "1.0.0+build.42"] {
7799            // From the canonical UpgradeFromEntry round-trip fixture
7800            // (`upgrade::tests::round_trip_load_module` peers).
7801            let entry = crate::UpgradeFromEntry {
7802                from: versao.to_string(),
7803                instructions: Vec::new(),
7804            };
7805            entry
7806                .validate()
7807                .unwrap_or_else(|e| panic!(":from {versao:?} must validate, got {e:?}"));
7808            caixa_with_versao(versao)
7809                .validate_versao()
7810                .unwrap_or_else(|e| {
7811                    panic!(":versao {versao:?} must validate, got {e:?} — peer axis diverges")
7812                });
7813        }
7814    }
7815
7816    // ── Caixa::validate_restart_window — supervisor restart-window
7817    //    folds through the shared `supervisor::duration_codec` ────────
7818
7819    fn caixa_with_restart_window(window: Option<&str>) -> Caixa {
7820        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
7821        c.kind = CaixaKind::Supervisor;
7822        c.restart_window = window.map(str::to_string);
7823        c
7824    }
7825
7826    #[test]
7827    fn validate_restart_window_accepts_none() {
7828        // The canonical "omit the slot to express no reset" shape — a
7829        // `None` raw string is the absence of the typed
7830        // `:restart-window` slot, which is exactly the SupervisorSpec
7831        // "never reset" semantics. The gate must be a no-op here; a
7832        // future tightening that rejected `None` would force every
7833        // supervisor caixa to authoring-time pin a window even when
7834        // the OTP semantics call for none.
7835        caixa_with_restart_window(None)
7836            .validate_restart_window()
7837            .unwrap();
7838    }
7839
7840    #[test]
7841    fn validate_restart_window_accepts_canonical_forms() {
7842        // Positive-set sweep across the canonical authoring units the
7843        // shared `supervisor::duration_codec::parse` accepts —
7844        // matches the codec-side `parse_accepts_integer_canonical_units`
7845        // pin in supervisor::tests so a future codec-side tightening
7846        // surfaces simultaneously on both axes.
7847        for window in ["60s", "5m", "1h", "500ms", "30", "0s"] {
7848            caixa_with_restart_window(Some(window))
7849                .validate_restart_window()
7850                .unwrap_or_else(|e| {
7851                    panic!("canonical :restart-window {window:?} must validate, got {e:?}")
7852                });
7853        }
7854    }
7855
7856    #[test]
7857    fn validate_restart_window_rejects_fractional_seconds() {
7858        // Fail-before-pass-after pin: the `"1.5s"` drift class (parses
7859        // as f64 to 1.5 → renders back as `"1500ms"` on first
7860        // serialize). Prior to the fold + this gate, the inline
7861        // `parse_window_inline` accepted f64 magnitudes and silently
7862        // produced a `Duration::from_secs_f64(1.5)`, divergent from
7863        // the shared codec's integer-magnitude discipline on the
7864        // serde-routed siblings. The gate now surfaces a self-locating
7865        // diagnostic at the manifest layer.
7866        let err = caixa_with_restart_window(Some("1.5s"))
7867            .validate_restart_window()
7868            .unwrap_err();
7869        let ManifestError::RestartWindowMalformed {
7870            restart_window,
7871            reason,
7872        } = err
7873        else {
7874            panic!("expected RestartWindowMalformed for fractional seconds");
7875        };
7876        assert_eq!(restart_window, "1.5s");
7877        assert!(
7878            reason.contains("\"1.5\"") && reason.contains("not a non-negative integer"),
7879            "diagnostic must carry shared-codec wording, got {reason:?}"
7880        );
7881    }
7882
7883    #[test]
7884    fn validate_restart_window_rejects_decimal_shaped_integer() {
7885        // The `"1.0s"` class — numerically `1s` exactly, but the
7886        // canonical form is `"1s"` not `"1.0s"`. Decimal-shape leak
7887        // gets the same canonical-form diagnostic.
7888        let err = caixa_with_restart_window(Some("1.0s"))
7889            .validate_restart_window()
7890            .unwrap_err();
7891        assert!(
7892            matches!(
7893                err,
7894                ManifestError::RestartWindowMalformed { ref restart_window, .. }
7895                    if restart_window == "1.0s"
7896            ),
7897            "got {err:?}"
7898        );
7899    }
7900
7901    #[test]
7902    fn validate_restart_window_rejects_half_unit_minute() {
7903        // `"0.5m"` is the unit-fraction footgun — author writes a
7904        // human-readable half-minute, the prior inline parser silently
7905        // produced `Duration::from_secs_f64(30.0)` and serde
7906        // re-emitted as `"30s"`, rewriting author intent. The gate
7907        // closes the loop at the manifest layer.
7908        let err = caixa_with_restart_window(Some("0.5m"))
7909            .validate_restart_window()
7910            .unwrap_err();
7911        let ManifestError::RestartWindowMalformed {
7912            restart_window,
7913            reason,
7914        } = err
7915        else {
7916            panic!("expected RestartWindowMalformed");
7917        };
7918        assert_eq!(restart_window, "0.5m");
7919        assert!(
7920            reason.contains("\"30s\""),
7921            "diagnostic must point at the canonical-form remediation, got {reason:?}"
7922        );
7923    }
7924
7925    #[test]
7926    fn validate_restart_window_rejects_leading_sign() {
7927        // `"+30s"` and `"-30s"` both round-tripped through f64 cleanly
7928        // on the prior parser (`+30` parses as `30.0`; `-30` parsed
7929        // and was caught by the `num < 0.0` arm which silently
7930        // returned `None`, dropping the author-supplied window). The
7931        // shared codec's digit-only gate rejects both with a unified
7932        // canonical-form diagnostic; the manifest-layer wrapper names
7933        // the offending value.
7934        for bad in ["+30s", "-30s"] {
7935            let err = caixa_with_restart_window(Some(bad))
7936                .validate_restart_window()
7937                .unwrap_err();
7938            assert!(
7939                matches!(
7940                    err,
7941                    ManifestError::RestartWindowMalformed { ref restart_window, .. }
7942                        if restart_window == bad
7943                ),
7944                "got {err:?} for {bad:?}"
7945            );
7946        }
7947    }
7948
7949    #[test]
7950    fn validate_restart_window_rejects_unknown_unit() {
7951        // `"30x"` — the typo / wrong-unit footgun. The shared codec's
7952        // unit dispatch surfaces an `unknown duration unit` reason;
7953        // the manifest-layer wrapper names the offending value.
7954        let err = caixa_with_restart_window(Some("30x"))
7955            .validate_restart_window()
7956            .unwrap_err();
7957        let ManifestError::RestartWindowMalformed {
7958            restart_window,
7959            reason,
7960        } = err
7961        else {
7962            panic!("expected RestartWindowMalformed for unknown unit");
7963        };
7964        assert_eq!(restart_window, "30x");
7965        assert!(
7966            reason.contains("unknown duration unit"),
7967            "diagnostic must carry shared-codec unit-rejection wording, got {reason:?}"
7968        );
7969    }
7970
7971    #[test]
7972    fn validate_restart_window_rejects_garbage() {
7973        // Pure non-numeric magnitude (`"abc"`) falls through to the
7974        // shared codec's narrower `"bad duration magnitude"` arm. Same
7975        // diagnostic shape as the codec-side
7976        // `parse_garbage_still_falls_through_to_bad_magnitude` pin.
7977        let err = caixa_with_restart_window(Some("abc"))
7978            .validate_restart_window()
7979            .unwrap_err();
7980        let ManifestError::RestartWindowMalformed {
7981            restart_window,
7982            reason,
7983        } = err
7984        else {
7985            panic!("expected RestartWindowMalformed for garbage");
7986        };
7987        assert_eq!(restart_window, "abc");
7988        assert!(
7989            reason.contains("bad duration magnitude"),
7990            "diagnostic must carry shared-codec garbage-rejection wording, got {reason:?}"
7991        );
7992    }
7993
7994    #[test]
7995    fn validate_restart_window_rejects_empty_string() {
7996        // The empty-after-trim edge case — distinct from the `None`
7997        // canonical "omit the slot" shape. The shared codec's
7998        // digit-only gate refuses an empty magnitude; the manifest
7999        // layer names the offending `""` so the author can grep for
8000        // the literal empty value in their `caixa.lisp` and either
8001        // remove the slot (the canonical "no reset" shape) or pin a
8002        // positive duration.
8003        let err = caixa_with_restart_window(Some(""))
8004            .validate_restart_window()
8005            .unwrap_err();
8006        assert!(
8007            matches!(
8008                err,
8009                ManifestError::RestartWindowMalformed { ref restart_window, .. }
8010                    if restart_window.is_empty()
8011            ),
8012            "got {err:?}"
8013        );
8014    }
8015
8016    #[test]
8017    fn validate_restart_window_diagnostic_carries_offending_value() {
8018        // Diagnostic-shape pin (peer with
8019        // `nome_invalid_diagnostic_carries_offending_nome` /
8020        // `versao_invalid_diagnostic_carries_offending_versao`): the
8021        // error names the offending raw `:restart-window` verbatim
8022        // with a non-empty shared-codec-shaped reason, so a `feira
8023        // lint` run can render the diagnostic without re-parsing.
8024        let err = caixa_with_restart_window(Some("1.5s"))
8025            .validate_restart_window()
8026            .unwrap_err();
8027        let ManifestError::RestartWindowMalformed {
8028            restart_window,
8029            reason,
8030        } = err
8031        else {
8032            panic!("expected RestartWindowMalformed variant");
8033        };
8034        assert_eq!(restart_window, "1.5s");
8035        assert!(
8036            !reason.is_empty(),
8037            "RestartWindowMalformed `reason` must carry the codec's wording verbatim"
8038        );
8039    }
8040
8041    #[test]
8042    fn supervisor_view_folds_through_shared_codec_on_canonical_form() {
8043        // Behavioral parity pin after the fold (`parse_window_inline`
8044        // deletion): the canonical `"60s"` still produces
8045        // `Duration::from_secs(60)` on the typed view — the fold is
8046        // semantically equivalent to the prior inline parser on the
8047        // accepted set. Mirrors the pre-fold `supervisor_view_returns_typed_shape`
8048        // pin, narrowed to the parser-side contract.
8049        let c = caixa_with_restart_window(Some("60s"));
8050        let view = c.supervisor_view().expect("Supervisor kind has a view");
8051        assert_eq!(
8052            view.restart_window,
8053            Some(std::time::Duration::from_secs(60))
8054        );
8055    }
8056
8057    #[test]
8058    fn supervisor_view_soft_swallows_what_validate_rejects() {
8059        // Parity pin between the view-construction path and the
8060        // manifest-level validator: the same `"1.5s"` that surfaces
8061        // `RestartWindowMalformed` at `validate_restart_window` time
8062        // becomes `restart_window: None` on the typed view (the fold
8063        // preserves the existing best-effort shape of `supervisor_view`).
8064        // The contract is: a layout-verifier / `feira lint` flow that
8065        // cares about the malformed-window axis MUST consult
8066        // `validate_restart_window` — relying solely on the view's
8067        // `None` swallows the diagnostic silently. This pin makes the
8068        // expectation a typed invariant.
8069        let c = caixa_with_restart_window(Some("1.5s"));
8070        let view = c.supervisor_view().expect("Supervisor kind has a view");
8071        assert_eq!(
8072            view.restart_window, None,
8073            "view-construction path soft-swallows the parse error to None"
8074        );
8075        // And the manifest-level validator does NOT soft-swallow:
8076        assert!(
8077            matches!(
8078                c.validate_restart_window().unwrap_err(),
8079                ManifestError::RestartWindowMalformed { ref restart_window, .. }
8080                    if restart_window == "1.5s"
8081            ),
8082            "validator must surface the offending value",
8083        );
8084    }
8085
8086    // ── validate_code_paths — per-entry shape on :bibliotecas / :exe / :servicos ──
8087
8088    fn caixa_with_code_paths(bibliotecas: Vec<&str>, exe: Vec<&str>, servicos: Vec<&str>) -> Caixa {
8089        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8090        c.bibliotecas = bibliotecas.into_iter().map(String::from).collect();
8091        c.exe = exe.into_iter().map(String::from).collect();
8092        c.servicos = servicos.into_iter().map(String::from).collect();
8093        c
8094    }
8095
8096    #[test]
8097    fn validate_code_paths_accepts_canonical_template() {
8098        // The bare `Caixa::template` shape is the gate's identity element
8099        // on the canonical authoring shape — `:bibliotecas
8100        // ("lib/demo.lisp")` + empty `:exe` + empty `:servicos`. Pins
8101        // that the gate is non-disruptive against every existing caixa.
8102        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8103        c.validate_code_paths().unwrap();
8104    }
8105
8106    #[test]
8107    fn validate_code_paths_accepts_explicit_relative_paths_on_every_slot() {
8108        // Positive control sweep: a canonical-shaped path on every slot
8109        // passes. Mirrors the peer
8110        // `behavior::validate_every_slot_relative_is_ok` pin.
8111        let c = caixa_with_code_paths(
8112            vec!["lib/demo.lisp", "lib/helpers.lisp"],
8113            vec!["exe/demo", "exe/tool"],
8114            vec!["servicos/demo.computeunit.yaml"],
8115        );
8116        c.validate_code_paths().unwrap();
8117    }
8118
8119    #[test]
8120    fn validate_code_paths_accepts_all_empty_lists() {
8121        // The empty-list identity element: every Caixa with no declared
8122        // code paths trivially passes (Supervisor / Aplicacao kinds rely
8123        // on this — the OwnCode gate already rejected them before the
8124        // path-shape gate runs in the layout, but the validator itself
8125        // must accept the empty shape).
8126        let c = caixa_with_code_paths(vec![], vec![], vec![]);
8127        c.validate_code_paths().unwrap();
8128    }
8129
8130    #[test]
8131    fn validate_code_paths_rejects_empty_bibliotecas_entry() {
8132        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
8133        let err = c.validate_code_paths().unwrap_err();
8134        assert!(
8135            matches!(
8136                err,
8137                ManifestError::CodePathEmpty {
8138                    slot: ":bibliotecas"
8139                }
8140            ),
8141            "got {err:?}",
8142        );
8143    }
8144
8145    #[test]
8146    fn validate_code_paths_rejects_empty_exe_entry() {
8147        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
8148        let err = c.validate_code_paths().unwrap_err();
8149        assert!(
8150            matches!(err, ManifestError::CodePathEmpty { slot: ":exe" }),
8151            "got {err:?}",
8152        );
8153    }
8154
8155    #[test]
8156    fn validate_code_paths_rejects_empty_servicos_entry() {
8157        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
8158        let err = c.validate_code_paths().unwrap_err();
8159        assert!(
8160            matches!(err, ManifestError::CodePathEmpty { slot: ":servicos" }),
8161            "got {err:?}",
8162        );
8163    }
8164
8165    #[test]
8166    fn validate_code_paths_rejects_absolute_bibliotecas_entry() {
8167        // `:bibliotecas` has no `starts_with(<dir>)` fence downstream,
8168        // so an absolute path that resolves on disk silently passes the
8169        // layout's existence check — the canonical sandbox-escape on
8170        // the biblioteca axis.
8171        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
8172        let err = c.validate_code_paths().unwrap_err();
8173        let ManifestError::CodePathAbsolute { slot, path } = err else {
8174            panic!("expected CodePathAbsolute, got {err:?}");
8175        };
8176        assert_eq!(slot, ":bibliotecas");
8177        assert_eq!(path, PathBuf::from("/etc/passwd"));
8178    }
8179
8180    #[test]
8181    fn validate_code_paths_rejects_absolute_exe_entry() {
8182        let c = caixa_with_code_paths(vec![], vec!["/usr/bin/env"], vec![]);
8183        let err = c.validate_code_paths().unwrap_err();
8184        let ManifestError::CodePathAbsolute { slot, path } = err else {
8185            panic!("expected CodePathAbsolute, got {err:?}");
8186        };
8187        assert_eq!(slot, ":exe");
8188        assert_eq!(path, PathBuf::from("/usr/bin/env"));
8189    }
8190
8191    #[test]
8192    fn validate_code_paths_rejects_absolute_servicos_entry() {
8193        let c = caixa_with_code_paths(vec![], vec![], vec!["/var/servicos/x.yaml"]);
8194        let err = c.validate_code_paths().unwrap_err();
8195        let ManifestError::CodePathAbsolute { slot, path } = err else {
8196            panic!("expected CodePathAbsolute, got {err:?}");
8197        };
8198        assert_eq!(slot, ":servicos");
8199        assert_eq!(path, PathBuf::from("/var/servicos/x.yaml"));
8200    }
8201
8202    #[test]
8203    fn validate_code_paths_rejects_parent_escape_bibliotecas_leading() {
8204        // Canonical "I want a lib from a sibling caixa" footgun on the
8205        // biblioteca axis. `:bibliotecas` has no `starts_with` fence
8206        // downstream, so a leading `..` traverses to the parent of the
8207        // caixa root with no diagnostic at layout time if the resolved
8208        // target exists.
8209        let c = caixa_with_code_paths(vec!["../sibling/x.lisp"], vec![], vec![]);
8210        let err = c.validate_code_paths().unwrap_err();
8211        let ManifestError::CodePathParentEscape { slot, path } = err else {
8212            panic!("expected CodePathParentEscape, got {err:?}");
8213        };
8214        assert_eq!(slot, ":bibliotecas");
8215        assert_eq!(path, PathBuf::from("../sibling/x.lisp"));
8216    }
8217
8218    #[test]
8219    fn validate_code_paths_rejects_parent_escape_exe_mid_path() {
8220        // Mid-path `..` defeats the layout's component-aware
8221        // `starts_with(exe_dir)` fence — `root.join("exe/../../escape")`
8222        // `starts_with(<root>/exe)` is true, but the canonical resolution
8223        // lives outside the caixa root. Caught regardless of where the
8224        // `..` sits — mirrors the peer
8225        // `behavior::validate_rejects_parent_escape_mid_path` pin.
8226        let c = caixa_with_code_paths(vec![], vec!["exe/../../escape"], vec![]);
8227        let err = c.validate_code_paths().unwrap_err();
8228        let ManifestError::CodePathParentEscape { slot, path } = err else {
8229            panic!("expected CodePathParentEscape, got {err:?}");
8230        };
8231        assert_eq!(slot, ":exe");
8232        assert_eq!(path, PathBuf::from("exe/../../escape"));
8233    }
8234
8235    #[test]
8236    fn validate_code_paths_rejects_parent_escape_servicos_trailing() {
8237        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/foo/../../escape.yaml"]);
8238        let err = c.validate_code_paths().unwrap_err();
8239        let ManifestError::CodePathParentEscape { slot, path } = err else {
8240            panic!("expected CodePathParentEscape, got {err:?}");
8241        };
8242        assert_eq!(slot, ":servicos");
8243        assert_eq!(path, PathBuf::from("servicos/foo/../../escape.yaml"));
8244    }
8245
8246    #[test]
8247    fn validate_code_paths_cross_slot_precedence_bibliotecas_before_exe_before_servicos() {
8248        // Cross-slot precedence pin: `:bibliotecas` → `:exe` →
8249        // `:servicos`. A manifest with malformed entries on all three
8250        // surfaces surfaces the `:bibliotecas` defect first, mirroring
8251        // the canonical declaration order
8252        // `Caixa::declared_foreign_code_slots` already establishes for
8253        // the foreign-code-slot diagnostic.
8254        let c = caixa_with_code_paths(vec![""], vec![""], vec![""]);
8255        let err = c.validate_code_paths().unwrap_err();
8256        assert!(
8257            matches!(
8258                err,
8259                ManifestError::CodePathEmpty {
8260                    slot: ":bibliotecas"
8261                }
8262            ),
8263            "got {err:?}",
8264        );
8265    }
8266
8267    #[test]
8268    fn validate_code_paths_within_slot_precedence_empty_before_absolute_before_parent_escape() {
8269        // Within-slot precedence pin: empty → absolute → parent-escape,
8270        // matching the [`PathShapeViolation`] arm-ordering every peer
8271        // `is_sandboxed_relative_path` caller follows (b0c8389
8272        // BehaviorSpec, 26da2c7 UpgradeInstruction::StateChange). A
8273        // `:bibliotecas` list whose first entry is empty *and* whose
8274        // later entries are absolute/parent-escape surfaces the empty
8275        // arm first, on the lexicographically-earliest offending entry.
8276        let c = caixa_with_code_paths(vec!["", "/etc/passwd", "../escape.lisp"], vec![], vec![]);
8277        let err = c.validate_code_paths().unwrap_err();
8278        assert!(
8279            matches!(
8280                err,
8281                ManifestError::CodePathEmpty {
8282                    slot: ":bibliotecas"
8283                }
8284            ),
8285            "got {err:?}",
8286        );
8287    }
8288
8289    #[test]
8290    fn validate_code_paths_first_offender_per_slot_wins() {
8291        // Within a single slot, the first declaration-order offender
8292        // surfaces — pins that the gate is left-to-right deterministic
8293        // (peer of every `*_first_collision_*` pin on duplicate gates).
8294        let c = caixa_with_code_paths(
8295            vec!["lib/ok.lisp", "/etc/escape", "../also-escape"],
8296            vec![],
8297            vec![],
8298        );
8299        let err = c.validate_code_paths().unwrap_err();
8300        let ManifestError::CodePathAbsolute { slot, path } = err else {
8301            panic!("expected CodePathAbsolute, got {err:?}");
8302        };
8303        assert_eq!(slot, ":bibliotecas");
8304        assert_eq!(path, PathBuf::from("/etc/escape"));
8305    }
8306
8307    #[test]
8308    fn validate_code_paths_diagnostic_carries_offending_slot_and_path() {
8309        // Diagnostic-shape pin (peer with
8310        // `nome_invalid_diagnostic_carries_offending_nome` /
8311        // `versao_invalid_diagnostic_carries_offending_versao`): the
8312        // error's Display surfaces both the offending `:slot` tag and
8313        // the offending path verbatim, so a `feira lint` run can render
8314        // the diagnostic without re-parsing.
8315        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
8316        let rendered = c.validate_code_paths().unwrap_err().to_string();
8317        assert!(
8318            rendered.contains(":bibliotecas"),
8319            "diagnostic must name the offending slot: {rendered}",
8320        );
8321        assert!(
8322            rendered.contains("/etc/passwd"),
8323            "diagnostic must quote the offending path: {rendered}",
8324        );
8325    }
8326
8327    #[test]
8328    fn validate_code_paths_rejects_duplicate_bibliotecas_entry() {
8329        // Canonical copy-paste-the-wrong-file footgun on the biblioteca
8330        // axis. Without the gate `feira build` re-parses the same lib
8331        // twice, wasting work and silently masking the author's intent
8332        // to declare a *second* biblioteca.
8333        let c = caixa_with_code_paths(vec!["lib/demo.lisp", "lib/demo.lisp"], vec![], vec![]);
8334        let err = c.validate_code_paths().unwrap_err();
8335        let ManifestError::CodePathDuplicate { slot, path } = err else {
8336            panic!("expected CodePathDuplicate, got {err:?}");
8337        };
8338        assert_eq!(slot, ":bibliotecas");
8339        assert_eq!(path, PathBuf::from("lib/demo.lisp"));
8340    }
8341
8342    #[test]
8343    fn validate_code_paths_rejects_duplicate_exe_entry() {
8344        // Same footgun on the Binario surface. The future `caixa-flake`
8345        // emitter that materializes each `:exe` entry as a flake
8346        // `packages.<name>` derivation would collide on the duplicate
8347        // package key — surfaced here at the typed-validate layer with a
8348        // self-locating diagnostic instead.
8349        let c = caixa_with_code_paths(vec![], vec!["exe/cli", "exe/cli"], vec![]);
8350        let err = c.validate_code_paths().unwrap_err();
8351        let ManifestError::CodePathDuplicate { slot, path } = err else {
8352            panic!("expected CodePathDuplicate, got {err:?}");
8353        };
8354        assert_eq!(slot, ":exe");
8355        assert_eq!(path, PathBuf::from("exe/cli"));
8356    }
8357
8358    #[test]
8359    fn validate_code_paths_rejects_duplicate_servicos_entry() {
8360        // Same footgun on the Servico surface. The peer caixa-helm /
8361        // caixa-flux renderers refuse `:servicos.len() != 1` with the
8362        // narrower `UnsupportedServicoCount` diagnostic, but that
8363        // diagnostic surfaces "too many servicos" without naming
8364        // "duplicate entry" — the typed self-locating framing only lands
8365        // at this gate.
8366        let c = caixa_with_code_paths(
8367            vec![],
8368            vec![],
8369            vec![
8370                "servicos/demo.computeunit.yaml",
8371                "servicos/demo.computeunit.yaml",
8372            ],
8373        );
8374        let err = c.validate_code_paths().unwrap_err();
8375        let ManifestError::CodePathDuplicate { slot, path } = err else {
8376            panic!("expected CodePathDuplicate, got {err:?}");
8377        };
8378        assert_eq!(slot, ":servicos");
8379        assert_eq!(path, PathBuf::from("servicos/demo.computeunit.yaml"));
8380    }
8381
8382    #[test]
8383    fn validate_code_paths_accepts_same_path_across_slots() {
8384        // Per-list scope pin: a `:bibliotecas` entry that happens to
8385        // collide with an `:exe` or `:servicos` entry as a *string* is
8386        // not a duplicate by this gate (each list gets its own HashSet),
8387        // mirroring the peer `:deps` ↔ `:deps-dev` per-list scope
8388        // (a `:nome` present in both lists is a legitimate dev-vs-runtime
8389        // shape on the dep axis). The structural `starts_with(<exe |
8390        // servicos>_dir)` fence at layout time prevents the realistic
8391        // cross-slot collision case from existing on disk, but the gate's
8392        // per-list scope is correct independent of that downstream fence.
8393        let c = caixa_with_code_paths(
8394            vec!["lib/x.lisp"],
8395            vec!["exe/x"],
8396            vec!["servicos/x.computeunit.yaml"],
8397        );
8398        c.validate_code_paths().unwrap();
8399    }
8400
8401    #[test]
8402    fn validate_code_paths_duplicate_fires_after_structural_checks_on_same_slot() {
8403        // Within-slot ordering pin: structural defects (empty / absolute
8404        // / parent-escape) fire before the duplicate gate on the same
8405        // slot. A `:bibliotecas ("" "lib/x.lisp" "lib/x.lisp")` shape
8406        // surfaces the narrower `CodePathEmpty` for the empty entry
8407        // first, not the duplicate on the later pair — same arm-ordering
8408        // every peer per-list duplicate gate uses (`:etiquetas` 360a499,
8409        // `:autores` 86c769b, `:deps` 359fba5).
8410        let c = caixa_with_code_paths(vec!["", "lib/x.lisp", "lib/x.lisp"], vec![], vec![]);
8411        let err = c.validate_code_paths().unwrap_err();
8412        assert!(
8413            matches!(
8414                err,
8415                ManifestError::CodePathEmpty {
8416                    slot: ":bibliotecas"
8417                }
8418            ),
8419            "got {err:?}",
8420        );
8421    }
8422
8423    #[test]
8424    fn validate_code_paths_duplicate_in_bibliotecas_fires_before_duplicate_in_exe() {
8425        // Cross-slot ordering pin on the duplicate arm: `:bibliotecas`
8426        // duplicates surface before `:exe` duplicates, matching the
8427        // canonical `:bibliotecas` → `:exe` → `:servicos` declaration
8428        // order every peer per-slot diagnostic on this surface follows.
8429        let c = caixa_with_code_paths(
8430            vec!["lib/x.lisp", "lib/x.lisp"],
8431            vec!["exe/y", "exe/y"],
8432            vec![],
8433        );
8434        let err = c.validate_code_paths().unwrap_err();
8435        let ManifestError::CodePathDuplicate { slot, path } = err else {
8436            panic!("expected CodePathDuplicate, got {err:?}");
8437        };
8438        assert_eq!(slot, ":bibliotecas");
8439        assert_eq!(path, PathBuf::from("lib/x.lisp"));
8440    }
8441
8442    #[test]
8443    fn validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path() {
8444        // Diagnostic-shape pin (peer with
8445        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
8446        // on the structural arm): the duplicate-arm Display surfaces both
8447        // the offending `:slot` tag and the offending path verbatim, so a
8448        // `feira lint` run can render the diagnostic without re-parsing.
8449        let c = caixa_with_code_paths(
8450            vec![],
8451            vec![],
8452            vec![
8453                "servicos/demo.computeunit.yaml",
8454                "servicos/demo.computeunit.yaml",
8455            ],
8456        );
8457        let rendered = c.validate_code_paths().unwrap_err().to_string();
8458        assert!(
8459            rendered.contains(":servicos"),
8460            "diagnostic must name the offending slot: {rendered}",
8461        );
8462        assert!(
8463            rendered.contains("servicos/demo.computeunit.yaml"),
8464            "diagnostic must quote the offending path: {rendered}",
8465        );
8466    }
8467
8468    // ── validate_code_paths — `.lisp` extension gate on :bibliotecas ──
8469    //
8470    // The lifted [`crate::render::is_lisp_extension`] predicate (33cc830)
8471    // now gates `:bibliotecas` entries on the tatara-lisp-source file-type
8472    // contract. The `feira build` loop (`caixa-feira/src/cmd/build.rs:33`)
8473    // reads every declared `:bibliotecas` entry through `tatara_lisp::read`
8474    // at parse time — the same downstream consumer the peer `:behavior
8475    // :on-*` (c97815a, [`crate::BehaviorError::NonLispExtension`]) and
8476    // `:upgrade-from :state-change :script` (33cc830,
8477    // [`crate::UpgradeError::NonLispExtensionScript`]) axes route through.
8478    // `:exe` and `:servicos` are deliberately excluded — `:exe` is the
8479    // nix-built executable surface (`"exe/<name>"` shape per the canonical
8480    // [`crate::LayoutError::ExeOutsideDir`] error message and every
8481    // in-tree `caixa_with_code_paths` positive control), and `:servicos`
8482    // is the `.computeunit.yaml` ComputeUnit-CR axis.
8483
8484    #[test]
8485    fn validate_code_paths_rejects_no_extension_bibliotecas_entry() {
8486        // Canonical "I dragged the wrong file from the workspace tree"
8487        // footgun on the biblioteca axis. Without the gate `feira build`
8488        // hands the extensionless path to `tatara_lisp::read` and fails
8489        // with a parser-shaped diagnostic far from the source caixa.lisp,
8490        // with no field naming the offending `:bibliotecas` entry.
8491        for relpath in ["lib/demo", "demo", "lib/handlers/inner"] {
8492            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
8493            let err = c.validate_code_paths().unwrap_err();
8494            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
8495                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
8496            };
8497            assert_eq!(slot, ":bibliotecas");
8498            assert_eq!(path, PathBuf::from(relpath));
8499        }
8500    }
8501
8502    #[test]
8503    fn validate_code_paths_rejects_wrong_extension_bibliotecas_entry() {
8504        // Wrong-extension sweep across common authoring footguns. Same
8505        // sweep posture as the peer
8506        // `behavior::validate_rejects_wrong_extension` (c97815a) and
8507        // `upgrade::tests::state_change_rejects_wrong_extension_script`
8508        // (33cc830) cases.
8509        for relpath in [
8510            "lib/demo.rs",
8511            "lib/demo.txt",
8512            "lib/demo.md",
8513            "lib/demo.json",
8514            "lib/demo.yaml",
8515            "lib/demo.toml",
8516            "lib/demo.lisp.bak",
8517            "lib/demo.lispx",
8518            "lib/demo.lis",
8519        ] {
8520            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
8521            let err = c.validate_code_paths().unwrap_err();
8522            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
8523                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
8524            };
8525            assert_eq!(slot, ":bibliotecas");
8526            assert_eq!(path, PathBuf::from(relpath));
8527        }
8528    }
8529
8530    #[test]
8531    fn validate_code_paths_rejects_case_folded_extension_bibliotecas_entry() {
8532        // Case-sensitivity sweep — pins the strict lowercase `.lisp`
8533        // contract. An uppercase `.LISP` shape that the layout's existence
8534        // check would (case-insensitively, on case-insensitive volumes)
8535        // match the on-disk file still mismatches the canonical form the
8536        // codec emits, breaking the THEORY.md §V.2.7 render-determinism
8537        // contract. Mirrors the peer
8538        // `behavior::validate_rejects_case_folded_extension` (c97815a) and
8539        // `upgrade::tests::state_change_rejects_case_folded_extension_script`
8540        // (33cc830) sweeps.
8541        for relpath in [
8542            "lib/demo.LISP",
8543            "lib/demo.Lisp",
8544            "lib/demo.LiSp",
8545            "lib/demo.lISP",
8546        ] {
8547            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
8548            let err = c.validate_code_paths().unwrap_err();
8549            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
8550                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
8551            };
8552            assert_eq!(slot, ":bibliotecas");
8553            assert_eq!(path, PathBuf::from(relpath));
8554        }
8555    }
8556
8557    #[test]
8558    fn validate_code_paths_accepts_canonical_lisp_shapes() {
8559        // Positive-control sweep through every canonical authoring shape
8560        // every in-tree fixture and the `Caixa::template` scaffold use.
8561        // Mirrors the peer `behavior::validate_accepts_canonical_lisp_paths`
8562        // (c97815a) and the lifted predicate's own
8563        // `is_lisp_extension_accepts_canonical_shapes` sweep in render.rs
8564        // (33cc830).
8565        for relpath in [
8566            "lib/demo.lisp",
8567            "lib/handlers.lisp",
8568            "lib/migrations/v01-to-v02.lisp",
8569            "demo.lisp",
8570            "a.lisp",
8571            "./lib/demo.lisp",
8572            "lib/./handlers.lisp",
8573            "lib/migrations/v.0.1.lisp",
8574        ] {
8575            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
8576            c.validate_code_paths()
8577                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
8578        }
8579    }
8580
8581    #[test]
8582    fn validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos() {
8583        // The file-type gate is per-slot — only `:bibliotecas` carries the
8584        // tatara-lisp-source contract. An extensionless `:exe` entry
8585        // (`exe/demo`) and a `.computeunit.yaml` `:servicos` entry are the
8586        // canonical shapes every in-tree fixture uses, and must continue
8587        // to pass validate. Pins that a future tightening that broadens
8588        // the `.lisp` gate to either axis surfaces as a test failure
8589        // rather than as a silent breaking change to existing valid
8590        // manifests.
8591        let c = caixa_with_code_paths(
8592            vec![],
8593            vec!["exe/demo", "exe/tool"],
8594            vec!["servicos/demo.computeunit.yaml"],
8595        );
8596        c.validate_code_paths().unwrap();
8597    }
8598
8599    #[test]
8600    fn validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension() {
8601        // Cross-arm precedence pin: a `:bibliotecas` entry that is *both*
8602        // sandbox-escaping and non-`.lisp` surfaces the more fundamental
8603        // sandbox-shape diagnostic first (the `.lisp` remediation would
8604        // be misleading when the offending path can never resolve under
8605        // the caixa root anyway). Mirrors the peer
8606        // `EmptyPath` → `AbsolutePath` → `ParentEscape` → `NonLispExtension`
8607        // ordering on `:behavior :on-*` (c97815a) and `EmptyScript` →
8608        // `AbsoluteScript` → `ParentEscapeScript` → `NonLispExtensionScript`
8609        // on `:upgrade-from :state-change :script` (33cc830).
8610        //
8611        // Empty wins (the strictly-smaller-scope structural arm).
8612        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
8613        assert!(
8614            matches!(
8615                c.validate_code_paths().unwrap_err(),
8616                ManifestError::CodePathEmpty {
8617                    slot: ":bibliotecas"
8618                }
8619            ),
8620            "empty must win over non-lisp-extension",
8621        );
8622        // Absolute wins (the path can't resolve under the caixa root).
8623        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
8624        let err = c.validate_code_paths().unwrap_err();
8625        let ManifestError::CodePathAbsolute { slot, .. } = err else {
8626            panic!("absolute must win over non-lisp-extension, got {err:?}");
8627        };
8628        assert_eq!(slot, ":bibliotecas");
8629        // ParentEscape wins (the path escapes the caixa root).
8630        let c = caixa_with_code_paths(vec!["../sibling/x.txt"], vec![], vec![]);
8631        let err = c.validate_code_paths().unwrap_err();
8632        let ManifestError::CodePathParentEscape { slot, .. } = err else {
8633            panic!("parent-escape must win over non-lisp-extension, got {err:?}");
8634        };
8635        assert_eq!(slot, ":bibliotecas");
8636    }
8637
8638    #[test]
8639    fn validate_code_paths_non_lisp_extension_precedes_duplicate() {
8640        // Within-slot precedence pin: the per-entry file-type shape gate
8641        // fires before the cross-entry duplicate gate, so the narrower
8642        // structural defect dominates the uniqueness diagnostic. A
8643        // `("lib/x.txt" "lib/x.txt")` shape surfaces
8644        // `CodePathNonLispExtension` on the first entry rather than
8645        // `CodePathDuplicate` on the pair — same posture every per-entry
8646        // shape-gate-precedes-duplicate cascade follows on this surface
8647        // (the empty / absolute / parent-escape arms already precede the
8648        // duplicate arm; the lifted file-type arm joins that set).
8649        let c = caixa_with_code_paths(vec!["lib/x.txt", "lib/x.txt"], vec![], vec![]);
8650        let err = c.validate_code_paths().unwrap_err();
8651        let ManifestError::CodePathNonLispExtension { slot, path } = err else {
8652            panic!("expected CodePathNonLispExtension, got {err:?}");
8653        };
8654        assert_eq!(slot, ":bibliotecas");
8655        assert_eq!(path, PathBuf::from("lib/x.txt"));
8656    }
8657
8658    #[test]
8659    fn validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path() {
8660        // Diagnostic-shape pin (peer with
8661        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
8662        // on the sandbox-shape arms and
8663        // `validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path`
8664        // on the duplicate arm): the file-type-arm Display surfaces both
8665        // the offending `:slot` tag, the offending path verbatim, and the
8666        // expected `.lisp` extension named in the remediation text, so a
8667        // `feira lint` run can render the diagnostic without re-parsing.
8668        let c = caixa_with_code_paths(vec!["lib/demo.rs"], vec![], vec![]);
8669        let rendered = c.validate_code_paths().unwrap_err().to_string();
8670        assert!(
8671            rendered.contains(":bibliotecas"),
8672            "diagnostic must name the offending slot: {rendered}",
8673        );
8674        assert!(
8675            rendered.contains("lib/demo.rs"),
8676            "diagnostic must quote the offending path: {rendered}",
8677        );
8678        assert!(
8679            rendered.contains(".lisp"),
8680            "diagnostic must name the expected extension: {rendered}",
8681        );
8682    }
8683
8684    // ── validate_code_paths — `.computeunit.yaml` compound-suffix gate on :servicos ──
8685    //
8686    // The lifted [`crate::render::is_computeunit_yaml_extension`] predicate
8687    // now gates `:servicos` entries on the ComputeUnit-CR YAML file-type
8688    // contract. The peer caixa-helm / caixa-flux renderers consume each
8689    // `:servicos` entry through `serde_yaml::from_str` as a typed
8690    // `ComputeUnit` CR — same downstream-consumer-shape lift as the peer
8691    // `:bibliotecas` `.lisp` gate (64772a9), here on the compound-suffix
8692    // axis `Path::extension` can't express on its own.
8693
8694    #[test]
8695    fn validate_code_paths_rejects_no_extension_servicos_entry() {
8696        // Canonical "I dragged the wrong file from the workspace tree"
8697        // footgun on the Servico axis. Without the gate the peer
8698        // caixa-helm / caixa-flux renderers hand the extensionless path
8699        // to `serde_yaml::from_str` and fail with a parser-shaped
8700        // diagnostic far from the source caixa.lisp, with no field
8701        // naming the offending `:servicos` entry.
8702        for relpath in ["servicos/demo", "demo", "servicos/sub/nested"] {
8703            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
8704            let err = c.validate_code_paths().unwrap_err();
8705            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
8706                panic!(
8707                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
8708                     got {err:?}"
8709                );
8710            };
8711            assert_eq!(slot, ":servicos");
8712            assert_eq!(path, PathBuf::from(relpath));
8713        }
8714    }
8715
8716    #[test]
8717    fn validate_code_paths_rejects_wrong_extension_servicos_entry() {
8718        // Wrong-extension sweep across common authoring footguns on the
8719        // Servico axis. Bare `.yaml` is the canonical "I forgot the
8720        // `.computeunit` segment" typo; the off-by-one-segment shapes
8721        // (`.computeunit-yaml` / `.computeunit_yaml`) silently pass the
8722        // bare `Path::extension` view but mismatch the typed compound
8723        // suffix the renderers' `serde_yaml::from_str` consumer demands.
8724        // Same sweep-posture as the peer
8725        // `validate_code_paths_rejects_wrong_extension_bibliotecas_entry`
8726        // (64772a9) on the sibling tatara-lisp-source axis.
8727        for relpath in [
8728            "servicos/demo.yaml",
8729            "servicos/demo.yml",
8730            "servicos/demo.json",
8731            "servicos/demo.toml",
8732            "servicos/demo.txt",
8733            "servicos/demo.computeunit.yaml.bak",
8734            "servicos/demo.computeunit.yam",
8735            "servicos/demo.computeunit",
8736            "servicos/demo-computeunit.yaml",
8737            "servicos/demo_computeunit.yaml",
8738        ] {
8739            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
8740            let err = c.validate_code_paths().unwrap_err();
8741            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
8742                panic!(
8743                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
8744                     got {err:?}"
8745                );
8746            };
8747            assert_eq!(slot, ":servicos");
8748            assert_eq!(path, PathBuf::from(relpath));
8749        }
8750    }
8751
8752    #[test]
8753    fn validate_code_paths_rejects_case_folded_extension_servicos_entry() {
8754        // Case-sensitivity sweep — pins the strict lowercase
8755        // `.computeunit.yaml` contract. A case-folded shape that the
8756        // layout's existence check would (case-insensitively, on
8757        // case-insensitive volumes) match the on-disk file still
8758        // mismatches the canonical form the codec emits, breaking the
8759        // THEORY.md §V.2.7 render-determinism contract. Mirrors the peer
8760        // `validate_code_paths_rejects_case_folded_extension_bibliotecas_entry`
8761        // (64772a9) sweep on the sibling tatara-lisp-source axis.
8762        for relpath in [
8763            "servicos/demo.ComputeUnit.yaml",
8764            "servicos/demo.COMPUTEUNIT.yaml",
8765            "servicos/demo.computeunit.YAML",
8766            "servicos/demo.computeunit.Yaml",
8767            "servicos/demo.COMPUTEUNIT.YAML",
8768        ] {
8769            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
8770            let err = c.validate_code_paths().unwrap_err();
8771            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
8772                panic!(
8773                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
8774                     got {err:?}"
8775                );
8776            };
8777            assert_eq!(slot, ":servicos");
8778            assert_eq!(path, PathBuf::from(relpath));
8779        }
8780    }
8781
8782    #[test]
8783    fn validate_code_paths_rejects_empty_stem_servicos_entry() {
8784        // Degenerate hidden-file shape: a file name exactly equal to the
8785        // suffix (`.computeunit.yaml` — no stem preceding the suffix) is
8786        // the structural "Servico declared with no identity" footgun.
8787        // The substrate identifies each ComputeUnit by the file-stem
8788        // segment that precedes `.computeunit.yaml` (the rendered
8789        // `lareira-<stem>` Helm chart, the per-Servico `metadata.name`,
8790        // the M3 `:contratos` membership lookup), so an empty stem
8791        // leaves the Servico unidentifiable. Pinned at the typed-axis
8792        // level so a future regression that drops the `name.len() >
8793        // SUFFIX.len()` bound at the predicate surfaces here, not
8794        // piecemeal as a `lareira-` chart-name collision at render time.
8795        for relpath in ["servicos/.computeunit.yaml"] {
8796            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
8797            let err = c.validate_code_paths().unwrap_err();
8798            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
8799                panic!(
8800                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
8801                     got {err:?}"
8802                );
8803            };
8804            assert_eq!(slot, ":servicos");
8805            assert_eq!(path, PathBuf::from(relpath));
8806        }
8807    }
8808
8809    #[test]
8810    fn validate_code_paths_accepts_canonical_computeunit_yaml_shapes() {
8811        // Positive-control sweep through every canonical authoring shape
8812        // every in-tree fixture and the `Caixa::template` scaffold use.
8813        // Mirrors the peer
8814        // `validate_code_paths_accepts_canonical_lisp_shapes` (64772a9)
8815        // and the lifted predicate's own
8816        // `computeunit_yaml_extension_accepts_canonical_shapes` sweep in
8817        // render.rs.
8818        for relpath in [
8819            "servicos/demo.computeunit.yaml",
8820            "servicos/hello-rio.computeunit.yaml",
8821            "servicos/my-service.computeunit.yaml",
8822            "servicos/a.computeunit.yaml",
8823            "./servicos/demo.computeunit.yaml",
8824            "servicos/./demo.computeunit.yaml",
8825            "servicos/sub/nested.computeunit.yaml",
8826            "servicos/v0.1.computeunit.yaml",
8827        ] {
8828            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
8829            c.validate_code_paths()
8830                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
8831        }
8832    }
8833
8834    #[test]
8835    fn validate_code_paths_non_computeunit_yaml_extension_does_not_fire_on_bibliotecas_or_exe() {
8836        // The file-type gate is per-slot — only `:servicos` carries the
8837        // ComputeUnit-CR YAML contract. A canonical `.lisp` `:bibliotecas`
8838        // entry and an extensionless `:exe` entry are the canonical
8839        // shapes every in-tree fixture uses, and must continue to pass
8840        // validate. Peer of
8841        // `validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos`
8842        // (64772a9) — together pin that the typed
8843        // [`CodePathFileType`] dispatch is exhaustively per-slot, with no
8844        // cross-axis leakage in either direction.
8845        let c = caixa_with_code_paths(
8846            vec!["lib/demo.lisp"],
8847            vec!["exe/demo", "exe/tool"],
8848            vec!["servicos/demo.computeunit.yaml"],
8849        );
8850        c.validate_code_paths().unwrap();
8851    }
8852
8853    #[test]
8854    fn validate_code_paths_sandbox_shape_arms_precede_non_computeunit_yaml_extension() {
8855        // Cross-arm precedence pin: a `:servicos` entry that is *both*
8856        // sandbox-escaping and wrong-extension surfaces the more
8857        // fundamental sandbox-shape diagnostic first (the
8858        // `.computeunit.yaml` remediation would be misleading when the
8859        // offending path can never resolve under the caixa root
8860        // anyway). Mirrors the peer
8861        // `validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension`
8862        // (64772a9) ordering on the sibling `:bibliotecas` axis and the
8863        // peer `EmptyPath` → `AbsolutePath` → `ParentEscape` →
8864        // `NonComputeUnitYamlExtension` arm-ordering the dispatch
8865        // table establishes.
8866        //
8867        // Empty wins (the strictly-smaller-scope structural arm).
8868        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
8869        assert!(
8870            matches!(
8871                c.validate_code_paths().unwrap_err(),
8872                ManifestError::CodePathEmpty { slot: ":servicos" }
8873            ),
8874            "empty must win over non-computeunit-yaml-extension",
8875        );
8876        // Absolute wins (the path can't resolve under the caixa root).
8877        let c = caixa_with_code_paths(vec![], vec![], vec!["/etc/foo.yaml"]);
8878        let err = c.validate_code_paths().unwrap_err();
8879        let ManifestError::CodePathAbsolute { slot, .. } = err else {
8880            panic!("absolute must win over non-computeunit-yaml-extension, got {err:?}");
8881        };
8882        assert_eq!(slot, ":servicos");
8883        // ParentEscape wins (the path escapes the caixa root).
8884        let c = caixa_with_code_paths(vec![], vec![], vec!["../sibling/x.yaml"]);
8885        let err = c.validate_code_paths().unwrap_err();
8886        let ManifestError::CodePathParentEscape { slot, .. } = err else {
8887            panic!("parent-escape must win over non-computeunit-yaml-extension, got {err:?}");
8888        };
8889        assert_eq!(slot, ":servicos");
8890    }
8891
8892    #[test]
8893    fn validate_code_paths_non_computeunit_yaml_extension_precedes_duplicate() {
8894        // Within-slot precedence pin: the per-entry file-type shape gate
8895        // fires before the cross-entry duplicate gate, so the narrower
8896        // structural defect dominates the uniqueness diagnostic. A
8897        // `("servicos/x.yaml" "servicos/x.yaml")` shape surfaces
8898        // `CodePathNonComputeUnitYamlExtension` on the first entry
8899        // rather than `CodePathDuplicate` on the pair — same posture
8900        // every per-entry shape-gate-precedes-duplicate cascade follows
8901        // on this surface, peer of the 64772a9 `:bibliotecas`
8902        // `("lib/x.txt" "lib/x.txt")` ordering.
8903        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/x.yaml", "servicos/x.yaml"]);
8904        let err = c.validate_code_paths().unwrap_err();
8905        let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
8906            panic!("expected CodePathNonComputeUnitYamlExtension, got {err:?}");
8907        };
8908        assert_eq!(slot, ":servicos");
8909        assert_eq!(path, PathBuf::from("servicos/x.yaml"));
8910    }
8911
8912    #[test]
8913    fn validate_code_paths_non_computeunit_yaml_extension_diagnostic_carries_offending_slot_and_path()
8914     {
8915        // Diagnostic-shape pin (peer with
8916        // `validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path`
8917        // on the sibling tatara-lisp-source axis): the file-type-arm
8918        // Display surfaces both the offending `:slot` tag, the
8919        // offending path verbatim, and the expected
8920        // `.computeunit.yaml` compound suffix named in the remediation
8921        // text, so a `feira lint` run can render the diagnostic without
8922        // re-parsing.
8923        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.yaml"]);
8924        let rendered = c.validate_code_paths().unwrap_err().to_string();
8925        assert!(
8926            rendered.contains(":servicos"),
8927            "diagnostic must name the offending slot: {rendered}",
8928        );
8929        assert!(
8930            rendered.contains("servicos/demo.yaml"),
8931            "diagnostic must quote the offending path: {rendered}",
8932        );
8933        assert!(
8934            rendered.contains(".computeunit.yaml"),
8935            "diagnostic must name the expected compound suffix: {rendered}",
8936        );
8937    }
8938
8939    // ── validate_etiquetas — universal-axis registry-search-tag shape ──
8940
8941    fn caixa_with_etiquetas(etiquetas: Vec<&str>) -> Caixa {
8942        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8943        c.etiquetas = etiquetas.into_iter().map(String::from).collect();
8944        c
8945    }
8946
8947    #[test]
8948    fn validate_etiquetas_accepts_empty_list() {
8949        // The empty-list identity: every caixa with no declared tags
8950        // trivially passes — `Caixa::template` emits `:etiquetas ()`,
8951        // so the gate is non-disruptive against every existing manifest.
8952        let c = caixa_with_etiquetas(vec![]);
8953        c.validate_etiquetas().unwrap();
8954    }
8955
8956    #[test]
8957    fn validate_etiquetas_accepts_canonical_forms() {
8958        // Positive control sweep: a canonical-shaped non-empty distinct
8959        // tag list passes, mirroring the example checkout-aplicacao
8960        // (`:etiquetas ("example" "aplicacao" "mesh" "ecommerce" "demo")`)
8961        // and the hello-rio fixture (`("hello-world" "wasm" "rust")`).
8962        let c = caixa_with_etiquetas(vec!["example", "aplicacao", "mesh", "ecommerce", "demo"]);
8963        c.validate_etiquetas().unwrap();
8964    }
8965
8966    #[test]
8967    fn validate_etiquetas_rejects_empty_entry() {
8968        // Canonical paste-from-blank-doc footgun. Without the gate the
8969        // empty entry rendered as `keywords: [""]` in `Chart.yaml`, a
8970        // no-op tag indexing nothing in the future caixa-registry.
8971        let c = caixa_with_etiquetas(vec![""]);
8972        let err = c.validate_etiquetas().unwrap_err();
8973        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
8974    }
8975
8976    #[test]
8977    fn validate_etiquetas_rejects_duplicate_entry() {
8978        // Canonical copy-paste-the-wrong-tag footgun. Without the gate
8979        // the duplicate was silently dedup'd by caixa-helm's BTreeSet
8980        // collect at chart render — a "second wins / one silently
8981        // disappears" shape divergent from every peer typed-graph set
8982        // gate. The duplicate-arm names the offending tag verbatim.
8983        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
8984        let err = c.validate_etiquetas().unwrap_err();
8985        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
8986            panic!("expected EtiquetaDuplicate, got {err:?}");
8987        };
8988        assert_eq!(etiqueta, "demo");
8989    }
8990
8991    #[test]
8992    fn validate_etiquetas_empty_takes_precedence_over_duplicate() {
8993        // Empty-first cascade pin: `("" "demo" "demo")` surfaces
8994        // `EtiquetaEmpty` not `EtiquetaDuplicate` — the narrower
8995        // structural "this entry has no value" defect dominates the
8996        // cross-entry uniqueness diagnostic. Mirrors the peer
8997        // empty-before-duplicate cascades on `:caracteristicas`
8998        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
8999        // fc3b4d5) and `:membros :caixa` (`MembroCaixaEmpty` before
9000        // `MembroDuplicate`).
9001        let c = caixa_with_etiquetas(vec!["", "demo", "demo"]);
9002        let err = c.validate_etiquetas().unwrap_err();
9003        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
9004    }
9005
9006    #[test]
9007    fn validate_etiquetas_duplicate_reports_first_collision() {
9008        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
9009        // duplicate (the lexicographically-earliest offending position
9010        // — the second `"a"` at index 2 collides with the first `"a"`
9011        // at index 0), not the later `"b"` collision at index 3,
9012        // peer with every other first-collision diagnostic posture on
9013        // this surface (`validate_load_singularity_reports_first_collision`,
9014        // `validate_cleanup_singularity_reports_first_collision`).
9015        let c = caixa_with_etiquetas(vec!["a", "b", "a", "b"]);
9016        let err = c.validate_etiquetas().unwrap_err();
9017        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
9018            panic!("expected EtiquetaDuplicate, got {err:?}");
9019        };
9020        assert_eq!(etiqueta, "a");
9021    }
9022
9023    #[test]
9024    fn validate_etiquetas_case_sensitive() {
9025        // Case-sensitivity pin: `("Foo" "foo")` is two distinct entries,
9026        // mirroring the peer `:membros :caixa` / `:children :caixa`
9027        // exact-string-match discipline. The shape gate this routine
9028        // landed (`is_chart_keyword_shape`, Cargo crates.io keyword
9029        // grammar) accepts mixed case — crates.io's keyword rule is
9030        // "case-insensitive" at the index layer but admits mixed case
9031        // at the entry layer (the canonical Helm chart `keywords:`
9032        // shape is lowercase by convention, but the grammar admits
9033        // uppercase). Case-sensitivity at the duplicate-set layer
9034        // remains structural — two distinct strings are two distinct
9035        // entries.
9036        let c = caixa_with_etiquetas(vec!["Foo", "foo"]);
9037        c.validate_etiquetas().unwrap();
9038    }
9039
9040    #[test]
9041    fn validate_etiquetas_diagnostic_carries_offending_tag() {
9042        // Diagnostic-shape pin (peer with
9043        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`):
9044        // the error's Display surfaces the offending tag verbatim, so a
9045        // `feira lint` run can render the diagnostic without re-parsing
9046        // and the author can grep their caixa.lisp for the offending
9047        // value.
9048        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
9049        let rendered = c.validate_etiquetas().unwrap_err().to_string();
9050        assert!(
9051            rendered.contains(":etiquetas"),
9052            "diagnostic must name the offending slot: {rendered}",
9053        );
9054        assert!(
9055            rendered.contains("demo"),
9056            "diagnostic must quote the offending tag: {rendered}",
9057        );
9058    }
9059
9060    #[test]
9061    fn validate_etiquetas_rejects_leading_whitespace_entry() {
9062        // Canonical paste-from-aligned-doc footgun. Without the shape
9063        // gate `" mesh"` silently passed validate and landed as a
9064        // YAML plain-style scalar with leading whitespace in the
9065        // rendered Chart.yaml `keywords:` array — every YAML 1.2
9066        // dumper trims leading whitespace from plain-style scalars,
9067        // so the authored space round-tripped inconsistently back
9068        // through `caixa.lisp`. Mirrors the peer
9069        // `validate_autores_rejects_leading_whitespace_entry`.
9070        let c = caixa_with_etiquetas(vec![" mesh"]);
9071        let err = c.validate_etiquetas().unwrap_err();
9072        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9073            panic!("expected EtiquetaInvalid, got {err:?}");
9074        };
9075        assert_eq!(etiqueta, " mesh");
9076        assert!(reason.contains("whitespace"), "got: {reason}");
9077    }
9078
9079    #[test]
9080    fn validate_etiquetas_rejects_embedded_newline_entry() {
9081        // Canonical paste-from-multiline-doc footgun — the author
9082        // pasted a multi-tag block into one `:etiquetas` entry
9083        // instead of splitting into one entry per tag. Without the
9084        // shape gate `"mesh\nhttp"` silently passed validate and
9085        // landed as a YAML-illegal multi-line scalar in the rendered
9086        // Chart.yaml `keywords:` array.
9087        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
9088        let err = c.validate_etiquetas().unwrap_err();
9089        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9090            panic!("expected EtiquetaInvalid, got {err:?}");
9091        };
9092        assert_eq!(etiqueta, "mesh\nhttp");
9093        assert!(reason.contains("newline"), "got: {reason}");
9094    }
9095
9096    #[test]
9097    fn validate_etiquetas_rejects_embedded_comma_entry() {
9098        // Canonical CSV-list-separator-confusion footgun: the author
9099        // confused the CSV-style separator convention with the
9100        // `:etiquetas` list grammar. Without the shape gate
9101        // `"mesh,http,grpc"` silently passed validate and landed as a
9102        // single malformed search tag in the rendered Chart.yaml
9103        // `keywords:` array — Artifact Hub's keyword index would
9104        // either silently drop the tag or index it as
9105        // `mesh,http,grpc` instead of three separate tags.
9106        let c = caixa_with_etiquetas(vec!["mesh,http,grpc"]);
9107        let err = c.validate_etiquetas().unwrap_err();
9108        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9109            panic!("expected EtiquetaInvalid, got {err:?}");
9110        };
9111        assert_eq!(etiqueta, "mesh,http,grpc");
9112        assert!(reason.contains('`'), "got: {reason}");
9113        assert!(reason.contains(','), "got: {reason}");
9114    }
9115
9116    #[test]
9117    fn validate_etiquetas_rejects_embedded_slash_entry() {
9118        // Canonical path-separator-confusion footgun: the author
9119        // confused namespace-path notation with the keyword grammar.
9120        let c = caixa_with_etiquetas(vec!["caixa/servico"]);
9121        let err = c.validate_etiquetas().unwrap_err();
9122        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9123            panic!("expected EtiquetaInvalid, got {err:?}");
9124        };
9125        assert_eq!(etiqueta, "caixa/servico");
9126        assert!(reason.contains('/'), "got: {reason}");
9127    }
9128
9129    #[test]
9130    fn validate_etiquetas_rejects_leading_digit_entry() {
9131        // Canonical paste-from-numbered-list footgun: the author
9132        // copied `1. mesh` from a numbered doc and the `1` leaked
9133        // into the tag.
9134        let c = caixa_with_etiquetas(vec!["1mesh"]);
9135        let err = c.validate_etiquetas().unwrap_err();
9136        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9137            panic!("expected EtiquetaInvalid, got {err:?}");
9138        };
9139        assert_eq!(etiqueta, "1mesh");
9140        assert!(reason.contains("digit"), "got: {reason}");
9141    }
9142
9143    #[test]
9144    fn validate_etiquetas_rejects_leading_hyphen_entry() {
9145        // Canonical kebab-leak footgun.
9146        let c = caixa_with_etiquetas(vec!["-foo"]);
9147        let err = c.validate_etiquetas().unwrap_err();
9148        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9149            panic!("expected EtiquetaInvalid, got {err:?}");
9150        };
9151        assert_eq!(etiqueta, "-foo");
9152        assert!(reason.contains('-'), "got: {reason}");
9153    }
9154
9155    #[test]
9156    fn validate_etiquetas_rejects_non_ascii_entry() {
9157        // Canonical paste-from-Unicode-doc footgun. Every legitimate
9158        // search tag is strict ASCII; raw non-ASCII silently
9159        // round-trips inconsistently across NFC/NFD normalization on
9160        // APFS / case-folding filesystems and breaks the Artifact Hub
9161        // keyword search index lookup.
9162        let c = caixa_with_etiquetas(vec!["café"]);
9163        let err = c.validate_etiquetas().unwrap_err();
9164        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9165            panic!("expected EtiquetaInvalid, got {err:?}");
9166        };
9167        assert_eq!(etiqueta, "café");
9168        assert!(reason.contains("non-ASCII"), "got: {reason}");
9169    }
9170
9171    #[test]
9172    fn validate_etiquetas_rejects_period_entry() {
9173        // Canonical namespace-confusion / version-suffix footgun
9174        // (`"http.1"` / `"v1.0"`): Cargo's crates.io keyword grammar
9175        // excludes `.` from the continuation set even though the
9176        // sibling `:caracteristicas` axis (Cargo's feature-name
9177        // grammar) admits it. Tighter than the sibling axis, peer
9178        // with Cargo's own crates.io keyword shape.
9179        let c = caixa_with_etiquetas(vec!["http.1"]);
9180        let err = c.validate_etiquetas().unwrap_err();
9181        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
9182            panic!("expected EtiquetaInvalid, got {err:?}");
9183        };
9184        assert_eq!(etiqueta, "http.1");
9185        assert!(reason.contains('.'), "got: {reason}");
9186    }
9187
9188    #[test]
9189    fn validate_etiquetas_empty_takes_precedence_over_shape() {
9190        // Per-entry empty-first cascade pin: an entry that is both
9191        // empty *and* shape-invalid surfaces `EtiquetaEmpty` (the
9192        // narrower "this entry has no value" structural defect
9193        // dominates the broader shape-predicate diagnostic). The
9194        // empty arm fires before the shape predicate is consulted,
9195        // mirroring the peer `validate_autores_empty_takes_precedence_over_shape`
9196        // cascade established on the sibling universal-axis Vec<String>
9197        // surface.
9198        let c = caixa_with_etiquetas(vec![""]);
9199        let err = c.validate_etiquetas().unwrap_err();
9200        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
9201    }
9202
9203    #[test]
9204    fn validate_etiquetas_shape_takes_precedence_over_duplicate() {
9205        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
9206        // entry that is malformed surfaces `EtiquetaInvalid` even when
9207        // a later entry would have collided on duplicate. The
9208        // per-entry shape arm fires inside the same loop iteration as
9209        // the empty arm, before the seen-set insert at end-of-iteration
9210        // — structural per-entry defects dominate the cross-entry
9211        // uniqueness diagnostic. Mirrors the peer
9212        // `validate_autores_shape_takes_precedence_over_duplicate`.
9213        let c = caixa_with_etiquetas(vec!["mesh\nhttp", "mesh\nhttp"]);
9214        let err = c.validate_etiquetas().unwrap_err();
9215        assert!(
9216            matches!(err, ManifestError::EtiquetaInvalid { .. }),
9217            "got {err:?}",
9218        );
9219    }
9220
9221    #[test]
9222    fn validate_etiquetas_invalid_diagnostic_names_offending_slot_and_value() {
9223        // Diagnostic-shape pin on the new shape arm (peer with
9224        // `validate_autores_invalid_diagnostic_names_offending_slot_and_value`):
9225        // the rendered Display surfaces both the offending slot name
9226        // and the offending value verbatim, so a `feira lint` run
9227        // points the author at the exact `:etiquetas` entry to fix.
9228        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
9229        let rendered = c.validate_etiquetas().unwrap_err().to_string();
9230        assert!(
9231            rendered.contains(":etiquetas"),
9232            "diagnostic must name the offending slot: {rendered}",
9233        );
9234        assert!(
9235            rendered.contains("mesh\\nhttp"),
9236            "diagnostic must quote the offending value (debug-escaped): {rendered}",
9237        );
9238    }
9239
9240    #[test]
9241    fn validate_etiquetas_rejects_at_21_byte_boundary() {
9242        // The 20-byte cap pin — boundary-exceeding case rejected,
9243        // boundary-accepting case passes. Mirrors the peer
9244        // `chart_keyword_shape_rejects_at_21_byte_boundary` substrate-
9245        // side pin, surfaced at the per-axis caller so the cap
9246        // propagates through validate end-to-end. Constructed as a
9247        // single all-`a` token so only the cap arm fires.
9248        let max_ok = "a".repeat(20);
9249        let c = caixa_with_etiquetas(vec![max_ok.as_str()]);
9250        c.validate_etiquetas().unwrap();
9251        let too_long = "a".repeat(21);
9252        let c = caixa_with_etiquetas(vec![too_long.as_str()]);
9253        let err = c.validate_etiquetas().unwrap_err();
9254        let ManifestError::EtiquetaInvalid { reason, .. } = err else {
9255            panic!("expected EtiquetaInvalid, got {err:?}");
9256        };
9257        assert!(reason.contains("20"), "got: {reason}");
9258        assert!(reason.contains("21"), "got: {reason}");
9259    }
9260
9261    #[test]
9262    fn validate_etiquetas_accepts_canonical_shaped_forms() {
9263        // Positive control sweep: every canonical-shaped tag from the
9264        // hello-rio / checkout-aplicacao / pangea-tatara-akeyless
9265        // example fixtures plus the substrate-fixed tags caixa-helm
9266        // unions in at chart render. Drift between this list and the
9267        // substrate-side `chart_keyword_shape_accepts_canonical_forms`
9268        // sweep surfaces here — one source of truth for the rule.
9269        let c = caixa_with_etiquetas(vec![
9270            "example",
9271            "aplicacao",
9272            "mesh",
9273            "ecommerce",
9274            "demo",
9275            "infrastructure",
9276            "aws",
9277            "akeyless",
9278            "pangea-native",
9279            "hello-world",
9280            "wasm",
9281            "rust",
9282            "tatara-lisp",
9283            "caixa-servico",
9284            "lareira",
9285        ]);
9286        c.validate_etiquetas().unwrap();
9287    }
9288
9289    // ── validate_autores — universal-axis maintainer shape ────────────
9290
9291    fn caixa_with_autores(autores: Vec<&str>) -> Caixa {
9292        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9293        c.autores = autores.into_iter().map(String::from).collect();
9294        c
9295    }
9296
9297    #[test]
9298    fn validate_autores_accepts_empty_list() {
9299        // The empty-list identity: `Caixa::template` emits `:autores ()`,
9300        // so the gate is non-disruptive against every existing manifest.
9301        let c = caixa_with_autores(vec![]);
9302        c.validate_autores().unwrap();
9303    }
9304
9305    #[test]
9306    fn validate_autores_accepts_canonical_forms() {
9307        // Positive control sweep: every canonical-shaped non-empty
9308        // distinct maintainer list passes — the hello-rio / checkout-
9309        // aplicacao fixtures' `:autores ("pleme-io")` shape, plus the
9310        // multi-author shape downstream packaging surfaces emit.
9311        let c = caixa_with_autores(vec!["pleme-io"]);
9312        c.validate_autores().unwrap();
9313        let c = caixa_with_autores(vec!["alice <alice@example.com>", "bob <bob@example.com>"]);
9314        c.validate_autores().unwrap();
9315    }
9316
9317    #[test]
9318    fn validate_autores_rejects_empty_entry() {
9319        // Canonical paste-from-blank-doc footgun. Without the gate the
9320        // empty entry rendered as `maintainers: [{name: "", email: null}]`
9321        // in `Chart.yaml`, a no-op maintainer the substrate cannot route
9322        // to.
9323        let c = caixa_with_autores(vec![""]);
9324        let err = c.validate_autores().unwrap_err();
9325        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
9326    }
9327
9328    #[test]
9329    fn validate_autores_rejects_duplicate_entry() {
9330        // Canonical copy-paste-the-wrong-author footgun. Unlike the
9331        // `:etiquetas` peer (caixa-helm's `BTreeSet` collect silently
9332        // dedups the rendered `keywords:` array), the `maintainers:`
9333        // rendering has *no* dedup — duplicates stack verbatim. The
9334        // duplicate-arm names the offending author verbatim.
9335        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
9336        let err = c.validate_autores().unwrap_err();
9337        let ManifestError::AutorDuplicate { autor } = err else {
9338            panic!("expected AutorDuplicate, got {err:?}");
9339        };
9340        assert_eq!(autor, "pleme-io");
9341    }
9342
9343    #[test]
9344    fn validate_autores_empty_takes_precedence_over_duplicate() {
9345        // Empty-first cascade pin: `("" "pleme-io" "pleme-io")` surfaces
9346        // `AutorEmpty` not `AutorDuplicate` — the narrower structural
9347        // "this entry has no value" defect dominates the cross-entry
9348        // uniqueness diagnostic. Mirrors the peer empty-before-duplicate
9349        // cascades on `:etiquetas` (`EtiquetaEmpty` before
9350        // `EtiquetaDuplicate`, 360a499), `:caracteristicas`
9351        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
9352        // fc3b4d5), and `:membros :caixa` (`MembroCaixaEmpty` before
9353        // `MembroDuplicate`).
9354        let c = caixa_with_autores(vec!["", "pleme-io", "pleme-io"]);
9355        let err = c.validate_autores().unwrap_err();
9356        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
9357    }
9358
9359    #[test]
9360    fn validate_autores_duplicate_reports_first_collision() {
9361        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
9362        // duplicate (the lexicographically-earliest offending position
9363        // — the second `"a"` at index 2 collides with the first `"a"`
9364        // at index 0), not the later `"b"` collision at index 3,
9365        // peer with every other first-collision diagnostic posture on
9366        // this surface.
9367        let c = caixa_with_autores(vec!["a", "b", "a", "b"]);
9368        let err = c.validate_autores().unwrap_err();
9369        let ManifestError::AutorDuplicate { autor } = err else {
9370            panic!("expected AutorDuplicate, got {err:?}");
9371        };
9372        assert_eq!(autor, "a");
9373    }
9374
9375    #[test]
9376    fn validate_autores_case_sensitive() {
9377        // Case-sensitivity pin: `("Pleme-io" "pleme-io")` is two distinct
9378        // entries, mirroring the peer `:etiquetas` / `:membros :caixa`
9379        // / `:children :caixa` exact-string-match discipline.
9380        let c = caixa_with_autores(vec!["Pleme-io", "pleme-io"]);
9381        c.validate_autores().unwrap();
9382    }
9383
9384    #[test]
9385    fn validate_autores_diagnostic_carries_offending_author() {
9386        // Diagnostic-shape pin (peer with
9387        // `validate_etiquetas_diagnostic_carries_offending_tag`): the
9388        // error's Display surfaces the offending author verbatim, so a
9389        // `feira lint` run can render the diagnostic without re-parsing
9390        // and the author can grep their caixa.lisp for the offending
9391        // value.
9392        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
9393        let rendered = c.validate_autores().unwrap_err().to_string();
9394        assert!(
9395            rendered.contains(":autores"),
9396            "diagnostic must name the offending slot: {rendered}",
9397        );
9398        assert!(
9399            rendered.contains("pleme-io"),
9400            "diagnostic must quote the offending author: {rendered}",
9401        );
9402    }
9403
9404    #[test]
9405    fn validate_autores_rejects_leading_whitespace_entry() {
9406        // Canonical paste-from-aligned-doc footgun. Without the shape
9407        // gate `" pleme-io"` silently passed validate and landed as a
9408        // YAML plain-style scalar with leading whitespace in the
9409        // rendered Chart.yaml `maintainers:` array — every YAML 1.2
9410        // dumper trims leading whitespace from plain-style scalars, so
9411        // the authored space round-tripped inconsistently back through
9412        // `caixa.lisp`. Mirrors the peer
9413        // `validate_descricao_rejects_leading_whitespace`.
9414        let c = caixa_with_autores(vec![" pleme-io"]);
9415        let err = c.validate_autores().unwrap_err();
9416        let ManifestError::AutorInvalid { autor, reason } = err else {
9417            panic!("expected AutorInvalid, got {err:?}");
9418        };
9419        assert_eq!(autor, " pleme-io");
9420        assert!(reason.contains("whitespace"), "got: {reason}");
9421    }
9422
9423    #[test]
9424    fn validate_autores_rejects_trailing_whitespace_entry() {
9425        // Canonical paste-from-doc footgun.
9426        let c = caixa_with_autores(vec!["pleme-io "]);
9427        let err = c.validate_autores().unwrap_err();
9428        let ManifestError::AutorInvalid { autor, reason } = err else {
9429            panic!("expected AutorInvalid, got {err:?}");
9430        };
9431        assert_eq!(autor, "pleme-io ");
9432        assert!(reason.contains("whitespace"), "got: {reason}");
9433    }
9434
9435    #[test]
9436    fn validate_autores_rejects_embedded_newline_entry() {
9437        // Canonical paste-from-multiline-doc footgun — the author
9438        // pasted a multi-line block of author records into one
9439        // `:autores` entry instead of splitting into one entry per
9440        // author. Without the shape gate `"alice\nbob"` silently
9441        // passed validate and landed as a YAML-illegal multi-line
9442        // scalar in the rendered Chart.yaml `maintainers:` array.
9443        let c = caixa_with_autores(vec!["alice\nbob"]);
9444        let err = c.validate_autores().unwrap_err();
9445        let ManifestError::AutorInvalid { autor, reason } = err else {
9446            panic!("expected AutorInvalid, got {err:?}");
9447        };
9448        assert_eq!(autor, "alice\nbob");
9449        assert!(reason.contains("newline"), "got: {reason}");
9450    }
9451
9452    #[test]
9453    fn validate_autores_rejects_embedded_carriage_return_entry() {
9454        // Canonical paste-from-Windows-CRLF-doc footgun.
9455        let c = caixa_with_autores(vec!["alice\rbob"]);
9456        let err = c.validate_autores().unwrap_err();
9457        let ManifestError::AutorInvalid { autor, reason } = err else {
9458            panic!("expected AutorInvalid, got {err:?}");
9459        };
9460        assert_eq!(autor, "alice\rbob");
9461        assert!(reason.contains("carriage return"), "got: {reason}");
9462    }
9463
9464    #[test]
9465    fn validate_autores_rejects_embedded_tab_entry() {
9466        // Canonical tab-from-aligned-doc footgun.
9467        let c = caixa_with_autores(vec!["Pleme\tContributors"]);
9468        let err = c.validate_autores().unwrap_err();
9469        let ManifestError::AutorInvalid { autor, reason } = err else {
9470            panic!("expected AutorInvalid, got {err:?}");
9471        };
9472        assert_eq!(autor, "Pleme\tContributors");
9473        assert!(reason.contains("tab"), "got: {reason}");
9474    }
9475
9476    #[test]
9477    fn validate_autores_rejects_embedded_control_bytes_entry() {
9478        // Paste-from-binary-blob footguns: NUL, BEL, ESC, DEL all
9479        // surface the same control-byte arm.
9480        for entry in [
9481            "alice\x00bob",
9482            "alice\x07bob",
9483            "alice\x1bbob",
9484            "alice\x7fbob",
9485        ] {
9486            let c = caixa_with_autores(vec![entry]);
9487            let err = c.validate_autores().unwrap_err();
9488            let ManifestError::AutorInvalid { autor, reason } = err else {
9489                panic!("expected AutorInvalid for {entry:?}, got {err:?}");
9490            };
9491            assert_eq!(autor, entry);
9492            assert!(
9493                reason.contains("control character"),
9494                "{entry:?} reason: {reason}",
9495            );
9496        }
9497    }
9498
9499    #[test]
9500    fn validate_autores_accepts_unicode_entry() {
9501        // Unicode positive control: realistic maintainer names carry
9502        // Unicode (`François`, `日本語`, `naïve`). The predicate must
9503        // round-trip Unicode losslessly, peer with the
9504        // `chart_maintainer_name_shape_accepts_unicode` substrate-side
9505        // sweep.
9506        let c = caixa_with_autores(vec![
9507            "François Dupont",
9508            "日本語の名前",
9509            "naïve <naive@example.com>",
9510        ]);
9511        c.validate_autores().unwrap();
9512    }
9513
9514    #[test]
9515    fn validate_autores_empty_takes_precedence_over_shape() {
9516        // Per-entry empty-first cascade pin: an entry that is both
9517        // empty *and* shape-invalid surfaces `AutorEmpty` (the narrower
9518        // "this entry has no value" structural defect dominates the
9519        // broader shape-predicate diagnostic). The empty arm fires
9520        // before the shape predicate is consulted, mirroring the peer
9521        // `validate_repositorio_empty_takes_precedence_over_shape`
9522        // cascade on the universal `Option<String>` siblings — and now
9523        // established on the Vec<String> per-entry surface.
9524        let c = caixa_with_autores(vec![""]);
9525        let err = c.validate_autores().unwrap_err();
9526        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
9527    }
9528
9529    #[test]
9530    fn validate_autores_shape_takes_precedence_over_duplicate() {
9531        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
9532        // entry that is malformed surfaces `AutorInvalid` even when a
9533        // later entry would have collided on duplicate. The per-entry
9534        // shape arm fires inside the same loop iteration as the empty
9535        // arm, before the seen-set insert at end-of-iteration —
9536        // structural per-entry defects dominate the cross-entry
9537        // uniqueness diagnostic.
9538        let c = caixa_with_autores(vec!["alice\nbob", "alice\nbob"]);
9539        let err = c.validate_autores().unwrap_err();
9540        assert!(
9541            matches!(err, ManifestError::AutorInvalid { .. }),
9542            "got {err:?}",
9543        );
9544    }
9545
9546    #[test]
9547    fn validate_autores_invalid_diagnostic_names_offending_slot_and_value() {
9548        // Diagnostic-shape pin on the new shape arm (peer with
9549        // `validate_descricao_invalid_diagnostic_carries_offending_value`):
9550        // the rendered Display surfaces both the offending slot name
9551        // and the offending value verbatim, so a `feira lint` run
9552        // points the author at the exact `:autores` entry to fix.
9553        let c = caixa_with_autores(vec!["alice\nbob"]);
9554        let rendered = c.validate_autores().unwrap_err().to_string();
9555        assert!(
9556            rendered.contains(":autores"),
9557            "diagnostic must name the offending slot: {rendered}",
9558        );
9559        assert!(
9560            rendered.contains("alice\\nbob"),
9561            "diagnostic must quote the offending value (debug-escaped): {rendered}",
9562        );
9563    }
9564
9565    #[test]
9566    fn validate_autores_rejects_at_129_byte_boundary() {
9567        // The 128-byte cap pin — boundary-exceeding case rejected,
9568        // boundary-accepting case passes. Mirrors the peer
9569        // `chart_maintainer_name_shape_rejects_at_129_byte_boundary`
9570        // substrate-side pin, surfaced at the per-axis caller so the
9571        // cap propagates through validate end-to-end. Constructed as
9572        // a single all-`a` token so only the cap arm fires.
9573        let max_ok = "a".repeat(128);
9574        let c = caixa_with_autores(vec![max_ok.as_str()]);
9575        c.validate_autores().unwrap();
9576        let too_long = "a".repeat(129);
9577        let c = caixa_with_autores(vec![too_long.as_str()]);
9578        let err = c.validate_autores().unwrap_err();
9579        let ManifestError::AutorInvalid { reason, .. } = err else {
9580            panic!("expected AutorInvalid, got {err:?}");
9581        };
9582        assert!(reason.contains("128"), "got: {reason}");
9583        assert!(reason.contains("129"), "got: {reason}");
9584    }
9585
9586    // ── validate_repositorio — universal-axis git-repo-URL shape ──────
9587
9588    fn caixa_with_repositorio(repositorio: Option<&str>) -> Caixa {
9589        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9590        c.repositorio = repositorio.map(String::from);
9591        c
9592    }
9593
9594    #[test]
9595    fn validate_repositorio_accepts_none() {
9596        // The omit-the-slot identity: `:repositorio` is optional. The
9597        // gate is a no-op when the author didn't declare a value —
9598        // every caixa without a `:repositorio` line trivially passes,
9599        // and the substrate-side renderers fall back to their
9600        // documented placeholder (`caixa-helm`'s `home: None`,
9601        // `caixa-flux`'s `https://github.com/pleme-io/<nome>` derived
9602        // URL). Mirrors the peer `validate_restart_window_accepts_none`
9603        // posture on the other `Option<String>` Caixa slot.
9604        let c = caixa_with_repositorio(None);
9605        c.validate_repositorio().unwrap();
9606    }
9607
9608    #[test]
9609    fn validate_repositorio_accepts_canonical_forms() {
9610        // Positive control sweep across every documented `:repositorio`
9611        // authoring shape — the same union the shared
9612        // `crate::render::is_git_repo_url` predicate accepts and the
9613        // peer `:deps :fonte :repo` axis already routes through.
9614        // Covers the `github:` shorthand (the canonical pleme-io
9615        // convention used in the `:repositorio` field of every
9616        // manifest fixture across `caixa-helm` / `caixa-mesh` and the
9617        // `examples/`), the `https://…` URL the README quickstart uses,
9618        // the `ssh://`, `git://`, `git@host:path` scp-style SSH, and
9619        // `file://` URL schemes the shared predicate documents.
9620        for repo in [
9621            "github:pleme-io/hello-rio",
9622            "github:pleme-io/checkout",
9623            "https://github.com/pleme-io/hello-rio",
9624            "ssh://git@github.com/pleme-io/hello-rio.git",
9625            "git://github.com/pleme-io/hello-rio.git",
9626            "git@github.com:pleme-io/hello-rio.git",
9627            "file:///srv/pleme/hello-rio",
9628        ] {
9629            let c = caixa_with_repositorio(Some(repo));
9630            c.validate_repositorio()
9631                .unwrap_or_else(|err| panic!("canonical {repo:?} must pass: {err:?}"));
9632        }
9633    }
9634
9635    #[test]
9636    fn validate_repositorio_rejects_empty_some() {
9637        // Canonical paste-from-blank-doc footgun. The narrower
9638        // [`ManifestError::RepositorioEmpty`] arm fires before the
9639        // shape predicate is consulted, mirroring the empty-first
9640        // cascade every peer per-axis identity gate uses
9641        // (`NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
9642        // `FonteRepoEmpty` → `FonteRepoInvalid`). Without this gate
9643        // the empty `Some("")` silently passed the renderer's
9644        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
9645        // on `None`) and landed as `home: ""` in `Chart.yaml` /
9646        // `url: ""` in the FluxCD `GitRepository`.
9647        let c = caixa_with_repositorio(Some(""));
9648        let err = c.validate_repositorio().unwrap_err();
9649        assert!(
9650            matches!(err, ManifestError::RepositorioEmpty),
9651            "got {err:?}",
9652        );
9653    }
9654
9655    #[test]
9656    fn validate_repositorio_rejects_whitespace() {
9657        // Paste-from-doc whitespace footgun. The shared
9658        // `is_git_repo_url` predicate refuses any whitespace byte; a
9659        // trailing space in a `:repositorio` value silently broke
9660        // `git clone '<value> '` at clone time. The diagnostic names
9661        // the offending value verbatim.
9662        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio "));
9663        let err = c.validate_repositorio().unwrap_err();
9664        let ManifestError::RepositorioInvalid { repositorio, .. } = err else {
9665            panic!("expected RepositorioInvalid, got {err:?}");
9666        };
9667        assert_eq!(repositorio, "github:pleme-io/hello-rio ");
9668    }
9669
9670    #[test]
9671    fn validate_repositorio_rejects_control_char() {
9672        // Paste-from-multiline-doc CRLF footgun — control characters
9673        // at the URL boundary are a class of subprocess-arg injection
9674        // and break git's URL parser at every porcelain entry point.
9675        let c = caixa_with_repositorio(Some("https://example.com/repo\n"));
9676        let err = c.validate_repositorio().unwrap_err();
9677        assert!(
9678            matches!(err, ManifestError::RepositorioInvalid { .. }),
9679            "got {err:?}",
9680        );
9681    }
9682
9683    #[test]
9684    fn validate_repositorio_rejects_leading_dash() {
9685        // Canonical CLI-argument-injection footgun: `git clone <repo>`
9686        // interprets a leading `-` as a CLI flag, so a
9687        // `-upload-pack=…` value escapes the subprocess argument
9688        // boundary. The shared predicate refuses every leading-`-`
9689        // shape at validate time.
9690        let c = caixa_with_repositorio(Some("-upload-pack=evil"));
9691        let err = c.validate_repositorio().unwrap_err();
9692        assert!(
9693            matches!(err, ManifestError::RepositorioInvalid { .. }),
9694            "got {err:?}",
9695        );
9696    }
9697
9698    #[test]
9699    fn validate_repositorio_rejects_missing_colon_separator() {
9700        // The bare `org/repo` ambiguity footgun — `git clone` reads
9701        // a no-`:` form as a relative filesystem path rather than the
9702        // GitHub-shorthand expansion the author probably intended.
9703        // The shared predicate refuses every shape without a `:`
9704        // separator.
9705        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
9706        let err = c.validate_repositorio().unwrap_err();
9707        assert!(
9708            matches!(err, ManifestError::RepositorioInvalid { .. }),
9709            "got {err:?}",
9710        );
9711    }
9712
9713    #[test]
9714    fn validate_repositorio_rejects_fragment_anchor() {
9715        // Paste-from-browser-address-bar footgun on the
9716        // `:repositorio` axis — an author copies a GitHub permalink
9717        // to a README section / line-permalink and forgets to trim
9718        // the `#fragment` tail. The shared `is_git_repo_url`
9719        // predicate refuses the byte at the URL-grammar layer
9720        // (libcurl strips the fragment before opening the
9721        // transport, so the byte rides verbatim into the rendered
9722        // `Chart.yaml` `home:` and FluxCD `GitRepository` `url:`
9723        // fields but is silently dropped on the wire — two
9724        // manifest variants whose values differ only in their
9725        // fragment anchor lock to two distinct rendered artifacts
9726        // for the byte-identical clone, defeating the THEORY.md
9727        // §V.2 render-determinism contract on the `:repositorio`
9728        // axis the peer `:fonte :repo` axis already closes).
9729        let c = caixa_with_repositorio(Some("https://github.com/pleme-io/hello-rio#readme"));
9730        let err = c.validate_repositorio().unwrap_err();
9731        let ManifestError::RepositorioInvalid {
9732            repositorio,
9733            reason,
9734        } = err
9735        else {
9736            panic!("expected RepositorioInvalid, got {err:?}");
9737        };
9738        assert_eq!(repositorio, "https://github.com/pleme-io/hello-rio#readme");
9739        assert!(
9740            reason.contains("must not contain `#`"),
9741            "reason must surface the fragment-`#` arm, got {reason:?}"
9742        );
9743    }
9744
9745    #[test]
9746    fn validate_repositorio_rejects_query_string() {
9747        // Paste-from-browser-address-bar footgun on the
9748        // `:repositorio` axis (peer with the a68f818 fragment-`#`
9749        // arm on the same axis). An author copies a GitHub tab
9750        // deep-link out of the address bar and forgets to trim
9751        // the `?tab=…` query tail. The shared `is_git_repo_url`
9752        // predicate refuses the byte at the URL-grammar layer
9753        // (GitHub / GitLab / Bitbucket silently ignore the
9754        // `?query` tail and serve the same repo regardless, so
9755        // the byte rides verbatim into the rendered `Chart.yaml`
9756        // `home:` and FluxCD `GitRepository` `url:` fields but
9757        // is silently masked at the wire — two manifest variants
9758        // whose values differ only in their query tail lock to
9759        // two distinct rendered artifacts for the byte-identical
9760        // clone, defeating the THEORY.md §V.2 render-determinism
9761        // contract on the `:repositorio` axis the peer `:fonte
9762        // :repo` axis already closes).
9763        let c = caixa_with_repositorio(Some(
9764            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file",
9765        ));
9766        let err = c.validate_repositorio().unwrap_err();
9767        let ManifestError::RepositorioInvalid {
9768            repositorio,
9769            reason,
9770        } = err
9771        else {
9772            panic!("expected RepositorioInvalid, got {err:?}");
9773        };
9774        assert_eq!(
9775            repositorio,
9776            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file"
9777        );
9778        assert!(
9779            reason.contains("must not contain `?`"),
9780            "reason must surface the query-`?` arm, got {reason:?}"
9781        );
9782    }
9783
9784    #[test]
9785    fn validate_repositorio_rejects_embedded_backslash() {
9786        // Windows-file-path-confusion footgun on the `:repositorio`
9787        // axis (peer with the prior fragment-`#` / query-`?` arms on
9788        // the same axis, and peer with the new dep-level `:fonte :repo`
9789        // backslash arm on the URL-grammar trajectory). An author
9790        // pastes a Windows Explorer address-bar `file:///C:\Users\me\
9791        // hello-rio` into the `:repositorio` slot, expecting the
9792        // `lareira-<nome>` chart's `home:` field and the FluxCD
9793        // `GitRepository` `url:` field to render the canonical local
9794        // file-URI. The shared `is_git_repo_url` predicate refuses
9795        // the byte at the URL-grammar layer (libcurl silently
9796        // translates `\` → `/` on some platforms and refuses it on
9797        // others, so the byte rides verbatim into the rendered
9798        // artifacts but is silently rewritten or rejected at the wire
9799        // — two manifest variants whose values differ only in
9800        // backslash-vs-forward-slash lock to two distinct rendered
9801        // artifacts for the byte-identical clone, defeating the
9802        // THEORY.md §V.2 render-determinism contract on the
9803        // `:repositorio` axis the peer `:fonte :repo` axis already
9804        // closes).
9805        let c = caixa_with_repositorio(Some("file:///C:\\Users\\me\\hello-rio"));
9806        let err = c.validate_repositorio().unwrap_err();
9807        let ManifestError::RepositorioInvalid {
9808            repositorio,
9809            reason,
9810        } = err
9811        else {
9812            panic!("expected RepositorioInvalid, got {err:?}");
9813        };
9814        assert_eq!(repositorio, "file:///C:\\Users\\me\\hello-rio");
9815        assert!(
9816            reason.contains("must not contain `\\`"),
9817            "reason must surface the backslash-`\\` arm, got {reason:?}"
9818        );
9819    }
9820
9821    #[test]
9822    fn validate_repositorio_rejects_uri_template_placeholder() {
9823        // URI Template (RFC 6570) placeholder footgun on the
9824        // `:repositorio` axis (peer with the prior fragment-`#` /
9825        // query-`?` / backslash-`\` arms on the same axis, and peer
9826        // with the new dep-level `:fonte :repo` `{` / `}` arm on the
9827        // URL-grammar trajectory). An author pastes a quick-start
9828        // README snippet / OpenAPI `servers:` URL / Helm chart
9829        // `home:` template carrying unresolved `{org}` / `{repo}`
9830        // placeholders into the `:repositorio` slot, expecting the
9831        // substrate to resolve the placeholder downstream. The
9832        // shared `is_git_repo_url` predicate refuses the byte at the
9833        // URL-grammar layer (libcurl percent-encodes `{` / `}` to
9834        // `%7B` / `%7D` on the wire, so the byte round-trips
9835        // inconsistently between the rendered `Chart.yaml home:` /
9836        // FluxCD `GitRepository url:` and the resolver's `git clone`
9837        // invocation, defeating the THEORY.md §V.2 render-
9838        // determinism contract on the `:repositorio` axis the peer
9839        // `:fonte :repo` axis already closes; every git porcelain
9840        // entry-point additionally fetches a nonexistent literal-
9841        // `{placeholder}`-named path far from the source caixa.lisp).
9842        let c = caixa_with_repositorio(Some("https://github.com/{org}/hello-rio"));
9843        let err = c.validate_repositorio().unwrap_err();
9844        let ManifestError::RepositorioInvalid {
9845            repositorio,
9846            reason,
9847        } = err
9848        else {
9849            panic!("expected RepositorioInvalid, got {err:?}");
9850        };
9851        assert_eq!(repositorio, "https://github.com/{org}/hello-rio");
9852        assert!(
9853            reason.contains("must not contain `{`"),
9854            "reason must surface the open-brace `{{` arm, got {reason:?}"
9855        );
9856        assert!(
9857            reason.contains("URI Template") || reason.contains("RFC 6570"),
9858            "reason must name the RFC 6570 URI Template grammar, got {reason:?}"
9859        );
9860    }
9861
9862    #[test]
9863    fn validate_repositorio_empty_takes_precedence_over_shape() {
9864        // Empty-first cascade pin: the empty `Some("")` surfaces the
9865        // narrower `RepositorioEmpty` not the shape-predicate-wrapped
9866        // `RepositorioInvalid`, mirroring the peer
9867        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
9868        // `FonteRepoEmpty` → `FonteRepoInvalid` cascades. The shared
9869        // `is_git_repo_url` predicate also rejects the empty input
9870        // (defensively, with its own `"must not be empty"` reason),
9871        // but the manifest-layer empty arm runs first to surface the
9872        // narrower diagnostic verbatim.
9873        let c = caixa_with_repositorio(Some(""));
9874        let err = c.validate_repositorio().unwrap_err();
9875        assert!(
9876            matches!(err, ManifestError::RepositorioEmpty),
9877            "got {err:?}",
9878        );
9879    }
9880
9881    #[test]
9882    fn validate_repositorio_diagnostic_carries_offending_value() {
9883        // Diagnostic-shape pin (peer with
9884        // `validate_autores_diagnostic_carries_offending_author`): the
9885        // error's Display surfaces the offending value + slot name
9886        // verbatim, so a `feira lint` run can render the diagnostic
9887        // without re-parsing and the author can grep their caixa.lisp
9888        // for the offending `:repositorio` value.
9889        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
9890        let rendered = c.validate_repositorio().unwrap_err().to_string();
9891        assert!(
9892            rendered.contains(":repositorio"),
9893            "diagnostic must name the offending slot: {rendered}",
9894        );
9895        assert!(
9896            rendered.contains("pleme-io/hello-rio"),
9897            "diagnostic must quote the offending value: {rendered}",
9898        );
9899    }
9900
9901    // ── validate_descricao — universal-axis Chart.yaml description shape ──
9902
9903    fn caixa_with_descricao(descricao: Option<&str>) -> Caixa {
9904        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9905        c.descricao = descricao.map(String::from);
9906        c
9907    }
9908
9909    #[test]
9910    fn validate_descricao_accepts_none() {
9911        // The omit-the-slot identity: `:descricao` is optional. The
9912        // gate is a no-op when the author didn't declare a value —
9913        // every caixa without a `:descricao` line trivially passes,
9914        // and the substrate-side renderers fall back to their
9915        // documented `caixa.nome`-derived placeholder. Mirrors the
9916        // peer `validate_repositorio_accepts_none` posture on the
9917        // sibling `Option<String>` Caixa slot.
9918        let c = caixa_with_descricao(None);
9919        c.validate_descricao().unwrap();
9920    }
9921
9922    #[test]
9923    fn validate_descricao_accepts_canonical_summary() {
9924        // Positive control: the canonical pleme-io descricao shape —
9925        // a short free-form prose summary — passes the gate. Covers
9926        // the fixture shapes the `caixa-helm` / `caixa-flux` /
9927        // `caixa-mesh` test fixtures use (`"Canonical Rust→wasm32-
9928        // wasip2 caixa Servico."`, `"Checkout flow."`).
9929        for desc in [
9930            "Canonical Rust→wasm32-wasip2 caixa Servico.",
9931            "Checkout flow.",
9932            "AWS provider caixa for tatara-lisp",
9933            "FIXME — describe this caixa",
9934            "x",
9935        ] {
9936            let c = caixa_with_descricao(Some(desc));
9937            c.validate_descricao()
9938                .unwrap_or_else(|err| panic!("canonical {desc:?} must pass: {err:?}"));
9939        }
9940    }
9941
9942    #[test]
9943    fn validate_descricao_rejects_empty_some() {
9944        // Canonical paste-from-blank-doc footgun. Without this gate
9945        // the empty `Some("")` silently passed the renderer's
9946        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
9947        // on `None`) and landed as `description: ""` in `Chart.yaml`
9948        // and a blank `README.md` header. Mirrors the peer
9949        // [`ManifestError::RepositorioEmpty`] empty-arm on the
9950        // sibling `Option<String>` Caixa slot.
9951        let c = caixa_with_descricao(Some(""));
9952        let err = c.validate_descricao().unwrap_err();
9953        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
9954    }
9955
9956    #[test]
9957    fn validate_descricao_rejects_leading_whitespace() {
9958        // Paste-from-aligned-doc footgun: a leading ASCII space the
9959        // bare empty-arm gate accepted, the shape predicate now
9960        // refuses. The diagnostic carries the offending value
9961        // verbatim (with the leading space preserved) so the author
9962        // can grep their caixa.lisp for the exact `:descricao` line
9963        // and fix the round-trip-inconsistent leading whitespace.
9964        // Mirrors the peer
9965        // `validate_licenca_rejects_leading_whitespace` arm on the
9966        // sibling `:licenca` axis.
9967        let c = caixa_with_descricao(Some(" Checkout flow."));
9968        let err = c.validate_descricao().unwrap_err();
9969        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
9970            panic!("expected DescricaoInvalid, got {err:?}");
9971        };
9972        assert_eq!(descricao, " Checkout flow.");
9973        assert!(reason.contains("whitespace"), "got: {reason:?}");
9974    }
9975
9976    #[test]
9977    fn validate_descricao_rejects_trailing_whitespace() {
9978        // Paste-from-doc footgun: a trailing ASCII space the bare
9979        // empty-arm gate accepted, the shape predicate now refuses.
9980        let c = caixa_with_descricao(Some("Checkout flow. "));
9981        let err = c.validate_descricao().unwrap_err();
9982        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
9983            panic!("expected DescricaoInvalid, got {err:?}");
9984        };
9985        assert_eq!(descricao, "Checkout flow. ");
9986        assert!(reason.contains("whitespace"), "got: {reason:?}");
9987    }
9988
9989    #[test]
9990    fn validate_descricao_rejects_embedded_newline() {
9991        // Paste-from-multiline-doc footgun: an embedded LF the bare
9992        // empty-arm gate accepted, the shape predicate now refuses.
9993        // Without this gate the embedded newline silently landed in
9994        // the rendered Chart.yaml as a multi-line YAML block scalar,
9995        // and every chart-aware UI (`helm list`, `helm search`,
9996        // Artifact Hub) renders the description in a single-line
9997        // column so the embedded newline is silently dropped at
9998        // every downstream consumer.
9999        let c = caixa_with_descricao(Some("Checkout\nflow."));
10000        let err = c.validate_descricao().unwrap_err();
10001        assert!(
10002            matches!(err, ManifestError::DescricaoInvalid { .. }),
10003            "got {err:?}",
10004        );
10005        assert!(err.to_string().contains("newline"), "got {err}");
10006    }
10007
10008    #[test]
10009    fn validate_descricao_rejects_embedded_carriage_return() {
10010        // Paste-from-Windows-CRLF-doc footgun.
10011        let c = caixa_with_descricao(Some("Checkout\rflow."));
10012        let err = c.validate_descricao().unwrap_err();
10013        assert!(
10014            matches!(err, ManifestError::DescricaoInvalid { .. }),
10015            "got {err:?}",
10016        );
10017        assert!(err.to_string().contains("carriage return"), "got {err}");
10018    }
10019
10020    #[test]
10021    fn validate_descricao_rejects_embedded_tab() {
10022        // Tab-from-aligned-doc footgun.
10023        let c = caixa_with_descricao(Some("Checkout\tflow."));
10024        let err = c.validate_descricao().unwrap_err();
10025        assert!(
10026            matches!(err, ManifestError::DescricaoInvalid { .. }),
10027            "got {err:?}",
10028        );
10029        assert!(err.to_string().contains("tab"), "got {err}");
10030    }
10031
10032    #[test]
10033    fn validate_descricao_rejects_embedded_control_bytes() {
10034        // Paste-from-binary-blob footgun: every other control byte
10035        // (NUL, BEL, ESC, DEL) is refused at validate time. Mirrors
10036        // the peer SPDX-expression control-byte arm.
10037        for s in [
10038            "Checkout\x00flow.",
10039            "Checkout\x07flow.",
10040            "Checkout\x1bflow.",
10041            "Checkout\x7fflow.",
10042        ] {
10043            let c = caixa_with_descricao(Some(s));
10044            let err = c.validate_descricao().unwrap_err();
10045            assert!(
10046                matches!(err, ManifestError::DescricaoInvalid { .. }),
10047                "{s:?} got {err:?}",
10048            );
10049            assert!(
10050                err.to_string().contains("control character"),
10051                "{s:?} got {err}",
10052            );
10053        }
10054    }
10055
10056    #[test]
10057    fn validate_descricao_accepts_unicode_prose() {
10058        // Positive control: Unicode prose is accepted — the
10059        // canonical fixtures carry `→` (U+2192) and `—` (U+2014),
10060        // and `Caixa::template`'s `"FIXME — describe this caixa"`
10061        // scaffold every `feira init` emits must continue to pass.
10062        for s in [
10063            "Canonical Rust→wasm32-wasip2 caixa Servico.",
10064            "FIXME — describe this caixa",
10065            "Caixa pour le projet tâche",
10066            "日本語の説明",
10067        ] {
10068            let c = caixa_with_descricao(Some(s));
10069            c.validate_descricao()
10070                .unwrap_or_else(|err| panic!("Unicode {s:?} must pass: {err:?}"));
10071        }
10072    }
10073
10074    #[test]
10075    fn validate_descricao_empty_takes_precedence_over_shape() {
10076        // Cascade pin: a `Some("")` surfaces the narrower
10077        // `DescricaoEmpty` arm, not the broader `DescricaoInvalid`
10078        // shape-predicate arm. Mirrors the peer
10079        // `validate_licenca_empty_takes_precedence_over_shape` pin
10080        // on the sibling `:licenca` axis.
10081        let c = caixa_with_descricao(Some(""));
10082        let err = c.validate_descricao().unwrap_err();
10083        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
10084    }
10085
10086    #[test]
10087    fn validate_descricao_invalid_diagnostic_carries_offending_value_and_slot() {
10088        // Diagnostic-shape pin: the error's Display surfaces both
10089        // the `:descricao` slot name and the offending value
10090        // verbatim, so a `feira lint` run can render the diagnostic
10091        // without re-parsing and the author can grep their caixa.lisp
10092        // for the offending `:descricao` line. Mirrors the peer
10093        // `validate_licenca_invalid_diagnostic_carries_offending_value_and_slot`
10094        // pin (ee2e888) on the sibling `:licenca` axis.
10095        // The `{descricao:?}` Debug format escapes embedded control
10096        // bytes; the quoted offending value surfaces as
10097        // `"Checkout\nflow."` (literal backslash-n) in the rendered
10098        // diagnostic. The author can grep their caixa.lisp for the
10099        // literal `Checkout` summary prefix.
10100        let c = caixa_with_descricao(Some("Checkout\nflow."));
10101        let rendered = c.validate_descricao().unwrap_err().to_string();
10102        assert!(
10103            rendered.contains(":descricao"),
10104            "diagnostic must name the offending slot: {rendered}",
10105        );
10106        assert!(
10107            rendered.contains("Checkout\\nflow."),
10108            "diagnostic must quote the offending value (debug-escaped): {rendered}",
10109        );
10110    }
10111
10112    #[test]
10113    fn validate_descricao_template_passes() {
10114        // Round-trip pin: the bare `Caixa::template` shape carries
10115        // `:descricao "FIXME — describe this caixa"` (a non-empty
10116        // sentinel), so the template-derived Caixa passes the gate by
10117        // construction. A future template-shape change that omits or
10118        // empties `:descricao` would surface here as a regression.
10119        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10120        c.validate_descricao().unwrap();
10121    }
10122
10123    #[test]
10124    fn validate_descricao_diagnostic_names_offending_slot() {
10125        // Diagnostic-shape pin (peer with
10126        // `validate_repositorio_diagnostic_carries_offending_value`):
10127        // the error's Display surfaces the `:descricao` slot name
10128        // verbatim, so a `feira lint` run can render the diagnostic
10129        // without re-parsing and the author can grep their caixa.lisp
10130        // for the offending `:descricao` line.
10131        let c = caixa_with_descricao(Some(""));
10132        let rendered = c.validate_descricao().unwrap_err().to_string();
10133        assert!(
10134            rendered.contains(":descricao"),
10135            "diagnostic must name the offending slot: {rendered}",
10136        );
10137    }
10138
10139    // ── validate_licenca — universal-axis chart README license shape ──
10140
10141    fn caixa_with_licenca(licenca: Option<&str>) -> Caixa {
10142        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10143        c.licenca = licenca.map(String::from);
10144        c
10145    }
10146
10147    #[test]
10148    fn validate_licenca_accepts_none() {
10149        // The omit-the-slot identity: `:licenca` is optional. The
10150        // gate is a no-op when the author didn't declare a value —
10151        // every caixa without a `:licenca` line trivially passes,
10152        // and the substrate-side `caixa-helm` renderer falls back to
10153        // the documented `"MIT"` placeholder. Mirrors the peer
10154        // `validate_descricao_accepts_none` posture on the sibling
10155        // `Option<String>` Caixa slot.
10156        let c = caixa_with_licenca(None);
10157        c.validate_licenca().unwrap();
10158    }
10159
10160    #[test]
10161    fn validate_licenca_accepts_canonical_expressions() {
10162        // Positive control: every canonical SPDX expression shape
10163        // pleme-io carries in its existing fixtures + the canonical
10164        // SPDX dual-license / with-exception / `+`-suffix / grouped /
10165        // user-defined-reference shapes all pass the gate. Covers
10166        // the single-license, `OR`-compound, `AND`-compound,
10167        // `WITH`-exception, parenthesis-grouped, `+`-suffix, and
10168        // `LicenseRef-` / `DocumentRef-:LicenseRef-` shapes — every
10169        // production the SPDX 2.1 expression grammar admits that
10170        // sits within the alphabet floor the
10171        // `is_spdx_expression_shape` predicate enforces.
10172        for lic in [
10173            "MIT",
10174            "Apache-2.0",
10175            "Apache-2.0 OR MIT",
10176            "Apache-2.0 AND MIT",
10177            "BSD-3-Clause",
10178            "MPL-2.0",
10179            "GPL-3.0-or-later",
10180            "GPL-2.0+",
10181            "Apache-2.0 WITH LLVM-exception",
10182            "(MIT OR Apache-2.0) AND BSD-3-Clause",
10183            "(MIT OR Apache-2.0) AND BSD-3-Clause AND ISC",
10184            "LicenseRef-MyLicense",
10185            "DocumentRef-spdx-tool:LicenseRef-MIT-Style",
10186            "x",
10187        ] {
10188            let c = caixa_with_licenca(Some(lic));
10189            c.validate_licenca()
10190                .unwrap_or_else(|err| panic!("canonical {lic:?} must pass: {err:?}"));
10191        }
10192    }
10193
10194    #[test]
10195    fn validate_licenca_rejects_trailing_whitespace() {
10196        // Paste-from-doc whitespace footgun. A trailing space in the
10197        // `:licenca` value would silently break a downstream SPDX
10198        // parser that splits on exact `AND` / `OR` / `WITH` keyword
10199        // boundaries. The shape predicate refuses every trailing
10200        // whitespace byte by construction. Peer with
10201        // `validate_repositorio_rejects_whitespace` and
10202        // `validate_edicao_rejects_trailing_whitespace`.
10203        let c = caixa_with_licenca(Some("MIT "));
10204        let err = c.validate_licenca().unwrap_err();
10205        let ManifestError::LicencaInvalid { licenca, .. } = err else {
10206            panic!("expected LicencaInvalid, got {err:?}");
10207        };
10208        assert_eq!(licenca, "MIT ");
10209    }
10210
10211    #[test]
10212    fn validate_licenca_rejects_leading_whitespace() {
10213        // Symmetric paste-from-doc whitespace footgun on the leading
10214        // boundary — the gate refuses every shape that starts with a
10215        // space byte by construction. Peer with
10216        // `validate_edicao_rejects_leading_whitespace`.
10217        let c = caixa_with_licenca(Some(" MIT"));
10218        let err = c.validate_licenca().unwrap_err();
10219        assert!(
10220            matches!(err, ManifestError::LicencaInvalid { .. }),
10221            "got {err:?}",
10222        );
10223    }
10224
10225    #[test]
10226    fn validate_licenca_rejects_control_char() {
10227        // Paste-from-multiline-doc CRLF footgun — control characters
10228        // at the value boundary land as a malformed line in the
10229        // rendered chart `README.md` `## License` section. Peer with
10230        // `validate_repositorio_rejects_control_char` and
10231        // `validate_edicao_rejects_control_char`.
10232        for lic in ["MIT\n", "MIT\r\n", "MIT\rApache-2.0"] {
10233            let c = caixa_with_licenca(Some(lic));
10234            let err = c.validate_licenca().unwrap_err();
10235            assert!(
10236                matches!(err, ManifestError::LicencaInvalid { .. }),
10237                "expected LicencaInvalid on {lic:?}, got {err:?}",
10238            );
10239        }
10240    }
10241
10242    #[test]
10243    fn validate_licenca_rejects_tab() {
10244        // Tab-from-aligned-doc footgun — SPDX expressions use a
10245        // single ASCII space between tokens; a tab breaks every
10246        // downstream SPDX parser that splits on exact `" "`
10247        // boundaries.
10248        let c = caixa_with_licenca(Some("MIT\tOR Apache-2.0"));
10249        let err = c.validate_licenca().unwrap_err();
10250        assert!(
10251            matches!(err, ManifestError::LicencaInvalid { .. }),
10252            "got {err:?}",
10253        );
10254    }
10255
10256    #[test]
10257    fn validate_licenca_rejects_non_ascii() {
10258        // Smart-quote / non-ASCII paste footgun — SPDX identifiers
10259        // are ASCII per the `idstring = 1*(ALPHA / DIGIT / "-" /
10260        // ".")` production. The shape predicate refuses every
10261        // non-ASCII byte by construction; peer with
10262        // `validate_edicao_rejects_non_ascii_lookalike`.
10263        for lic in ["MIT\u{a0}OR Apache-2.0", "MIT\u{2013}1.0", "Café-1.0"] {
10264            let c = caixa_with_licenca(Some(lic));
10265            let err = c.validate_licenca().unwrap_err();
10266            assert!(
10267                matches!(err, ManifestError::LicencaInvalid { .. }),
10268                "expected LicencaInvalid on {lic:?}, got {err:?}",
10269            );
10270        }
10271    }
10272
10273    #[test]
10274    fn validate_licenca_rejects_underscore() {
10275        // Underscore-instead-of-hyphen typo footgun — `Apache_2.0` /
10276        // `MIT_Style` / `BSD_3_Clause` are familiar shapes from
10277        // snake-case identifier conventions that don't apply to the
10278        // SPDX `idstring` grammar (which admits only `ALPHA / DIGIT /
10279        // "-" / "."`). The shape predicate refuses every underscore
10280        // byte by construction.
10281        for lic in ["Apache_2.0", "MIT_Style", "BSD_3_Clause"] {
10282            let c = caixa_with_licenca(Some(lic));
10283            let err = c.validate_licenca().unwrap_err();
10284            assert!(
10285                matches!(err, ManifestError::LicencaInvalid { .. }),
10286                "expected LicencaInvalid on {lic:?}, got {err:?}",
10287            );
10288        }
10289    }
10290
10291    #[test]
10292    fn validate_licenca_rejects_comma_separator() {
10293        // Comma-instead-of-`OR`-keyword colloquial idiom footgun —
10294        // SPDX expressions compose multiple licenses via `AND` / `OR`
10295        // keywords, not the comma separator. The shape predicate
10296        // refuses every comma byte by construction.
10297        for lic in ["MIT, Apache-2.0", "MIT,Apache-2.0"] {
10298            let c = caixa_with_licenca(Some(lic));
10299            let err = c.validate_licenca().unwrap_err();
10300            assert!(
10301                matches!(err, ManifestError::LicencaInvalid { .. }),
10302                "expected LicencaInvalid on {lic:?}, got {err:?}",
10303            );
10304        }
10305    }
10306
10307    #[test]
10308    fn validate_licenca_rejects_slash_dual_license() {
10309        // Slash-dual-license colloquial idiom footgun — the
10310        // `MIT/Apache-2.0` shape is common in Cargo's pre-SPDX
10311        // `package.license` field but non-SPDX; the SPDX equivalent
10312        // is `MIT OR Apache-2.0`. The shape predicate refuses every
10313        // forward-slash byte by construction.
10314        for lic in ["MIT/Apache-2.0", "MIT/BSD-3-Clause"] {
10315            let c = caixa_with_licenca(Some(lic));
10316            let err = c.validate_licenca().unwrap_err();
10317            assert!(
10318                matches!(err, ManifestError::LicencaInvalid { .. }),
10319                "expected LicencaInvalid on {lic:?}, got {err:?}",
10320            );
10321        }
10322    }
10323
10324    #[test]
10325    fn validate_licenca_rejects_semicolon_separator() {
10326        // Semicolon-list-separator confusion footgun — adjacent to
10327        // the comma-separator idiom, every list-separator-belongs-
10328        // to-list-grammar confusion lands here.
10329        let c = caixa_with_licenca(Some("MIT; Apache-2.0"));
10330        let err = c.validate_licenca().unwrap_err();
10331        assert!(
10332            matches!(err, ManifestError::LicencaInvalid { .. }),
10333            "got {err:?}",
10334        );
10335    }
10336
10337    #[test]
10338    fn validate_licenca_empty_takes_precedence_over_shape() {
10339        // Empty-first cascade pin: the empty `Some("")` surfaces the
10340        // narrower `LicencaEmpty` not the shape-predicate-wrapped
10341        // `LicencaInvalid`, mirroring the peer
10342        // `validate_edicao_empty_takes_precedence_over_shape` and
10343        // `validate_repositorio_empty_takes_precedence_over_shape`
10344        // (`RepositorioEmpty` → `RepositorioInvalid`), `NomeEmpty` →
10345        // `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid` cascades.
10346        // The shape predicate also refuses the empty input
10347        // (defensively — `"must not be empty"`), but the manifest-
10348        // layer empty arm runs first to surface the narrower
10349        // diagnostic verbatim.
10350        let c = caixa_with_licenca(Some(""));
10351        let err = c.validate_licenca().unwrap_err();
10352        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
10353    }
10354
10355    #[test]
10356    fn validate_licenca_invalid_diagnostic_carries_offending_value() {
10357        // Diagnostic-shape pin on the shape-predicate arm (peer with
10358        // `validate_edicao_invalid_diagnostic_carries_offending_value`
10359        // and `validate_repositorio_diagnostic_carries_offending_value`):
10360        // the error's Display surfaces the offending value + slot
10361        // name verbatim, so a `feira lint` run can render the
10362        // diagnostic without re-parsing and the author can grep
10363        // their caixa.lisp for the offending `:licenca` value.
10364        let c = caixa_with_licenca(Some("Apache_2.0"));
10365        let rendered = c.validate_licenca().unwrap_err().to_string();
10366        assert!(
10367            rendered.contains(":licenca"),
10368            "diagnostic must name the offending slot: {rendered}",
10369        );
10370        assert!(
10371            rendered.contains("Apache_2.0"),
10372            "diagnostic must quote the offending value: {rendered}",
10373        );
10374    }
10375
10376    #[test]
10377    fn validate_licenca_rejects_empty_some() {
10378        // Canonical paste-from-blank-doc footgun. Without this gate
10379        // the empty `Some("")` silently passed the renderer's
10380        // `Option::unwrap_or_else(|| "MIT".into())` (which only
10381        // fires on `None`) and landed as a bare trailing period in
10382        // the rendered chart `README.md` `## License` section.
10383        // Mirrors the peer [`ManifestError::DescricaoEmpty`] empty-
10384        // arm on the sibling `Option<String>` Caixa slot.
10385        let c = caixa_with_licenca(Some(""));
10386        let err = c.validate_licenca().unwrap_err();
10387        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
10388    }
10389
10390    #[test]
10391    fn validate_licenca_template_passes() {
10392        // Round-trip pin: the bare `Caixa::template` shape (whether
10393        // it carries `:licenca` or omits it) passes the gate by
10394        // construction. A future template-shape change that
10395        // introduced `(:licenca "")` would surface here as a
10396        // regression. Mirrors the peer
10397        // `validate_descricao_template_passes` pin.
10398        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10399        c.validate_licenca().unwrap();
10400    }
10401
10402    #[test]
10403    fn validate_licenca_diagnostic_names_offending_slot() {
10404        // Diagnostic-shape pin (peer with
10405        // `validate_descricao_diagnostic_names_offending_slot`):
10406        // the error's Display surfaces the `:licenca` slot name
10407        // verbatim, so a `feira lint` run can render the diagnostic
10408        // without re-parsing and the author can grep their caixa.lisp
10409        // for the offending `:licenca` line.
10410        let c = caixa_with_licenca(Some(""));
10411        let rendered = c.validate_licenca().unwrap_err().to_string();
10412        assert!(
10413            rendered.contains(":licenca"),
10414            "diagnostic must name the offending slot: {rendered}",
10415        );
10416    }
10417
10418    // ── Caixa::licenca — outer top-level Option<&str> scalar accessor ──
10419
10420    #[test]
10421    fn licenca_returns_licenca_byte_string_verbatim_across_permutations() {
10422        // The canonical per-`Caixa` `:licenca` SPDX-expression scalar
10423        // pin: [`Caixa::licenca`] must return the `:licenca` typed
10424        // byte-string verbatim as an `Option<&str>`, byte-equal to the
10425        // raw `self.licenca.as_deref()` access across every
10426        // representative value in the accept-set — `None` (the "omit
10427        // the slot to defer to the caixa-helm renderer's `MIT`
10428        // fallback" arm every existing fixture without a `:licenca`
10429        // line carries), `Some("")` (a past-the-guard sentinel that
10430        // pins the accessor doesn't perform a silent
10431        // `Some("") → None` collapse on the empty arm — validate
10432        // rejects `Some("")` through `LicencaEmpty` but the accessor
10433        // must ship the raw slot verbatim so a validate-time gate
10434        // regression surfaces at the caixa-helm emit boundary rather
10435        // than being silently absorbed into the fallback), `Some("MIT")`
10436        // (the canonical single-license shape every `feira init`
10437        // template scaffolds), `Some("Apache-2.0 OR MIT")` (the
10438        // canonical `OR`-compound shape the peer
10439        // `validate_licenca_accepts_canonical_expressions` positive
10440        // sweep exercises), `Some("(MIT OR Apache-2.0) AND
10441        // BSD-3-Clause")` (the canonical parenthesis-grouped shape),
10442        // `Some("MIT ")` / `Some(" MIT")` / `Some("MIT\n")` /
10443        // `Some("Apache_2.0")` / `Some("MIT,Apache-2.0")` (past-the-
10444        // guard sentinels — validate rejects each through
10445        // `LicencaInvalid` but the accessor must ship the raw slot
10446        // verbatim).
10447        //
10448        // First outer top-level [`Caixa`] `Option<&str>`-return scalar
10449        // accessor pin on the substrate primitive — opens the "outer
10450        // [`Caixa`] `Option<&str>` scalar" projection pattern the
10451        // sibling per-`Caixa` `:descricao` / `:repositorio` / `:edicao`
10452        // future lifts fold on. Sibling in shape to the peer per-`:placement`
10453        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
10454        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
10455        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
10456        // axes, extended onto the outer top-level [`Caixa`] universal-
10457        // axis surface. Pins against a future silent detour that
10458        // returned an owned `Option<String>` (which would type-check
10459        // but silently allocate on every accessor call, breaking the
10460        // zero-cost projection every peer sibling accessor carries), a
10461        // `Some("") → None` collapse (which would silently absorb the
10462        // `LicencaEmpty` refusal case at the accessor boundary and the
10463        // caixa-helm emit path would silently fall back to `"MIT"` on
10464        // a struct-literal `Caixa { licenca: Some(""), .. }`), or a
10465        // `None → Some("MIT")` collapse (which would silently reify
10466        // the caixa-helm renderer's `"MIT"` fallback at the accessor
10467        // boundary and every downstream consumer keying off the
10468        // `Option::is_none()` discriminator would lose the "author
10469        // omitted the slot" signal).
10470        for licenca in [
10471            None,
10472            Some(""),
10473            Some("MIT"),
10474            Some("Apache-2.0 OR MIT"),
10475            Some("(MIT OR Apache-2.0) AND BSD-3-Clause"),
10476            Some("MIT "),
10477            Some(" MIT"),
10478            Some("MIT\n"),
10479            Some("Apache_2.0"),
10480            Some("MIT,Apache-2.0"),
10481        ] {
10482            let c = caixa_with_licenca(licenca);
10483            assert_eq!(
10484                c.licenca(),
10485                licenca,
10486                "Caixa::licenca must return :licenca verbatim (got {:?}, \
10487                 expected {licenca:?})",
10488                c.licenca(),
10489            );
10490            assert_eq!(
10491                c.licenca(),
10492                c.licenca.as_deref(),
10493                "Caixa::licenca must byte-equal the raw \
10494                 `self.licenca.as_deref()` field access across every \
10495                 value in the Option<&str> accept-set",
10496            );
10497        }
10498    }
10499
10500    #[test]
10501    fn validate_licenca_empty_arm_routes_through_accessor() {
10502        // Composition pin: [`Caixa::validate_licenca`]'s empty-arm gate
10503        // must key off [`Caixa::licenca`], not the raw
10504        // `self.licenca.as_deref()` field access. Structurally: a
10505        // `Caixa { licenca: Some(""), .. }` must surface the
10506        // `LicencaEmpty` refusal exactly, and a
10507        // `Caixa { licenca: Some("MIT"), .. }` (the canonical
10508        // single-license form) must pass validate. The pair jointly
10509        // pins the accessor + validate-gate composition: any future
10510        // silent detour that had the accessor return `None` on the
10511        // empty arm (a `.filter(|s| !s.is_empty())` collapse) would
10512        // silently absorb the `LicencaEmpty` refusal at the accessor
10513        // boundary and the validate gate would accept a struct-literal
10514        // `Caixa { licenca: Some(""), .. }` — the composition pin
10515        // catches that at caixa-core build time.
10516        //
10517        // Peer of the per-`:politicas :circuit-breaker`
10518        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
10519        // accessor-composition pin
10520        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
10521        // on the sibling per-M3-mesh-slot required-`u32` axis — same
10522        // "the validate / shape-gate predicate must route through the
10523        // substrate-primitive typed dispatch" discipline extended onto
10524        // the outer top-level [`Caixa`] universal-axis
10525        // `Option<&str>`-composition surface.
10526        let c = caixa_with_licenca(Some(""));
10527        assert!(
10528            matches!(c.validate_licenca(), Err(ManifestError::LicencaEmpty)),
10529            "validate_licenca must reject licenca == Some(\"\") with \
10530             LicencaEmpty — the accessor and the validate gate must \
10531             route through the same substrate-primitive typed dispatch \
10532             on the :licenca empty arm",
10533        );
10534        let c = caixa_with_licenca(Some("MIT"));
10535        assert!(
10536            c.validate_licenca().is_ok(),
10537            "validate_licenca must accept licenca == Some(\"MIT\") \
10538             (the canonical single-license SPDX shape)",
10539        );
10540    }
10541
10542    #[test]
10543    fn licenca_projects_option_str_by_borrow() {
10544        // The by-borrow pin: [`Caixa::licenca`] returns
10545        // `Option<&str>` by borrow — the `&str` borrows the underlying
10546        // `String` storage of the `Option<String>` slot and the
10547        // accessor must not allocate a fresh `String` on every call.
10548        // Peer of the per-`:placement`
10549        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
10550        // borrow pin on the peer per-M3-mesh-slot
10551        // `Option<&str>`-return axis, extended onto the outer top-
10552        // level [`Caixa`] universal-axis `Option<&str>` shape — the
10553        // accessor's returned `&str` must borrow from `&self` (the
10554        // returned reference's lifetime is tied to `&self`), and
10555        // calling the accessor twice on the same [`Caixa`] must yield
10556        // the same `Option<&str>` verbatim (idempotent, no side
10557        // effects on `&self`).
10558        //
10559        // Pins against a future silent detour that returned an owned
10560        // `Option<String>` (which would type-check but silently
10561        // allocate on every call, breaking the zero-cost projection
10562        // every peer sibling accessor carries), or a one-arm-only
10563        // accessor that returned a saturating value on some sentinel
10564        // input (breaking the pass-through invariant the sibling
10565        // required-scalar accessors carry).
10566        for licenca in [None, Some(""), Some("MIT"), Some("Apache-2.0 OR MIT")] {
10567            let c = caixa_with_licenca(licenca);
10568            let first = c.licenca();
10569            let second = c.licenca();
10570            assert_eq!(
10571                first, second,
10572                "Caixa::licenca must be idempotent — two successive \
10573                 calls on the same &self must return the same \
10574                 Option<&str>",
10575            );
10576            assert_eq!(
10577                first, licenca,
10578                "Caixa::licenca must return :licenca verbatim by \
10579                 borrow — got {first:?}, expected {licenca:?}",
10580            );
10581        }
10582    }
10583
10584    // ── Caixa::repositorio — outer top-level Option<&str> scalar accessor ──
10585
10586    #[test]
10587    fn repositorio_returns_repositorio_byte_string_verbatim_across_permutations() {
10588        // The canonical per-`Caixa` `:repositorio` git-repo-URL scalar
10589        // pin: [`Caixa::repositorio`] must return the `:repositorio`
10590        // typed byte-string verbatim as an `Option<&str>`, byte-equal
10591        // to the raw `self.repositorio.as_deref()` access across every
10592        // representative value in the accept-set — `None` (the "omit
10593        // the slot to defer to the per-renderer placeholder" arm every
10594        // existing fixture without a `:repositorio` line carries),
10595        // `Some("")` (a past-the-guard sentinel that pins the accessor
10596        // doesn't perform a silent `Some("") → None` collapse on the
10597        // empty arm — validate rejects `Some("")` through
10598        // `RepositorioEmpty` but the accessor must ship the raw slot
10599        // verbatim so a validate-time gate regression surfaces at the
10600        // caixa-helm / caixa-flux emit boundary rather than being
10601        // silently absorbed into the per-renderer fallback),
10602        // `Some("github:pleme-io/hello-rio")` (the canonical `github:`
10603        // shorthand every existing manifest fixture across
10604        // `caixa-helm` / `caixa-mesh` and the `examples/` uses),
10605        // `Some("https://github.com/pleme-io/checkout")` (the canonical
10606        // `https://` URL the README quickstart uses),
10607        // `Some("ssh://git@github.com/pleme-io/checkout.git")` /
10608        // `Some("git://github.com/pleme-io/checkout.git")` /
10609        // `Some("git@github.com:pleme-io/checkout.git")` /
10610        // `Some("file:///opt/mirrors/pleme-io/checkout")` (every non-
10611        // github scheme the shared `is_git_repo_url` predicate
10612        // documents), and five past-the-guard sentinels for the
10613        // `RepositorioInvalid` refusal cases (`Some("pleme-io/checkout")`
10614        // missing-colon, `Some("-upload-pack=evil")` leading-dash, /
10615        // `Some("github:pleme-io/checkout?ref=main")` query-string, /
10616        // `Some("github:pleme-io/checkout#main")` fragment-anchor, /
10617        // `Some("github:pleme-io/{tpl}")` URI-template-placeholder — the
10618        // sentinels pin the accessor doesn't silently absorb the
10619        // refusal cases into a fallback).
10620        //
10621        // Second outer top-level [`Caixa`] `Option<&str>`-return scalar
10622        // accessor pin on the substrate primitive — sibling of the peer
10623        // [`Caixa::licenca`] (6d5bc28) pin
10624        // (`licenca_returns_licenca_byte_string_verbatim_across_permutations`)
10625        // that opened the "outer [`Caixa`] `Option<&str>` scalar"
10626        // projection pin pattern this pin folds on. Sibling in shape to
10627        // the peer per-`:placement`
10628        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
10629        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
10630        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
10631        // axes, extended onto the outer top-level [`Caixa`] universal-
10632        // axis surface. Pins against a future silent detour that
10633        // returned an owned `Option<String>` (which would type-check
10634        // but silently allocate on every accessor call, breaking the
10635        // zero-cost projection every peer sibling accessor carries), a
10636        // `Some("") → None` collapse (which would silently absorb the
10637        // `RepositorioEmpty` refusal case at the accessor boundary and
10638        // the caixa-helm `Chart.yaml` `home:` fold would silently
10639        // render a `home: null` / omitted field on a struct-literal
10640        // `Caixa { repositorio: Some(""), .. }`), or a
10641        // `None → Some(<default>)` collapse (which would silently reify
10642        // the per-renderer fallback at the accessor boundary and every
10643        // downstream consumer keying off the `Option::is_none()`
10644        // discriminator would lose the "author omitted the slot"
10645        // signal).
10646        for repositorio in [
10647            None,
10648            Some(""),
10649            Some("github:pleme-io/hello-rio"),
10650            Some("https://github.com/pleme-io/checkout"),
10651            Some("ssh://git@github.com/pleme-io/checkout.git"),
10652            Some("git://github.com/pleme-io/checkout.git"),
10653            Some("git@github.com:pleme-io/checkout.git"),
10654            Some("file:///opt/mirrors/pleme-io/checkout"),
10655            Some("pleme-io/checkout"),
10656            Some("-upload-pack=evil"),
10657            Some("github:pleme-io/checkout?ref=main"),
10658            Some("github:pleme-io/checkout#main"),
10659            Some("github:pleme-io/{tpl}"),
10660        ] {
10661            let c = caixa_with_repositorio(repositorio);
10662            assert_eq!(
10663                c.repositorio(),
10664                repositorio,
10665                "Caixa::repositorio must return :repositorio verbatim \
10666                 (got {:?}, expected {repositorio:?})",
10667                c.repositorio(),
10668            );
10669            assert_eq!(
10670                c.repositorio(),
10671                c.repositorio.as_deref(),
10672                "Caixa::repositorio must byte-equal the raw \
10673                 `self.repositorio.as_deref()` field access across every \
10674                 value in the Option<&str> accept-set",
10675            );
10676        }
10677    }
10678
10679    #[test]
10680    fn validate_repositorio_empty_arm_routes_through_accessor() {
10681        // Composition pin: [`Caixa::validate_repositorio`]'s empty-arm
10682        // gate must key off [`Caixa::repositorio`], not the raw
10683        // `self.repositorio.as_deref()` field access. Structurally: a
10684        // `Caixa { repositorio: Some(""), .. }` must surface the
10685        // `RepositorioEmpty` refusal exactly, and a
10686        // `Caixa { repositorio: Some("github:pleme-io/hello-rio"), .. }`
10687        // (the canonical `github:` shorthand form) must pass validate.
10688        // The pair jointly pins the accessor + validate-gate
10689        // composition: any future silent detour that had the accessor
10690        // return `None` on the empty arm (a `.filter(|s| !s.is_empty())`
10691        // collapse) would silently absorb the `RepositorioEmpty` refusal
10692        // at the accessor boundary and the validate gate would accept a
10693        // struct-literal `Caixa { repositorio: Some(""), .. }` — the
10694        // composition pin catches that at caixa-core build time.
10695        //
10696        // Peer of the [`Caixa::licenca`] (6d5bc28)
10697        // `validate_licenca_empty_arm_routes_through_accessor`
10698        // composition pin on the sibling outer top-level [`Caixa`]
10699        // `Option<&str>` universal-axis surface — same "the validate /
10700        // shape-gate predicate must route through the substrate-
10701        // primitive typed dispatch" discipline extended onto the second
10702        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
10703        // composition surface.
10704        let c = caixa_with_repositorio(Some(""));
10705        assert!(
10706            matches!(
10707                c.validate_repositorio(),
10708                Err(ManifestError::RepositorioEmpty),
10709            ),
10710            "validate_repositorio must reject repositorio == Some(\"\") \
10711             with RepositorioEmpty — the accessor and the validate gate \
10712             must route through the same substrate-primitive typed \
10713             dispatch on the :repositorio empty arm",
10714        );
10715        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio"));
10716        assert!(
10717            c.validate_repositorio().is_ok(),
10718            "validate_repositorio must accept repositorio == \
10719             Some(\"github:pleme-io/hello-rio\") (the canonical \
10720             `github:` shorthand git-repo-URL shape)",
10721        );
10722    }
10723
10724    #[test]
10725    fn repositorio_projects_option_str_by_borrow() {
10726        // The by-borrow pin: [`Caixa::repositorio`] returns
10727        // `Option<&str>` by borrow — the `&str` borrows the underlying
10728        // `String` storage of the `Option<String>` slot and the
10729        // accessor must not allocate a fresh `String` on every call.
10730        // Peer of the per-`:placement`
10731        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) and the
10732        // [`Caixa::licenca`] (6d5bc28) by-borrow pins on the peer
10733        // `Option<&str>`-return axes, extended onto the second outer
10734        // top-level [`Caixa`] universal-axis `Option<&str>` shape —
10735        // the accessor's returned `&str` must borrow from `&self` (the
10736        // returned reference's lifetime is tied to `&self`), and
10737        // calling the accessor twice on the same [`Caixa`] must yield
10738        // the same `Option<&str>` verbatim (idempotent, no side effects
10739        // on `&self`).
10740        //
10741        // Pins against a future silent detour that returned an owned
10742        // `Option<String>` (which would type-check but silently
10743        // allocate on every call, breaking the zero-cost projection
10744        // every peer sibling accessor carries), or a one-arm-only
10745        // accessor that returned a saturating value on some sentinel
10746        // input (breaking the pass-through invariant the sibling
10747        // required-scalar accessors carry).
10748        for repositorio in [
10749            None,
10750            Some(""),
10751            Some("github:pleme-io/hello-rio"),
10752            Some("https://github.com/pleme-io/checkout"),
10753        ] {
10754            let c = caixa_with_repositorio(repositorio);
10755            let first = c.repositorio();
10756            let second = c.repositorio();
10757            assert_eq!(
10758                first, second,
10759                "Caixa::repositorio must be idempotent — two successive \
10760                 calls on the same &self must return the same \
10761                 Option<&str>",
10762            );
10763            assert_eq!(
10764                first, repositorio,
10765                "Caixa::repositorio must return :repositorio verbatim by \
10766                 borrow — got {first:?}, expected {repositorio:?}",
10767            );
10768        }
10769    }
10770
10771    // ── Caixa::canonical_git_url — resolved-git-URL composer ──────────
10772
10773    #[test]
10774    fn canonical_git_url_returns_repositorio_verbatim_on_some_arm() {
10775        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] must
10776        // return the author-declared `:repositorio` byte-string verbatim
10777        // on the `Some` arm — no scheme rewrite, no trailing-slash
10778        // canonicalization, no `github:` → `https://github.com/`
10779        // desugaring. The resolved-URL composer is the projection of
10780        // the raw [`Caixa::repositorio`] `Option<&str>` accessor onto
10781        // the `String`-return arity every substrate-side field-fill
10782        // consumer keys off; on the `Some` arm the projection is
10783        // `str::to_owned` verbatim, so every accept-set value the
10784        // sibling `repositorio_returns_repositorio_byte_string_verbatim_
10785        // across_permutations` pin covers (`https://…`, `github:…`,
10786        // `ssh://…`, `git://…`, `git@…`, `file://…`, and the past-the-
10787        // guard sentinel `pleme-io/…`) must survive the accessor
10788        // byte-equal. Pins against a future silent detour that rewrote
10789        // the `github:` shorthand to the `https://github.com/` full URL
10790        // at the accessor boundary (which would silently split the
10791        // resolved-URL surface from the raw [`Caixa::repositorio`]
10792        // accessor's documented pass-through invariant), or a trailing-
10793        // slash normalization (which would silently break the
10794        // FluxCD `GitRepository` `spec.url` byte-exact match every
10795        // downstream consumer keys the source-controller reconcile off).
10796        for repositorio in [
10797            "github:pleme-io/hello-rio",
10798            "https://github.com/pleme-io/checkout",
10799            "ssh://git@github.com/pleme-io/checkout.git",
10800            "git://github.com/pleme-io/checkout.git",
10801            "git@github.com:pleme-io/checkout.git",
10802            "file:///opt/mirrors/pleme-io/checkout",
10803        ] {
10804            let c = caixa_with_repositorio(Some(repositorio));
10805            assert_eq!(
10806                c.canonical_git_url(),
10807                repositorio,
10808                "Caixa::canonical_git_url on the Some arm must return \
10809                 :repositorio verbatim (got {:?}, expected {repositorio:?})",
10810                c.canonical_git_url(),
10811            );
10812        }
10813    }
10814
10815    #[test]
10816    fn canonical_git_url_falls_back_to_pleme_org_url_on_none_arm() {
10817        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] on the
10818        // `None` arm must emit the substrate's canonical pleme-org github
10819        // URL derived from `caixa.nome()` — `https://github.com/<org>/
10820        // <nome>` with `<org>` bound to [`crate::DEFAULT_PLEME_GIT_ORG`]
10821        // and `<nome>` bound to the typed [`Caixa::nome`] accessor. This
10822        // is the exact byte-image of the prior inline
10823        // [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url`
10824        // composer at caixa-flux/src/lib.rs:2080 that every prior caller
10825        // re-derived open-coded. Pins against a future silent detour
10826        // that migrated the `<org>` segment to a different constant (a
10827        // fork rebranding that split off a new
10828        // `DEFAULT_PLEME_GIT_ORG_MIRROR` const the accessor would need
10829        // to migrate onto), a scheme change (`https://` → `git://` or
10830        // `ssh://`), or a per-`Caixa` `.canonical_git_url_prefix`
10831        // override (which would break the substrate-wide single-source-
10832        // of-truth guarantee this method encodes).
10833        let c = caixa_with_repositorio(None);
10834        let expected = format!(
10835            "https://github.com/{org}/{nome}",
10836            org = crate::DEFAULT_PLEME_GIT_ORG,
10837            nome = c.nome(),
10838        );
10839        assert_eq!(
10840            c.canonical_git_url(),
10841            expected,
10842            "Caixa::canonical_git_url on the None arm must fold through \
10843             the substrate's canonical pleme-org github URL fallback \
10844             `https://github.com/<DEFAULT_PLEME_GIT_ORG>/<nome>` — got \
10845             {:?}, expected {expected:?}",
10846            c.canonical_git_url(),
10847        );
10848    }
10849
10850    #[test]
10851    fn canonical_git_url_byte_matches_manual_composition() {
10852        // Byte-parity pin: [`Caixa::canonical_git_url`] must render
10853        // byte-identically to the manual open-coded
10854        // `caixa.repositorio().map(str::to_owned).unwrap_or_else(||
10855        //  format!("https://github.com/{org}/{nome}", ...))` composition
10856        // every prior substrate-side caller re-derived. Guards the
10857        // paired-site convergence just applied at caixa-flux's
10858        // [`ClusterBundleOpts::for_caixa`] `git_url` composer (which
10859        // now routes through this accessor): a future implementation of
10860        // this method that reordered the format arguments, swapped the
10861        // `<org>` constant for a different one, or interposed a
10862        // canonicalization pass on the `Some` arm surfaces here as a
10863        // caixa-core build-time test failure rather than as a downstream
10864        // FluxCD `GitRepository` reconcile mismatch far from this
10865        // method's source.
10866        for repositorio in [
10867            None,
10868            Some("github:pleme-io/hello-rio"),
10869            Some("https://github.com/pleme-io/checkout"),
10870            Some("ssh://git@github.com/pleme-io/checkout.git"),
10871        ] {
10872            let c = caixa_with_repositorio(repositorio);
10873            let manual = c.repositorio().map_or_else(
10874                || {
10875                    format!(
10876                        "https://github.com/{org}/{nome}",
10877                        org = crate::DEFAULT_PLEME_GIT_ORG,
10878                        nome = c.nome(),
10879                    )
10880                },
10881                str::to_owned,
10882            );
10883            assert_eq!(
10884                c.canonical_git_url(),
10885                manual,
10886                "Caixa::canonical_git_url must byte-equal the manual \
10887                 open-coded `repositorio().map(str::to_owned)\
10888                 .unwrap_or_else(|| format!(...))` composition across \
10889                 every representative :repositorio input — got {:?}, \
10890                 expected {manual:?}",
10891                c.canonical_git_url(),
10892            );
10893        }
10894    }
10895
10896    // ── Caixa::publish_tag — resolved-publish-tag composer ───────────
10897
10898    #[test]
10899    fn publish_tag_composes_prefix_and_versao_on_all_shapes() {
10900        // Fail-before-pass-after pin: [`Caixa::publish_tag`] must compose
10901        // [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] against the caixa's typed
10902        // [`Caixa::versao`] byte-string across every SemVer-2 shape the
10903        // sibling [`validate_versao_accepts_canonical_forms`] positive-set
10904        // sweep documents — bare MAJOR.MINOR.PATCH, pre-release tags
10905        // (`-rc.1`), build metadata (`+build.42`), the combined form, and
10906        // the `0.0.0` boundary case. Every accept-set value the peer
10907        // validate gate lets through must survive the resolved-tag
10908        // projection byte-equal.
10909        for versao in [
10910            "0.1.0",
10911            "0.0.0",
10912            "1.0.0",
10913            "1.2.3-rc.1",
10914            "1.2.3+build.42",
10915            "1.2.3-rc.1+build.42",
10916        ] {
10917            let c = caixa_with_versao(versao);
10918            let expected = format!(
10919                "{prefix}{versao}",
10920                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
10921            );
10922            assert_eq!(
10923                c.publish_tag(),
10924                expected,
10925                "Caixa::publish_tag must compose \
10926                 DEFAULT_PUBLISH_TAG_PREFIX ({prefix:?}) against \
10927                 :versao ({versao:?}) verbatim — got {got:?}, \
10928                 expected {expected:?}",
10929                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
10930                got = c.publish_tag(),
10931            );
10932        }
10933    }
10934
10935    #[test]
10936    fn publish_tag_starts_with_default_publish_tag_prefix() {
10937        // Prefix-shape pin: every [`Caixa::publish_tag`] emission must
10938        // begin with the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
10939        // byte-string on every input, guarding a hypothetical future
10940        // implementation that migrated the prefix segment to an inline
10941        // literal (`"v"`) that would silently drift from any rebrand of
10942        // the lifted constant. Peer to the sibling caixa-flux
10943        // `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`
10944        // test which pins the same prefix invariant at the reader-side
10945        // `GitRefSpec::Tag` emit site.
10946        for versao in ["0.0.0", "0.1.0", "1.2.3-rc.1", "9.9.9+build.1"] {
10947            let c = caixa_with_versao(versao);
10948            let tag = c.publish_tag();
10949            assert!(
10950                tag.starts_with(crate::DEFAULT_PUBLISH_TAG_PREFIX),
10951                "Caixa::publish_tag emission {tag:?} must start with \
10952                 the lifted crate::DEFAULT_PUBLISH_TAG_PREFIX \
10953                 ({prefix:?})",
10954                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
10955            );
10956        }
10957    }
10958
10959    #[test]
10960    fn publish_tag_byte_matches_manual_composition() {
10961        // Byte-parity pin: [`Caixa::publish_tag`] must render byte-
10962        // identically to the manual open-coded
10963        // `format!("{prefix}{versao}", prefix =
10964        //  caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao =
10965        //  caixa.versao())` composition every prior substrate-side
10966        // caller re-derived. Guards the paired-site convergence just
10967        // applied at caixa-flux's [`ClusterBundleOpts::for_caixa`]
10968        // `git_ref` composer (which now routes through this accessor):
10969        // a future implementation of this method that reordered the
10970        // format arguments, swapped the `<prefix>` constant for a
10971        // different one, or interposed a canonicalization pass on the
10972        // `:versao` axis surfaces here as a caixa-core build-time test
10973        // failure rather than as a downstream FluxCD `GitRepository`
10974        // reconcile mismatch far from this method's source.
10975        for versao in [
10976            "0.1.0",
10977            "0.0.0",
10978            "1.2.3-rc.1",
10979            "1.2.3+build.42",
10980            "1.2.3-rc.1+build.42",
10981        ] {
10982            let c = caixa_with_versao(versao);
10983            let manual = format!(
10984                "{prefix}{versao}",
10985                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
10986                versao = c.versao(),
10987            );
10988            assert_eq!(
10989                c.publish_tag(),
10990                manual,
10991                "Caixa::publish_tag must byte-equal the manual \
10992                 open-coded `format!(\"{{prefix}}{{versao}}\", ...)` \
10993                 composition across every representative :versao input \
10994                 — got {got:?}, expected {manual:?}",
10995                got = c.publish_tag(),
10996            );
10997        }
10998    }
10999
11000    // ── Caixa::lareira_chart_name — resolved-chart-name composer ─────
11001
11002    #[test]
11003    fn lareira_chart_name_composes_prefix_and_nome_on_all_shapes() {
11004        // Fail-before-pass-after pin: [`Caixa::lareira_chart_name`] must
11005        // compose [`crate::LAREIRA_CHART_NAME_PREFIX`] against the caixa's
11006        // typed [`Caixa::nome`] byte-string across every DNS-1123 shape
11007        // the sibling [`validate_nome_accepts_canonical_forms`] positive-
11008        // set sweep documents — single-word, hyphen-joined, version-
11009        // suffixed, single-char, two-char, digit-start, retry-suffixed.
11010        // Every accept-set value the peer validate gate lets through must
11011        // survive the resolved-chart-name projection byte-equal.
11012        for nome in [
11013            "checkout",
11014            "cart-v2",
11015            "a",
11016            "db",
11017            "3rd-party-shim",
11018            "payment-retry",
11019            "0",
11020        ] {
11021            let c = caixa_with_nome(nome);
11022            let expected = format!("{prefix}{nome}", prefix = crate::LAREIRA_CHART_NAME_PREFIX);
11023            assert_eq!(
11024                c.lareira_chart_name(),
11025                expected,
11026                "Caixa::lareira_chart_name must compose \
11027                 LAREIRA_CHART_NAME_PREFIX ({prefix:?}) against \
11028                 :nome ({nome:?}) verbatim — got {got:?}, \
11029                 expected {expected:?}",
11030                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
11031                got = c.lareira_chart_name(),
11032            );
11033        }
11034    }
11035
11036    #[test]
11037    fn lareira_chart_name_starts_with_lifted_prefix() {
11038        // Prefix-shape pin: every [`Caixa::lareira_chart_name`] emission
11039        // must begin with the canonical
11040        // [`crate::LAREIRA_CHART_NAME_PREFIX`] byte-string on every
11041        // input, guarding a hypothetical future implementation that
11042        // migrated the prefix segment to an inline literal (`"lareira-"`)
11043        // that would silently drift from any rebrand of the lifted
11044        // constant. Peer to the sibling
11045        // [`publish_tag_starts_with_default_publish_tag_prefix`] pin on
11046        // the co-resident resolved-publish-tag composer's prefix axis.
11047        for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
11048            let c = caixa_with_nome(nome);
11049            let chart = c.lareira_chart_name();
11050            assert!(
11051                chart.starts_with(crate::LAREIRA_CHART_NAME_PREFIX),
11052                "Caixa::lareira_chart_name emission {chart:?} must start \
11053                 with the lifted crate::LAREIRA_CHART_NAME_PREFIX \
11054                 ({prefix:?})",
11055                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
11056            );
11057        }
11058    }
11059
11060    #[test]
11061    fn lareira_chart_name_byte_matches_canonical_helper_composition() {
11062        // Byte-parity pin: [`Caixa::lareira_chart_name`] must render
11063        // byte-identically to the manual open-coded
11064        // `caixa_core::lareira_chart_name(caixa.nome())` two-step
11065        // composition every prior substrate-side caller re-derived.
11066        // Guards the paired-site convergence just applied at caixa-helm's
11067        // [`render_chart_for_servico_with`] `ChartDir.name` composer,
11068        // caixa-flux's [`cluster_bundle`] per-CR `chart_name` binding,
11069        // and caixa-tatara's [`process_for_aplicacao`] `release_name`
11070        // composer (all of which now route through this accessor): a
11071        // future implementation of this method that reordered the
11072        // composition arguments, swapped the `<prefix>` constant for a
11073        // different one, or interposed a canonicalization pass on the
11074        // `:nome` axis surfaces here as a caixa-core build-time test
11075        // failure rather than as a downstream Helm chart-render / FluxCD
11076        // reconcile / tatara Process-CR mismatch far from this method's
11077        // source.
11078        for nome in [
11079            "checkout",
11080            "cart-v2",
11081            "a",
11082            "db",
11083            "3rd-party-shim",
11084            "payment-retry",
11085        ] {
11086            let c = caixa_with_nome(nome);
11087            let manual = crate::lareira_chart_name(c.nome());
11088            assert_eq!(
11089                c.lareira_chart_name(),
11090                manual,
11091                "Caixa::lareira_chart_name must byte-equal the manual \
11092                 open-coded `caixa_core::lareira_chart_name(caixa.nome())` \
11093                 composition across every representative :nome input — \
11094                 got {got:?}, expected {manual:?}",
11095                got = c.lareira_chart_name(),
11096            );
11097        }
11098    }
11099
11100    // ── Caixa::oci_chart_ref — resolved-OCI-chart-ref composer ────────
11101
11102    #[test]
11103    fn oci_chart_ref_composes_scheme_and_lareira_chart_name_on_all_shapes() {
11104        // Fail-before-pass-after pin: [`Caixa::oci_chart_ref`] must
11105        // compose [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied
11106        // `registry` + [`crate::lareira_chart_name`]-of-[`Caixa::nome`]
11107        // across the full paired `(registry, :nome)` accept-set — every
11108        // representative registry the substrate-side emitters carry
11109        // (`ghcr.io/pleme-io/charts`, the canonical CAIXA-SDLC §II
11110        // ArtifactHub-tier registry; `ghcr.io/pleme-io`, the bare-org
11111        // arm the sibling `oci_chart_ref_pins_byte_shape_against_prior_
11112        // inline_format` render-side pin exercises; `registry.example.
11113        // com`, an off-org shape; `localhost:5000`, the local-dev shape
11114        // every `feira chart` iteration path lands under) × every DNS-
11115        // 1123 `:nome` shape the peer `validate_nome_accepts_canonical_
11116        // forms` positive-set sweep documents (single-word, hyphen-
11117        // joined, single-char, two-char, digit-start, retry-suffixed).
11118        // Every accept-set pair the peer validate gates let through must
11119        // survive the resolved-OCI-ref projection byte-equal.
11120        for registry in [
11121            "ghcr.io/pleme-io/charts",
11122            "ghcr.io/pleme-io",
11123            "registry.example.com",
11124            "localhost:5000",
11125        ] {
11126            for nome in [
11127                "checkout",
11128                "cart-v2",
11129                "a",
11130                "db",
11131                "3rd-party-shim",
11132                "payment-retry",
11133                "0",
11134            ] {
11135                let c = caixa_with_nome(nome);
11136                let expected = format!(
11137                    "{scheme}{registry}/{chart}",
11138                    scheme = crate::OCI_SCHEME_PREFIX,
11139                    chart = crate::lareira_chart_name(nome),
11140                );
11141                assert_eq!(
11142                    c.oci_chart_ref(registry),
11143                    expected,
11144                    "Caixa::oci_chart_ref must compose \
11145                     OCI_SCHEME_PREFIX ({scheme:?}) + registry ({registry:?}) + \
11146                     lareira_chart_name(:nome ({nome:?})) verbatim — got {got:?}, \
11147                     expected {expected:?}",
11148                    scheme = crate::OCI_SCHEME_PREFIX,
11149                    got = c.oci_chart_ref(registry),
11150                );
11151            }
11152        }
11153    }
11154
11155    #[test]
11156    fn oci_chart_ref_starts_with_lifted_scheme_prefix() {
11157        // Scheme-prefix-shape pin: every [`Caixa::oci_chart_ref`]
11158        // emission must begin with the canonical
11159        // [`crate::OCI_SCHEME_PREFIX`] byte-string on every input, guarding
11160        // a hypothetical future implementation that migrated the scheme
11161        // segment to an inline literal (`"oci://"`) that would silently
11162        // drift from any rebrand of the lifted constant. Peer to the
11163        // sibling [`publish_tag_starts_with_default_publish_tag_prefix`]
11164        // + [`lareira_chart_name_starts_with_lifted_prefix`] pins on the
11165        // co-resident resolved-publish-tag / resolved-chart-name
11166        // composers' prefix axes.
11167        for registry in [
11168            "ghcr.io/pleme-io/charts",
11169            "ghcr.io/pleme-io",
11170            "localhost:5000",
11171        ] {
11172            for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
11173                let c = caixa_with_nome(nome);
11174                let ref_ = c.oci_chart_ref(registry);
11175                assert!(
11176                    ref_.starts_with(crate::OCI_SCHEME_PREFIX),
11177                    "Caixa::oci_chart_ref emission {ref_:?} must start \
11178                     with the lifted crate::OCI_SCHEME_PREFIX ({scheme:?}) \
11179                     — registry ({registry:?}), :nome ({nome:?})",
11180                    scheme = crate::OCI_SCHEME_PREFIX,
11181                );
11182            }
11183        }
11184    }
11185
11186    #[test]
11187    fn oci_chart_ref_byte_matches_canonical_helper_composition() {
11188        // Byte-parity pin: [`Caixa::oci_chart_ref`] must render byte-
11189        // identically to the manual open-coded
11190        // `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step
11191        // composition every prior substrate-side caller re-derived.
11192        // Guards the paired-site convergence just applied at caixa-
11193        // tatara's [`derive_chart_ref`] helper (which now routes through
11194        // this accessor): a future implementation of this method that
11195        // reordered the composition arguments, swapped the `<scheme>`
11196        // constant for a different one, migrated the `<chart>` segment
11197        // off the paired [`crate::lareira_chart_name`] composer, or
11198        // interposed a canonicalization pass on either input axis
11199        // surfaces here as a caixa-core build-time test failure rather
11200        // than as a downstream `helm install` / FluxCD OCI-source
11201        // reconcile / tatara `Process`-CR mismatch far from this
11202        // method's source. Sibling to the peer
11203        // [`lareira_chart_name_byte_matches_canonical_helper_composition`]
11204        // / [`publish_tag_byte_matches_manual_composition`] /
11205        // [`canonical_git_url_byte_matches_manual_composition`] byte-
11206        // parity pins that carry the same discipline on the co-resident
11207        // resolved-chart-name / resolved-publish-tag / resolved-git-URL
11208        // composers.
11209        for registry in [
11210            "ghcr.io/pleme-io/charts",
11211            "ghcr.io/pleme-io",
11212            "registry.example.com",
11213            "localhost:5000",
11214        ] {
11215            for nome in [
11216                "checkout",
11217                "cart-v2",
11218                "a",
11219                "db",
11220                "3rd-party-shim",
11221                "payment-retry",
11222            ] {
11223                let c = caixa_with_nome(nome);
11224                let manual = crate::oci_chart_ref(registry, c.nome());
11225                assert_eq!(
11226                    c.oci_chart_ref(registry),
11227                    manual,
11228                    "Caixa::oci_chart_ref must byte-equal the manual \
11229                     open-coded `caixa_core::oci_chart_ref(registry, \
11230                     caixa.nome())` composition across every representative \
11231                     (registry, :nome) pair — registry ({registry:?}), \
11232                     :nome ({nome:?}), got {got:?}, expected {manual:?}",
11233                    got = c.oci_chart_ref(registry),
11234                );
11235            }
11236        }
11237    }
11238
11239    // ── Caixa::descricao — outer top-level Option<&str> scalar accessor ──
11240
11241    #[test]
11242    fn descricao_returns_descricao_byte_string_verbatim_across_permutations() {
11243        // The canonical per-`Caixa` `:descricao` free-form-prose scalar
11244        // pin: [`Caixa::descricao`] must return the `:descricao` typed
11245        // byte-string verbatim as an `Option<&str>`, byte-equal to the
11246        // raw `self.descricao.as_deref()` access across every
11247        // representative value in the accept-set — `None` (the "omit
11248        // the slot to defer to the per-renderer `caixa.nome`-derived
11249        // fallback" arm every existing fixture without a `:descricao`
11250        // line carries), `Some("")` (a past-the-guard sentinel that
11251        // pins the accessor doesn't perform a silent `Some("") → None`
11252        // collapse on the empty arm — validate rejects `Some("")`
11253        // through `DescricaoEmpty` but the accessor must ship the raw
11254        // slot verbatim so a validate-time gate regression surfaces at
11255        // the caixa-helm / caixa-feira emit boundary rather than being
11256        // silently absorbed into the per-renderer `caixa.nome`-derived
11257        // fallback), `Some("Checkout flow.")` (the canonical one-line
11258        // prose descriptor the peer
11259        // `validate_descricao_accepts_canonical_value` positive sweep
11260        // exercises), `Some("Canonical Rust→wasm32-wasip2 caixa
11261        // Servico.")` (the multi-byte Unicode continuation-byte shape
11262        // the `hello-rio` fixture carries), `Some("→ — · ✓")` (a
11263        // multi-glyph Unicode shape the peer
11264        // `is_chart_description_shape` predicate accepts), and five
11265        // past-the-guard sentinels for the `DescricaoInvalid` refusal
11266        // cases (`Some(" Checkout flow.")` leading-whitespace,
11267        // `Some("Checkout flow. ")` trailing-whitespace,
11268        // `Some("Checkout\nflow.")` embedded-LF,
11269        // `Some("Checkout\tflow.")` embedded-TAB, and
11270        // `Some("Checkout\x00flow.")` embedded-NUL — the sentinels pin
11271        // the accessor doesn't silently absorb the refusal cases into
11272        // a fallback).
11273        //
11274        // Third outer top-level [`Caixa`] `Option<&str>`-return scalar
11275        // accessor pin on the substrate primitive — sibling of the peer
11276        // [`Caixa::licenca`] (6d5bc28) and [`Caixa::repositorio`]
11277        // (cc7332d) pins that opened the "outer [`Caixa`]
11278        // `Option<&str>` scalar" projection pin pattern this pin folds
11279        // on. Sibling in shape to the peer per-`:placement`
11280        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
11281        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
11282        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
11283        // axes, extended onto the outer top-level [`Caixa`] universal-
11284        // axis surface. Pins against a future silent detour that
11285        // returned an owned `Option<String>` (which would type-check
11286        // but silently allocate on every accessor call, breaking the
11287        // zero-cost projection every peer sibling accessor carries), a
11288        // `Some("") → None` collapse (which would silently absorb the
11289        // `DescricaoEmpty` refusal case at the accessor boundary and
11290        // the caixa-helm `Chart.yaml` `description:` fold would
11291        // silently render a `caixa.nome`-derived fallback on a
11292        // struct-literal `Caixa { descricao: Some(""), .. }`), or a
11293        // `None → Some(<default>)` collapse (which would silently
11294        // reify the per-renderer `caixa.nome`-derived fallback at the
11295        // accessor boundary and every downstream consumer keying off
11296        // the `Option::is_none()` discriminator would lose the "author
11297        // omitted the slot" signal).
11298        for descricao in [
11299            None,
11300            Some(""),
11301            Some("Checkout flow."),
11302            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
11303            Some("→ — · ✓"),
11304            Some(" Checkout flow."),
11305            Some("Checkout flow. "),
11306            Some("Checkout\nflow."),
11307            Some("Checkout\tflow."),
11308            Some("Checkout\x00flow."),
11309        ] {
11310            let c = caixa_with_descricao(descricao);
11311            assert_eq!(
11312                c.descricao(),
11313                descricao,
11314                "Caixa::descricao must return :descricao verbatim (got \
11315                 {:?}, expected {descricao:?})",
11316                c.descricao(),
11317            );
11318            assert_eq!(
11319                c.descricao(),
11320                c.descricao.as_deref(),
11321                "Caixa::descricao must byte-equal the raw \
11322                 `self.descricao.as_deref()` field access across every \
11323                 value in the Option<&str> accept-set",
11324            );
11325        }
11326    }
11327
11328    #[test]
11329    fn validate_descricao_empty_arm_routes_through_accessor() {
11330        // Composition pin: [`Caixa::validate_descricao`]'s empty-arm
11331        // gate must key off [`Caixa::descricao`], not the raw
11332        // `self.descricao.as_deref()` field access. Structurally: a
11333        // `Caixa { descricao: Some(""), .. }` must surface the
11334        // `DescricaoEmpty` refusal exactly, and a
11335        // `Caixa { descricao: Some("Checkout flow."), .. }` (the
11336        // canonical one-line-prose form) must pass validate. The pair
11337        // jointly pins the accessor + validate-gate composition: any
11338        // future silent detour that had the accessor return `None` on
11339        // the empty arm (a `.filter(|s| !s.is_empty())` collapse) would
11340        // silently absorb the `DescricaoEmpty` refusal at the accessor
11341        // boundary and the validate gate would accept a struct-literal
11342        // `Caixa { descricao: Some(""), .. }` — the composition pin
11343        // catches that at caixa-core build time.
11344        //
11345        // Peer of the [`Caixa::licenca`] (6d5bc28)
11346        // `validate_licenca_empty_arm_routes_through_accessor` and
11347        // [`Caixa::repositorio`] (cc7332d)
11348        // `validate_repositorio_empty_arm_routes_through_accessor`
11349        // composition pins on the sibling outer top-level [`Caixa`]
11350        // `Option<&str>` universal-axis surface — same "the validate /
11351        // shape-gate predicate must route through the substrate-
11352        // primitive typed dispatch" discipline extended onto the third
11353        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
11354        // composition surface.
11355        let c = caixa_with_descricao(Some(""));
11356        assert!(
11357            matches!(c.validate_descricao(), Err(ManifestError::DescricaoEmpty),),
11358            "validate_descricao must reject descricao == Some(\"\") \
11359             with DescricaoEmpty — the accessor and the validate gate \
11360             must route through the same substrate-primitive typed \
11361             dispatch on the :descricao empty arm",
11362        );
11363        let c = caixa_with_descricao(Some("Checkout flow."));
11364        assert!(
11365            c.validate_descricao().is_ok(),
11366            "validate_descricao must accept descricao == \
11367             Some(\"Checkout flow.\") (the canonical one-line-prose \
11368             chart-description shape)",
11369        );
11370    }
11371
11372    #[test]
11373    fn descricao_projects_option_str_by_borrow() {
11374        // The by-borrow pin: [`Caixa::descricao`] returns
11375        // `Option<&str>` by borrow — the `&str` borrows the underlying
11376        // `String` storage of the `Option<String>` slot and the
11377        // accessor must not allocate a fresh `String` on every call.
11378        // Peer of the [`Caixa::licenca`] (6d5bc28) and
11379        // [`Caixa::repositorio`] (cc7332d) by-borrow pins on the peer
11380        // outer top-level [`Caixa`] `Option<&str>`-return axes, and of
11381        // the per-`:placement`
11382        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
11383        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
11384        // return axis, extended onto the third outer top-level
11385        // [`Caixa`] universal-axis `Option<&str>` shape — the
11386        // accessor's returned `&str` must borrow from `&self` (the
11387        // returned reference's lifetime is tied to `&self`), and
11388        // calling the accessor twice on the same [`Caixa`] must yield
11389        // the same `Option<&str>` verbatim (idempotent, no side
11390        // effects on `&self`).
11391        //
11392        // Pins against a future silent detour that returned an owned
11393        // `Option<String>` (which would type-check but silently
11394        // allocate on every call, breaking the zero-cost projection
11395        // every peer sibling accessor carries), or a one-arm-only
11396        // accessor that returned a saturating value on some sentinel
11397        // input (breaking the pass-through invariant the sibling
11398        // required-scalar accessors carry).
11399        for descricao in [
11400            None,
11401            Some(""),
11402            Some("Checkout flow."),
11403            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
11404        ] {
11405            let c = caixa_with_descricao(descricao);
11406            let first = c.descricao();
11407            let second = c.descricao();
11408            assert_eq!(
11409                first, second,
11410                "Caixa::descricao must be idempotent — two successive \
11411                 calls on the same &self must return the same \
11412                 Option<&str>",
11413            );
11414            assert_eq!(
11415                first, descricao,
11416                "Caixa::descricao must return :descricao verbatim by \
11417                 borrow — got {first:?}, expected {descricao:?}",
11418            );
11419        }
11420    }
11421
11422    // ── validate_edicao — universal-axis language-edition shape ──
11423
11424    fn caixa_with_edicao(edicao: Option<&str>) -> Caixa {
11425        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11426        c.edicao = edicao.map(String::from);
11427        c
11428    }
11429
11430    #[test]
11431    fn validate_edicao_accepts_none() {
11432        // The omit-the-slot identity: `:edicao` is optional. The
11433        // gate is a no-op when the author didn't declare a value —
11434        // every caixa without an `:edicao` line trivially passes,
11435        // and the substrate-side build pipeline falls back to the
11436        // documented default edition. Mirrors the peer
11437        // `validate_licenca_accepts_none` posture on the sibling
11438        // `Option<String>` Caixa slot.
11439        let c = caixa_with_edicao(None);
11440        c.validate_edicao().unwrap();
11441    }
11442
11443    #[test]
11444    fn validate_edicao_accepts_canonical_value() {
11445        // Positive control: the canonical `"2026"` edition every
11446        // existing renderer-side fixture (`caixa-helm`, `caixa-flux`,
11447        // `caixa-mesh`) carries by construction passes the gate.
11448        // Future-introduced sibling editions (`"2027"`, `"2030"`,
11449        // `"2049"`) that match the same 4-digit ASCII decimal year
11450        // shape must also trivially pass — the structural shape
11451        // predicate accepts every well-formed year regardless of
11452        // whether the substrate yet understands the specific value
11453        // (a future known-edition allowlist tightens that).
11454        for ed in ["2026", "2027", "2030", "2049"] {
11455            let c = caixa_with_edicao(Some(ed));
11456            c.validate_edicao()
11457                .unwrap_or_else(|err| panic!("canonical {ed:?} must pass: {err:?}"));
11458        }
11459    }
11460
11461    #[test]
11462    fn validate_edicao_rejects_empty_some() {
11463        // Canonical paste-from-blank-doc footgun. Without this gate
11464        // the empty `Some("")` silently lands as `(:edicao "")` in
11465        // the rendered caixa.lisp and a future renderer-side
11466        // consumer's `Option::unwrap_or_else` (which only fires on
11467        // `None`) skips its fallback. Mirrors the peer
11468        // [`ManifestError::LicencaEmpty`] empty-arm on the sibling
11469        // `Option<String>` Caixa slot.
11470        let c = caixa_with_edicao(Some(""));
11471        let err = c.validate_edicao().unwrap_err();
11472        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
11473    }
11474
11475    #[test]
11476    fn validate_edicao_rejects_free_form_non_year() {
11477        // Free-form non-year footgun: the bare `"x"` / `"latest"` /
11478        // `"nightly"` shapes carry no operational meaning on the
11479        // substrate's build-time edition selector. Until this gate
11480        // landed the bare empty-arm check let every such value
11481        // through and broke far from the source caixa.lisp. Peer
11482        // with the shape-predicate cascade
11483        // `validate_repositorio_rejects_missing_colon_separator`
11484        // establishes past its own empty arm.
11485        for ed in ["x", "latest", "nightly", "stable"] {
11486            let c = caixa_with_edicao(Some(ed));
11487            let err = c.validate_edicao().unwrap_err();
11488            assert!(
11489                matches!(err, ManifestError::EdicaoInvalid { .. }),
11490                "expected EdicaoInvalid on {ed:?}, got {err:?}",
11491            );
11492        }
11493    }
11494
11495    #[test]
11496    fn validate_edicao_rejects_trailing_whitespace() {
11497        // Paste-from-doc whitespace footgun. A trailing space in
11498        // the `:edicao` value would silently break the substrate's
11499        // build-time edition match-table lookup at the rendered
11500        // artifact's edition-selector consumer. The shape predicate
11501        // refuses every whitespace byte by construction (any byte
11502        // outside `0-9` fails `is_ascii_digit`). Peer with
11503        // `validate_repositorio_rejects_whitespace`.
11504        let c = caixa_with_edicao(Some("2026 "));
11505        let err = c.validate_edicao().unwrap_err();
11506        let ManifestError::EdicaoInvalid { edicao, .. } = err else {
11507            panic!("expected EdicaoInvalid, got {err:?}");
11508        };
11509        assert_eq!(edicao, "2026 ");
11510    }
11511
11512    #[test]
11513    fn validate_edicao_rejects_leading_whitespace() {
11514        // Symmetric paste-from-doc whitespace footgun on the leading
11515        // boundary — the gate refuses every shape with a non-digit
11516        // byte by construction.
11517        let c = caixa_with_edicao(Some(" 2026"));
11518        let err = c.validate_edicao().unwrap_err();
11519        assert!(
11520            matches!(err, ManifestError::EdicaoInvalid { .. }),
11521            "got {err:?}",
11522        );
11523    }
11524
11525    #[test]
11526    fn validate_edicao_rejects_control_char() {
11527        // Paste-from-multiline-doc CRLF footgun — control characters
11528        // at the value boundary break the substrate's build-time
11529        // edition-selector parser. Peer with
11530        // `validate_repositorio_rejects_control_char`.
11531        let c = caixa_with_edicao(Some("2026\n"));
11532        let err = c.validate_edicao().unwrap_err();
11533        assert!(
11534            matches!(err, ManifestError::EdicaoInvalid { .. }),
11535            "got {err:?}",
11536        );
11537    }
11538
11539    #[test]
11540    fn validate_edicao_rejects_non_ascii_lookalike() {
11541        // Fullwidth-keyboard look-alike footgun — `"2026"` is
11542        // the U+FF12 U+FF10 U+FF12 U+FF16 sequence (CJK fullwidth
11543        // digits), 4 codepoints but 12 UTF-8 bytes; the substrate's
11544        // edition selector wants an ASCII year, and the gate
11545        // refuses every non-ASCII shape by construction (length in
11546        // bytes is 12 ≠ 4, *and* every byte falls outside
11547        // `is_ascii_digit`'s `0-9` range).
11548        let c = caixa_with_edicao(Some("2026"));
11549        let err = c.validate_edicao().unwrap_err();
11550        assert!(
11551            matches!(err, ManifestError::EdicaoInvalid { .. }),
11552            "got {err:?}",
11553        );
11554    }
11555
11556    #[test]
11557    fn validate_edicao_rejects_version_tag_prefix() {
11558        // Common version-tag idiom footgun — `"v2026"` / `"e2026"`
11559        // / `"r2026"` are familiar shapes from git-tag / Rust
11560        // edition / release-tag conventions that don't apply to
11561        // the year-shaped edition axis. The shape predicate refuses
11562        // every leading non-digit prefix.
11563        for ed in ["v2026", "e2026", "r2026"] {
11564            let c = caixa_with_edicao(Some(ed));
11565            let err = c.validate_edicao().unwrap_err();
11566            assert!(
11567                matches!(err, ManifestError::EdicaoInvalid { .. }),
11568                "expected EdicaoInvalid on {ed:?}, got {err:?}",
11569            );
11570        }
11571    }
11572
11573    #[test]
11574    fn validate_edicao_rejects_decimal_shape() {
11575        // Decimal-shaped pseudo-version footgun — `"2026.1"` /
11576        // `"2026.0"` are familiar shapes from semver / float
11577        // conventions that don't apply to the year-shaped edition
11578        // axis. The shape predicate refuses every non-digit byte
11579        // (`.` falls outside `is_ascii_digit`).
11580        for ed in ["2026.1", "2026.0", "2026.0.1"] {
11581            let c = caixa_with_edicao(Some(ed));
11582            let err = c.validate_edicao().unwrap_err();
11583            assert!(
11584                matches!(err, ManifestError::EdicaoInvalid { .. }),
11585                "expected EdicaoInvalid on {ed:?}, got {err:?}",
11586            );
11587        }
11588    }
11589
11590    #[test]
11591    fn validate_edicao_rejects_wrong_length_numeric() {
11592        // Wrong-length numeric footgun — `"26"` (truncated) /
11593        // `"202"` (truncated) / `"20260"` (extra digit) / `"00026"`
11594        // (zero-padded too wide) all parse as integers but don't
11595        // name a 4-digit year. The shape predicate refuses every
11596        // value whose length isn't exactly 4 bytes.
11597        for ed in ["26", "202", "20260", "00026", "9"] {
11598            let c = caixa_with_edicao(Some(ed));
11599            let err = c.validate_edicao().unwrap_err();
11600            assert!(
11601                matches!(err, ManifestError::EdicaoInvalid { .. }),
11602                "expected EdicaoInvalid on {ed:?}, got {err:?}",
11603            );
11604        }
11605    }
11606
11607    #[test]
11608    fn validate_edicao_empty_takes_precedence_over_shape() {
11609        // Empty-first cascade pin: the empty `Some("")` surfaces
11610        // the narrower `EdicaoEmpty` not the shape-predicate-
11611        // wrapped `EdicaoInvalid`, mirroring the peer
11612        // `validate_repositorio_empty_takes_precedence_over_shape`
11613        // (`RepositorioEmpty` → `RepositorioInvalid`),
11614        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` →
11615        // `VersaoInvalid`, `FonteRepoEmpty` → `FonteRepoInvalid`
11616        // cascades. The shape predicate also refuses the empty
11617        // input (defensively — `s.len() != 4`), but the
11618        // manifest-layer empty arm runs first to surface the
11619        // narrower diagnostic verbatim.
11620        let c = caixa_with_edicao(Some(""));
11621        let err = c.validate_edicao().unwrap_err();
11622        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
11623    }
11624
11625    #[test]
11626    fn validate_edicao_template_passes() {
11627        // Round-trip pin: the bare `Caixa::template` shape (which
11628        // carries `:edicao "2026"` verbatim) passes the gate by
11629        // construction. A future template-shape change that
11630        // introduced `(:edicao "")` or a non-year value would
11631        // surface here as a regression. Mirrors the peer
11632        // `validate_licenca_template_passes` pin.
11633        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11634        c.validate_edicao().unwrap();
11635    }
11636
11637    #[test]
11638    fn validate_edicao_diagnostic_names_offending_slot() {
11639        // Diagnostic-shape pin (peer with
11640        // `validate_licenca_diagnostic_names_offending_slot`): the
11641        // error's Display surfaces the `:edicao` slot name verbatim,
11642        // so a `feira lint` run can render the diagnostic without
11643        // re-parsing and the author can grep their caixa.lisp for
11644        // the offending `:edicao` line.
11645        let c = caixa_with_edicao(Some(""));
11646        let rendered = c.validate_edicao().unwrap_err().to_string();
11647        assert!(
11648            rendered.contains(":edicao"),
11649            "diagnostic must name the offending slot: {rendered}",
11650        );
11651    }
11652
11653    #[test]
11654    fn validate_edicao_invalid_diagnostic_carries_offending_value() {
11655        // Diagnostic-shape pin on the shape-predicate arm (peer
11656        // with `validate_repositorio_diagnostic_carries_offending_value`):
11657        // the error's Display surfaces the offending value + slot
11658        // name verbatim, so a `feira lint` run can render the
11659        // diagnostic without re-parsing and the author can grep
11660        // their caixa.lisp for the offending `:edicao` value.
11661        let c = caixa_with_edicao(Some("v2026"));
11662        let rendered = c.validate_edicao().unwrap_err().to_string();
11663        assert!(
11664            rendered.contains(":edicao"),
11665            "diagnostic must name the offending slot: {rendered}",
11666        );
11667        assert!(
11668            rendered.contains("v2026"),
11669            "diagnostic must quote the offending value: {rendered}",
11670        );
11671    }
11672
11673    // ── Caixa::edicao — outer top-level Option<&str> scalar accessor ──
11674
11675    #[test]
11676    fn edicao_returns_edicao_byte_string_verbatim_across_permutations() {
11677        // The canonical per-`Caixa` `:edicao` language-edition scalar
11678        // pin: [`Caixa::edicao`] must return the `:edicao` typed
11679        // byte-string verbatim as an `Option<&str>`, byte-equal to the
11680        // raw `self.edicao.as_deref()` access across every representative
11681        // value in the accept-set — `None` (the "omit the slot to defer
11682        // to the substrate's default edition" arm every existing
11683        // [`caixa-resolver`] fixture without an `:edicao` line carries),
11684        // `Some("")` (a past-the-guard sentinel that pins the accessor
11685        // doesn't perform a silent `Some("") → None` collapse on the
11686        // empty arm — validate rejects `Some("")` through `EdicaoEmpty`
11687        // but the accessor must ship the raw slot verbatim so a
11688        // validate-time gate regression surfaces at any future edition-
11689        // aware consumer's boundary rather than being silently absorbed
11690        // into the substrate's default edition), `Some("2026")` (the
11691        // canonical 4-digit-ASCII-decimal-year shape every `feira init`
11692        // template scaffolds via [`Caixa::template`] and every
11693        // renderer-side fixture at `caixa-helm/src/lib.rs:978` /
11694        // `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208`
11695        // carries by construction), `Some("2018")` / `Some("2021")` /
11696        // `Some("2024")` (canonical 4-digit-ASCII-decimal-year shapes
11697        // peer with Cargo's `[package] edition` grammar every future-
11698        // introduced sibling to `"2026"` will follow), and eight
11699        // past-the-guard sentinels for the `EdicaoInvalid` refusal cases
11700        // (`Some("2026 ")` trailing-whitespace, `Some(" 2026")` leading-
11701        // whitespace, `Some("2026\n")` embedded-LF, `Some("2026")`
11702        // fullwidth-non-ASCII-lookalike, `Some("v2026")` version-tag-
11703        // prefix, `Some("2026.1")` decimal-shape, `Some("26")` wrong-
11704        // length-numeric, `Some("latest")` free-form-non-year — the
11705        // sentinels pin the accessor doesn't silently absorb the
11706        // refusal cases into a substrate-default-edition fallback).
11707        //
11708        // Fourth and final outer top-level [`Caixa`] `Option<&str>`-
11709        // return scalar accessor pin on the substrate primitive —
11710        // sibling of the peer [`Caixa::licenca`] (6d5bc28),
11711        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
11712        // (3f16e2f) pins that opened the "outer [`Caixa`]
11713        // `Option<&str>` scalar" projection pin pattern this pin folds
11714        // on. Sibling in shape to the peer per-`:placement`
11715        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
11716        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
11717        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
11718        // axes, extended onto the outer top-level [`Caixa`] universal-
11719        // axis surface's last unlifted `Option<String>` slot. Pins
11720        // against a future silent detour that returned an owned
11721        // `Option<String>` (which would type-check but silently
11722        // allocate on every accessor call, breaking the zero-cost
11723        // projection every peer sibling accessor carries), a
11724        // `Some("") → None` collapse (which would silently absorb the
11725        // `EdicaoEmpty` refusal case at the accessor boundary and any
11726        // future edition-aware consumer would silently fall back to
11727        // the substrate's default edition on a struct-literal
11728        // `Caixa { edicao: Some(""), .. }`), or a
11729        // `None → Some("2026")` collapse (which would silently reify
11730        // the substrate's default edition at the accessor boundary
11731        // and every downstream consumer keying off the
11732        // `Option::is_none()` discriminator would lose the "author
11733        // omitted the slot" signal).
11734        for edicao in [
11735            None,
11736            Some(""),
11737            Some("2026"),
11738            Some("2018"),
11739            Some("2021"),
11740            Some("2024"),
11741            Some("2026 "),
11742            Some(" 2026"),
11743            Some("2026\n"),
11744            Some("2026"),
11745            Some("v2026"),
11746            Some("2026.1"),
11747            Some("26"),
11748            Some("latest"),
11749        ] {
11750            let c = caixa_with_edicao(edicao);
11751            assert_eq!(
11752                c.edicao(),
11753                edicao,
11754                "Caixa::edicao must return :edicao verbatim (got {:?}, \
11755                 expected {edicao:?})",
11756                c.edicao(),
11757            );
11758            assert_eq!(
11759                c.edicao(),
11760                c.edicao.as_deref(),
11761                "Caixa::edicao must byte-equal the raw \
11762                 `self.edicao.as_deref()` field access across every \
11763                 value in the Option<&str> accept-set",
11764            );
11765        }
11766    }
11767
11768    #[test]
11769    fn validate_edicao_empty_arm_routes_through_accessor() {
11770        // Composition pin: [`Caixa::validate_edicao`]'s empty-arm gate
11771        // must key off [`Caixa::edicao`], not the raw
11772        // `self.edicao.as_deref()` field access. Structurally: a
11773        // `Caixa { edicao: Some(""), .. }` must surface the
11774        // `EdicaoEmpty` refusal exactly, and a
11775        // `Caixa { edicao: Some("2026"), .. }` (the canonical
11776        // 4-digit-ASCII-decimal-year form) must pass validate. The
11777        // pair jointly pins the accessor + validate-gate composition:
11778        // any future silent detour that had the accessor return `None`
11779        // on the empty arm (a `.filter(|s| !s.is_empty())` collapse)
11780        // would silently absorb the `EdicaoEmpty` refusal at the
11781        // accessor boundary and the validate gate would accept a
11782        // struct-literal `Caixa { edicao: Some(""), .. }` — the
11783        // composition pin catches that at caixa-core build time.
11784        //
11785        // Peer of the [`Caixa::licenca`] (6d5bc28)
11786        // `validate_licenca_empty_arm_routes_through_accessor`,
11787        // [`Caixa::repositorio`] (cc7332d)
11788        // `validate_repositorio_empty_arm_routes_through_accessor`,
11789        // and [`Caixa::descricao`] (3f16e2f)
11790        // `validate_descricao_empty_arm_routes_through_accessor`
11791        // composition pins on the sibling outer top-level [`Caixa`]
11792        // `Option<&str>` universal-axis surface — same "the validate /
11793        // shape-gate predicate must route through the substrate-
11794        // primitive typed dispatch" discipline extended onto the
11795        // fourth and final outer top-level [`Caixa`] universal-axis
11796        // `Option<&str>`-composition surface, closing the accessor-
11797        // composition family.
11798        let c = caixa_with_edicao(Some(""));
11799        assert!(
11800            matches!(c.validate_edicao(), Err(ManifestError::EdicaoEmpty)),
11801            "validate_edicao must reject edicao == Some(\"\") with \
11802             EdicaoEmpty — the accessor and the validate gate must \
11803             route through the same substrate-primitive typed dispatch \
11804             on the :edicao empty arm",
11805        );
11806        let c = caixa_with_edicao(Some("2026"));
11807        assert!(
11808            c.validate_edicao().is_ok(),
11809            "validate_edicao must accept edicao == Some(\"2026\") \
11810             (the canonical 4-digit-ASCII-decimal-year shape)",
11811        );
11812    }
11813
11814    #[test]
11815    fn edicao_projects_option_str_by_borrow() {
11816        // The by-borrow pin: [`Caixa::edicao`] returns
11817        // `Option<&str>` by borrow — the `&str` borrows the underlying
11818        // `String` storage of the `Option<String>` slot and the
11819        // accessor must not allocate a fresh `String` on every call.
11820        // Peer of the [`Caixa::licenca`] (6d5bc28),
11821        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
11822        // (3f16e2f) by-borrow pins on the peer outer top-level
11823        // [`Caixa`] `Option<&str>`-return axes, and of the
11824        // per-`:placement`
11825        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
11826        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
11827        // return axis, extended onto the fourth and final outer top-
11828        // level [`Caixa`] universal-axis `Option<&str>` shape — the
11829        // accessor's returned `&str` must borrow from `&self` (the
11830        // returned reference's lifetime is tied to `&self`), and
11831        // calling the accessor twice on the same [`Caixa`] must yield
11832        // the same `Option<&str>` verbatim (idempotent, no side
11833        // effects on `&self`).
11834        //
11835        // Pins against a future silent detour that returned an owned
11836        // `Option<String>` (which would type-check but silently
11837        // allocate on every call, breaking the zero-cost projection
11838        // every peer sibling accessor carries), or a one-arm-only
11839        // accessor that returned a saturating value on some sentinel
11840        // input (breaking the pass-through invariant the sibling
11841        // required-scalar accessors carry).
11842        for edicao in [None, Some(""), Some("2026"), Some("2018")] {
11843            let c = caixa_with_edicao(edicao);
11844            let first = c.edicao();
11845            let second = c.edicao();
11846            assert_eq!(
11847                first, second,
11848                "Caixa::edicao must be idempotent — two successive \
11849                 calls on the same &self must return the same \
11850                 Option<&str>",
11851            );
11852            assert_eq!(
11853                first, edicao,
11854                "Caixa::edicao must return :edicao verbatim by \
11855                 borrow — got {first:?}, expected {edicao:?}",
11856            );
11857        }
11858    }
11859
11860    #[test]
11861    fn nome_returns_nome_byte_string_verbatim_across_permutations() {
11862        // The canonical per-`Caixa` `:nome` universal-axis DNS-1123-
11863        // label caixa-identity scalar pin: [`Caixa::nome`] must return
11864        // the `:nome` typed `String` verbatim as `&str`, byte-equal to
11865        // the raw field access across every representative value in
11866        // the accept-set — the canonical `"demo"` template baseline
11867        // (the same `feira init`-scaffolded default the sibling
11868        // `validate_nome_accepts_canonical_template` positive-control
11869        // gate pins), plus every sibling per-typed-slot atom accessor's
11870        // canonical positive-arm byte-string (`"catalog"` per
11871        // [`crate::aplicacao::Membro::nome`], `"cart"` per the peer
11872        // per-`:contratos` `:de`, `"hello-rio"` per the canonical
11873        // `caixa-helm`/`caixa-flux` cross-crate integration-test
11874        // fixture, `"checkout"` per the M3 mesh-slot Aplicacao
11875        // canonical example), plus every past-the-guard sentinel for
11876        // the `NomeEmpty` / `NomeInvalid` / `NomeChartNameBudgetExceeded`
11877        // refusal cases (`""`, `"Bad_Name"`, `"a"` × 56 — 56 bytes fits
11878        // the bare DNS-1123 63-byte cap but overflows the joint
11879        // `lareira-<nome>` chart-name budget the sibling
11880        // [`Caixa::validate_nome_chart_name_budget`] gate closes on).
11881        //
11882        // The past-the-guard sentinels pin the accessor doesn't
11883        // silently absorb the refusal cases into a template-derived
11884        // fallback (a future `.nome().is_empty().then(|| "demo")`
11885        // collapse would silently absorb the `NomeEmpty` refusal at
11886        // the accessor boundary and the validate gate would accept a
11887        // struct-literal `Caixa { nome: "".into(), .. }` — the pin
11888        // catches that at caixa-core build time).
11889        //
11890        // First outer top-level [`Caixa`] `&str`-return required-
11891        // scalar accessor pin — opens the "outer [`Caixa`] `&str`
11892        // required-scalar" projection pattern the sibling per-`Caixa`
11893        // `:versao` future lift folds on. Sibling in shape to the peer
11894        // per-`:membros` [`crate::aplicacao::Membro::nome`] (4a32abf)
11895        // required-`String`-carry accessor pin on the sibling per-
11896        // sub-struct required-axis, extended onto the outer top-level
11897        // [`Caixa`] universal-axis required-`String`-carry axis.
11898        for nome in [
11899            "demo",
11900            "catalog",
11901            "cart",
11902            "hello-rio",
11903            "checkout",
11904            "",
11905            "Bad_Name",
11906            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
11907        ] {
11908            let c = caixa_with_nome(nome);
11909            assert_eq!(
11910                c.nome(),
11911                nome,
11912                "Caixa::nome must return :nome verbatim (got {}, \
11913                 expected {nome})",
11914                c.nome(),
11915            );
11916            assert_eq!(
11917                c.nome(),
11918                c.nome.as_str(),
11919                "Caixa::nome must byte-equal the raw .nome field \
11920                 access across every value in the String accept-set",
11921            );
11922        }
11923    }
11924
11925    #[test]
11926    fn validate_nome_empty_arm_routes_through_accessor() {
11927        // Composition pin: [`Caixa::validate_nome`]'s empty-arm must
11928        // key off [`Caixa::nome`], not the raw `.nome` field access.
11929        // Structurally: a `Caixa { nome: "".into(), .. }` must surface
11930        // the `NomeEmpty` refusal exactly, and the canonical `"demo"`
11931        // template baseline (the peer positive-arm the sibling
11932        // `validate_nome_accepts_canonical_template` gate carves out)
11933        // must pass validate. The pair jointly pins the accessor +
11934        // validate-gate composition: any future silent detour that
11935        // had the accessor return a fresh `"demo"` on the empty arm
11936        // (a `.nome().is_empty().then(|| "demo")` fallback collapse)
11937        // would silently absorb the `NomeEmpty` refusal at the
11938        // accessor boundary and the validate gate would accept a
11939        // struct-literal `Caixa { nome: "".into(), .. }` — the
11940        // composition pin catches that at caixa-core build time.
11941        //
11942        // Peer of the sibling per-`Caixa`
11943        // `validate_licenca_empty_arm_routes_through_accessor` (6d5bc28)
11944        // / `validate_repositorio_empty_arm_routes_through_accessor`
11945        // (cc7332d) / `validate_descricao_empty_arm_routes_through_accessor`
11946        // (3f16e2f) / `validate_edicao_empty_arm_routes_through_accessor`
11947        // (2641cbd) composition pins on the sibling outer top-level
11948        // [`Caixa`] `Option<&str>` axes — same "the validate /
11949        // shape-gate predicate must route through the substrate-
11950        // primitive typed dispatch" discipline extended onto the peer
11951        // outer top-level [`Caixa`] required-`&str` composition axis.
11952        let c = caixa_with_nome("");
11953        assert!(
11954            matches!(c.validate_nome(), Err(ManifestError::NomeEmpty)),
11955            "validate_nome must reject nome == \"\" with NomeEmpty — \
11956             the accessor and the validate gate must route through the \
11957             same substrate-primitive typed dispatch on the :nome \
11958             empty-arm",
11959        );
11960        let c = caixa_with_nome("demo");
11961        assert!(
11962            c.validate_nome().is_ok(),
11963            "validate_nome must accept nome == \"demo\" (the canonical \
11964             DNS-1123-label template baseline)",
11965        );
11966    }
11967
11968    #[test]
11969    fn nome_projects_str_by_borrow() {
11970        // The by-borrow pin: [`Caixa::nome`] returns `&str` by borrow
11971        // — the `&str` borrows the underlying `String` storage of the
11972        // required `nome` slot and the accessor must not allocate a
11973        // fresh `String` on every call. Peer of the [`Caixa::licenca`]
11974        // (6d5bc28) / [`Caixa::repositorio`] (cc7332d) /
11975        // [`Caixa::descricao`] (3f16e2f) / [`Caixa::edicao`] (2641cbd)
11976        // by-borrow pins on the peer outer top-level [`Caixa`]
11977        // `Option<&str>`-return axes, extended onto the first outer
11978        // top-level [`Caixa`] required-`&str`-return axis — the
11979        // accessor's returned `&str` must borrow from `&self` (the
11980        // returned reference's lifetime is tied to `&self`), and
11981        // calling the accessor twice on the same [`Caixa`] must yield
11982        // the same `&str` verbatim (idempotent, no side effects on
11983        // `&self`).
11984        //
11985        // Pins against a future silent detour that returned an owned
11986        // `String` (which would type-check but silently allocate on
11987        // every call, breaking the zero-cost projection every peer
11988        // sibling accessor carries), an accidental
11989        // `.nome.to_lowercase()` detour that returned a fresh
11990        // allocation through an already-DNS-1123-lowercase-only
11991        // string (breaking a future `const fn` regression), or a
11992        // one-arm-only accessor that returned a canonicalized value
11993        // on some sentinel input (breaking the pass-through invariant
11994        // the sibling required-scalar accessors carry).
11995        for nome in ["demo", "catalog", "hello-rio", "checkout"] {
11996            let c = caixa_with_nome(nome);
11997            let first = c.nome();
11998            let second = c.nome();
11999            assert_eq!(
12000                first, second,
12001                "Caixa::nome must be idempotent — two successive calls \
12002                 on the same &self must return the same &str",
12003            );
12004            assert_eq!(
12005                first, nome,
12006                "Caixa::nome must return :nome verbatim by borrow — \
12007                 got {first}, expected {nome}",
12008            );
12009        }
12010    }
12011
12012    #[test]
12013    fn versao_returns_versao_byte_string_verbatim_across_permutations() {
12014        // The canonical per-`Caixa` `:versao` universal-axis SemVer-2
12015        // pinned-version scalar pin: [`Caixa::versao`] must return the
12016        // `:versao` typed `String` verbatim as `&str`, byte-equal to the
12017        // raw `.versao` field access across every representative value
12018        // in the accept-set — the canonical `"0.1.0"` template baseline
12019        // (the same `feira init`-scaffolded default the sibling
12020        // `validate_versao_accepts_canonical_template` positive-control
12021        // gate pins), plus every canonical SemVer-2 shape the sibling
12022        // `validate_versao_accepts_canonical_forms` positive-arm sweep
12023        // covers (`"0.0.0"`, `"1.0.0"`, `"0.2.0-rc.1"`,
12024        // `"1.0.0-alpha.0"`, `"1.0.0+build.42"`, `"1.0.0-rc.1+build.42"`,
12025        // `"10.20.30"`), plus every past-the-guard sentinel for the
12026        // `VersaoEmpty` / `VersaoInvalid` refusal cases (`""` the empty
12027        // arm, `"v0.1.0"` the git-tag-shape-leak footgun, `"0.1"` the
12028        // missing-patch footgun, `"^0.1"` the requirement-shape-leak
12029        // footgun, `"0.1.0.0"` the four-part-Java-convention footgun,
12030        // `"latest"` the docker-tag-shape footgun — the sentinels pin
12031        // the accessor doesn't silently absorb the refusal cases into a
12032        // template-derived fallback like `"0.1.0"`).
12033        //
12034        // The past-the-guard sentinels pin the accessor doesn't silently
12035        // absorb the refusal cases into a template-derived fallback (a
12036        // future `.versao().is_empty().then(|| "0.1.0")` collapse would
12037        // silently absorb the `VersaoEmpty` refusal at the accessor
12038        // boundary and the validate gate would accept a struct-literal
12039        // `Caixa { versao: "".into(), .. }` — the pin catches that at
12040        // caixa-core build time).
12041        //
12042        // Second outer top-level [`Caixa`] `&str`-return required-scalar
12043        // accessor pin — folds on the "outer [`Caixa`] `&str` required-
12044        // scalar" projection pattern the sibling per-`Caixa`
12045        // [`Caixa::nome`] (e6b7d97) opened. Sibling in shape to the peer
12046        // per-`:membros` [`crate::aplicacao::Membro::versao_requirement`]
12047        // (4127bb6) / per-`:children`
12048        // [`crate::supervisor::ChildSpec::versao_requirement`] (2c053c8)
12049        // / per-`:upgrade-from`
12050        // [`crate::UpgradeFromEntry::prior_versao`] (75d27a8) per-sub-
12051        // struct `:versao`-shaped `&str`-return accessor pins on the
12052        // sibling per-typed-slot version-carrier axes, extended onto the
12053        // second outer top-level [`Caixa`] universal-axis required-
12054        // `String`-carry axis so the two universal-axis identity-
12055        // carrying scalars every `defcaixa` form supplies (`:nome` +
12056        // `:versao`) share the same "one typed dispatch per axis" pin
12057        // discipline.
12058        for versao in [
12059            "0.1.0",
12060            "0.0.0",
12061            "1.0.0",
12062            "0.2.0-rc.1",
12063            "1.0.0-alpha.0",
12064            "1.0.0+build.42",
12065            "1.0.0-rc.1+build.42",
12066            "10.20.30",
12067            "",
12068            "v0.1.0",
12069            "0.1",
12070            "^0.1",
12071            "0.1.0.0",
12072            "latest",
12073        ] {
12074            let c = caixa_with_versao(versao);
12075            assert_eq!(
12076                c.versao(),
12077                versao,
12078                "Caixa::versao must return :versao verbatim (got {}, \
12079                 expected {versao})",
12080                c.versao(),
12081            );
12082            assert_eq!(
12083                c.versao(),
12084                c.versao.as_str(),
12085                "Caixa::versao must byte-equal the raw .versao field \
12086                 access across every value in the String accept-set",
12087            );
12088        }
12089    }
12090
12091    #[test]
12092    fn validate_versao_empty_arm_routes_through_accessor() {
12093        // Composition pin: [`Caixa::validate_versao`]'s empty-arm gate
12094        // must key off [`Caixa::versao`], not the raw `.versao` field
12095        // access. Structurally: a `Caixa { versao: "".into(), .. }` must
12096        // surface the `VersaoEmpty` refusal exactly, and the canonical
12097        // `"0.1.0"` template baseline (the peer positive-arm the sibling
12098        // `validate_versao_accepts_canonical_template` gate carves out)
12099        // must pass validate. The pair jointly pins the accessor +
12100        // validate-gate composition: any future silent detour that had
12101        // the accessor return a fresh `"0.1.0"` on the empty arm
12102        // (a `.versao().is_empty().then(|| "0.1.0")` fallback collapse)
12103        // would silently absorb the `VersaoEmpty` refusal at the
12104        // accessor boundary and the validate gate would accept a
12105        // struct-literal `Caixa { versao: "".into(), .. }` — the
12106        // composition pin catches that at caixa-core build time.
12107        //
12108        // Peer of the sibling per-`Caixa`
12109        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97)
12110        // composition pin on the sibling outer top-level [`Caixa`]
12111        // required-`&str` universal-axis surface — same "the validate /
12112        // shape-gate predicate must route through the substrate-
12113        // primitive typed dispatch" discipline extended onto the peer
12114        // outer top-level [`Caixa`] required-`&str` universal-axis
12115        // pinned-version composition axis, closing the second
12116        // coordinate of the "one canonical typed dispatch per per-Caixa
12117        // required-`&str` universal-axis" discipline.
12118        let c = caixa_with_versao("");
12119        assert!(
12120            matches!(c.validate_versao(), Err(ManifestError::VersaoEmpty)),
12121            "validate_versao must reject versao == \"\" with VersaoEmpty — \
12122             the accessor and the validate gate must route through the \
12123             same substrate-primitive typed dispatch on the :versao \
12124             empty-arm",
12125        );
12126        let c = caixa_with_versao("0.1.0");
12127        assert!(
12128            c.validate_versao().is_ok(),
12129            "validate_versao must accept versao == \"0.1.0\" (the \
12130             canonical SemVer-2 template baseline)",
12131        );
12132    }
12133
12134    #[test]
12135    fn versao_projects_str_by_borrow() {
12136        // The by-borrow pin: [`Caixa::versao`] returns `&str` by borrow
12137        // — the `&str` borrows the underlying `String` storage of the
12138        // required `versao` slot and the accessor must not allocate a
12139        // fresh `String` on every call. Peer of the [`Caixa::nome`]
12140        // (e6b7d97) by-borrow pin on the sibling outer top-level
12141        // [`Caixa`] required-`&str`-return axis, extended onto the
12142        // second outer top-level [`Caixa`] required-`&str`-return
12143        // universal-axis pinned-version surface — the accessor's
12144        // returned `&str` must borrow from `&self` (the returned
12145        // reference's lifetime is tied to `&self`), and calling the
12146        // accessor twice on the same [`Caixa`] must yield the same
12147        // `&str` verbatim (idempotent, no side effects on `&self`).
12148        //
12149        // Pins against a future silent detour that returned an owned
12150        // `String` (which would type-check but silently allocate on
12151        // every call, breaking the zero-cost projection every peer
12152        // sibling accessor carries), an accidental
12153        // `semver::Version::parse(&self.versao).unwrap().to_string()`
12154        // detour that returned a canonicalized fresh allocation through
12155        // an already-canonical byte-string (breaking a future `const fn`
12156        // regression and silently absorbing the `VersaoInvalid` refusal
12157        // at the accessor boundary), or a one-arm-only accessor that
12158        // returned a canonicalized value on some sentinel input
12159        // (breaking the pass-through invariant the sibling required-
12160        // scalar accessors carry).
12161        for versao in ["0.1.0", "1.0.0", "0.2.0-rc.1", "1.0.0+build.42"] {
12162            let c = caixa_with_versao(versao);
12163            let first = c.versao();
12164            let second = c.versao();
12165            assert_eq!(
12166                first, second,
12167                "Caixa::versao must be idempotent — two successive \
12168                 calls on the same &self must return the same &str",
12169            );
12170            assert_eq!(
12171                first, versao,
12172                "Caixa::versao must return :versao verbatim by borrow \
12173                 — got {first}, expected {versao}",
12174            );
12175        }
12176    }
12177
12178    fn caixa_with_kind(kind: CaixaKind) -> Caixa {
12179        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12180        c.kind = kind;
12181        c
12182    }
12183
12184    #[test]
12185    fn kind_returns_kind_variant_verbatim_across_permutations() {
12186        // The canonical per-`Caixa` `:kind` universal-axis closed-set-
12187        // enum discriminant pin: [`Caixa::kind`] must return the `:kind`
12188        // typed [`CaixaKind`] variant verbatim by `Copy`, byte-equal to
12189        // the raw `.kind` field access across every variant in the
12190        // closed accept-set (`Biblioteca` — the library kind that
12191        // exports lisp forms; `Binario` — the nix-built executable kind
12192        // under `exe/`; `Servico` — the wasm-component daemon kind
12193        // under `servicos/`; `Supervisor` — the OTP-shaped hierarchical
12194        // reconciliation kind; `Aplicacao` — the M3 typed-mesh
12195        // composition kind).
12196        //
12197        // Pins against a future silent detour that re-derived the kind
12198        // from a peer axis (an accidental fallback to
12199        // `if !servicos.is_empty() { Servico } else if
12200        // !membros.is_empty() { Aplicacao } else { Biblioteca }`
12201        // collapse that read the code-surface / mesh-slot columns into
12202        // the kind discriminator), a variant remap the operator
12203        // authors on one consumer without the other, or a stale-derive
12204        // detour that substituted [`CaixaKind::Biblioteca`] as the
12205        // default when the field held any other variant (which would
12206        // silently collapse the distinction between "author explicitly
12207        // declared `:kind Servico`" and "author declared any other
12208        // kind" every downstream renderer-dispatch site depends on).
12209        //
12210        // First outer top-level [`Caixa`] `Copy`-return required-enum-
12211        // discriminant accessor pin — opens the "outer [`Caixa`]
12212        // `Copy`-return required-discriminant" projection pattern.
12213        // Sibling in shape to the peer per-`:supervisor`
12214        // [`crate::supervisor::SupervisorSpec::estrategia`] (eafb619),
12215        // per-`:placement` [`crate::aplicacao::Placement::estrategia`]
12216        // (921fe1b), and per-`:children`
12217        // [`crate::supervisor::ChildSpec::restart`] (dfb4a81)
12218        // `Copy`-return closed-set-enum discriminant accessor pins on
12219        // the sibling nested-spec typed-slot discriminator axes,
12220        // extended here to the outer top-level [`Caixa`] universal-
12221        // axis surface.
12222        for kind in [
12223            CaixaKind::Biblioteca,
12224            CaixaKind::Binario,
12225            CaixaKind::Servico,
12226            CaixaKind::Supervisor,
12227            CaixaKind::Aplicacao,
12228        ] {
12229            let c = caixa_with_kind(kind);
12230            assert_eq!(
12231                c.kind(),
12232                kind,
12233                "Caixa::kind must return :kind verbatim (got {:?}, \
12234                 expected {kind:?})",
12235                c.kind(),
12236            );
12237            assert_eq!(
12238                c.kind(),
12239                c.kind,
12240                "Caixa::kind accessor and .kind field access must \
12241                 byte-equal — the accessor is the substrate-primitive \
12242                 typed dispatch every downstream kind-gate consumer \
12243                 must route through",
12244            );
12245        }
12246    }
12247
12248    #[test]
12249    fn require_kind_reads_through_lifted_kind_accessor() {
12250        // Two-consumer coherence pin: the [`crate::render::require_kind`]
12251        // entry-gate predicate (the canonical two-line
12252        // `require_kind(caixa, Servico)?` prelude every per-Servico /
12253        // per-Aplicacao renderer runs at its entry-point) and the
12254        // sibling [`crate::render::KindMismatch`] error carrier's
12255        // `actual:` field (which names the offending caixa's variant
12256        // in the diagnostic) must both key off the lifted accessor, so
12257        // any future rebrand on the typed slot's reader shape lands at
12258        // exactly one place. Pins the two-site coherence by exercising
12259        // every off-diagonal `(actual, expected)` pair across the
12260        // closed accept-set — the `KindMismatch { actual, expected }`
12261        // surfaced on the mismatch arm must byte-equal the pair the
12262        // accessor returns for each side.
12263        //
12264        // Peer of the sibling per-`:placement`
12265        // `validate_placement_reads_through_lifted_estrategia_accessor`
12266        // (921fe1b) two-arm consumer-coherence pin on the M3 mesh-slot
12267        // `Copy`-return discriminant axis — same "the entry-gate
12268        // predicate and the error carrier's `actual:` field must route
12269        // through the substrate-primitive typed dispatch" discipline
12270        // extended onto the outer top-level [`Caixa`] universal-axis
12271        // discriminant surface.
12272        for expected in [
12273            CaixaKind::Biblioteca,
12274            CaixaKind::Binario,
12275            CaixaKind::Servico,
12276            CaixaKind::Supervisor,
12277            CaixaKind::Aplicacao,
12278        ] {
12279            for actual in [
12280                CaixaKind::Biblioteca,
12281                CaixaKind::Binario,
12282                CaixaKind::Servico,
12283                CaixaKind::Supervisor,
12284                CaixaKind::Aplicacao,
12285            ] {
12286                let c = caixa_with_kind(actual);
12287                let result = crate::render::require_kind(&c, expected);
12288                if expected == actual {
12289                    assert!(
12290                        result.is_ok(),
12291                        "require_kind must accept when actual == expected \
12292                         (actual={actual:?}, expected={expected:?})",
12293                    );
12294                } else {
12295                    let err = result.expect_err("require_kind must reject when actual != expected");
12296                    assert_eq!(
12297                        err.actual,
12298                        c.kind(),
12299                        "KindMismatch.actual must byte-equal Caixa::kind() \
12300                         — the error carrier's `actual:` field reads \
12301                         through the lifted accessor",
12302                    );
12303                    assert_eq!(
12304                        err.expected, expected,
12305                        "KindMismatch.expected must byte-equal the \
12306                         expected variant passed to require_kind",
12307                    );
12308                }
12309            }
12310        }
12311    }
12312
12313    #[test]
12314    fn aplicacao_view_kind_gate_routes_through_accessor() {
12315        // Composition pin: [`Caixa::aplicacao_view`]'s kind-gate arm
12316        // must key off [`Caixa::kind`], not the raw `.kind` field
12317        // access. Structurally: a `Caixa { kind: X, .. }` for any
12318        // non-`Aplicacao` variant must fold to `None` on the
12319        // `aplicacao_view` composer (the "kind mismatch → no typed
12320        // view" contract every downstream Aplicacao consumer keys off
12321        // via `?`), and a `Caixa { kind: Aplicacao, .. }` must fold to
12322        // `Some(_)`. The pair jointly pins the accessor + view-gate
12323        // composition: any future silent detour that had the accessor
12324        // return a fresh [`CaixaKind::Aplicacao`] on some sentinel
12325        // input would silently absorb the kind-mismatch case at the
12326        // accessor boundary and every per-Aplicacao renderer would
12327        // silently render a non-Aplicacao caixa's mesh slots — the
12328        // composition pin catches that at caixa-core build time.
12329        //
12330        // Peer of the sibling per-`Caixa`
12331        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97) /
12332        // `validate_versao_empty_arm_routes_through_accessor` (20c0539)
12333        // composition pins on the sibling outer top-level [`Caixa`]
12334        // required-`&str` universal-axis surfaces — same "the
12335        // composer / validate gate must route through the substrate-
12336        // primitive typed dispatch" discipline extended onto the
12337        // outer top-level [`Caixa`] `Copy`-return required-
12338        // discriminant composition axis.
12339        for kind in [
12340            CaixaKind::Biblioteca,
12341            CaixaKind::Binario,
12342            CaixaKind::Servico,
12343            CaixaKind::Supervisor,
12344        ] {
12345            let c = caixa_with_kind(kind);
12346            assert!(
12347                c.aplicacao_view().is_none(),
12348                "aplicacao_view must return None on non-Aplicacao \
12349                 kind {kind:?} — the composer's kind-gate must route \
12350                 through Caixa::kind()",
12351            );
12352        }
12353        let c = caixa_with_kind(CaixaKind::Aplicacao);
12354        assert!(
12355            c.aplicacao_view().is_some(),
12356            "aplicacao_view must return Some on kind Aplicacao — \
12357             the composer's kind-gate must accept the matching arm \
12358             through Caixa::kind()",
12359        );
12360    }
12361
12362    #[test]
12363    fn supervisor_view_kind_gate_routes_through_accessor() {
12364        // Composition pin (mirror of the sibling
12365        // `aplicacao_view_kind_gate_routes_through_accessor` on the
12366        // second `_view` composer): [`Caixa::supervisor_view`]'s kind-
12367        // gate arm must key off [`Caixa::kind`], not the raw `.kind`
12368        // field access. A `Caixa { kind: X, .. }` for any non-
12369        // `Supervisor` variant must fold to `None` on the
12370        // `supervisor_view` composer, and a `Caixa { kind:
12371        // Supervisor, .. }` must fold to `Some(_)`. Same peer
12372        // composition pin discipline on the second `_view` composer
12373        // axis.
12374        for kind in [
12375            CaixaKind::Biblioteca,
12376            CaixaKind::Binario,
12377            CaixaKind::Servico,
12378            CaixaKind::Aplicacao,
12379        ] {
12380            let c = caixa_with_kind(kind);
12381            assert!(
12382                c.supervisor_view().is_none(),
12383                "supervisor_view must return None on non-Supervisor \
12384                 kind {kind:?} — the composer's kind-gate must route \
12385                 through Caixa::kind()",
12386            );
12387        }
12388        let mut c = caixa_with_kind(CaixaKind::Supervisor);
12389        // A Supervisor caixa needs a strategy + at least one child to
12390        // fold to a Some(_) that also validates; the composer itself
12391        // requires only the kind arm, so bare kind flip is enough to
12392        // pin the `Some(_)` return, but we populate the minimum
12393        // supervisor shape so a future strengthening of the composer
12394        // to reject an empty spec doesn't false-positive this pin.
12395        c.estrategia = Some(crate::supervisor::RestartStrategy::OneForOne);
12396        c.children = vec![crate::supervisor::ChildSpec {
12397            caixa: "child".into(),
12398            versao: "^0.1".into(),
12399            restart: crate::supervisor::RestartPolicy::Permanent,
12400        }];
12401        assert!(
12402            c.supervisor_view().is_some(),
12403            "supervisor_view must return Some on kind Supervisor — \
12404             the composer's kind-gate must accept the matching arm \
12405             through Caixa::kind()",
12406        );
12407    }
12408
12409    #[test]
12410    fn kind_projects_by_copy() {
12411        // The by-`Copy` pin: [`Caixa::kind`] returns a fresh
12412        // [`CaixaKind`] by `Copy` — the accessor must not borrow from
12413        // `&self` (the returned value is owned, `Copy`-projected from
12414        // the underlying [`CaixaKind`] storage; two calls on the same
12415        // [`Caixa`] must yield byte-equal values). Peer of the peer
12416        // per-`:placement` `Placement::estrategia` / per-`:supervisor`
12417        // `SupervisorSpec::estrategia` / per-`:children`
12418        // `ChildSpec::restart` `Copy`-return discriminant accessor
12419        // pins on the sibling nested-spec typed-slot discriminator
12420        // axes, extended onto the first outer top-level [`Caixa`]
12421        // required-`Copy`-return axis — pins against a future silent
12422        // detour that returned `&CaixaKind` (which would type-check
12423        // but silently constrain every consumer's callsite to a
12424        // borrow-shaped dispatch, breaking the zero-cost `Copy`
12425        // projection every peer sibling accessor carries).
12426        for kind in [
12427            CaixaKind::Biblioteca,
12428            CaixaKind::Binario,
12429            CaixaKind::Servico,
12430            CaixaKind::Supervisor,
12431            CaixaKind::Aplicacao,
12432        ] {
12433            let c = caixa_with_kind(kind);
12434            let first: CaixaKind = c.kind();
12435            let second: CaixaKind = c.kind();
12436            assert_eq!(
12437                first, second,
12438                "Caixa::kind must be idempotent — two successive \
12439                 calls on the same &self must return the same \
12440                 CaixaKind variant",
12441            );
12442            assert_eq!(
12443                first, kind,
12444                "Caixa::kind must return :kind verbatim by Copy — \
12445                 got {first:?}, expected {kind:?}",
12446            );
12447        }
12448    }
12449
12450    // ── Caixa::autores — outer top-level &[T] slice accessor ──────────
12451
12452    #[test]
12453    fn autores_returns_autores_slice_verbatim_across_permutations() {
12454        // The canonical per-`Caixa` `:autores` universal-axis maintainer-
12455        // name-list slice pin: [`Caixa::autores`] must return the
12456        // `:autores` typed [`Vec<String>`] list verbatim as a
12457        // `&[String]`, byte-equal to the raw `self.autores.as_slice()`
12458        // access across every representative value in the accept-set —
12459        // `[]` (the "no maintainers declared" arm every existing
12460        // fixture without an `:autores` line carries), `[""]` (a past-
12461        // the-guard sentinel that pins the accessor doesn't perform a
12462        // silent `[""] → []` collapse on the empty-entry arm — validate
12463        // rejects `[""]` through `AutorEmpty` but the accessor must
12464        // ship the raw slot verbatim so a validate-time gate regression
12465        // surfaces at the caixa-helm emit boundary rather than being
12466        // silently absorbed into a maintainer-drop), `["pleme-io"]` (the
12467        // canonical single-maintainer form every `feira init` template
12468        // scaffolds), `["alice", "bob"]` (a canonical multi-maintainer
12469        // form), `["alice <alice@example.com>", "bob <bob@example.com>"]`
12470        // (the canonical RFC-5322 `<name> <email>` form the
12471        // `is_chart_maintainer_name_shape` predicate accepts), and
12472        // `["pleme-io", "pleme-io"]` (a past-the-guard duplicate
12473        // sentinel — validate rejects through `AutorDuplicate` but the
12474        // accessor must ship the raw slot verbatim).
12475        //
12476        // First outer top-level [`Caixa`] `&[T]`-return slice accessor
12477        // pin on the substrate primitive — opens the "outer [`Caixa`]
12478        // `&[T]` slice" projection pattern the sibling per-`Caixa`
12479        // `:etiquetas` / `:deps` / `:deps-dev` / `:exe` / `:bibliotecas`
12480        // / `:servicos` / `:upgrade-from` / `:children` future lifts
12481        // fold on. Sibling in shape to the peer per-`:supervisor`
12482        // [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
12483        // per-`:placement` [`crate::aplicacao::Placement::clusters`]
12484        // (a6e18d7), per-`:membros`
12485        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
12486        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
12487        // (0dcc926), and per-`:upgrade-from :instructions`
12488        // [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
12489        // `&[T]`-return slice accessor pins on the sibling per-M2 /
12490        // per-M3 typed-slot list axes, extended onto the outer top-
12491        // level [`Caixa`] universal-axis surface. Pins against a future
12492        // silent detour that returned an owned `Vec<String>` (which
12493        // would type-check but silently clone on every accessor call,
12494        // breaking the zero-cost projection every peer sibling slice
12495        // accessor carries), a `[""] → []` collapse (which would
12496        // silently absorb the `AutorEmpty` refusal case at the accessor
12497        // boundary), or a `["a", "a"] → ["a"]` dedup collapse (which
12498        // would silently absorb the `AutorDuplicate` refusal case at
12499        // the accessor boundary and the caixa-helm `maintainers:` fold
12500        // would silently render a dedupped list on a struct-literal
12501        // `Caixa { autores: vec!["a".into(), "a".into()], .. }`).
12502        for autores in [
12503            vec![],
12504            vec![""],
12505            vec!["pleme-io"],
12506            vec!["alice", "bob"],
12507            vec!["alice <alice@example.com>", "bob <bob@example.com>"],
12508            vec!["pleme-io", "pleme-io"],
12509        ] {
12510            let c = caixa_with_autores(autores.clone());
12511            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
12512            assert_eq!(
12513                c.autores(),
12514                expected.as_slice(),
12515                "Caixa::autores must return :autores verbatim (got {:?}, \
12516                 expected {expected:?})",
12517                c.autores(),
12518            );
12519            assert_eq!(
12520                c.autores(),
12521                c.autores.as_slice(),
12522                "Caixa::autores must byte-equal the raw \
12523                 `self.autores.as_slice()` field access across every \
12524                 value in the Vec<String> accept-set",
12525            );
12526        }
12527    }
12528
12529    #[test]
12530    fn validate_autores_empty_entry_arm_routes_through_accessor() {
12531        // Composition pin: [`Caixa::validate_autores`]'s per-entry
12532        // empty-arm gate must key off [`Caixa::autores`], not the raw
12533        // `&self.autores` field-borrow walk. Structurally: a
12534        // `Caixa { autores: vec!["".into()], .. }` must surface the
12535        // `AutorEmpty` refusal exactly, and a
12536        // `Caixa { autores: vec!["pleme-io".into()], .. }` (the
12537        // canonical single-maintainer form) must pass validate. The
12538        // pair jointly pins the accessor + validate-gate composition:
12539        // any future silent detour that had the accessor return an
12540        // empty slice on the `[""]` arm (a
12541        // `.iter().filter(|s| !s.is_empty()).collect()` collapse)
12542        // would silently absorb the `AutorEmpty` refusal at the
12543        // accessor boundary and the validate gate would accept a
12544        // struct-literal `Caixa { autores: vec!["".into()], .. }` —
12545        // the composition pin catches that at caixa-core build time.
12546        //
12547        // Peer of the per-`Caixa` [`Caixa::validate_licenca`] (6d5bc28)
12548        // accessor-composition pin
12549        // (`validate_licenca_empty_arm_routes_through_accessor`) on the
12550        // sibling `Option<&str>`-composition axis and the
12551        // per-`:politicas :circuit-breaker`
12552        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
12553        // accessor-composition pin
12554        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
12555        // on the sibling required-`u32`-composition axis — same "the
12556        // validate / shape-gate predicate must route through the
12557        // substrate-primitive typed dispatch" discipline extended onto
12558        // the outer top-level [`Caixa`] universal-axis `&[T]`-
12559        // composition surface.
12560        let c = caixa_with_autores(vec![""]);
12561        assert!(
12562            matches!(c.validate_autores(), Err(ManifestError::AutorEmpty)),
12563            "validate_autores must reject autores == vec![\"\"] with \
12564             AutorEmpty — the accessor and the validate gate must \
12565             route through the same substrate-primitive typed dispatch \
12566             on the :autores per-entry empty arm",
12567        );
12568        let c = caixa_with_autores(vec!["pleme-io"]);
12569        assert!(
12570            c.validate_autores().is_ok(),
12571            "validate_autores must accept autores == vec![\"pleme-io\"] \
12572             (the canonical single-maintainer shape every `feira init` \
12573             template scaffolds)",
12574        );
12575    }
12576
12577    #[test]
12578    fn autores_projects_slice_by_borrow() {
12579        // The by-borrow pin: [`Caixa::autores`] returns `&[String]` by
12580        // borrow — the returned slice borrows the underlying
12581        // `Vec<String>` storage of the `:autores` slot and the
12582        // accessor must not clone the backing `Vec` on every call.
12583        // Peer of the per-`:membros`
12584        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36) /
12585        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
12586        // (0dcc926) / per-`:placement`
12587        // [`crate::aplicacao::Placement::clusters`] (a6e18d7) /
12588        // per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
12589        // (bc92bce) by-borrow pins on the sibling per-M2 / per-M3
12590        // typed-slot `&[T]`-return axes, extended onto the outer top-
12591        // level [`Caixa`] universal-axis `&[String]` shape — the
12592        // accessor's returned slice must borrow from `&self` (the
12593        // returned reference's lifetime is tied to `&self`), and
12594        // calling the accessor twice on the same [`Caixa`] must yield
12595        // slices that are pointer-equal (the underlying byte-buffer is
12596        // the storage `Vec`'s allocation, not a fresh copy) as well as
12597        // value-equal (idempotent, no side effects on `&self`).
12598        //
12599        // Pins against a future silent detour that returned an owned
12600        // `Vec<String>` (which would type-check but silently clone on
12601        // every call, breaking the zero-cost projection every peer
12602        // sibling slice accessor carries), a `&Vec<String>` return
12603        // (which would leak the backing `Vec`'s grow/push/reserve
12604        // surface no downstream consumer reaches for), or a one-arm-
12605        // only accessor that returned a saturating value on some
12606        // sentinel input (breaking the pass-through invariant the
12607        // sibling slice accessors carry).
12608        for autores in [
12609            vec![],
12610            vec!["pleme-io"],
12611            vec!["alice", "bob"],
12612            vec!["pleme-io", "pleme-io"],
12613        ] {
12614            let c = caixa_with_autores(autores.clone());
12615            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
12616            let first = c.autores();
12617            let second = c.autores();
12618            assert_eq!(
12619                first, second,
12620                "Caixa::autores must be idempotent — two successive \
12621                 calls on the same &self must return the same \
12622                 &[String]",
12623            );
12624            assert_eq!(
12625                first.as_ptr(),
12626                second.as_ptr(),
12627                "Caixa::autores must borrow the underlying Vec<String> \
12628                 storage — two successive calls must return slices \
12629                 with the same backing pointer (a fresh Vec<String> \
12630                 clone would change the pointer on every call)",
12631            );
12632            assert_eq!(
12633                first,
12634                expected.as_slice(),
12635                "Caixa::autores must return :autores verbatim by \
12636                 borrow — got {first:?}, expected {expected:?}",
12637            );
12638        }
12639    }
12640
12641    // ── Caixa::etiquetas — outer top-level &[T] slice accessor ────────
12642
12643    #[test]
12644    fn etiquetas_returns_etiquetas_slice_verbatim_across_permutations() {
12645        // The canonical per-`Caixa` `:etiquetas` universal-axis
12646        // registry-search-tag-list slice pin: [`Caixa::etiquetas`] must
12647        // return the `:etiquetas` typed [`Vec<String>`] list verbatim
12648        // as a `&[String]`, byte-equal to the raw
12649        // `self.etiquetas.as_slice()` access across every representative
12650        // value in the accept-set — `[]` (the "no tags declared" arm
12651        // every existing fixture without an `:etiquetas` line carries),
12652        // `[""]` (a past-the-guard sentinel that pins the accessor
12653        // doesn't perform a silent `[""] → []` collapse on the empty-
12654        // entry arm — validate rejects `[""]` through `EtiquetaEmpty`
12655        // but the accessor must ship the raw slot verbatim so a
12656        // validate-time gate regression surfaces at the caixa-helm emit
12657        // boundary rather than being silently absorbed into a keyword-
12658        // drop), `["demo"]` (the canonical single-tag form every
12659        // `feira init` template scaffolds), `["example", "aplicacao",
12660        // "mesh", "ecommerce", "demo"]` (the canonical multi-tag form
12661        // the checkout-aplicacao fixture emits), and `["demo", "demo"]`
12662        // (a past-the-guard duplicate sentinel — validate rejects
12663        // through `EtiquetaDuplicate` but the accessor must ship the
12664        // raw slot verbatim so the caixa-helm `BTreeSet::collect` dedup
12665        // at chart-render time isn't silently promoted into the
12666        // accessor boundary and struct-literal
12667        // `Caixa { etiquetas: vec!["demo".into(), "demo".into()], .. }`
12668        // fixtures continue to expose the duplicate at the accessor).
12669        //
12670        // Second outer top-level [`Caixa`] `&[T]`-return slice accessor
12671        // pin on the substrate primitive — folds on the "outer
12672        // [`Caixa`] `&[T]` slice" projection pattern
12673        // `autores_returns_autores_slice_verbatim_across_permutations`
12674        // (b5d813f) opened, sibling in shape and idiom. Pins against a
12675        // future silent detour that returned an owned `Vec<String>`
12676        // (which would type-check but silently clone on every accessor
12677        // call, breaking the zero-cost projection every peer sibling
12678        // slice accessor carries), a `[""] → []` collapse (which would
12679        // silently absorb the `EtiquetaEmpty` refusal case at the
12680        // accessor boundary), or a `["a", "a"] → ["a"]` dedup collapse
12681        // (which would silently absorb the `EtiquetaDuplicate` refusal
12682        // case at the accessor boundary — the caixa-helm chart-render
12683        // `BTreeSet::collect` dedup is downstream of the accessor and
12684        // must not be silently promoted into it).
12685        for etiquetas in [
12686            vec![],
12687            vec![""],
12688            vec!["demo"],
12689            vec!["example", "aplicacao", "mesh", "ecommerce", "demo"],
12690            vec!["demo", "demo"],
12691        ] {
12692            let c = caixa_with_etiquetas(etiquetas.clone());
12693            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
12694            assert_eq!(
12695                c.etiquetas(),
12696                expected.as_slice(),
12697                "Caixa::etiquetas must return :etiquetas verbatim (got \
12698                 {:?}, expected {expected:?})",
12699                c.etiquetas(),
12700            );
12701            assert_eq!(
12702                c.etiquetas(),
12703                c.etiquetas.as_slice(),
12704                "Caixa::etiquetas must byte-equal the raw \
12705                 `self.etiquetas.as_slice()` field access across every \
12706                 value in the Vec<String> accept-set",
12707            );
12708        }
12709    }
12710
12711    #[test]
12712    fn validate_etiquetas_empty_entry_arm_routes_through_accessor() {
12713        // Composition pin: [`Caixa::validate_etiquetas`]'s per-entry
12714        // empty-arm gate must key off [`Caixa::etiquetas`], not the raw
12715        // `&self.etiquetas` field-borrow walk. Structurally: a
12716        // `Caixa { etiquetas: vec!["".into()], .. }` must surface the
12717        // `EtiquetaEmpty` refusal exactly, and a
12718        // `Caixa { etiquetas: vec!["demo".into()], .. }` (the canonical
12719        // single-tag form) must pass validate. The pair jointly pins
12720        // the accessor + validate-gate composition: any future silent
12721        // detour that had the accessor return an empty slice on the
12722        // `[""]` arm (a
12723        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
12724        // silently absorb the `EtiquetaEmpty` refusal at the accessor
12725        // boundary and the validate gate would accept a struct-literal
12726        // `Caixa { etiquetas: vec!["".into()], .. }` — the composition
12727        // pin catches that at caixa-core build time.
12728        //
12729        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
12730        // through_accessor` (b5d813f) accessor-composition pin on the
12731        // sibling `&[T]`-composition axis — same "the validate / shape-
12732        // gate predicate must route through the substrate-primitive
12733        // typed dispatch" discipline extended onto the sibling outer
12734        // top-level [`Caixa`] `&[T]`-composition surface.
12735        let c = caixa_with_etiquetas(vec![""]);
12736        assert!(
12737            matches!(c.validate_etiquetas(), Err(ManifestError::EtiquetaEmpty)),
12738            "validate_etiquetas must reject etiquetas == vec![\"\"] \
12739             with EtiquetaEmpty — the accessor and the validate gate \
12740             must route through the same substrate-primitive typed \
12741             dispatch on the :etiquetas per-entry empty arm",
12742        );
12743        let c = caixa_with_etiquetas(vec!["demo"]);
12744        assert!(
12745            c.validate_etiquetas().is_ok(),
12746            "validate_etiquetas must accept etiquetas == vec![\"demo\"] \
12747             (the canonical single-tag shape every `feira init` \
12748             template scaffolds)",
12749        );
12750    }
12751
12752    #[test]
12753    fn etiquetas_projects_slice_by_borrow() {
12754        // The by-borrow pin: [`Caixa::etiquetas`] returns `&[String]`
12755        // by borrow — the returned slice borrows the underlying
12756        // `Vec<String>` storage of the `:etiquetas` slot and the
12757        // accessor must not clone the backing `Vec` on every call.
12758        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
12759        // (b5d813f) by-borrow pin on the sibling outer top-level
12760        // [`Caixa`] `&[String]`-return axis — the accessor's returned
12761        // slice must borrow from `&self` (the returned reference's
12762        // lifetime is tied to `&self`), and calling the accessor twice
12763        // on the same [`Caixa`] must yield slices that are pointer-
12764        // equal (the underlying byte-buffer is the storage `Vec`'s
12765        // allocation, not a fresh copy) as well as value-equal
12766        // (idempotent, no side effects on `&self`).
12767        //
12768        // Pins against a future silent detour that returned an owned
12769        // `Vec<String>` (which would type-check but silently clone on
12770        // every call, breaking the zero-cost projection every peer
12771        // sibling slice accessor carries), a `&Vec<String>` return
12772        // (which would leak the backing `Vec`'s grow/push/reserve
12773        // surface no downstream consumer reaches for), or a one-arm-
12774        // only accessor that returned a saturating value on some
12775        // sentinel input (breaking the pass-through invariant the
12776        // sibling slice accessors carry).
12777        for etiquetas in [
12778            vec![],
12779            vec!["demo"],
12780            vec!["example", "aplicacao", "mesh"],
12781            vec!["demo", "demo"],
12782        ] {
12783            let c = caixa_with_etiquetas(etiquetas.clone());
12784            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
12785            let first = c.etiquetas();
12786            let second = c.etiquetas();
12787            assert_eq!(
12788                first, second,
12789                "Caixa::etiquetas must be idempotent — two successive \
12790                 calls on the same &self must return the same \
12791                 &[String]",
12792            );
12793            assert_eq!(
12794                first.as_ptr(),
12795                second.as_ptr(),
12796                "Caixa::etiquetas must borrow the underlying \
12797                 Vec<String> storage — two successive calls must \
12798                 return slices with the same backing pointer (a fresh \
12799                 Vec<String> clone would change the pointer on every \
12800                 call)",
12801            );
12802            assert_eq!(
12803                first,
12804                expected.as_slice(),
12805                "Caixa::etiquetas must return :etiquetas verbatim by \
12806                 borrow — got {first:?}, expected {expected:?}",
12807            );
12808        }
12809    }
12810
12811    // ── Caixa::bibliotecas — outer top-level &[T] slice accessor ──────
12812
12813    #[test]
12814    fn bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations() {
12815        // The canonical per-`Caixa` `:bibliotecas` universal-axis
12816        // library-source-path-list slice pin: [`Caixa::bibliotecas`]
12817        // must return the `:bibliotecas` typed [`Vec<String>`] list
12818        // verbatim as a `&[String]`, byte-equal to the raw
12819        // `self.bibliotecas.as_slice()` access across every
12820        // representative value in the accept-set — `[]` (the "no
12821        // libraries declared" arm every `:kind` other than `Biblioteca`
12822        // + every `Biblioteca` relying on the canonical
12823        // `lib/<nome>.lisp` implicit-default path carries; the
12824        // layout's [`crate::LayoutInvariants`] `MissingLib` arm-gate
12825        // fires exactly on this empty-slot + `Biblioteca`-kind
12826        // combination), `[""]` (a past-the-guard sentinel that pins
12827        // the accessor doesn't perform a silent `[""] → []` collapse
12828        // on the empty-entry arm — validate rejects `[""]` through
12829        // `CodePathEmpty { slot: ":bibliotecas" }` but the accessor
12830        // must ship the raw slot verbatim so a validate-time gate
12831        // regression surfaces at the `feira build` phase-1 parse
12832        // boundary rather than being silently absorbed into a
12833        // library-drop), `["lib/demo.lisp"]` (the canonical single-
12834        // entry form `Caixa::template` scaffolds and every `feira init`
12835        // template emits), `["lib/demo.lisp", "lib/helpers.lisp"]`
12836        // (the canonical multi-library form the
12837        // `validate_code_paths_accepts_explicit_relative_paths_on_
12838        // every_slot` fixture emits), and `["lib/foo.lisp",
12839        // "lib/foo.lisp"]` (a past-the-guard duplicate sentinel —
12840        // validate rejects through `CodePathDuplicate { slot:
12841        // ":bibliotecas" }` per the per-slot set-not-multiset gate,
12842        // but the accessor must ship the raw slot verbatim so the
12843        // `feira build` `for entry in caixa.bibliotecas()` parse walk
12844        // sees the duplicate at the accessor boundary and struct-
12845        // literal `Caixa { bibliotecas: vec!["lib/foo.lisp".into(),
12846        // "lib/foo.lisp".into()], .. }` fixtures continue to expose
12847        // the duplicate at the accessor).
12848        //
12849        // Third outer top-level [`Caixa`] `&[T]`-return slice accessor
12850        // pin on the substrate primitive — folds on the "outer
12851        // [`Caixa`] `&[T]` slice" projection pattern
12852        // `autores_returns_autores_slice_verbatim_across_permutations`
12853        // (b5d813f) opened and
12854        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
12855        // (78c7d3c) folded on, sibling in shape and idiom. Pins
12856        // against a future silent detour that returned an owned
12857        // `Vec<String>` (which would type-check but silently clone on
12858        // every accessor call, breaking the zero-cost projection
12859        // every peer sibling slice accessor carries), a `[""] → []`
12860        // collapse (which would silently absorb the `CodePathEmpty`
12861        // refusal case at the accessor boundary), or a `["lib/foo.lisp",
12862        // "lib/foo.lisp"] → ["lib/foo.lisp"]` dedup collapse (which
12863        // would silently absorb the `CodePathDuplicate` refusal case
12864        // at the accessor boundary — the per-slot set-not-multiset
12865        // gate is downstream of the accessor and must not be silently
12866        // promoted into it).
12867        for bibliotecas in [
12868            vec![],
12869            vec![""],
12870            vec!["lib/demo.lisp"],
12871            vec!["lib/demo.lisp", "lib/helpers.lisp"],
12872            vec!["lib/foo.lisp", "lib/foo.lisp"],
12873        ] {
12874            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
12875            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
12876            assert_eq!(
12877                c.bibliotecas(),
12878                expected.as_slice(),
12879                "Caixa::bibliotecas must return :bibliotecas verbatim \
12880                 (got {:?}, expected {expected:?})",
12881                c.bibliotecas(),
12882            );
12883            assert_eq!(
12884                c.bibliotecas(),
12885                c.bibliotecas.as_slice(),
12886                "Caixa::bibliotecas must byte-equal the raw \
12887                 `self.bibliotecas.as_slice()` field access across \
12888                 every value in the Vec<String> accept-set",
12889            );
12890        }
12891    }
12892
12893    #[test]
12894    fn validate_code_paths_bibliotecas_empty_arm_routes_through_accessor() {
12895        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
12896        // empty-arm gate on the `:bibliotecas` slot must key off
12897        // [`Caixa::bibliotecas`], not a divergent raw
12898        // `&self.bibliotecas` field-borrow walk. Structurally: a
12899        // `Caixa { bibliotecas: vec!["".into()], .. }` must surface
12900        // the `CodePathEmpty { slot: ":bibliotecas" }` refusal
12901        // exactly, and a `Caixa { bibliotecas: vec!["lib/demo.lisp".
12902        // into()], .. }` (the canonical single-library form
12903        // `Caixa::template` scaffolds) must pass validate. The pair
12904        // jointly pins the accessor + validate-gate composition: any
12905        // future silent detour that had the accessor return an empty
12906        // slice on the `[""]` arm (a `.iter().filter(|s|
12907        // !s.is_empty()).collect()` collapse) would silently absorb
12908        // the `CodePathEmpty` refusal at the accessor boundary and
12909        // the validate gate would accept a struct-literal
12910        // `Caixa { bibliotecas: vec!["".into()], .. }` — the
12911        // composition pin catches that at caixa-core build time.
12912        //
12913        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
12914        // through_accessor` (b5d813f) and
12915        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
12916        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
12917        // composition axes — same "the validate / shape-gate
12918        // predicate must route through the substrate-primitive typed
12919        // dispatch" discipline extended onto the sibling outer top-
12920        // level [`Caixa`] `&[T]`-composition surface. Nominally the
12921        // in-tree `validate_code_paths` production body still keys
12922        // off the internal `[(":bibliotecas", &self.bibliotecas,
12923        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
12924        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
12925        // (the tuple's homogeneous slice-typed shape blocks a per-
12926        // element accessor swap in isolation — a future companion
12927        // lift for `:exe` and `:servicos` on the same outer-`Caixa`
12928        // `&[T]` slice-accessor axis closes that tuple onto the
12929        // triple of typed dispatches as a unit); the composition pin
12930        // catches any future accessor-side silent filter drop against
12931        // that eventual tuple-closure regardless of whether the
12932        // `:bibliotecas` slot is threaded through the accessor or the
12933        // raw field access at the tuple's construction site.
12934        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
12935        assert!(
12936            matches!(
12937                c.validate_code_paths(),
12938                Err(ManifestError::CodePathEmpty {
12939                    slot: ":bibliotecas"
12940                })
12941            ),
12942            "validate_code_paths must reject bibliotecas == vec![\"\"] \
12943             with CodePathEmpty {{ slot: \":bibliotecas\" }} — the \
12944             accessor and the validate gate must route through the \
12945             same substrate-primitive typed dispatch on the \
12946             :bibliotecas per-entry empty arm",
12947        );
12948        let c = caixa_with_code_paths(vec!["lib/demo.lisp"], vec![], vec![]);
12949        assert!(
12950            c.validate_code_paths().is_ok(),
12951            "validate_code_paths must accept bibliotecas == \
12952             vec![\"lib/demo.lisp\"] (the canonical single-library \
12953             shape every `feira init` template scaffolds)",
12954        );
12955    }
12956
12957    #[test]
12958    fn bibliotecas_projects_slice_by_borrow() {
12959        // The by-borrow pin: [`Caixa::bibliotecas`] returns
12960        // `&[String]` by borrow — the returned slice borrows the
12961        // underlying `Vec<String>` storage of the `:bibliotecas` slot
12962        // and the accessor must not clone the backing `Vec` on every
12963        // call. Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
12964        // (b5d813f) and `etiquetas_projects_slice_by_borrow` (78c7d3c)
12965        // by-borrow pins on the sibling outer top-level [`Caixa`]
12966        // `&[String]`-return axes — the accessor's returned slice
12967        // must borrow from `&self` (the returned reference's lifetime
12968        // is tied to `&self`), and calling the accessor twice on the
12969        // same [`Caixa`] must yield slices that are pointer-equal
12970        // (the underlying byte-buffer is the storage `Vec`'s
12971        // allocation, not a fresh copy) as well as value-equal
12972        // (idempotent, no side effects on `&self`).
12973        //
12974        // Pins against a future silent detour that returned an owned
12975        // `Vec<String>` (which would type-check but silently clone on
12976        // every call, breaking the zero-cost projection every peer
12977        // sibling slice accessor carries), a `&Vec<String>` return
12978        // (which would leak the backing `Vec`'s grow/push/reserve
12979        // surface no downstream consumer reaches for), or a one-arm-
12980        // only accessor that returned a saturating value on some
12981        // sentinel input (breaking the pass-through invariant the
12982        // sibling slice accessors carry).
12983        for bibliotecas in [
12984            vec![],
12985            vec!["lib/demo.lisp"],
12986            vec!["lib/demo.lisp", "lib/helpers.lisp"],
12987            vec!["lib/foo.lisp", "lib/foo.lisp"],
12988        ] {
12989            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
12990            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
12991            let first = c.bibliotecas();
12992            let second = c.bibliotecas();
12993            assert_eq!(
12994                first, second,
12995                "Caixa::bibliotecas must be idempotent — two \
12996                 successive calls on the same &self must return the \
12997                 same &[String]",
12998            );
12999            assert_eq!(
13000                first.as_ptr(),
13001                second.as_ptr(),
13002                "Caixa::bibliotecas must borrow the underlying \
13003                 Vec<String> storage — two successive calls must \
13004                 return slices with the same backing pointer (a \
13005                 fresh Vec<String> clone would change the pointer on \
13006                 every call)",
13007            );
13008            assert_eq!(
13009                first,
13010                expected.as_slice(),
13011                "Caixa::bibliotecas must return :bibliotecas verbatim \
13012                 by borrow — got {first:?}, expected {expected:?}",
13013            );
13014        }
13015    }
13016
13017    // ── Caixa::exe — outer top-level &[T] slice accessor ──────────────
13018
13019    #[test]
13020    fn exe_returns_exe_slice_verbatim_across_permutations() {
13021        // The canonical per-`Caixa` `:exe` universal-axis
13022        // nix-built-executable-entry-path-list slice pin: [`Caixa::exe`]
13023        // must return the `:exe` typed [`Vec<String>`] list verbatim as
13024        // a `&[String]`, byte-equal to the raw `self.exe.as_slice()`
13025        // access across every representative value in the accept-set —
13026        // `[]` (the "no executable declared" arm every `:kind` other
13027        // than `Binario` carries; the layout's [`crate::LayoutInvariants`]
13028        // `BinarioWithoutExe` arm-gate fires exactly on this empty-slot
13029        // + `Binario`-kind combination), `[""]` (a past-the-guard
13030        // sentinel that pins the accessor doesn't perform a silent
13031        // `[""] → []` collapse on the empty-entry arm — validate rejects
13032        // `[""]` through `CodePathEmpty { slot: ":exe" }` but the
13033        // accessor must ship the raw slot verbatim so a validate-time
13034        // gate regression surfaces at the layout / `feira nix` boundary
13035        // rather than being silently absorbed into an executable-drop),
13036        // `["exe/cli"]` (the canonical single-entry Binario form every
13037        // in-tree `caixa_with_code_paths` positive control uses),
13038        // `["exe/cli", "exe/serve"]` (the canonical multi-executable
13039        // form the `validate_code_paths_accepts_explicit_relative_paths_
13040        // on_every_slot` fixture emits), and `["exe/cli", "exe/cli"]`
13041        // (a past-the-guard duplicate sentinel — validate rejects
13042        // through `CodePathDuplicate { slot: ":exe" }` per the per-slot
13043        // set-not-multiset gate, but the accessor must ship the raw
13044        // slot verbatim so struct-literal `Caixa { exe: vec!["exe/cli".
13045        // into(), "exe/cli".into()], .. }` fixtures continue to expose
13046        // the duplicate at the accessor).
13047        //
13048        // Fourth outer top-level [`Caixa`] `&[T]`-return slice accessor
13049        // pin on the substrate primitive — folds on the "outer
13050        // [`Caixa`] `&[T]` slice" projection pattern
13051        // `autores_returns_autores_slice_verbatim_across_permutations`
13052        // (b5d813f) opened,
13053        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
13054        // (78c7d3c) folded on, and
13055        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
13056        // (8a36c23) closed the universal-axis text-tag family of.
13057        // Opens the outer-`Caixa` foreign-code-slot `&[T]` sub-family
13058        // the sibling `:servicos` future lift closes onto. Pins against
13059        // a future silent detour that returned an owned `Vec<String>`
13060        // (which would type-check but silently clone on every accessor
13061        // call, breaking the zero-cost projection every peer sibling
13062        // slice accessor carries), a `[""] → []` collapse (which would
13063        // silently absorb the `CodePathEmpty` refusal case at the
13064        // accessor boundary), or an `["exe/cli", "exe/cli"] →
13065        // ["exe/cli"]` dedup collapse (which would silently absorb the
13066        // `CodePathDuplicate` refusal case at the accessor boundary —
13067        // the per-slot set-not-multiset gate is downstream of the
13068        // accessor and must not be silently promoted into it).
13069        for exe in [
13070            vec![],
13071            vec![""],
13072            vec!["exe/cli"],
13073            vec!["exe/cli", "exe/serve"],
13074            vec!["exe/cli", "exe/cli"],
13075        ] {
13076            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
13077            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
13078            assert_eq!(
13079                c.exe(),
13080                expected.as_slice(),
13081                "Caixa::exe must return :exe verbatim (got {:?}, \
13082                 expected {expected:?})",
13083                c.exe(),
13084            );
13085            assert_eq!(
13086                c.exe(),
13087                c.exe.as_slice(),
13088                "Caixa::exe must byte-equal the raw \
13089                 `self.exe.as_slice()` field access across every value \
13090                 in the Vec<String> accept-set",
13091            );
13092        }
13093    }
13094
13095    #[test]
13096    fn validate_code_paths_exe_empty_arm_routes_through_accessor() {
13097        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
13098        // empty-arm gate on the `:exe` slot must key off
13099        // [`Caixa::exe`], not a divergent raw `&self.exe` field-borrow
13100        // walk. Structurally: a `Caixa { exe: vec!["".into()], .. }`
13101        // must surface the `CodePathEmpty { slot: ":exe" }` refusal
13102        // exactly, and a `Caixa { exe: vec!["exe/cli".into()], .. }`
13103        // (the canonical single-executable form every in-tree
13104        // `caixa_with_code_paths` positive control uses) must pass
13105        // validate. The pair jointly pins the accessor + validate-gate
13106        // composition: any future silent detour that had the accessor
13107        // return an empty slice on the `[""]` arm (a
13108        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
13109        // silently absorb the `CodePathEmpty` refusal at the accessor
13110        // boundary and the validate gate would accept a struct-literal
13111        // `Caixa { exe: vec!["".into()], .. }` — the composition pin
13112        // catches that at caixa-core build time.
13113        //
13114        // Peer of the per-`Caixa`
13115        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
13116        // (8a36c23), `validate_autores_empty_arm_routes_through_accessor`
13117        // (b5d813f), and
13118        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
13119        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
13120        // composition axes — same "the validate / shape-gate predicate
13121        // must route through the substrate-primitive typed dispatch"
13122        // discipline extended onto the sibling outer top-level [`Caixa`]
13123        // `&[T]`-composition surface. Nominally the in-tree
13124        // `validate_code_paths` production body still keys off the
13125        // internal `[(":bibliotecas", &self.bibliotecas,
13126        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
13127        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
13128        // (the tuple's homogeneous slice-typed shape blocks a per-
13129        // element accessor swap in isolation — a future companion lift
13130        // for `:servicos` on the same outer-`Caixa` `&[T]` slice-
13131        // accessor axis closes that tuple onto the triple of typed
13132        // dispatches as a unit); the composition pin catches any future
13133        // accessor-side silent filter drop against that eventual tuple-
13134        // closure regardless of whether the `:exe` slot is threaded
13135        // through the accessor or the raw field access at the tuple's
13136        // construction site.
13137        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
13138        assert!(
13139            matches!(
13140                c.validate_code_paths(),
13141                Err(ManifestError::CodePathEmpty { slot: ":exe" })
13142            ),
13143            "validate_code_paths must reject exe == vec![\"\"] \
13144             with CodePathEmpty {{ slot: \":exe\" }} — the \
13145             accessor and the validate gate must route through the \
13146             same substrate-primitive typed dispatch on the \
13147             :exe per-entry empty arm",
13148        );
13149        let c = caixa_with_code_paths(vec![], vec!["exe/cli"], vec![]);
13150        assert!(
13151            c.validate_code_paths().is_ok(),
13152            "validate_code_paths must accept exe == vec![\"exe/cli\"] \
13153             (the canonical single-executable shape every in-tree \
13154             `caixa_with_code_paths` positive control uses)",
13155        );
13156    }
13157
13158    #[test]
13159    fn exe_projects_slice_by_borrow() {
13160        // The by-borrow pin: [`Caixa::exe`] returns `&[String]` by
13161        // borrow — the returned slice borrows the underlying
13162        // `Vec<String>` storage of the `:exe` slot and the accessor
13163        // must not clone the backing `Vec` on every call. Peer of the
13164        // per-`Caixa` `autores_projects_slice_by_borrow` (b5d813f),
13165        // `etiquetas_projects_slice_by_borrow` (78c7d3c), and
13166        // `bibliotecas_projects_slice_by_borrow` (8a36c23) by-borrow
13167        // pins on the sibling outer top-level [`Caixa`] `&[String]`-
13168        // return axes — the accessor's returned slice must borrow from
13169        // `&self` (the returned reference's lifetime is tied to
13170        // `&self`), and calling the accessor twice on the same
13171        // [`Caixa`] must yield slices that are pointer-equal (the
13172        // underlying byte-buffer is the storage `Vec`'s allocation,
13173        // not a fresh copy) as well as value-equal (idempotent, no
13174        // side effects on `&self`).
13175        //
13176        // Pins against a future silent detour that returned an owned
13177        // `Vec<String>` (which would type-check but silently clone on
13178        // every call, breaking the zero-cost projection every peer
13179        // sibling slice accessor carries), a `&Vec<String>` return
13180        // (which would leak the backing `Vec`'s grow/push/reserve
13181        // surface no downstream consumer reaches for), or a one-arm-
13182        // only accessor that returned a saturating value on some
13183        // sentinel input (breaking the pass-through invariant the
13184        // sibling slice accessors carry).
13185        for exe in [
13186            vec![],
13187            vec!["exe/cli"],
13188            vec!["exe/cli", "exe/serve"],
13189            vec!["exe/cli", "exe/cli"],
13190        ] {
13191            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
13192            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
13193            let first = c.exe();
13194            let second = c.exe();
13195            assert_eq!(
13196                first, second,
13197                "Caixa::exe must be idempotent — two successive calls \
13198                 on the same &self must return the same &[String]",
13199            );
13200            assert_eq!(
13201                first.as_ptr(),
13202                second.as_ptr(),
13203                "Caixa::exe must borrow the underlying Vec<String> \
13204                 storage — two successive calls must return slices \
13205                 with the same backing pointer (a fresh Vec<String> \
13206                 clone would change the pointer on every call)",
13207            );
13208            assert_eq!(
13209                first,
13210                expected.as_slice(),
13211                "Caixa::exe must return :exe verbatim by borrow — \
13212                 got {first:?}, expected {expected:?}",
13213            );
13214        }
13215    }
13216
13217    // ── Caixa::servicos — outer top-level &[T] slice accessor ─────────
13218
13219    #[test]
13220    fn servicos_returns_servicos_slice_verbatim_across_permutations() {
13221        // The canonical per-`Caixa` `:servicos` universal-axis
13222        // ComputeUnit-CR-YAML-entry-path-list slice pin:
13223        // [`Caixa::servicos`] must return the `:servicos` typed
13224        // [`Vec<String>`] list verbatim as a `&[String]`, byte-equal to
13225        // the raw `self.servicos.as_slice()` access across every
13226        // representative value in the accept-set — `[]` (the "no
13227        // ComputeUnit-CR declared" arm every `:kind` other than
13228        // `Servico` carries; the layout's [`crate::LayoutInvariants`]
13229        // `ServicoWithoutServicos` arm-gate fires exactly on this
13230        // empty-slot + `Servico`-kind combination), `[""]` (a past-the-
13231        // guard sentinel that pins the accessor doesn't perform a
13232        // silent `[""] → []` collapse on the empty-entry arm — validate
13233        // rejects `[""]` through `CodePathEmpty { slot: ":servicos" }`
13234        // but the accessor must ship the raw slot verbatim so a
13235        // validate-time gate regression surfaces at the layout /
13236        // per-Servico renderer boundary rather than being silently
13237        // absorbed into a component-drop),
13238        // `["servicos/demo.computeunit.yaml"]` (the canonical
13239        // singleton V0-shape every in-tree `caixa_with_code_paths`
13240        // positive control uses; the same shape
13241        // [`crate::require_single_servico`] admits),
13242        // `["servicos/a.computeunit.yaml", "servicos/b.computeunit.
13243        // yaml"]` (a past-the-guard `len != 1` sentinel — the V0
13244        // singularity gate rejects through `ServicoCountMismatch
13245        // { count: 2 }` but the accessor must ship the raw slot
13246        // verbatim so struct-literal `Caixa { servicos: vec![...,
13247        // ...], .. }` fixtures continue to expose the count at the
13248        // accessor), and `["servicos/a.computeunit.yaml",
13249        // "servicos/a.computeunit.yaml"]` (a past-the-guard duplicate
13250        // sentinel — validate rejects through
13251        // `CodePathDuplicate { slot: ":servicos" }` per the per-slot
13252        // set-not-multiset gate, but the accessor must ship the raw
13253        // slot verbatim so struct-literal fixtures continue to expose
13254        // the duplicate at the accessor).
13255        //
13256        // Fifth and final outer top-level [`Caixa`] `&[T]`-return
13257        // slice accessor pin on the substrate primitive — folds on the
13258        // "outer [`Caixa`] `&[T]` slice" projection pattern
13259        // `autores_returns_autores_slice_verbatim_across_permutations`
13260        // (b5d813f) opened,
13261        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
13262        // (78c7d3c) folded on,
13263        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
13264        // (8a36c23) closed the universal-axis text-tag family of, and
13265        // `exe_returns_exe_slice_verbatim_across_permutations`
13266        // (65d9527) opened the foreign-code-slot sub-family of. Closes
13267        // the outer-`Caixa` foreign-code-slot `&[T]` sub-family — the
13268        // trio of code-surface list slots (`:bibliotecas` + `:exe` +
13269        // `:servicos`) now each carries a substrate-canonical slice
13270        // accessor. Pins against a future silent detour that returned
13271        // an owned `Vec<String>` (which would type-check but silently
13272        // clone on every accessor call, breaking the zero-cost
13273        // projection every peer sibling slice accessor carries), a
13274        // `[""] → []` collapse (which would silently absorb the
13275        // `CodePathEmpty` refusal case at the accessor boundary), an
13276        // `[a, a] → [a]` dedup collapse (which would silently absorb
13277        // the `CodePathDuplicate` refusal case at the accessor
13278        // boundary — the per-slot set-not-multiset gate is downstream
13279        // of the accessor and must not be silently promoted into it),
13280        // or a `[a, b] → [a]` singleton collapse (which would silently
13281        // absorb the V0 `ServicoCountMismatch` refusal case at the
13282        // accessor boundary — the V0 singularity gate is downstream of
13283        // the accessor and must not be silently promoted into it).
13284        for servicos in [
13285            vec![],
13286            vec![""],
13287            vec!["servicos/demo.computeunit.yaml"],
13288            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
13289            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
13290        ] {
13291            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
13292            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
13293            assert_eq!(
13294                c.servicos(),
13295                expected.as_slice(),
13296                "Caixa::servicos must return :servicos verbatim (got \
13297                 {:?}, expected {expected:?})",
13298                c.servicos(),
13299            );
13300            assert_eq!(
13301                c.servicos(),
13302                c.servicos.as_slice(),
13303                "Caixa::servicos must byte-equal the raw \
13304                 `self.servicos.as_slice()` field access across every \
13305                 value in the Vec<String> accept-set",
13306            );
13307        }
13308    }
13309
13310    #[test]
13311    fn validate_code_paths_servicos_empty_arm_routes_through_accessor() {
13312        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
13313        // empty-arm gate on the `:servicos` slot must key off
13314        // [`Caixa::servicos`], not a divergent raw `&self.servicos`
13315        // field-borrow walk. Structurally: a `Caixa { servicos:
13316        // vec!["".into()], .. }` must surface the `CodePathEmpty
13317        // { slot: ":servicos" }` refusal exactly, and a `Caixa
13318        // { servicos: vec!["servicos/demo.computeunit.yaml".into()],
13319        // .. }` (the canonical singleton V0-shape every in-tree
13320        // `caixa_with_code_paths` positive control uses) must pass
13321        // validate. The pair jointly pins the accessor + validate-gate
13322        // composition: any future silent detour that had the accessor
13323        // return an empty slice on the `[""]` arm (a `.iter().filter
13324        // (|s| !s.is_empty()).collect()` collapse) would silently
13325        // absorb the `CodePathEmpty` refusal at the accessor boundary
13326        // and the validate gate would accept a struct-literal
13327        // `Caixa { servicos: vec!["".into()], .. }` — the composition
13328        // pin catches that at caixa-core build time.
13329        //
13330        // Peer of the per-`Caixa`
13331        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
13332        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
13333        // (65d9527), `validate_autores_empty_arm_routes_through_accessor`
13334        // (b5d813f), and
13335        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
13336        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
13337        // composition axes — same "the validate / shape-gate predicate
13338        // must route through the substrate-primitive typed dispatch"
13339        // discipline extended onto the sibling outer top-level
13340        // [`Caixa`] `&[T]`-composition surface, closing the trio of
13341        // code-surface accessor-composition pins on the same axis.
13342        // Nominally the in-tree `validate_code_paths` production body
13343        // still keys off the internal
13344        // `[(":bibliotecas", &self.bibliotecas,
13345        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
13346        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
13347        // (the tuple's homogeneous `&Vec<String>`-typed shape blocks a
13348        // per-element accessor swap in isolation — a future companion
13349        // lift promotes the tuple's element type to `&[String]` and
13350        // threads the triple of typed dispatches through as a unit);
13351        // the composition pin catches any future accessor-side silent
13352        // filter drop against that eventual tuple-closure regardless
13353        // of whether the `:servicos` slot is threaded through the
13354        // accessor or the raw field access at the tuple's construction
13355        // site.
13356        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
13357        assert!(
13358            matches!(
13359                c.validate_code_paths(),
13360                Err(ManifestError::CodePathEmpty { slot: ":servicos" })
13361            ),
13362            "validate_code_paths must reject servicos == vec![\"\"] \
13363             with CodePathEmpty {{ slot: \":servicos\" }} — the \
13364             accessor and the validate gate must route through the \
13365             same substrate-primitive typed dispatch on the \
13366             :servicos per-entry empty arm",
13367        );
13368        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.computeunit.yaml"]);
13369        assert!(
13370            c.validate_code_paths().is_ok(),
13371            "validate_code_paths must accept servicos == \
13372             vec![\"servicos/demo.computeunit.yaml\"] (the canonical \
13373             singleton V0-shape every in-tree `caixa_with_code_paths` \
13374             positive control uses)",
13375        );
13376    }
13377
13378    #[test]
13379    fn servicos_projects_slice_by_borrow() {
13380        // The by-borrow pin: [`Caixa::servicos`] returns `&[String]` by
13381        // borrow — the returned slice borrows the underlying
13382        // `Vec<String>` storage of the `:servicos` slot and the
13383        // accessor must not clone the backing `Vec` on every call.
13384        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
13385        // (b5d813f), `etiquetas_projects_slice_by_borrow` (78c7d3c),
13386        // `bibliotecas_projects_slice_by_borrow` (8a36c23), and
13387        // `exe_projects_slice_by_borrow` (65d9527) by-borrow pins on
13388        // the sibling outer top-level [`Caixa`] `&[String]`-return
13389        // axes — the accessor's returned slice must borrow from
13390        // `&self` (the returned reference's lifetime is tied to
13391        // `&self`), and calling the accessor twice on the same
13392        // [`Caixa`] must yield slices that are pointer-equal (the
13393        // underlying byte-buffer is the storage `Vec`'s allocation,
13394        // not a fresh copy) as well as value-equal (idempotent, no
13395        // side effects on `&self`).
13396        //
13397        // Pins against a future silent detour that returned an owned
13398        // `Vec<String>` (which would type-check but silently clone on
13399        // every call, breaking the zero-cost projection every peer
13400        // sibling slice accessor carries), a `&Vec<String>` return
13401        // (which would leak the backing `Vec`'s grow/push/reserve
13402        // surface no downstream consumer reaches for), or a one-arm-
13403        // only accessor that returned a saturating value on some
13404        // sentinel input (breaking the pass-through invariant the
13405        // sibling slice accessors carry).
13406        for servicos in [
13407            vec![],
13408            vec!["servicos/demo.computeunit.yaml"],
13409            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
13410            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
13411        ] {
13412            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
13413            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
13414            let first = c.servicos();
13415            let second = c.servicos();
13416            assert_eq!(
13417                first, second,
13418                "Caixa::servicos must be idempotent — two successive \
13419                 calls on the same &self must return the same &[String]",
13420            );
13421            assert_eq!(
13422                first.as_ptr(),
13423                second.as_ptr(),
13424                "Caixa::servicos must borrow the underlying \
13425                 Vec<String> storage — two successive calls must \
13426                 return slices with the same backing pointer (a fresh \
13427                 Vec<String> clone would change the pointer on every \
13428                 call)",
13429            );
13430            assert_eq!(
13431                first,
13432                expected.as_slice(),
13433                "Caixa::servicos must return :servicos verbatim by \
13434                 borrow — got {first:?}, expected {expected:?}",
13435            );
13436        }
13437    }
13438
13439    // ── Caixa::deps — outer top-level &[Dep] slice accessor ───────────
13440
13441    fn caixa_with_deps(deps: Vec<Dep>) -> Caixa {
13442        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13443        c.deps = deps;
13444        c
13445    }
13446
13447    #[test]
13448    fn deps_returns_deps_slice_verbatim_across_permutations() {
13449        // The canonical per-`Caixa` `:deps` universal-axis runtime-
13450        // dependency-declaration-list slice pin: [`Caixa::deps`] must
13451        // return the `:deps` typed [`Vec<Dep>`] list verbatim as a
13452        // `&[Dep]`, element-equal to the raw `self.deps.as_slice()`
13453        // access across every representative value in the accept-set —
13454        // `[]` (the "no runtime deps declared" arm every existing
13455        // fixture without a `:deps` line carries; the
13456        // [`Caixa::template`] scaffold emits `:deps ()`), a canonical
13457        // single-entry list (the shape most consumer caixas carry), a
13458        // canonical two-entry list (the multi-dep runtime closure), and
13459        // two past-the-guard sentinels — a `[""]`-`:nome` entry
13460        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
13461        // `NomeInvalid` but the accessor must ship the raw slot
13462        // verbatim) and a `[a, a]` duplicate (validate rejects through
13463        // `DuplicateNome { list: ":deps" }` but the accessor must ship
13464        // the raw slot verbatim so struct-literal fixtures continue to
13465        // expose the duplicate at the accessor).
13466        //
13467        // First outer top-level [`Caixa`] `&[Dep]`-return slice accessor
13468        // pin on the substrate primitive — opens the outer-`Caixa`
13469        // dependency-slot `&[Dep]` sub-family the sibling `:deps-dev`
13470        // future lift closes on. Peer of the closed outer-`Caixa`
13471        // foreign-code-slot `&[String]` sub-family
13472        // (`bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
13473        // 8a36c23, `exe_returns_exe_slice_verbatim_across_permutations`
13474        // 65d9527, `servicos_returns_servicos_slice_verbatim_across_permutations`
13475        // 611f78b) and the outer-`Caixa` universal-axis text-tag family
13476        // (`autores_returns_autores_slice_verbatim_across_permutations`
13477        // b5d813f, `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
13478        // 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice"
13479        // projection pattern onto a novel element-type axis (`Dep`
13480        // composite vs the prior sibling family's `String` scalar).
13481        // Pins against a future silent detour that returned an owned
13482        // `Vec<Dep>` (which would type-check but silently clone on every
13483        // accessor call, breaking the zero-cost projection every peer
13484        // sibling slice accessor carries), a `[""] → []` collapse (which
13485        // would silently absorb the `NomeEmpty` refusal case at the
13486        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
13487        // would silently absorb the `DuplicateNome` refusal case at the
13488        // accessor boundary).
13489        for deps in [
13490            vec![],
13491            vec![Dep::simple("", "^0.1")],
13492            vec![Dep::simple("caixa-teia", "^0.1")],
13493            vec![
13494                Dep::simple("caixa-teia", "^0.1"),
13495                Dep::simple("caixa-core", "^0.1"),
13496            ],
13497            vec![
13498                Dep::simple("caixa-teia", "^0.1"),
13499                Dep::simple("caixa-teia", "^0.2"),
13500            ],
13501        ] {
13502            let c = caixa_with_deps(deps.clone());
13503            assert_eq!(
13504                c.deps(),
13505                deps.as_slice(),
13506                "Caixa::deps must return :deps verbatim (got {:?}, \
13507                 expected {deps:?})",
13508                c.deps(),
13509            );
13510            assert_eq!(
13511                c.deps(),
13512                c.deps.as_slice(),
13513                "Caixa::deps must element-equal the raw \
13514                 `self.deps.as_slice()` field access across every \
13515                 value in the Vec<Dep> accept-set",
13516            );
13517        }
13518    }
13519
13520    #[test]
13521    fn validate_deps_duplicate_arm_routes_through_accessor() {
13522        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps`
13523        // duplicate-`:nome` gate must key off [`Caixa::deps`], not the
13524        // raw `&self.deps` field-borrow walk. Structurally: a `Caixa
13525        // { deps: vec![Dep::simple("d", "^0.1"), Dep::simple("d",
13526        // "^0.2")], .. }` must surface the `DuplicateNome { list:
13527        // ":deps" }` refusal exactly, and a `Caixa { deps: vec![
13528        // Dep::simple("d", "^0.1")], .. }` (the canonical single-entry
13529        // form) must pass validate. The pair jointly pins the accessor +
13530        // validate-gate composition: any future silent detour that had
13531        // the accessor return a dedupped slice on the `[a, a]` arm (a
13532        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
13533        // would silently absorb the `DuplicateNome` refusal at the
13534        // accessor boundary and the validate gate would accept a
13535        // struct-literal `Caixa` carrying the drift — the composition
13536        // pin catches that at caixa-core build time.
13537        //
13538        // Peer of the per-`Caixa`
13539        // `validate_autores_empty_entry_arm_routes_through_accessor`
13540        // (b5d813f), `validate_etiquetas_empty_entry_arm_routes_through_accessor`
13541        // (78c7d3c), `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
13542        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
13543        // (65d9527), and `validate_code_paths_servicos_empty_arm_routes_through_accessor`
13544        // (611f78b) accessor-composition pins on the sibling `&[T]`-
13545        // composition axes — same "the validate gate must route through
13546        // the substrate-primitive typed dispatch" discipline extended
13547        // onto the sibling outer top-level [`Caixa`] `&[Dep]`-
13548        // composition surface, opening the outer-`Caixa` dependency-slot
13549        // arm of the composition-pin family.
13550        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
13551        let err = c.validate_deps().unwrap_err();
13552        assert!(
13553            matches!(
13554                err,
13555                DepError::DuplicateNome { ref nome, list } if nome == "d"
13556                    && list == crate::render::DEP_AUTHOR_KEY_DEPS
13557            ),
13558            "validate_deps must reject deps == \
13559             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
13560             DuplicateNome {{ nome: \"d\", list: \":deps\" }} — the \
13561             accessor and the validate gate must route through the \
13562             same substrate-primitive typed dispatch on the :deps \
13563             within-list duplicate arm (got {err:?})",
13564        );
13565        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1")]);
13566        assert!(
13567            c.validate_deps().is_ok(),
13568            "validate_deps must accept deps == vec![Dep(\"d\",\"^0.1\")] \
13569             (the canonical single-entry form)",
13570        );
13571    }
13572
13573    #[test]
13574    fn deps_projects_slice_by_borrow() {
13575        // The by-borrow pin: [`Caixa::deps`] returns `&[Dep]` by borrow
13576        // — the returned slice borrows the underlying `Vec<Dep>` storage
13577        // of the `:deps` slot and the accessor must not clone the
13578        // backing `Vec` on every call. Peer of the per-`Caixa`
13579        // `autores_projects_slice_by_borrow` (b5d813f),
13580        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
13581        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
13582        // `exe_projects_slice_by_borrow` (65d9527), and
13583        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
13584        // on the sibling outer top-level [`Caixa`] `&[String]`-return
13585        // axes — the accessor's returned slice must borrow from `&self`
13586        // (the returned reference's lifetime is tied to `&self`), and
13587        // calling the accessor twice on the same [`Caixa`] must yield
13588        // slices that are pointer-equal (the underlying byte-buffer is
13589        // the storage `Vec`'s allocation, not a fresh copy) as well as
13590        // value-equal (idempotent, no side effects on `&self`).
13591        //
13592        // Pins against a future silent detour that returned an owned
13593        // `Vec<Dep>` (which would type-check but silently clone on
13594        // every call), a `&Vec<Dep>` return (which would leak the
13595        // backing `Vec`'s grow/push/reserve surface no downstream
13596        // consumer reaches for), or a one-arm-only accessor that
13597        // returned a saturating value on some sentinel input.
13598        for deps in [
13599            vec![],
13600            vec![Dep::simple("caixa-teia", "^0.1")],
13601            vec![
13602                Dep::simple("caixa-teia", "^0.1"),
13603                Dep::simple("caixa-core", "^0.1"),
13604            ],
13605        ] {
13606            let c = caixa_with_deps(deps.clone());
13607            let first = c.deps();
13608            let second = c.deps();
13609            assert_eq!(
13610                first, second,
13611                "Caixa::deps must be idempotent — two successive calls \
13612                 on the same &self must return the same &[Dep]",
13613            );
13614            assert_eq!(
13615                first.as_ptr(),
13616                second.as_ptr(),
13617                "Caixa::deps must borrow the underlying Vec<Dep> \
13618                 storage — two successive calls must return slices \
13619                 with the same backing pointer (a fresh Vec<Dep> clone \
13620                 would change the pointer on every call)",
13621            );
13622            assert_eq!(
13623                first,
13624                deps.as_slice(),
13625                "Caixa::deps must return :deps verbatim by borrow — \
13626                 got {first:?}, expected {deps:?}",
13627            );
13628        }
13629    }
13630
13631    // ── Caixa::deps_dev — outer top-level &[Dep] slice accessor ──────
13632
13633    fn caixa_with_deps_dev(deps_dev: Vec<Dep>) -> Caixa {
13634        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13635        c.deps_dev = deps_dev;
13636        c
13637    }
13638
13639    #[test]
13640    fn deps_dev_returns_deps_dev_slice_verbatim_across_permutations() {
13641        // The canonical per-`Caixa` `:deps-dev` universal-axis dev-only-
13642        // dependency-declaration-list slice pin: [`Caixa::deps_dev`]
13643        // must return the `:deps-dev` typed [`Vec<Dep>`] list verbatim as
13644        // a `&[Dep]`, element-equal to the raw `self.deps_dev.as_slice()`
13645        // access across every representative value in the accept-set —
13646        // `[]` (the "no dev deps declared" arm every existing fixture
13647        // without a `:deps-dev` line carries; the [`Caixa::template`]
13648        // scaffold emits `:deps-dev ()`), a canonical single-entry list
13649        // (the shape most consumer caixas carry — a `tatara-check` dev
13650        // pin), a canonical two-entry list (the multi-dev-dep closure),
13651        // and two past-the-guard sentinels — a `[""]`-`:nome` entry
13652        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
13653        // `NomeInvalid` but the accessor must ship the raw slot
13654        // verbatim) and a `[a, a]` duplicate (validate rejects through
13655        // `DuplicateNome { list: ":deps-dev" }` but the accessor must
13656        // ship the raw slot verbatim so struct-literal fixtures continue
13657        // to expose the duplicate at the accessor).
13658        //
13659        // Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor
13660        // pin on the substrate primitive — closes the outer-`Caixa`
13661        // dependency-slot `&[Dep]` sub-family the sibling
13662        // `deps_returns_deps_slice_verbatim_across_permutations`
13663        // (ad34b4e) opened on. Folds the "outer [`Caixa`] `&[Dep]`
13664        // slice" projection pattern onto the sibling dev-dep axis —
13665        // pins against a future silent detour that returned an owned
13666        // `Vec<Dep>` (which would type-check but silently clone on every
13667        // accessor call, breaking the zero-cost projection every peer
13668        // sibling slice accessor carries), a `[""] → []` collapse (which
13669        // would silently absorb the `NomeEmpty` refusal case at the
13670        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
13671        // would silently absorb the `DuplicateNome` refusal case at the
13672        // accessor boundary).
13673        for deps_dev in [
13674            vec![],
13675            vec![Dep::simple("", "^0.1")],
13676            vec![Dep::simple("tatara-check", "^0.1")],
13677            vec![
13678                Dep::simple("tatara-check", "^0.1"),
13679                Dep::simple("caixa-lint", "^0.1"),
13680            ],
13681            vec![
13682                Dep::simple("tatara-check", "^0.1"),
13683                Dep::simple("tatara-check", "^0.2"),
13684            ],
13685        ] {
13686            let c = caixa_with_deps_dev(deps_dev.clone());
13687            assert_eq!(
13688                c.deps_dev(),
13689                deps_dev.as_slice(),
13690                "Caixa::deps_dev must return :deps-dev verbatim (got \
13691                 {:?}, expected {deps_dev:?})",
13692                c.deps_dev(),
13693            );
13694            assert_eq!(
13695                c.deps_dev(),
13696                c.deps_dev.as_slice(),
13697                "Caixa::deps_dev must element-equal the raw \
13698                 `self.deps_dev.as_slice()` field access across every \
13699                 value in the Vec<Dep> accept-set",
13700            );
13701        }
13702    }
13703
13704    #[test]
13705    fn validate_deps_duplicate_deps_dev_arm_routes_through_accessor() {
13706        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps-dev`
13707        // duplicate-`:nome` gate must key off [`Caixa::deps_dev`], not
13708        // the raw `&self.deps_dev` field-borrow walk. Structurally: a
13709        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1"),
13710        // Dep::simple("d", "^0.2")], .. }` must surface the
13711        // `DuplicateNome { list: ":deps-dev" }` refusal exactly, and a
13712        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1")], .. }` (the
13713        // canonical single-entry form) must pass validate. The pair
13714        // jointly pins the accessor + validate-gate composition: any
13715        // future silent detour that had the accessor return a dedupped
13716        // slice on the `[a, a]` arm (a
13717        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
13718        // would silently absorb the `DuplicateNome` refusal at the
13719        // accessor boundary and the validate gate would accept a
13720        // struct-literal `Caixa` carrying the drift — the composition
13721        // pin catches that at caixa-core build time.
13722        //
13723        // Peer of `validate_deps_duplicate_arm_routes_through_accessor`
13724        // (ad34b4e) on the sibling `:deps` axis — same "the validate
13725        // gate must route through the substrate-primitive typed
13726        // dispatch" discipline folded onto the sibling `:deps-dev`
13727        // axis, closing the two-list dep-graph composition-pin family.
13728        // The `:deps-dev` diagnostic must carry the
13729        // `DEP_AUTHOR_KEY_DEPS_DEV` list-tag (not
13730        // `DEP_AUTHOR_KEY_DEPS`) so the emitted error names the
13731        // offending list unambiguously.
13732        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
13733        let err = c.validate_deps().unwrap_err();
13734        assert!(
13735            matches!(
13736                err,
13737                DepError::DuplicateNome { ref nome, list } if nome == "d"
13738                    && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
13739            ),
13740            "validate_deps must reject deps_dev == \
13741             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
13742             DuplicateNome {{ nome: \"d\", list: \":deps-dev\" }} — the \
13743             accessor and the validate gate must route through the \
13744             same substrate-primitive typed dispatch on the :deps-dev \
13745             within-list duplicate arm (got {err:?})",
13746        );
13747        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1")]);
13748        assert!(
13749            c.validate_deps().is_ok(),
13750            "validate_deps must accept deps_dev == \
13751             vec![Dep(\"d\",\"^0.1\")] (the canonical single-entry form)",
13752        );
13753    }
13754
13755    #[test]
13756    fn deps_dev_projects_slice_by_borrow() {
13757        // The by-borrow pin: [`Caixa::deps_dev`] returns `&[Dep]` by
13758        // borrow — the returned slice borrows the underlying `Vec<Dep>`
13759        // storage of the `:deps-dev` slot and the accessor must not
13760        // clone the backing `Vec` on every call. Peer of
13761        // `deps_projects_slice_by_borrow` (ad34b4e) on the sibling
13762        // `:deps` axis, and of the per-`Caixa`
13763        // `autores_projects_slice_by_borrow` (b5d813f),
13764        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
13765        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
13766        // `exe_projects_slice_by_borrow` (65d9527), and
13767        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
13768        // on the sibling outer top-level [`Caixa`] `&[String]`-return
13769        // axes — the accessor's returned slice must borrow from `&self`
13770        // (the returned reference's lifetime is tied to `&self`), and
13771        // calling the accessor twice on the same [`Caixa`] must yield
13772        // slices that are pointer-equal (the underlying byte-buffer is
13773        // the storage `Vec`'s allocation, not a fresh copy) as well as
13774        // value-equal (idempotent, no side effects on `&self`).
13775        //
13776        // Pins against a future silent detour that returned an owned
13777        // `Vec<Dep>` (which would type-check but silently clone on
13778        // every call), a `&Vec<Dep>` return (which would leak the
13779        // backing `Vec`'s grow/push/reserve surface no downstream
13780        // consumer reaches for), or a one-arm-only accessor that
13781        // returned a saturating value on some sentinel input.
13782        for deps_dev in [
13783            vec![],
13784            vec![Dep::simple("tatara-check", "^0.1")],
13785            vec![
13786                Dep::simple("tatara-check", "^0.1"),
13787                Dep::simple("caixa-lint", "^0.1"),
13788            ],
13789        ] {
13790            let c = caixa_with_deps_dev(deps_dev.clone());
13791            let first = c.deps_dev();
13792            let second = c.deps_dev();
13793            assert_eq!(
13794                first, second,
13795                "Caixa::deps_dev must be idempotent — two successive \
13796                 calls on the same &self must return the same &[Dep]",
13797            );
13798            assert_eq!(
13799                first.as_ptr(),
13800                second.as_ptr(),
13801                "Caixa::deps_dev must borrow the underlying Vec<Dep> \
13802                 storage — two successive calls must return slices \
13803                 with the same backing pointer (a fresh Vec<Dep> clone \
13804                 would change the pointer on every call)",
13805            );
13806            assert_eq!(
13807                first,
13808                deps_dev.as_slice(),
13809                "Caixa::deps_dev must return :deps-dev verbatim by \
13810                 borrow — got {first:?}, expected {deps_dev:?}",
13811            );
13812        }
13813    }
13814
13815    // ── Caixa::limits — outer top-level Option<&LimitsSpec> composite-reference accessor ──
13816
13817    fn caixa_with_limits(limits: Option<crate::LimitsSpec>) -> Caixa {
13818        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13819        c.limits = limits;
13820        c
13821    }
13822
13823    #[test]
13824    fn limits_returns_limits_option_ref_verbatim_across_permutations() {
13825        // The canonical per-`Caixa` `:limits` M2 typed-slot outer-
13826        // composite optional-composite-reference-shape pin:
13827        // [`Caixa::limits`] must return the `:limits` typed
13828        // `Option<LimitsSpec>` verbatim as an `Option<&LimitsSpec>`
13829        // reference over the same backing storage the raw
13830        // `self.limits.as_ref()` field access borrows from, byte-equal
13831        // across every representative fixture in the accept-set — the
13832        // author-omitted `None` shape (the "engine-default applies"
13833        // partition every downstream Servico M2 overlay emitter treats
13834        // as "emit nothing"), the empty-composite `Some(LimitsSpec {
13835        // .. default })` shape ([`LimitsSpec::is_empty`] holds — every
13836        // per-axis cap is `None`, so the peer M2 overlay emitter's
13837        // `.is_empty()`-gated projection still emits nothing but the
13838        // outer presence-bit is `Some`, so [`Caixa::declared_servico_slots`]
13839        // still pushes the `M2_AUTHOR_KEY_LIMITS` label), a single-axis
13840        // fixture (only `:memory` set — the canonical shape most
13841        // memory-heavy Servicos carry), and a fully-populated composite
13842        // (every per-axis cap set — the canonical shape a
13843        // sandboxed-by-default Servico carries).
13844        //
13845        // Pins against a future silent detour that returned a fresh-
13846        // cloned [`LimitsSpec`] copy (which would type-check via the
13847        // `Clone` impl but silently break every downstream caller that
13848        // relied on the reference sharing the composite's backing
13849        // identity), a reference to an operator-resolved overlay (the
13850        // future per-cluster `:limits-overrides` slot — its resolution
13851        // must land at exactly this accessor body, not silently divert
13852        // the raw slot away from a second consumer), a
13853        // `None` → `Some(LimitsSpec::default)` cluster-default
13854        // projection (which would collapse the load-bearing
13855        // "author-omitted `:limits` ⇒ engine-default applies" partition
13856        // the peer [`crate::render::servico_m2_overlay`] emitter and
13857        // the peer [`Caixa::declared_servico_slots`] enumerator both
13858        // read), or an axis-shuffled projection (a future detour that
13859        // swapped `memory` and `fuel` through the accessor would
13860        // silently split the paired [`crate::StandardLayout::verify`]
13861        // per-`:limits` shape gate's traversal input from the peer
13862        // `servico_m2_overlay` emitter's projection input).
13863        //
13864        // First outer top-level [`Caixa`] `Option<&Composite>`-return
13865        // composite-reference accessor pin on the substrate primitive
13866        // — opens the outer-`Caixa` `Option<&Composite>` composite-
13867        // reference projection pattern the sibling `:behavior`
13868        // [`crate::BehaviorSpec`] / `:politicas`
13869        // [`crate::aplicacao::MeshPolicy`] / `:placement`
13870        // [`crate::aplicacao::Placement`] / `:entrada`
13871        // [`crate::aplicacao::Entrada`] future outer-composite lifts
13872        // fold on. Peer of the closed M3 outer-composite family the
13873        // sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
13874        // [`crate::AplicacaoSpec::placement`] (9abb8f0) /
13875        // [`crate::AplicacaoSpec::entrada`] (d32111c) composite-
13876        // reference accessor pins already carry on the outer
13877        // [`crate::AplicacaoSpec`] altitude — extends the outer-
13878        // accessor byte-equal-projection discipline onto the outer
13879        // top-level [`Caixa`] M2 Servico-runtime slot altitude.
13880        use crate::LimitsSpec;
13881        use std::time::Duration;
13882        let fixtures: Vec<Option<LimitsSpec>> = vec![
13883            None,
13884            Some(LimitsSpec::default()),
13885            Some(LimitsSpec {
13886                memory: Some(64 * 1024 * 1024),
13887                ..Default::default()
13888            }),
13889            Some(LimitsSpec {
13890                memory: Some(64 * 1024 * 1024),
13891                fuel: Some(1_000_000),
13892                wall_clock: Some(Duration::from_secs(30)),
13893                cpu: Some(500),
13894            }),
13895        ];
13896        for limits in fixtures {
13897            let c = caixa_with_limits(limits.clone());
13898            assert_eq!(
13899                c.limits(),
13900                limits.as_ref(),
13901                "Caixa::limits must return :limits verbatim (got {:?}, \
13902                 expected {:?})",
13903                c.limits(),
13904                limits.as_ref(),
13905            );
13906            match (c.limits(), c.limits.as_ref()) {
13907                (Some(a), Some(b)) => assert!(
13908                    std::ptr::eq(a, b),
13909                    "Caixa::limits accessor and self.limits.as_ref() \
13910                     field access must borrow the same backing storage \
13911                     — the accessor is the substrate-primitive typed \
13912                     dispatch every downstream Servico-M2-overlay \
13913                     composite consumer must route through, and a \
13914                     reference-identity split would silently break \
13915                     every consumer that relied on the borrow sharing \
13916                     the composite's storage",
13917                ),
13918                (None, None) => {}
13919                _ => panic!(
13920                    "Caixa::limits presence bit must byte-equal \
13921                     self.limits.is_some() — a presence-bit drift would \
13922                     silently split the paired StandardLayout::verify \
13923                     per-`:limits` shape gate's traversal head from \
13924                     the peer render::servico_m2_overlay M2 overlay \
13925                     emitter's traversal head from the peer \
13926                     Caixa::declared_servico_slots M2 declared-slot \
13927                     enumerator's presence probe",
13928                ),
13929            }
13930            assert_eq!(
13931                c.limits().is_some(),
13932                c.limits.is_some(),
13933                "Caixa::limits().is_some() must byte-equal \
13934                 self.limits.is_some() — a presence-bit drift would \
13935                 silently split every downstream Option<&LimitsSpec> \
13936                 consumer's partition on the engine-default arm",
13937            );
13938        }
13939    }
13940
13941    #[test]
13942    fn declared_servico_slots_limits_arm_routes_through_accessor() {
13943        // Composition pin: [`Caixa::declared_servico_slots`]'s
13944        // `:limits` presence-probe arm must key off [`Caixa::limits`],
13945        // not the raw `self.limits.is_some()` field-probe. Structurally:
13946        // a `Caixa { limits: Some(LimitsSpec::default()), .. }` must
13947        // still push `M2_AUTHOR_KEY_LIMITS` onto the declared-slot list
13948        // (the presence bit is `Some`, so the M2 kind-coherence gate
13949        // must surface the slot as "declared" even when every per-axis
13950        // cap is unset), and a `Caixa { limits: None, .. }` must NOT
13951        // push the label (the "author omitted the slot entirely"
13952        // partition). The pair jointly pins the accessor + declared-
13953        // slot enumerator composition: any future silent detour that
13954        // had the accessor collapse `Some(LimitsSpec::default())` to
13955        // `None` (a `.filter(|l| !l.is_empty())` projection) would
13956        // silently absorb the "declared but empty" arm at the
13957        // accessor boundary and the [`crate::LayoutError::ServicoSlotsOnNonServico`]
13958        // kind-coherence gate would silently accept a
13959        // struct-literal `Caixa` carrying the drift.
13960        //
13961        // Peer of the sibling per-`Caixa`
13962        // `validate_deps_duplicate_arm_routes_through_accessor` (ad34b4e)
13963        // and `validate_deps_duplicate_deps_dev_arm_routes_through_accessor`
13964        // (f7fd81e) accessor-composition pins on the sibling `:deps` /
13965        // `:deps-dev` outer-`&[Dep]`-composition axes — same "the
13966        // enumerator gate must route through the substrate-primitive
13967        // typed dispatch" discipline extended onto the outer top-level
13968        // [`Caixa`] `Option<&LimitsSpec>`-composition surface, opening
13969        // the outer-`Caixa` M2 Servico-runtime-slot arm of the
13970        // composition-pin family.
13971        use crate::LimitsSpec;
13972        let c = caixa_with_limits(Some(LimitsSpec::default()));
13973        let slots = c.declared_servico_slots();
13974        assert!(
13975            slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
13976            "declared_servico_slots must push M2_AUTHOR_KEY_LIMITS \
13977             when `:limits` is Some (even for LimitsSpec::default()) \
13978             — the accessor and the enumerator gate must route through \
13979             the same substrate-primitive typed dispatch on the outer \
13980             :limits presence bit (got slots={slots:?})",
13981        );
13982        let c = caixa_with_limits(None);
13983        let slots = c.declared_servico_slots();
13984        assert!(
13985            !slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
13986            "declared_servico_slots must NOT push M2_AUTHOR_KEY_LIMITS \
13987             when `:limits` is None — the author-omitted arm must \
13988             route through the accessor's None-return unchanged (got \
13989             slots={slots:?})",
13990        );
13991    }
13992
13993    #[test]
13994    fn servico_m2_overlay_limits_arm_routes_through_accessor() {
13995        // Composition pin: [`crate::render::servico_m2_overlay`]'s
13996        // per-`:limits` M2 overlay emit arm must key off
13997        // [`Caixa::limits`], not the raw `&caixa.limits` field-borrow.
13998        // Structurally: a `Caixa { limits: Some(LimitsSpec { memory:
13999        // Some(64 MiB), .. default }), .. }` must surface the
14000        // `M2_KEY_LIMITS` key with the per-axis
14001        // `memory: "64MiB"` sub-mapping in the overlay, a `Caixa {
14002        // limits: Some(LimitsSpec::default()), .. }` must omit the
14003        // key entirely (the `.is_empty()`-gated inner arm elides an
14004        // empty composite even when the outer presence bit is `Some`),
14005        // and a `Caixa { limits: None, .. }` must also omit the key
14006        // (the "author omitted the slot entirely" partition). The
14007        // three-fixture family jointly pins the accessor + M2 overlay
14008        // emitter composition: any future silent detour that had the
14009        // accessor return a fresh-cloned copy on the `Some` arm (a
14010        // `LimitsSpec::clone()` projection) would silently break the
14011        // reference-identity pin the peer per-axis
14012        // `serde_yaml::to_value(limits)` projection reads from.
14013        use crate::LimitsSpec;
14014        use crate::render::{M2_KEY_LIMITS, servico_m2_overlay};
14015        let c = caixa_with_limits(Some(LimitsSpec {
14016            memory: Some(64 * 1024 * 1024),
14017            ..Default::default()
14018        }));
14019        let overlay = servico_m2_overlay(&c).unwrap();
14020        assert!(
14021            overlay.contains_key(M2_KEY_LIMITS),
14022            "servico_m2_overlay must surface M2_KEY_LIMITS when \
14023             `:limits` carries a non-empty composite — the accessor \
14024             and the M2 overlay emitter must route through the same \
14025             substrate-primitive typed dispatch on the outer :limits \
14026             composite (got overlay={overlay:?})",
14027        );
14028        let c = caixa_with_limits(Some(LimitsSpec::default()));
14029        let overlay = servico_m2_overlay(&c).unwrap();
14030        assert!(
14031            !overlay.contains_key(M2_KEY_LIMITS),
14032            "servico_m2_overlay must omit M2_KEY_LIMITS when \
14033             `:limits` is Some(LimitsSpec::default()) — the empty \
14034             composite's `.is_empty()`-gated inner arm must elide \
14035             the key regardless of the outer presence bit (got \
14036             overlay={overlay:?})",
14037        );
14038        let c = caixa_with_limits(None);
14039        let overlay = servico_m2_overlay(&c).unwrap();
14040        assert!(
14041            !overlay.contains_key(M2_KEY_LIMITS),
14042            "servico_m2_overlay must omit M2_KEY_LIMITS when \
14043             `:limits` is None — the author-omitted arm must route \
14044             through the accessor's None-return unchanged (got \
14045             overlay={overlay:?})",
14046        );
14047    }
14048
14049    #[test]
14050    fn limits_projects_option_ref_by_borrow() {
14051        // The by-borrow pin: [`Caixa::limits`] returns
14052        // `Option<&LimitsSpec>` by borrow — the returned reference
14053        // borrows the underlying `Option<LimitsSpec>` storage of the
14054        // `:limits` slot and the accessor must not clone the backing
14055        // composite on every call. Peer of the sibling
14056        // `deps_projects_slice_by_borrow` (ad34b4e) /
14057        // `deps_dev_projects_slice_by_borrow` (f7fd81e) by-borrow pins
14058        // on the outer top-level [`Caixa`] `&[Dep]`-return axes —
14059        // extended here to the outer [`Caixa`] `Option<&Composite>`-
14060        // return axis: the accessor's returned reference must borrow
14061        // from `&self` (the returned reference's lifetime is tied to
14062        // `&self`), and calling the accessor twice on the same
14063        // [`Caixa`] must yield references that are pointer-equal (the
14064        // underlying byte-buffer is the storage `LimitsSpec`'s
14065        // allocation, not a fresh copy) as well as value-equal
14066        // (idempotent, no side effects on `&self`).
14067        //
14068        // Pins against a future silent detour that returned an owned
14069        // `LimitsSpec` (which would type-check via the `Clone` impl
14070        // but silently clone on every call), a `&LimitsSpec` panic-
14071        // return on the `None` arm (which would collapse the load-
14072        // bearing `Option` presence-bit into a runtime panic), or a
14073        // one-arm-only accessor that returned a saturating composite
14074        // on some sentinel input.
14075        use crate::LimitsSpec;
14076        use std::time::Duration;
14077        for limits in [
14078            Some(LimitsSpec::default()),
14079            Some(LimitsSpec {
14080                memory: Some(64 * 1024 * 1024),
14081                fuel: Some(1_000_000),
14082                wall_clock: Some(Duration::from_secs(30)),
14083                cpu: Some(500),
14084            }),
14085        ] {
14086            let c = caixa_with_limits(limits.clone());
14087            let first = c.limits().unwrap();
14088            let second = c.limits().unwrap();
14089            assert_eq!(
14090                first, second,
14091                "Caixa::limits must be idempotent — two successive \
14092                 calls on the same &self must return the same \
14093                 &LimitsSpec",
14094            );
14095            assert!(
14096                std::ptr::eq(first, second),
14097                "Caixa::limits must borrow the underlying \
14098                 Option<LimitsSpec> storage — two successive calls \
14099                 must return references with the same backing pointer \
14100                 (a fresh LimitsSpec clone would change the pointer \
14101                 on every call)",
14102            );
14103            assert_eq!(
14104                Some(first),
14105                limits.as_ref(),
14106                "Caixa::limits must return :limits verbatim by borrow \
14107                 — got {first:?}, expected {:?}",
14108                limits.as_ref(),
14109            );
14110        }
14111        let c = caixa_with_limits(None);
14112        assert!(
14113            c.limits().is_none(),
14114            "Caixa::limits must return None when :limits is absent — \
14115             the author-omitted arm must project through the \
14116             accessor's Option::None unchanged",
14117        );
14118    }
14119
14120    // ── Caixa::behavior — outer top-level Option<&BehaviorSpec> composite-reference accessor ──
14121
14122    fn caixa_with_behavior(behavior: Option<crate::BehaviorSpec>) -> Caixa {
14123        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14124        c.behavior = behavior;
14125        c
14126    }
14127
14128    #[test]
14129    fn behavior_returns_behavior_option_ref_verbatim_across_permutations() {
14130        // The canonical per-`Caixa` `:behavior` M2 typed-slot outer-
14131        // composite optional-composite-reference-shape pin:
14132        // [`Caixa::behavior`] must return the `:behavior` typed
14133        // `Option<BehaviorSpec>` verbatim as an `Option<&BehaviorSpec>`
14134        // reference over the same backing storage the raw
14135        // `self.behavior.as_ref()` field access borrows from, byte-equal
14136        // across every representative fixture in the accept-set — the
14137        // author-omitted `None` shape (the "runtime-default applies"
14138        // partition every downstream Servico M2 overlay emitter treats
14139        // as "emit nothing"), the empty-composite `Some(BehaviorSpec {
14140        // .. default })` shape ([`BehaviorSpec::is_empty`] holds —
14141        // every per-callback path is `None`, so the peer M2 overlay
14142        // emitter's `.is_empty()`-gated projection still emits nothing
14143        // but the outer presence-bit is `Some`, so
14144        // [`Caixa::declared_servico_slots`] still pushes the
14145        // `M2_AUTHOR_KEY_BEHAVIOR` label), a single-callback fixture
14146        // (only `:on-state-change` set — the canonical shape a caixa
14147        // that only wires the hot-upgrade migration path carries), and
14148        // a fully-populated composite (every per-callback path set —
14149        // the canonical shape a fully-instrumented gen_server-shaped
14150        // Servico carries).
14151        //
14152        // Peer of the sibling
14153        // `limits_returns_limits_option_ref_verbatim_across_permutations`
14154        // (b2bd9d7) opening fixture-family + reference-identity +
14155        // presence-bit tetrad pin on the outer top-level [`Caixa`]
14156        // `Option<&Composite>`-return sub-family — extended here to the
14157        // second axis of that sub-family so both of the currently-lifted
14158        // M2 Servico-runtime `Option<&Composite>` slots (`:limits` /
14159        // `:behavior`) carry the same "byte-equal, borrow-shared,
14160        // presence-bit-preserved" outer-accessor discipline.
14161        //
14162        // Pins against a future silent detour that returned a fresh-
14163        // cloned [`crate::BehaviorSpec`] copy (which would type-check
14164        // via the `Clone` impl but silently break every downstream
14165        // caller that relied on the reference sharing the composite's
14166        // backing identity), a reference to an operator-resolved
14167        // overlay (a future per-cluster `:behavior-overrides` slot —
14168        // its resolution must land at exactly this accessor body, not
14169        // silently divert the raw slot away from a second consumer), a
14170        // `None` → `Some(BehaviorSpec::default)` cluster-default
14171        // projection (which would collapse the load-bearing
14172        // "author-omitted `:behavior` ⇒ runtime-default applies"
14173        // partition the peer [`crate::render::servico_m2_overlay`]
14174        // emitter, the peer [`Caixa::declared_servico_slots`]
14175        // enumerator, and the cross-slot
14176        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
14177        // gate all read), or a callback-shuffled projection (a future
14178        // detour that swapped `on_init` and `on_terminate` through the
14179        // accessor would silently split the paired
14180        // [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
14181        // traversal input from the peer `servico_m2_overlay` emitter's
14182        // projection input from the cross-slot `:state-change`
14183        // composition gate's traversal input).
14184        use crate::BehaviorSpec;
14185        use std::path::PathBuf;
14186        let fixtures: Vec<Option<BehaviorSpec>> = vec![
14187            None,
14188            Some(BehaviorSpec::default()),
14189            Some(BehaviorSpec {
14190                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
14191                ..Default::default()
14192            }),
14193            Some(BehaviorSpec {
14194                on_init: Some(PathBuf::from("lib/init.lisp")),
14195                on_call: Some(PathBuf::from("lib/handlers.lisp")),
14196                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
14197                on_info: Some(PathBuf::from("lib/handlers.lisp")),
14198                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
14199                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
14200            }),
14201        ];
14202        for behavior in fixtures {
14203            let c = caixa_with_behavior(behavior.clone());
14204            assert_eq!(
14205                c.behavior(),
14206                behavior.as_ref(),
14207                "Caixa::behavior must return :behavior verbatim (got \
14208                 {:?}, expected {:?})",
14209                c.behavior(),
14210                behavior.as_ref(),
14211            );
14212            match (c.behavior(), c.behavior.as_ref()) {
14213                (Some(a), Some(b)) => assert!(
14214                    std::ptr::eq(a, b),
14215                    "Caixa::behavior accessor and self.behavior.as_ref() \
14216                     field access must borrow the same backing storage \
14217                     — the accessor is the substrate-primitive typed \
14218                     dispatch every downstream Servico-M2-overlay \
14219                     composite consumer must route through, and a \
14220                     reference-identity split would silently break \
14221                     every consumer that relied on the borrow sharing \
14222                     the composite's storage",
14223                ),
14224                (None, None) => {}
14225                _ => panic!(
14226                    "Caixa::behavior presence bit must byte-equal \
14227                     self.behavior.is_some() — a presence-bit drift \
14228                     would silently split the paired \
14229                     StandardLayout::verify per-`:behavior` shape \
14230                     gate's traversal head from the peer \
14231                     render::servico_m2_overlay M2 overlay emitter's \
14232                     traversal head from the cross-slot \
14233                     validate_upgrade_from_against_behavior \
14234                     composition gate's traversal head from the peer \
14235                     Caixa::declared_servico_slots M2 declared-slot \
14236                     enumerator's presence probe",
14237                ),
14238            }
14239            assert_eq!(
14240                c.behavior().is_some(),
14241                c.behavior.is_some(),
14242                "Caixa::behavior().is_some() must byte-equal \
14243                 self.behavior.is_some() — a presence-bit drift would \
14244                 silently split every downstream Option<&BehaviorSpec> \
14245                 consumer's partition on the runtime-default arm",
14246            );
14247        }
14248    }
14249
14250    #[test]
14251    fn declared_servico_slots_behavior_arm_routes_through_accessor() {
14252        // Composition pin: [`Caixa::declared_servico_slots`]'s
14253        // `:behavior` presence-probe arm must key off
14254        // [`Caixa::behavior`], not the raw `self.behavior.is_some()`
14255        // field-probe. Structurally: a `Caixa { behavior:
14256        // Some(BehaviorSpec::default()), .. }` must still push
14257        // `M2_AUTHOR_KEY_BEHAVIOR` onto the declared-slot list (the
14258        // presence bit is `Some`, so the M2 kind-coherence gate must
14259        // surface the slot as "declared" even when every per-callback
14260        // path is unset), and a `Caixa { behavior: None, .. }` must
14261        // NOT push the label (the "author omitted the slot entirely"
14262        // partition). The pair jointly pins the accessor + declared-
14263        // slot enumerator composition: any future silent detour that
14264        // had the accessor collapse `Some(BehaviorSpec::default())`
14265        // to `None` (a `.filter(|b| !b.is_empty())` projection) would
14266        // silently absorb the "declared but empty" arm at the
14267        // accessor boundary and the
14268        // [`crate::LayoutError::ServicoSlotsOnNonServico`]
14269        // kind-coherence gate would silently accept a struct-literal
14270        // `Caixa` carrying the drift.
14271        //
14272        // Peer of the sibling
14273        // `declared_servico_slots_limits_arm_routes_through_accessor`
14274        // (b2bd9d7) composition pin on the sibling `:limits` outer-
14275        // `Option<&LimitsSpec>` arm of the same
14276        // [`Caixa::declared_servico_slots`] M2 declared-slot
14277        // enumerator's traversal — same "the enumerator gate must
14278        // route through the substrate-primitive typed dispatch"
14279        // discipline extended onto the outer top-level [`Caixa`]
14280        // `Option<&BehaviorSpec>`-composition surface.
14281        use crate::BehaviorSpec;
14282        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
14283        let slots = c.declared_servico_slots();
14284        assert!(
14285            slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
14286            "declared_servico_slots must push M2_AUTHOR_KEY_BEHAVIOR \
14287             when `:behavior` is Some (even for BehaviorSpec::default()) \
14288             — the accessor and the enumerator gate must route through \
14289             the same substrate-primitive typed dispatch on the outer \
14290             :behavior presence bit (got slots={slots:?})",
14291        );
14292        let c = caixa_with_behavior(None);
14293        let slots = c.declared_servico_slots();
14294        assert!(
14295            !slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
14296            "declared_servico_slots must NOT push M2_AUTHOR_KEY_BEHAVIOR \
14297             when `:behavior` is None — the author-omitted arm must \
14298             route through the accessor's None-return unchanged (got \
14299             slots={slots:?})",
14300        );
14301    }
14302
14303    #[test]
14304    fn servico_m2_overlay_behavior_arm_routes_through_accessor() {
14305        // Composition pin: [`crate::render::servico_m2_overlay`]'s
14306        // per-`:behavior` M2 overlay emit arm must key off
14307        // [`Caixa::behavior`], not the raw `&caixa.behavior`
14308        // field-borrow. Structurally: a `Caixa { behavior:
14309        // Some(BehaviorSpec { on_state_change: Some(...), .. default
14310        // }), .. }` must surface the `M2_KEY_BEHAVIOR` key with the
14311        // per-callback `onStateChange` sub-mapping in the overlay, a
14312        // `Caixa { behavior: Some(BehaviorSpec::default()), .. }`
14313        // must omit the key entirely (the `.is_empty()`-gated inner
14314        // arm elides an empty composite even when the outer presence
14315        // bit is `Some`), and a `Caixa { behavior: None, .. }` must
14316        // also omit the key (the "author omitted the slot entirely"
14317        // partition). The three-fixture family jointly pins the
14318        // accessor + M2 overlay emitter composition: any future
14319        // silent detour that had the accessor return a fresh-cloned
14320        // copy on the `Some` arm (a `BehaviorSpec::clone()`
14321        // projection) would silently break the reference-identity
14322        // pin the peer per-callback `serde_yaml::to_value(behavior)`
14323        // projection reads from.
14324        //
14325        // Peer of the sibling
14326        // `servico_m2_overlay_limits_arm_routes_through_accessor`
14327        // (b2bd9d7) composition pin on the sibling `:limits` outer-
14328        // `Option<&LimitsSpec>` arm of the same
14329        // [`crate::render::servico_m2_overlay`] M2 overlay emitter's
14330        // traversal — same "the emitter must route through the
14331        // substrate-primitive typed dispatch on the outer composite"
14332        // discipline extended onto the outer top-level [`Caixa`]
14333        // `Option<&BehaviorSpec>`-composition surface.
14334        use crate::BehaviorSpec;
14335        use crate::render::{M2_KEY_BEHAVIOR, servico_m2_overlay};
14336        use std::path::PathBuf;
14337        let c = caixa_with_behavior(Some(BehaviorSpec {
14338            on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
14339            ..Default::default()
14340        }));
14341        let overlay = servico_m2_overlay(&c).unwrap();
14342        assert!(
14343            overlay.contains_key(M2_KEY_BEHAVIOR),
14344            "servico_m2_overlay must surface M2_KEY_BEHAVIOR when \
14345             `:behavior` carries a non-empty composite — the accessor \
14346             and the M2 overlay emitter must route through the same \
14347             substrate-primitive typed dispatch on the outer :behavior \
14348             composite (got overlay={overlay:?})",
14349        );
14350        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
14351        let overlay = servico_m2_overlay(&c).unwrap();
14352        assert!(
14353            !overlay.contains_key(M2_KEY_BEHAVIOR),
14354            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
14355             `:behavior` is Some(BehaviorSpec::default()) — the empty \
14356             composite's `.is_empty()`-gated inner arm must elide the \
14357             key regardless of the outer presence bit (got \
14358             overlay={overlay:?})",
14359        );
14360        let c = caixa_with_behavior(None);
14361        let overlay = servico_m2_overlay(&c).unwrap();
14362        assert!(
14363            !overlay.contains_key(M2_KEY_BEHAVIOR),
14364            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
14365             `:behavior` is None — the author-omitted arm must route \
14366             through the accessor's None-return unchanged (got \
14367             overlay={overlay:?})",
14368        );
14369    }
14370
14371    #[test]
14372    fn behavior_projects_option_ref_by_borrow() {
14373        // The by-borrow pin: [`Caixa::behavior`] returns
14374        // `Option<&BehaviorSpec>` by borrow — the returned reference
14375        // borrows the underlying `Option<BehaviorSpec>` storage of the
14376        // `:behavior` slot and the accessor must not clone the backing
14377        // composite on every call. Peer of the sibling
14378        // `limits_projects_option_ref_by_borrow` (b2bd9d7) by-borrow
14379        // pin on the outer top-level [`Caixa`] `Option<&Composite>`-
14380        // return sub-family — extended here to the second axis of the
14381        // same sub-family: the accessor's returned reference must
14382        // borrow from `&self` (the returned reference's lifetime is
14383        // tied to `&self`), and calling the accessor twice on the same
14384        // [`Caixa`] must yield references that are pointer-equal (the
14385        // underlying byte-buffer is the storage `BehaviorSpec`'s
14386        // allocation, not a fresh copy) as well as value-equal
14387        // (idempotent, no side effects on `&self`).
14388        //
14389        // Pins against a future silent detour that returned an owned
14390        // `BehaviorSpec` (which would type-check via the `Clone` impl
14391        // but silently clone on every call), a `&BehaviorSpec` panic-
14392        // return on the `None` arm (which would collapse the load-
14393        // bearing `Option` presence-bit into a runtime panic), or a
14394        // one-arm-only accessor that returned a saturating composite
14395        // on some sentinel input.
14396        use crate::BehaviorSpec;
14397        use std::path::PathBuf;
14398        for behavior in [
14399            Some(BehaviorSpec::default()),
14400            Some(BehaviorSpec {
14401                on_init: Some(PathBuf::from("lib/init.lisp")),
14402                on_call: Some(PathBuf::from("lib/handlers.lisp")),
14403                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
14404                on_info: Some(PathBuf::from("lib/handlers.lisp")),
14405                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
14406                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
14407            }),
14408        ] {
14409            let c = caixa_with_behavior(behavior.clone());
14410            let first = c.behavior().unwrap();
14411            let second = c.behavior().unwrap();
14412            assert_eq!(
14413                first, second,
14414                "Caixa::behavior must be idempotent — two successive \
14415                 calls on the same &self must return the same \
14416                 &BehaviorSpec",
14417            );
14418            assert!(
14419                std::ptr::eq(first, second),
14420                "Caixa::behavior must borrow the underlying \
14421                 Option<BehaviorSpec> storage — two successive calls \
14422                 must return references with the same backing pointer \
14423                 (a fresh BehaviorSpec clone would change the pointer \
14424                 on every call)",
14425            );
14426            assert_eq!(
14427                Some(first),
14428                behavior.as_ref(),
14429                "Caixa::behavior must return :behavior verbatim by \
14430                 borrow — got {first:?}, expected {:?}",
14431                behavior.as_ref(),
14432            );
14433        }
14434        let c = caixa_with_behavior(None);
14435        assert!(
14436            c.behavior().is_none(),
14437            "Caixa::behavior must return None when :behavior is absent \
14438             — the author-omitted arm must project through the \
14439             accessor's Option::None unchanged",
14440        );
14441    }
14442
14443    // ── Caixa::politicas — outer top-level Option<&MeshPolicy> composite-reference accessor ──
14444
14445    fn caixa_aplicacao_with_politicas(politicas: Option<crate::aplicacao::MeshPolicy>) -> Caixa {
14446        use crate::aplicacao::{Membro, WitContract};
14447        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14448        c.kind = CaixaKind::Aplicacao;
14449        c.membros = vec![Membro {
14450            caixa: "a".into(),
14451            versao: "^0.1".into(),
14452        }];
14453        c.contratos = vec![WitContract {
14454            de: "a".into(),
14455            para: "a".into(),
14456            wit: "wasi:http/proxy".into(),
14457            endpoint: Some("/x".into()),
14458            subject: None,
14459            slot: None,
14460        }];
14461        c.politicas = politicas;
14462        c
14463    }
14464
14465    #[test]
14466    fn politicas_returns_politicas_option_ref_verbatim_across_permutations() {
14467        // The canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
14468        // composite optional-composite-reference-shape pin:
14469        // [`Caixa::politicas`] must return the `:politicas` typed
14470        // `Option<MeshPolicy>` verbatim as an `Option<&MeshPolicy>`
14471        // reference over the same backing storage the raw
14472        // `self.politicas.as_ref()` field access borrows from,
14473        // byte-equal across every representative fixture in the
14474        // accept-set — the author-omitted `None` shape (the "cluster-
14475        // default applies" partition every downstream mesh-artifact
14476        // emitter treats as "emit no `:politicas` overlay"), the
14477        // empty-composite `Some(MeshPolicy { .. default })` shape
14478        // ([`crate::aplicacao::MeshPolicy::is_empty`] holds — every
14479        // per-axis mesh-policy scalar is `None`, so the peer inner
14480        // [`crate::AplicacaoSpec::politicas`] `.is_empty()`-gated
14481        // caixa-mesh overlay elides every per-axis emit but the outer
14482        // presence-bit is `Some`, so [`Caixa::declared_mesh_slots`]
14483        // still pushes the `M3_AUTHOR_KEY_POLITICAS` label), a
14484        // single-axis fixture (only `:timeout` set — the canonical
14485        // shape a latency-sensitive Aplicacao carries), and a
14486        // fully-populated composite (every per-axis mesh-policy
14487        // scalar set — the canonical shape a fully-governed
14488        // Aplicacao carries).
14489        //
14490        // Pins against a future silent detour that returned a fresh-
14491        // cloned [`crate::aplicacao::MeshPolicy`] copy (which would
14492        // type-check via the `Clone` impl but silently break every
14493        // downstream caller that relied on the reference sharing the
14494        // composite's backing identity), a reference to an operator-
14495        // resolved overlay (the future per-cluster
14496        // `:politicas-overrides` slot — its resolution must land at
14497        // exactly this accessor body, not silently divert the raw
14498        // slot away from the peer [`Caixa::declared_mesh_slots`]
14499        // enumerator's presence probe), a
14500        // `None` → `Some(MeshPolicy::default)` cluster-default
14501        // projection (which would collapse the load-bearing
14502        // "author-omitted `:politicas` ⇒ cluster-default applies"
14503        // partition the peer [`Caixa::declared_mesh_slots`]
14504        // enumerator and the peer [`Caixa::aplicacao_view`]
14505        // Aplicacao-composition seed both read), or an axis-shuffled
14506        // projection (a future detour that swapped `timeout` and
14507        // `retries` through the accessor would silently split the
14508        // paired [`Caixa::aplicacao_view`] seed's fold input from the
14509        // sibling M3 mesh-artifact emitter's projection input).
14510        //
14511        // Third outer top-level [`Caixa`] `Option<&Composite>`-return
14512        // composite-reference accessor pin on the substrate primitive
14513        // — peer of the sibling
14514        // `limits_returns_limits_option_ref_verbatim_across_permutations`
14515        // (b2bd9d7) and
14516        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
14517        // (35d8b52) opening tetrad pins on the outer top-level
14518        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
14519        // here to the first of the three M3 mesh-slot axes so the
14520        // opening third of the outer `Option<&Composite>` sub-family
14521        // carries the same "byte-equal, borrow-shared, presence-bit-
14522        // preserved" outer-accessor discipline.
14523        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
14524        use std::time::Duration;
14525        let fixtures: Vec<Option<MeshPolicy>> = vec![
14526            None,
14527            Some(MeshPolicy::default()),
14528            Some(MeshPolicy {
14529                timeout: Some(Duration::from_secs(30)),
14530                ..Default::default()
14531            }),
14532            Some(MeshPolicy {
14533                timeout: Some(Duration::from_secs(30)),
14534                retries: Some(3),
14535                circuit_breaker: Some(CircuitBreaker {
14536                    max_failures: 5,
14537                    window: Duration::from_secs(60),
14538                }),
14539                mtls_required: Some(true),
14540                rate_limit: Some(RateLimit {
14541                    rate: 100,
14542                    window: Duration::from_secs(1),
14543                }),
14544            }),
14545        ];
14546        for politicas in fixtures {
14547            let c = caixa_aplicacao_with_politicas(politicas.clone());
14548            assert_eq!(
14549                c.politicas(),
14550                politicas.as_ref(),
14551                "Caixa::politicas must return :politicas verbatim (got \
14552                 {:?}, expected {:?})",
14553                c.politicas(),
14554                politicas.as_ref(),
14555            );
14556            match (c.politicas(), c.politicas.as_ref()) {
14557                (Some(a), Some(b)) => assert!(
14558                    std::ptr::eq(a, b),
14559                    "Caixa::politicas accessor and self.politicas.as_ref() \
14560                     field access must borrow the same backing storage \
14561                     — the accessor is the substrate-primitive typed \
14562                     dispatch every downstream Aplicacao-mesh-overlay \
14563                     composite consumer must route through, and a \
14564                     reference-identity split would silently break \
14565                     every consumer that relied on the borrow sharing \
14566                     the composite's storage",
14567                ),
14568                (None, None) => {}
14569                _ => panic!(
14570                    "Caixa::politicas presence bit must byte-equal \
14571                     self.politicas.is_some() — a presence-bit drift \
14572                     would silently split the paired \
14573                     Caixa::aplicacao_view Aplicacao-composition seed's \
14574                     traversal head from the peer \
14575                     Caixa::declared_mesh_slots M3 declared-slot \
14576                     enumerator's presence probe",
14577                ),
14578            }
14579            assert_eq!(
14580                c.politicas().is_some(),
14581                c.politicas.is_some(),
14582                "Caixa::politicas().is_some() must byte-equal \
14583                 self.politicas.is_some() — a presence-bit drift would \
14584                 silently split every downstream Option<&MeshPolicy> \
14585                 consumer's partition on the cluster-default arm",
14586            );
14587        }
14588    }
14589
14590    #[test]
14591    fn declared_mesh_slots_politicas_arm_routes_through_accessor() {
14592        // Composition pin: [`Caixa::declared_mesh_slots`]'s
14593        // `:politicas` presence-probe arm must key off
14594        // [`Caixa::politicas`], not the raw `self.politicas.is_some()`
14595        // field-probe. Structurally: a `Caixa { politicas:
14596        // Some(MeshPolicy::default()), .. }` must still push
14597        // `M3_AUTHOR_KEY_POLITICAS` onto the declared-slot list (the
14598        // presence bit is `Some`, so the M3 kind-coherence gate must
14599        // surface the slot as "declared" even when every per-axis
14600        // scalar is unset), and a `Caixa { politicas: None, .. }` must
14601        // NOT push the label (the "author omitted the slot entirely"
14602        // partition). The pair jointly pins the accessor + declared-
14603        // slot enumerator composition: any future silent detour that
14604        // had the accessor collapse `Some(MeshPolicy::default())` to
14605        // `None` (a `.filter(|p| !p.is_empty())` projection) would
14606        // silently absorb the "declared but empty" arm at the
14607        // accessor boundary and the
14608        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
14609        // coherence gate would silently accept a struct-literal
14610        // `Caixa` carrying the drift.
14611        //
14612        // Peer of the sibling
14613        // `declared_servico_slots_limits_arm_routes_through_accessor`
14614        // (b2bd9d7) and
14615        // `declared_servico_slots_behavior_arm_routes_through_accessor`
14616        // (35d8b52) composition pins on the sibling `:limits` /
14617        // `:behavior` outer-`Option<&Composite>` arms of the peer
14618        // [`Caixa::declared_servico_slots`] M2 declared-slot
14619        // enumerator's traversal — same "the enumerator gate must
14620        // route through the substrate-primitive typed dispatch"
14621        // discipline extended onto the outer top-level [`Caixa`] M3
14622        // mesh-slot family so the [`Caixa::declared_mesh_slots`]
14623        // enumerator carries the same routing invariant as its M2
14624        // sibling.
14625        use crate::aplicacao::MeshPolicy;
14626        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
14627        let slots = c.declared_mesh_slots();
14628        assert!(
14629            slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
14630            "declared_mesh_slots must push M3_AUTHOR_KEY_POLITICAS \
14631             when `:politicas` is Some (even for MeshPolicy::default()) \
14632             — the accessor and the enumerator gate must route through \
14633             the same substrate-primitive typed dispatch on the outer \
14634             :politicas presence bit (got slots={slots:?})",
14635        );
14636        let c = caixa_aplicacao_with_politicas(None);
14637        let slots = c.declared_mesh_slots();
14638        assert!(
14639            !slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
14640            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_POLITICAS \
14641             when `:politicas` is None — the author-omitted arm must \
14642             route through the accessor's None-return unchanged (got \
14643             slots={slots:?})",
14644        );
14645    }
14646
14647    #[test]
14648    fn aplicacao_view_politicas_arm_folds_through_accessor() {
14649        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:politicas`
14650        // Aplicacao-composition seed must fold through
14651        // [`Caixa::politicas`], not the raw
14652        // `self.politicas.clone().unwrap_or_default()` field-borrow.
14653        // Structurally: a `Caixa { politicas: Some(MeshPolicy {
14654        // timeout: Some(30s), .. default }), kind: Aplicacao, .. }`
14655        // must surface a projected [`crate::AplicacaoSpec`] whose
14656        // `politicas().timeout()` field byte-equals the outer
14657        // composite's `timeout` scalar (the fold must project the
14658        // authored composite verbatim), a `Caixa { politicas:
14659        // Some(MeshPolicy::default()), kind: Aplicacao, .. }` must
14660        // surface an [`crate::AplicacaoSpec`] whose `politicas()`
14661        // byte-equals [`crate::aplicacao::MeshPolicy::default`] (the
14662        // fold's empty-composite arm collapses to the same default the
14663        // author-omitted arm does), and a `Caixa { politicas: None,
14664        // kind: Aplicacao, .. }` must surface an
14665        // [`crate::AplicacaoSpec`] whose `politicas()` byte-equals
14666        // [`crate::aplicacao::MeshPolicy::default`] (the "author
14667        // omitted the slot entirely" arm folds through the
14668        // `unwrap_or_default` onto the cluster-default). The triad
14669        // jointly pins the accessor + Aplicacao-composition seed
14670        // composition: any future silent detour that had the accessor
14671        // divert the raw slot away from the seed's fold (an operator-
14672        // resolved overlay's default-fold arm silently differing from
14673        // the raw slot's default-fold arm) would silently split the
14674        // build-time mesh-artifact emission gate from the caixa-mesh
14675        // renderer's Aplicacao-view input at the composition boundary.
14676        use crate::aplicacao::MeshPolicy;
14677        use std::time::Duration;
14678        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy {
14679            timeout: Some(Duration::from_secs(30)),
14680            ..Default::default()
14681        }));
14682        let view = c.aplicacao_view().unwrap();
14683        assert_eq!(
14684            view.politicas().timeout(),
14685            Some(Duration::from_secs(30)),
14686            "Caixa::aplicacao_view must fold the authored :politicas \
14687             :timeout scalar through the accessor verbatim onto the \
14688             projected AplicacaoSpec — a future silent detour at the \
14689             seed's fold arm would surface here as a projected-scalar \
14690             drift (got {:?})",
14691            view.politicas().timeout(),
14692        );
14693        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
14694        let view = c.aplicacao_view().unwrap();
14695        assert_eq!(
14696            view.politicas(),
14697            &MeshPolicy::default(),
14698            "Caixa::aplicacao_view must fold Some(MeshPolicy::default()) \
14699             through the accessor onto MeshPolicy::default — the empty- \
14700             composite arm collapses to the same default the author- \
14701             omitted arm does (got {:?})",
14702            view.politicas(),
14703        );
14704        let c = caixa_aplicacao_with_politicas(None);
14705        let view = c.aplicacao_view().unwrap();
14706        assert_eq!(
14707            view.politicas(),
14708            &MeshPolicy::default(),
14709            "Caixa::aplicacao_view must fold None through the accessor's \
14710             unwrap_or_default onto MeshPolicy::default — the author- \
14711             omitted arm must route through the accessor's None-return \
14712             unchanged (got {:?})",
14713            view.politicas(),
14714        );
14715    }
14716
14717    #[test]
14718    fn politicas_projects_option_ref_by_borrow() {
14719        // The by-borrow pin: [`Caixa::politicas`] returns
14720        // `Option<&MeshPolicy>` by borrow — the returned reference
14721        // borrows the underlying `Option<MeshPolicy>` storage of the
14722        // `:politicas` slot and the accessor must not clone the
14723        // backing composite on every call. Peer of the sibling
14724        // `limits_projects_option_ref_by_borrow` (b2bd9d7) and
14725        // `behavior_projects_option_ref_by_borrow` (35d8b52) by-borrow
14726        // pins on the outer top-level [`Caixa`]
14727        // `Option<&Composite>`-return sub-family — extended here to
14728        // the third axis of the same sub-family: the accessor's
14729        // returned reference must borrow from `&self` (the returned
14730        // reference's lifetime is tied to `&self`), and calling the
14731        // accessor twice on the same [`Caixa`] must yield references
14732        // that are pointer-equal (the underlying byte-buffer is the
14733        // storage `MeshPolicy`'s allocation, not a fresh copy) as
14734        // well as value-equal (idempotent, no side effects on
14735        // `&self`).
14736        //
14737        // Pins against a future silent detour that returned an owned
14738        // `MeshPolicy` (which would type-check via the `Clone` impl
14739        // but silently clone on every call), a `&MeshPolicy` panic-
14740        // return on the `None` arm (which would collapse the load-
14741        // bearing `Option` presence-bit into a runtime panic), or a
14742        // one-arm-only accessor that returned a saturating composite
14743        // on some sentinel input.
14744        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
14745        use std::time::Duration;
14746        for politicas in [
14747            Some(MeshPolicy::default()),
14748            Some(MeshPolicy {
14749                timeout: Some(Duration::from_secs(30)),
14750                retries: Some(3),
14751                circuit_breaker: Some(CircuitBreaker {
14752                    max_failures: 5,
14753                    window: Duration::from_secs(60),
14754                }),
14755                mtls_required: Some(true),
14756                rate_limit: Some(RateLimit {
14757                    rate: 100,
14758                    window: Duration::from_secs(1),
14759                }),
14760            }),
14761        ] {
14762            let c = caixa_aplicacao_with_politicas(politicas.clone());
14763            let first = c.politicas().unwrap();
14764            let second = c.politicas().unwrap();
14765            assert_eq!(
14766                first, second,
14767                "Caixa::politicas must be idempotent — two successive \
14768                 calls on the same &self must return the same \
14769                 &MeshPolicy",
14770            );
14771            assert!(
14772                std::ptr::eq(first, second),
14773                "Caixa::politicas must borrow the underlying \
14774                 Option<MeshPolicy> storage — two successive calls \
14775                 must return references with the same backing pointer \
14776                 (a fresh MeshPolicy clone would change the pointer on \
14777                 every call)",
14778            );
14779            assert_eq!(
14780                Some(first),
14781                politicas.as_ref(),
14782                "Caixa::politicas must return :politicas verbatim by \
14783                 borrow — got {first:?}, expected {:?}",
14784                politicas.as_ref(),
14785            );
14786        }
14787        let c = caixa_aplicacao_with_politicas(None);
14788        assert!(
14789            c.politicas().is_none(),
14790            "Caixa::politicas must return None when :politicas is \
14791             absent — the author-omitted arm must project through the \
14792             accessor's Option::None unchanged",
14793        );
14794    }
14795
14796    // ── Caixa::placement — outer top-level Option<&Placement> composite-reference accessor ──
14797
14798    fn caixa_aplicacao_with_placement(placement: Option<crate::aplicacao::Placement>) -> Caixa {
14799        use crate::aplicacao::{Membro, WitContract};
14800        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14801        c.kind = CaixaKind::Aplicacao;
14802        c.membros = vec![Membro {
14803            caixa: "a".into(),
14804            versao: "^0.1".into(),
14805        }];
14806        c.contratos = vec![WitContract {
14807            de: "a".into(),
14808            para: "a".into(),
14809            wit: "wasi:http/proxy".into(),
14810            endpoint: Some("/x".into()),
14811            subject: None,
14812            slot: None,
14813        }];
14814        c.placement = placement;
14815        c
14816    }
14817
14818    #[test]
14819    fn placement_returns_placement_option_ref_verbatim_across_permutations() {
14820        // The canonical per-`Caixa` `:placement` M3 mesh-slot outer-
14821        // composite optional-composite-reference-shape pin:
14822        // [`Caixa::placement`] must return the `:placement` typed
14823        // `Option<Placement>` verbatim as an `Option<&Placement>`
14824        // reference over the same backing storage the raw
14825        // `self.placement.as_ref()` field access borrows from,
14826        // byte-equal across every representative fixture in the
14827        // accept-set — the author-omitted `None` shape (the
14828        // "cluster-default applies" partition every downstream mesh-
14829        // artifact emitter treats as "emit no `:placement` overlay"),
14830        // the empty-composite `Some(Placement { .. default })` shape
14831        // (`estrategia: SingleNode`, empty clusters, no shard-key /
14832        // affinity — the outer presence-bit is `Some` so
14833        // [`Caixa::declared_mesh_slots`] still pushes the
14834        // `M3_AUTHOR_KEY_PLACEMENT` label), a single-axis
14835        // `Replicated`-on-two-clusters fixture (the canonical shape a
14836        // stateless HTTP Aplicacao carries), and a fully-populated
14837        // `Sharded`-with-shard-key-and-affinity fixture (the canonical
14838        // shape a stateful Akka-style cluster-sharding Aplicacao
14839        // carries).
14840        //
14841        // Pins against a future silent detour that returned a fresh-
14842        // cloned [`crate::aplicacao::Placement`] copy (which would
14843        // type-check via the `Clone` impl but silently break every
14844        // downstream caller that relied on the reference sharing the
14845        // composite's backing identity), a reference to an operator-
14846        // resolved overlay (the future per-cluster
14847        // `:placement-overrides` slot — its resolution must land at
14848        // exactly this accessor body, not silently divert the raw
14849        // slot away from the peer [`Caixa::declared_mesh_slots`]
14850        // enumerator's presence probe), a `None` →
14851        // `Some(Placement::default)` cluster-default projection (which
14852        // would collapse the load-bearing "author-omitted `:placement`
14853        // ⇒ cluster-default applies" partition the peer
14854        // [`Caixa::declared_mesh_slots`] enumerator and the peer
14855        // [`Caixa::aplicacao_view`] Aplicacao-composition seed both
14856        // read), or an axis-shuffled projection (a future detour that
14857        // swapped `clusters` and `affinity` through the accessor would
14858        // silently split the paired [`Caixa::aplicacao_view`] seed's
14859        // fold input from the sibling M3 mesh-artifact emitter's
14860        // projection input).
14861        //
14862        // Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
14863        // composite-reference accessor pin on the substrate primitive
14864        // — peer of the sibling
14865        // `limits_returns_limits_option_ref_verbatim_across_permutations`
14866        // (b2bd9d7),
14867        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
14868        // (35d8b52), and
14869        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
14870        // (5d23d29) opening triad pins on the outer top-level
14871        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
14872        // here to the second of the three M3 mesh-slot axes so the
14873        // opening four-fifths of the outer `Option<&Composite>` sub-
14874        // family carries the same "byte-equal, borrow-shared,
14875        // presence-bit-preserved" outer-accessor discipline.
14876        use crate::aplicacao::{Placement, PlacementStrategy};
14877        let fixtures: Vec<Option<Placement>> = vec![
14878            None,
14879            Some(Placement::default()),
14880            Some(Placement {
14881                estrategia: PlacementStrategy::Replicated,
14882                clusters: vec!["rio".into(), "sao-paulo".into()],
14883                affinity: None,
14884                shard_key: None,
14885            }),
14886            Some(Placement {
14887                estrategia: PlacementStrategy::Sharded,
14888                clusters: vec!["rio".into(), "sao-paulo".into(), "brasilia".into()],
14889                affinity: Some("data-locality".into()),
14890                shard_key: Some("$tenantId".into()),
14891            }),
14892        ];
14893        for placement in fixtures {
14894            let c = caixa_aplicacao_with_placement(placement.clone());
14895            assert_eq!(
14896                c.placement(),
14897                placement.as_ref(),
14898                "Caixa::placement must return :placement verbatim (got \
14899                 {:?}, expected {:?})",
14900                c.placement(),
14901                placement.as_ref(),
14902            );
14903            match (c.placement(), c.placement.as_ref()) {
14904                (Some(a), Some(b)) => assert!(
14905                    std::ptr::eq(a, b),
14906                    "Caixa::placement accessor and self.placement.as_ref() \
14907                     field access must borrow the same backing storage \
14908                     — the accessor is the substrate-primitive typed \
14909                     dispatch every downstream Aplicacao-distribution- \
14910                     overlay composite consumer must route through, and \
14911                     a reference-identity split would silently break \
14912                     every consumer that relied on the borrow sharing \
14913                     the composite's storage",
14914                ),
14915                (None, None) => {}
14916                _ => panic!(
14917                    "Caixa::placement presence bit must byte-equal \
14918                     self.placement.is_some() — a presence-bit drift \
14919                     would silently split the paired \
14920                     Caixa::aplicacao_view Aplicacao-composition seed's \
14921                     traversal head from the peer \
14922                     Caixa::declared_mesh_slots M3 declared-slot \
14923                     enumerator's presence probe",
14924                ),
14925            }
14926            assert_eq!(
14927                c.placement().is_some(),
14928                c.placement.is_some(),
14929                "Caixa::placement().is_some() must byte-equal \
14930                 self.placement.is_some() — a presence-bit drift would \
14931                 silently split every downstream Option<&Placement> \
14932                 consumer's partition on the cluster-default arm",
14933            );
14934        }
14935    }
14936
14937    #[test]
14938    fn declared_mesh_slots_placement_arm_routes_through_accessor() {
14939        // Composition pin: [`Caixa::declared_mesh_slots`]'s
14940        // `:placement` presence-probe arm must key off
14941        // [`Caixa::placement`], not the raw `self.placement.is_some()`
14942        // field-probe. Structurally: a `Caixa { placement:
14943        // Some(Placement::default()), .. }` must still push
14944        // `M3_AUTHOR_KEY_PLACEMENT` onto the declared-slot list (the
14945        // presence bit is `Some`, so the M3 kind-coherence gate must
14946        // surface the slot as "declared" even when every per-axis
14947        // scalar defers to the cluster-default arm), and a `Caixa {
14948        // placement: None, .. }` must NOT push the label (the "author
14949        // omitted the slot entirely" partition). The pair jointly pins
14950        // the accessor + declared-slot enumerator composition: any
14951        // future silent detour that had the accessor collapse
14952        // `Some(Placement::default())` to `None` (a `.filter(|p|
14953        // p.clusters().is_empty().not())` projection) would silently
14954        // absorb the "declared but empty" arm at the accessor boundary
14955        // and the [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
14956        // kind-coherence gate would silently accept a struct-literal
14957        // `Caixa` carrying the drift.
14958        //
14959        // Peer of the sibling
14960        // `declared_servico_slots_limits_arm_routes_through_accessor`
14961        // (b2bd9d7),
14962        // `declared_servico_slots_behavior_arm_routes_through_accessor`
14963        // (35d8b52), and
14964        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
14965        // (5d23d29) composition pins on the sibling `:limits` /
14966        // `:behavior` / `:politicas` outer-`Option<&Composite>` arms
14967        // — same "the enumerator gate must route through the
14968        // substrate-primitive typed dispatch" discipline extended onto
14969        // the second of the three M3 mesh-slot axes so the
14970        // [`Caixa::declared_mesh_slots`] enumerator carries the same
14971        // routing invariant on the `:placement` arm as the peer
14972        // `:politicas` arm.
14973        use crate::aplicacao::Placement;
14974        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
14975        let slots = c.declared_mesh_slots();
14976        assert!(
14977            slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
14978            "declared_mesh_slots must push M3_AUTHOR_KEY_PLACEMENT \
14979             when `:placement` is Some (even for Placement::default()) \
14980             — the accessor and the enumerator gate must route through \
14981             the same substrate-primitive typed dispatch on the outer \
14982             :placement presence bit (got slots={slots:?})",
14983        );
14984        let c = caixa_aplicacao_with_placement(None);
14985        let slots = c.declared_mesh_slots();
14986        assert!(
14987            !slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
14988            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_PLACEMENT \
14989             when `:placement` is None — the author-omitted arm must \
14990             route through the accessor's None-return unchanged (got \
14991             slots={slots:?})",
14992        );
14993    }
14994
14995    #[test]
14996    fn aplicacao_view_placement_arm_folds_through_accessor() {
14997        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:placement`
14998        // Aplicacao-composition seed must fold through
14999        // [`Caixa::placement`], not the raw
15000        // `self.placement.clone().unwrap_or_default()` field-borrow.
15001        // Structurally: a `Caixa { placement: Some(Placement {
15002        // estrategia: Replicated, clusters: ["rio"], .. default }),
15003        // kind: Aplicacao, .. }` must surface a projected
15004        // [`crate::AplicacaoSpec`] whose `placement().estrategia()` +
15005        // `placement().clusters()` byte-equal the outer composite's
15006        // authored values (the fold must project the authored
15007        // composite verbatim), a `Caixa { placement:
15008        // Some(Placement::default()), kind: Aplicacao, .. }` must
15009        // surface an [`crate::AplicacaoSpec`] whose `placement()`
15010        // byte-equals [`crate::aplicacao::Placement::default`] (the
15011        // fold's empty-composite arm collapses to the same default
15012        // the author-omitted arm does), and a `Caixa { placement:
15013        // None, kind: Aplicacao, .. }` must surface an
15014        // [`crate::AplicacaoSpec`] whose `placement()` byte-equals
15015        // [`crate::aplicacao::Placement::default`] (the "author
15016        // omitted the slot entirely" arm folds through the
15017        // `unwrap_or_default` onto the cluster-default). The triad
15018        // jointly pins the accessor + Aplicacao-composition seed
15019        // composition: any future silent detour that had the accessor
15020        // divert the raw slot away from the seed's fold (an operator-
15021        // resolved overlay's default-fold arm silently differing from
15022        // the raw slot's default-fold arm) would silently split the
15023        // build-time distribution-artifact emission gate from the
15024        // caixa-mesh renderer's Aplicacao-view input at the
15025        // composition boundary.
15026        use crate::aplicacao::{Placement, PlacementStrategy};
15027        let c = caixa_aplicacao_with_placement(Some(Placement {
15028            estrategia: PlacementStrategy::Replicated,
15029            clusters: vec!["rio".into()],
15030            affinity: None,
15031            shard_key: None,
15032        }));
15033        let view = c.aplicacao_view().unwrap();
15034        assert_eq!(
15035            view.placement().estrategia(),
15036            PlacementStrategy::Replicated,
15037            "Caixa::aplicacao_view must fold the authored :placement \
15038             :estrategia scalar through the accessor verbatim onto the \
15039             projected AplicacaoSpec — a future silent detour at the \
15040             seed's fold arm would surface here as a projected-scalar \
15041             drift (got {:?})",
15042            view.placement().estrategia(),
15043        );
15044        assert_eq!(
15045            view.placement().clusters(),
15046            &["rio"],
15047            "Caixa::aplicacao_view must fold the authored :placement \
15048             :clusters list through the accessor verbatim onto the \
15049             projected AplicacaoSpec — a future silent detour at the \
15050             seed's fold arm would surface here as a projected-list \
15051             drift (got {:?})",
15052            view.placement().clusters(),
15053        );
15054        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
15055        let view = c.aplicacao_view().unwrap();
15056        assert_eq!(
15057            view.placement(),
15058            &Placement::default(),
15059            "Caixa::aplicacao_view must fold Some(Placement::default()) \
15060             through the accessor onto Placement::default — the empty- \
15061             composite arm collapses to the same default the author- \
15062             omitted arm does (got {:?})",
15063            view.placement(),
15064        );
15065        let c = caixa_aplicacao_with_placement(None);
15066        let view = c.aplicacao_view().unwrap();
15067        assert_eq!(
15068            view.placement(),
15069            &Placement::default(),
15070            "Caixa::aplicacao_view must fold None through the accessor's \
15071             unwrap_or_default onto Placement::default — the author- \
15072             omitted arm must route through the accessor's None-return \
15073             unchanged (got {:?})",
15074            view.placement(),
15075        );
15076    }
15077
15078    #[test]
15079    fn placement_projects_option_ref_by_borrow() {
15080        // The by-borrow pin: [`Caixa::placement`] returns
15081        // `Option<&Placement>` by borrow — the returned reference
15082        // borrows the underlying `Option<Placement>` storage of the
15083        // `:placement` slot and the accessor must not clone the
15084        // backing composite on every call. Peer of the sibling
15085        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
15086        // `behavior_projects_option_ref_by_borrow` (35d8b52), and
15087        // `politicas_projects_option_ref_by_borrow` (5d23d29) by-borrow
15088        // pins on the outer top-level [`Caixa`]
15089        // `Option<&Composite>`-return sub-family — extended here to
15090        // the fourth axis of the same sub-family: the accessor's
15091        // returned reference must borrow from `&self` (the returned
15092        // reference's lifetime is tied to `&self`), and calling the
15093        // accessor twice on the same [`Caixa`] must yield references
15094        // that are pointer-equal (the underlying byte-buffer is the
15095        // storage `Placement`'s allocation, not a fresh copy) as well
15096        // as value-equal (idempotent, no side effects on `&self`).
15097        //
15098        // Pins against a future silent detour that returned an owned
15099        // `Placement` (which would type-check via the `Clone` impl
15100        // but silently clone on every call), a `&Placement` panic-
15101        // return on the `None` arm (which would collapse the load-
15102        // bearing `Option` presence-bit into a runtime panic), or a
15103        // one-arm-only accessor that returned a saturating composite
15104        // on some sentinel input.
15105        use crate::aplicacao::{Placement, PlacementStrategy};
15106        for placement in [
15107            Some(Placement::default()),
15108            Some(Placement {
15109                estrategia: PlacementStrategy::Sharded,
15110                clusters: vec!["rio".into(), "sao-paulo".into()],
15111                affinity: Some("data-locality".into()),
15112                shard_key: Some("$tenantId".into()),
15113            }),
15114        ] {
15115            let c = caixa_aplicacao_with_placement(placement.clone());
15116            let first = c.placement().unwrap();
15117            let second = c.placement().unwrap();
15118            assert_eq!(
15119                first, second,
15120                "Caixa::placement must be idempotent — two successive \
15121                 calls on the same &self must return the same \
15122                 &Placement",
15123            );
15124            assert!(
15125                std::ptr::eq(first, second),
15126                "Caixa::placement must borrow the underlying \
15127                 Option<Placement> storage — two successive calls \
15128                 must return references with the same backing pointer \
15129                 (a fresh Placement clone would change the pointer on \
15130                 every call)",
15131            );
15132            assert_eq!(
15133                Some(first),
15134                placement.as_ref(),
15135                "Caixa::placement must return :placement verbatim by \
15136                 borrow — got {first:?}, expected {:?}",
15137                placement.as_ref(),
15138            );
15139        }
15140        let c = caixa_aplicacao_with_placement(None);
15141        assert!(
15142            c.placement().is_none(),
15143            "Caixa::placement must return None when :placement is \
15144             absent — the author-omitted arm must project through the \
15145             accessor's Option::None unchanged",
15146        );
15147    }
15148
15149    // ── Caixa::entrada — outer top-level Option<&Entrada> composite-reference accessor ──
15150
15151    fn caixa_aplicacao_with_entrada(entrada: Option<crate::aplicacao::Entrada>) -> Caixa {
15152        use crate::aplicacao::{Membro, WitContract};
15153        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15154        c.kind = CaixaKind::Aplicacao;
15155        c.membros = vec![Membro {
15156            caixa: "a".into(),
15157            versao: "^0.1".into(),
15158        }];
15159        c.contratos = vec![WitContract {
15160            de: "a".into(),
15161            para: "a".into(),
15162            wit: "wasi:http/proxy".into(),
15163            endpoint: Some("/x".into()),
15164            subject: None,
15165            slot: None,
15166        }];
15167        c.entrada = entrada;
15168        c
15169    }
15170
15171    #[test]
15172    fn entrada_returns_entrada_option_ref_verbatim_across_permutations() {
15173        // The canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
15174        // composite optional-composite-reference-shape pin:
15175        // [`Caixa::entrada`] must return the `:entrada` typed
15176        // `Option<Entrada>` verbatim as an `Option<&Entrada>`
15177        // reference over the same backing storage the raw
15178        // `self.entrada.as_ref()` field access borrows from,
15179        // byte-equal across every representative fixture in the
15180        // accept-set — the author-omitted `None` shape (the
15181        // "cluster-internal Aplicacao" partition every downstream
15182        // Gateway-API emitter treats as "emit no listener + no
15183        // HTTPRoute"), a bare-`host`/`para` minimum-composite fixture
15184        // (empty `paths` — the resolved-paths fallback the peer
15185        // [`crate::aplicacao::Entrada::resolved_paths`] cascade folds
15186        // onto the substrate catch-all), and a fully-populated
15187        // multi-path-with-non-default-port fixture (the canonical
15188        // shape a public HTTP Aplicacao carries).
15189        //
15190        // Pins against a future silent detour that returned a fresh-
15191        // cloned [`crate::aplicacao::Entrada`] copy (which would
15192        // type-check via the `Clone` impl but silently break every
15193        // downstream caller that relied on the reference sharing the
15194        // composite's backing identity), a reference to an operator-
15195        // resolved overlay (the future per-cluster
15196        // `:entrada-overrides` slot — its resolution must land at
15197        // exactly this accessor body, not silently divert the raw
15198        // slot away from the peer [`Caixa::declared_mesh_slots`]
15199        // enumerator's presence probe), or an axis-shuffled projection
15200        // (a future detour that swapped `host` and `para` through the
15201        // accessor would silently split the paired
15202        // [`Caixa::aplicacao_view`] seed's forward input from the
15203        // sibling M3 gateway-artifact emitter's projection input).
15204        //
15205        // Fifth and final outer top-level [`Caixa`]
15206        // `Option<&Composite>`-return composite-reference accessor pin
15207        // on the substrate primitive — peer of the sibling
15208        // `limits_returns_limits_option_ref_verbatim_across_permutations`
15209        // (b2bd9d7),
15210        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
15211        // (35d8b52),
15212        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
15213        // (5d23d29), and
15214        // `placement_returns_placement_option_ref_verbatim_across_permutations`
15215        // (4fb8074) opening tetrad pins on the outer top-level
15216        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
15217        // here to the third and final M3 mesh-slot axis so the closed
15218        // outer `Option<&Composite>` sub-family carries the same
15219        // "byte-equal, borrow-shared, presence-bit-preserved" outer-
15220        // accessor discipline across all five arms.
15221        use crate::aplicacao::Entrada;
15222        let fixtures: Vec<Option<Entrada>> = vec![
15223            None,
15224            Some(Entrada {
15225                host: "checkout.quero.cloud".into(),
15226                para: "gateway".into(),
15227                paths: Vec::new(),
15228                port: crate::DEFAULT_SERVICO_PORT,
15229            }),
15230            Some(Entrada {
15231                host: "api.pleme.io".into(),
15232                para: "public-api".into(),
15233                paths: vec!["/v1".into(), "/v2".into()],
15234                port: 8080,
15235            }),
15236        ];
15237        for entrada in fixtures {
15238            let c = caixa_aplicacao_with_entrada(entrada.clone());
15239            assert_eq!(
15240                c.entrada(),
15241                entrada.as_ref(),
15242                "Caixa::entrada must return :entrada verbatim (got \
15243                 {:?}, expected {:?})",
15244                c.entrada(),
15245                entrada.as_ref(),
15246            );
15247            match (c.entrada(), c.entrada.as_ref()) {
15248                (Some(a), Some(b)) => assert!(
15249                    std::ptr::eq(a, b),
15250                    "Caixa::entrada accessor and self.entrada.as_ref() \
15251                     field access must borrow the same backing storage \
15252                     — the accessor is the substrate-primitive typed \
15253                     dispatch every downstream Aplicacao-external- \
15254                     gateway composite consumer must route through, and \
15255                     a reference-identity split would silently break \
15256                     every consumer that relied on the borrow sharing \
15257                     the composite's storage",
15258                ),
15259                (None, None) => {}
15260                _ => panic!(
15261                    "Caixa::entrada presence bit must byte-equal \
15262                     self.entrada.is_some() — a presence-bit drift \
15263                     would silently split the paired \
15264                     Caixa::aplicacao_view Aplicacao-composition seed's \
15265                     traversal head from the peer \
15266                     Caixa::declared_mesh_slots M3 declared-slot \
15267                     enumerator's presence probe",
15268                ),
15269            }
15270            assert_eq!(
15271                c.entrada().is_some(),
15272                c.entrada.is_some(),
15273                "Caixa::entrada().is_some() must byte-equal \
15274                 self.entrada.is_some() — a presence-bit drift would \
15275                 silently split every downstream Option<&Entrada> \
15276                 consumer's partition on the cluster-internal arm",
15277            );
15278        }
15279    }
15280
15281    #[test]
15282    fn declared_mesh_slots_entrada_arm_routes_through_accessor() {
15283        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:entrada`
15284        // presence-probe arm must key off [`Caixa::entrada`], not the
15285        // raw `self.entrada.is_some()` field-probe. Structurally: a
15286        // `Caixa { entrada: Some(Entrada { host: "...", para: "...",
15287        // paths: [], port: DEFAULT_SERVICO_PORT }), .. }` must push
15288        // `M3_AUTHOR_KEY_ENTRADA` onto the declared-slot list (the
15289        // presence bit is `Some`, so the M3 kind-coherence gate must
15290        // surface the slot as "declared" even when every per-axis
15291        // scalar defers to the substrate catch-all / default port),
15292        // and a `Caixa { entrada: None, .. }` must NOT push the label
15293        // (the "author omitted the slot entirely" partition). The pair
15294        // jointly pins the accessor + declared-slot enumerator
15295        // composition: any future silent detour that had the accessor
15296        // collapse `Some(Entrada { paths: [], .. })` to `None` (a
15297        // `.filter(|e| !e.paths.is_empty())` projection) would silently
15298        // absorb the "declared but empty-paths" arm at the accessor
15299        // boundary and the
15300        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
15301        // coherence gate would silently accept a struct-literal
15302        // `Caixa` carrying the drift.
15303        //
15304        // Peer of the sibling
15305        // `declared_servico_slots_limits_arm_routes_through_accessor`
15306        // (b2bd9d7),
15307        // `declared_servico_slots_behavior_arm_routes_through_accessor`
15308        // (35d8b52),
15309        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
15310        // (5d23d29), and
15311        // `declared_mesh_slots_placement_arm_routes_through_accessor`
15312        // (4fb8074) composition pins on the sibling `:limits` /
15313        // `:behavior` / `:politicas` / `:placement` outer-
15314        // `Option<&Composite>` arms — same "the enumerator gate must
15315        // route through the substrate-primitive typed dispatch"
15316        // discipline extended onto the third and final M3 mesh-slot
15317        // axis so the [`Caixa::declared_mesh_slots`] enumerator now
15318        // carries the routing invariant on every M3 mesh-slot arm.
15319        use crate::aplicacao::Entrada;
15320        let c = caixa_aplicacao_with_entrada(Some(Entrada {
15321            host: "checkout.quero.cloud".into(),
15322            para: "gateway".into(),
15323            paths: Vec::new(),
15324            port: crate::DEFAULT_SERVICO_PORT,
15325        }));
15326        let slots = c.declared_mesh_slots();
15327        assert!(
15328            slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
15329            "declared_mesh_slots must push M3_AUTHOR_KEY_ENTRADA when \
15330             `:entrada` is Some (even for empty-paths / default-port) \
15331             — the accessor and the enumerator gate must route through \
15332             the same substrate-primitive typed dispatch on the outer \
15333             :entrada presence bit (got slots={slots:?})",
15334        );
15335        let c = caixa_aplicacao_with_entrada(None);
15336        let slots = c.declared_mesh_slots();
15337        assert!(
15338            !slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
15339            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_ENTRADA \
15340             when `:entrada` is None — the author-omitted arm must \
15341             route through the accessor's None-return unchanged (got \
15342             slots={slots:?})",
15343        );
15344    }
15345
15346    #[test]
15347    fn aplicacao_view_entrada_arm_folds_through_accessor() {
15348        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:entrada`
15349        // Aplicacao-composition seed must fold through
15350        // [`Caixa::entrada`], not the raw `self.entrada.clone()` field-
15351        // borrow. Structurally: a `Caixa { entrada: Some(Entrada {
15352        // host: "api.pleme.io", para: "public-api", paths: ["/v1"],
15353        // port: 8080 }), kind: Aplicacao, .. }` must surface a projected
15354        // [`crate::AplicacaoSpec`] whose `entrada().unwrap()` byte-
15355        // equals the outer composite's authored value (the fold must
15356        // project the authored composite verbatim), and a `Caixa {
15357        // entrada: None, kind: Aplicacao, .. }` must surface an
15358        // [`crate::AplicacaoSpec`] whose `entrada()` is `None` (the
15359        // "author omitted the slot entirely" arm folds through the
15360        // accessor's `Option::cloned` onto the same `None` presence
15361        // bit — unlike the peer `:politicas` / `:placement` arms
15362        // `:entrada` has no cluster-default fold, the omitted arm
15363        // stays omitted). The pair jointly pins the accessor +
15364        // Aplicacao-composition seed composition: any future silent
15365        // detour that had the accessor divert the raw slot away from
15366        // the seed's fold (an operator-resolved overlay's forward arm
15367        // silently differing from the raw slot's forward arm) would
15368        // silently split the build-time gateway-artifact emission gate
15369        // from the caixa-mesh renderer's Aplicacao-view input at the
15370        // composition boundary.
15371        use crate::aplicacao::Entrada;
15372        let authored = Entrada {
15373            host: "api.pleme.io".into(),
15374            para: "public-api".into(),
15375            paths: vec!["/v1".into()],
15376            port: 8080,
15377        };
15378        let c = caixa_aplicacao_with_entrada(Some(authored.clone()));
15379        let view = c.aplicacao_view().unwrap();
15380        assert_eq!(
15381            view.entrada(),
15382            Some(&authored),
15383            "Caixa::aplicacao_view must fold the authored :entrada \
15384             composite through the accessor verbatim onto the \
15385             projected AplicacaoSpec — a future silent detour at the \
15386             seed's fold arm would surface here as a projected- \
15387             composite drift (got {:?})",
15388            view.entrada(),
15389        );
15390        let c = caixa_aplicacao_with_entrada(None);
15391        let view = c.aplicacao_view().unwrap();
15392        assert!(
15393            view.entrada().is_none(),
15394            "Caixa::aplicacao_view must fold None through the \
15395             accessor's Option::cloned onto None — the author- \
15396             omitted arm must route through the accessor's None-return \
15397             unchanged (got {:?})",
15398            view.entrada(),
15399        );
15400    }
15401
15402    #[test]
15403    fn entrada_projects_option_ref_by_borrow() {
15404        // The by-borrow pin: [`Caixa::entrada`] returns
15405        // `Option<&Entrada>` by borrow — the returned reference
15406        // borrows the underlying `Option<Entrada>` storage of the
15407        // `:entrada` slot and the accessor must not clone the backing
15408        // composite on every call. Peer of the sibling
15409        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
15410        // `behavior_projects_option_ref_by_borrow` (35d8b52),
15411        // `politicas_projects_option_ref_by_borrow` (5d23d29), and
15412        // `placement_projects_option_ref_by_borrow` (4fb8074) by-
15413        // borrow pins on the outer top-level [`Caixa`]
15414        // `Option<&Composite>`-return sub-family — extended here to
15415        // the fifth and final axis of the same sub-family, closing
15416        // the discipline: the accessor's returned reference must
15417        // borrow from `&self` (the returned reference's lifetime is
15418        // tied to `&self`), and calling the accessor twice on the
15419        // same [`Caixa`] must yield references that are pointer-equal
15420        // (the underlying byte-buffer is the storage `Entrada`'s
15421        // allocation, not a fresh copy) as well as value-equal
15422        // (idempotent, no side effects on `&self`).
15423        //
15424        // Pins against a future silent detour that returned an owned
15425        // `Entrada` (which would type-check via the `Clone` impl but
15426        // silently clone on every call), a `&Entrada` panic-return on
15427        // the `None` arm (which would collapse the load-bearing
15428        // `Option` presence-bit into a runtime panic), or a one-arm-
15429        // only accessor that returned a saturating composite on some
15430        // sentinel input.
15431        use crate::aplicacao::Entrada;
15432        for entrada in [
15433            Some(Entrada {
15434                host: "checkout.quero.cloud".into(),
15435                para: "gateway".into(),
15436                paths: Vec::new(),
15437                port: crate::DEFAULT_SERVICO_PORT,
15438            }),
15439            Some(Entrada {
15440                host: "api.pleme.io".into(),
15441                para: "public-api".into(),
15442                paths: vec!["/v1".into(), "/v2".into()],
15443                port: 8080,
15444            }),
15445        ] {
15446            let c = caixa_aplicacao_with_entrada(entrada.clone());
15447            let first = c.entrada().unwrap();
15448            let second = c.entrada().unwrap();
15449            assert_eq!(
15450                first, second,
15451                "Caixa::entrada must be idempotent — two successive \
15452                 calls on the same &self must return the same &Entrada",
15453            );
15454            assert!(
15455                std::ptr::eq(first, second),
15456                "Caixa::entrada must borrow the underlying \
15457                 Option<Entrada> storage — two successive calls must \
15458                 return references with the same backing pointer (a \
15459                 fresh Entrada clone would change the pointer on every \
15460                 call)",
15461            );
15462            assert_eq!(
15463                Some(first),
15464                entrada.as_ref(),
15465                "Caixa::entrada must return :entrada verbatim by \
15466                 borrow — got {first:?}, expected {:?}",
15467                entrada.as_ref(),
15468            );
15469        }
15470        let c = caixa_aplicacao_with_entrada(None);
15471        assert!(
15472            c.entrada().is_none(),
15473            "Caixa::entrada must return None when :entrada is absent \
15474             — the author-omitted arm must project through the \
15475             accessor's Option::None unchanged",
15476        );
15477    }
15478
15479    // ── Caixa::estrategia — outer top-level Option<RestartStrategy> flat-spread supervisor-tree accessor ──
15480
15481    fn caixa_with_estrategia(estrategia: Option<crate::supervisor::RestartStrategy>) -> Caixa {
15482        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15483        c.estrategia = estrategia;
15484        c
15485    }
15486
15487    #[test]
15488    fn estrategia_returns_estrategia_option_verbatim_across_permutations() {
15489        // The canonical per-`Caixa` `:estrategia` M2 supervisor-tree-slot
15490        // flat-spread `Option<RestartStrategy>`-return `Copy`-composite-
15491        // enum-arm scalar shape pin: [`Caixa::estrategia`] must return
15492        // the `:estrategia` typed `Option<crate::supervisor::RestartStrategy>`
15493        // verbatim as an `Option<RestartStrategy>` `Copy`-projected value
15494        // over the same discriminant the raw `self.estrategia` field
15495        // access carries, byte-equal across every representative fixture
15496        // in the accept-set — the author-omitted `None` shape (the
15497        // "defer to [`RestartStrategy::default`] through the
15498        // [`Self::supervisor_view`] `unwrap_or_default()` fold" partition
15499        // every non-`Supervisor`-kind `defcaixa` carries by
15500        // `#[serde(default)]`), and each of the four closed-set variants
15501        // [`RestartStrategy::OneForOne`] / [`RestartStrategy::OneForAll`]
15502        // / [`RestartStrategy::RestForOne`] /
15503        // [`RestartStrategy::SimpleOneForOne`] the author-declared arm
15504        // partitions on.
15505        //
15506        // Pins against a future silent detour that re-derived the
15507        // strategy from a peer axis (an accidental fallback to
15508        // `if children.is_empty() { SimpleOneForOne } else { OneForOne }`
15509        // collapse that read the outer `:children` list-length axis into
15510        // the strategy discriminator at the accessor boundary), a
15511        // stale-derive detour that substituted [`RestartStrategy::default`]
15512        // when the outer `Option` held `None` (which would silently
15513        // collapse the load-bearing "author explicitly declared
15514        // `:estrategia OneForOne`" vs "author omitted the slot and
15515        // inherited the default" partition the [`Self::declared_supervisor_slots`]
15516        // presence-probe reads — the enumerator gate would still push
15517        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` on the omitted arm, silently
15518        // splitting the paired [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
15519        // kind-coherence gate's traversal head from the
15520        // [`Self::supervisor_view`] `unwrap_or_default()` fold's
15521        // composition head), a reference to an operator-resolved overlay
15522        // (the future per-cluster `:estrategia-overrides` slot — its
15523        // resolution must land at exactly this accessor body, not
15524        // silently divert the raw slot away from a second consumer), or
15525        // an axis-remap projection (a future detour that mapped
15526        // `OneForAll` through the accessor onto `OneForOne` would
15527        // silently split every downstream sibling-restart-strategy
15528        // consumer's per-arm fan-out).
15529        //
15530        // First outer top-level [`Caixa`] `Option<Copy>`-return
15531        // supervisor-tree-slot flat-spread accessor pin on the substrate
15532        // primitive — opens the outer-`Caixa` `Option<Copy>` flat-spread
15533        // projection pattern the sibling per-`Caixa` `:max-restarts` /
15534        // `:restart-window` future outer-scalar pins fold on. Peer of
15535        // the inner-altitude
15536        // `supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
15537        // (eafb619) pin on the post-composition [`SupervisorSpec`]
15538        // altitude — same "the substrate-primitive accessor must byte-
15539        // equal the raw field access verbatim across every author-
15540        // declared value" discipline extended onto the pre-composition
15541        // outer author-surface [`Caixa`] altitude. Peer of the closed
15542        // outer-`Caixa` `Option<&Composite>` composite-reference family
15543        // the sibling `limits` / `behavior` / `politicas` / `placement` /
15544        // `entrada`
15545        // `..._returns_..._option_ref_verbatim_across_permutations` pins
15546        // already carry on the outer `Option<&Composite>` altitude.
15547        use crate::supervisor::RestartStrategy;
15548        let fixtures: Vec<Option<RestartStrategy>> = vec![
15549            None,
15550            Some(RestartStrategy::OneForOne),
15551            Some(RestartStrategy::OneForAll),
15552            Some(RestartStrategy::RestForOne),
15553            Some(RestartStrategy::SimpleOneForOne),
15554        ];
15555        for estrategia in fixtures {
15556            let c = caixa_with_estrategia(estrategia);
15557            assert_eq!(
15558                c.estrategia(),
15559                estrategia,
15560                "Caixa::estrategia must return :estrategia verbatim (got \
15561                 {:?}, expected {:?})",
15562                c.estrategia(),
15563                estrategia,
15564            );
15565            assert_eq!(
15566                c.estrategia(),
15567                c.estrategia,
15568                "Caixa::estrategia accessor and self.estrategia field \
15569                 access must byte-equal — the accessor is the substrate-\
15570                 primitive typed dispatch every downstream supervisor-\
15571                 tree flat-spread consumer must route through, and a \
15572                 discriminant split would silently break every consumer \
15573                 that relied on the accessor sharing the field's own \
15574                 Option<Copy> shape",
15575            );
15576            assert_eq!(
15577                c.estrategia().is_some(),
15578                c.estrategia.is_some(),
15579                "Caixa::estrategia().is_some() must byte-equal \
15580                 self.estrategia.is_some() — a presence-bit drift would \
15581                 silently split the paired Caixa::declared_supervisor_slots \
15582                 presence-probe arm from the Caixa::supervisor_view \
15583                 unwrap_or_default() fold's composition input",
15584            );
15585        }
15586    }
15587
15588    #[test]
15589    fn declared_supervisor_slots_estrategia_arm_routes_through_accessor() {
15590        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
15591        // `:estrategia` presence-probe arm must key off
15592        // [`Caixa::estrategia`], not the raw `self.estrategia.is_some()`
15593        // field-probe. Structurally: every `Caixa { estrategia:
15594        // Some(RestartStrategy::_), .. }` variant must push
15595        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` onto the declared-slot list
15596        // (the presence bit is `Some` for every closed-set variant, so
15597        // the M2 supervisor-tree kind-coherence gate must surface the
15598        // slot as "declared" regardless of which variant the author
15599        // picked), and a `Caixa { estrategia: None, .. }` must NOT push
15600        // the label (the "author omitted the slot entirely, deferring
15601        // to [`RestartStrategy::default`] through the supervisor_view
15602        // fold" partition). The pair jointly pins the accessor +
15603        // declared-slot enumerator composition: any future silent detour
15604        // that had the accessor collapse `Some(RestartStrategy::default())`
15605        // to `None` (a `.filter(|e| *e != RestartStrategy::default())`
15606        // projection) would silently absorb the "declared but default-
15607        // valued" arm at the accessor boundary and the
15608        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
15609        // coherence gate would silently accept a struct-literal `Caixa`
15610        // carrying the drift.
15611        //
15612        // Peer of the sibling per-`Caixa`
15613        // `declared_servico_slots_limits_arm_routes_through_accessor`
15614        // (b2bd9d7) accessor-composition pin on the sibling outer-`Caixa`
15615        // `Option<&LimitsSpec>` composition axis — same "the enumerator
15616        // gate must route through the substrate-primitive typed
15617        // dispatch" discipline extended onto the flat-spread M2
15618        // supervisor-tree `Option<RestartStrategy>`-composition surface,
15619        // opening the outer-`Caixa` supervisor-tree-slot arm of the
15620        // composition-pin family.
15621        use crate::supervisor::RestartStrategy;
15622        for estrategia in [
15623            RestartStrategy::OneForOne,
15624            RestartStrategy::OneForAll,
15625            RestartStrategy::RestForOne,
15626            RestartStrategy::SimpleOneForOne,
15627        ] {
15628            let c = caixa_with_estrategia(Some(estrategia));
15629            let slots = c.declared_supervisor_slots();
15630            assert!(
15631                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
15632                "declared_supervisor_slots must push \
15633                 SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is \
15634                 Some({estrategia:?}) — the accessor and the enumerator \
15635                 gate must route through the same substrate-primitive \
15636                 typed dispatch on the outer :estrategia presence bit \
15637                 (got slots={slots:?})",
15638            );
15639        }
15640        let c = caixa_with_estrategia(None);
15641        let slots = c.declared_supervisor_slots();
15642        assert!(
15643            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
15644            "declared_supervisor_slots must NOT push \
15645             SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is None \
15646             — the author-omitted arm must route through the accessor's \
15647             None-return unchanged (got slots={slots:?})",
15648        );
15649    }
15650
15651    #[test]
15652    fn supervisor_view_estrategia_arm_routes_through_accessor() {
15653        // Composition pin: [`Caixa::supervisor_view`]'s per-`:estrategia`
15654        // [`SupervisorSpec`] construction arm must key off
15655        // [`Caixa::estrategia`]'s `unwrap_or_default()` fold, not the raw
15656        // `self.estrategia.unwrap_or_default()` field-fold. Structurally:
15657        // for every `:kind Supervisor` `Caixa` carrying an author-
15658        // declared `Some(RestartStrategy::_)` variant, the composed
15659        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal the
15660        // outer accessor's declared variant unchanged; and for a
15661        // `:kind Supervisor` `Caixa` carrying `None`, the composed
15662        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal
15663        // [`RestartStrategy::default`] (the [`RestartStrategy::OneForOne`]
15664        // arm the flat-spread `unwrap_or_default()` fold projects to on
15665        // the author-omitted arm — this is the *composition* between the
15666        // outer `Option<RestartStrategy>` accessor's presence-bit
15667        // surface and the inner post-composition non-`Option`
15668        // [`SupervisorSpec::estrategia`] altitude). The pair jointly
15669        // pins the accessor + supervisor_view composition: any future
15670        // silent detour that had the accessor promote `None` to
15671        // `Some(RestartStrategy::default())` (a `.or_else(|| Some(RestartStrategy::default()))`
15672        // projection) would silently collapse the two arms into one at
15673        // the accessor boundary and the [`Self::declared_supervisor_slots`]
15674        // presence probe would silently drift from the composition site.
15675        //
15676        // Peer of the sibling M2 supervisor-slot post-composition
15677        // `validate_reads_through_lifted_estrategia_accessor` (eafb619)
15678        // pin on the [`SupervisorSpec::validate`] altitude — this pin
15679        // extends that inner-altitude accessor-routing discipline onto
15680        // the pre-composition outer author-surface [`Caixa`] altitude,
15681        // pinning the composition edge between the flat-spread outer
15682        // `Option<RestartStrategy>` and the composed [`SupervisorSpec`]
15683        // `RestartStrategy` axes.
15684        use crate::CaixaKind;
15685        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
15686        for estrategia in [
15687            RestartStrategy::OneForOne,
15688            RestartStrategy::OneForAll,
15689            RestartStrategy::RestForOne,
15690            RestartStrategy::SimpleOneForOne,
15691        ] {
15692            let mut c = caixa_with_estrategia(Some(estrategia));
15693            c.kind = CaixaKind::Supervisor;
15694            // Route the `SimpleOneForOne ↔ non-SimpleOneForOne` fixture-
15695            // shape partition through the [`gen_platform::IsVariant`]
15696            // derive-generated
15697            // [`RestartStrategy::is_simple_one_for_one`] predicate rather
15698            // than the raw `matches!(estrategia, RestartStrategy::
15699            // SimpleOneForOne)` open-coded pattern-match — same closed-
15700            // set-typed-enum arm-discriminator dispatch discipline the
15701            // sibling [`crate::upgrade::UpgradeInstruction::is_restart`]
15702            // convergence (915a934) extended onto its two paired positive
15703            // / negated `matches!` sites and the peer
15704            // [`crate::aplicacao::PlacementStrategy`] `IsVariant`-derived
15705            // predicate convergence (766ec63) extended onto the M3 mesh-
15706            // slot per-`:placement` distribution-strategy discriminator
15707            // axis. See the sibling `supervisor::tests::
15708            // round_trip_all_strategies` and
15709            // `supervisor::tests::supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
15710            // fixtures — the three sites (all test-only,
15711            // acknowledged in 915a934's Prior-commits footnote as the
15712            // outstanding follow-up) now consult one typed dispatch on
15713            // the substrate primitive.
15714            c.children = if estrategia.is_simple_one_for_one() {
15715                Vec::new()
15716            } else {
15717                vec![ChildSpec {
15718                    caixa: "worker".into(),
15719                    versao: "^0.1".into(),
15720                    restart: RestartPolicy::Permanent,
15721                }]
15722            };
15723            let view = c.supervisor_view().expect(
15724                "supervisor_view must materialize a SupervisorSpec for a \
15725                 :kind Supervisor Caixa carrying a Some(:estrategia) slot",
15726            );
15727            assert_eq!(
15728                view.estrategia(),
15729                c.estrategia().unwrap(),
15730                "supervisor_view must carry the outer Caixa::estrategia() \
15731                 declared variant onto the composed SupervisorSpec.estrategia \
15732                 field verbatim on the Some arm (got {:?}, expected {:?})",
15733                view.estrategia(),
15734                c.estrategia().unwrap(),
15735            );
15736        }
15737        // The author-omitted arm: outer `None` → composed
15738        // `RestartStrategy::default()` through the flat-spread
15739        // `unwrap_or_default()` fold.
15740        let mut c = caixa_with_estrategia(None);
15741        c.kind = CaixaKind::Supervisor;
15742        // Populate children so the sibling supervisor slots are coherent
15743        // for the [`Self::supervisor_view`] projection; the `:estrategia`
15744        // arm still defers to [`RestartStrategy::default`] on the
15745        // author-omitted arm even when the sibling slots carry values.
15746        c.children = vec![ChildSpec {
15747            caixa: "worker".into(),
15748            versao: "^0.1".into(),
15749            restart: RestartPolicy::Permanent,
15750        }];
15751        let view = c.supervisor_view().expect(
15752            "supervisor_view must materialize a SupervisorSpec for a \
15753             :kind Supervisor Caixa carrying a None `:estrategia` slot",
15754        );
15755        assert_eq!(
15756            view.estrategia(),
15757            RestartStrategy::default(),
15758            "supervisor_view must project the outer Caixa::estrategia() \
15759             None arm onto RestartStrategy::default() through the flat-\
15760             spread unwrap_or_default() fold (got {:?}, expected {:?})",
15761            view.estrategia(),
15762            RestartStrategy::default(),
15763        );
15764        assert!(
15765            c.estrategia().is_none(),
15766            "Caixa::estrategia() must remain None on the author-omitted \
15767             arm — the supervisor_view fold must not mutate the outer \
15768             flat-spread presence bit",
15769        );
15770    }
15771
15772    #[test]
15773    fn estrategia_projects_option_by_copy() {
15774        // The by-`Copy` pin: [`Caixa::estrategia`] returns
15775        // `Option<RestartStrategy>` by value (`RestartStrategy: Copy`) —
15776        // the accessor does not borrow `&self` past the call (no
15777        // lifetime on the return type), and calling the accessor twice
15778        // on the same [`Caixa`] must yield discriminant-equal values
15779        // (idempotent, no side effects on `&self`). Peer of the sibling
15780        // outer-`Caixa` `Option<&Composite>` by-borrow
15781        // `limits_projects_option_ref_by_borrow` (b2bd9d7) /
15782        // `behavior_projects_option_ref_by_borrow` (35d8b52) /
15783        // `politicas_projects_option_ref_by_borrow` (5d23d29) /
15784        // `placement_projects_option_ref_by_borrow` (4fb8074) /
15785        // `entrada_projects_option_ref_by_borrow` (e4128e4) by-borrow
15786        // pins on the outer-`Caixa` `Option<&Composite>`-return axes —
15787        // extended here to the outer-`Caixa` `Option<Copy>`-return
15788        // flat-spread axis. The `Copy` discipline replaces the pointer-
15789        // equality claim the by-borrow siblings pin (a fresh `Copy` of a
15790        // `Copy` discriminant is definitionally the same discriminant, so
15791        // the axis reduces to discriminant equality).
15792        //
15793        // Pins against a future silent detour that returned a fresh
15794        // `Option<&RestartStrategy>` (which would type-check but silently
15795        // introduce a borrow of `&self` past the call, collapsing the
15796        // load-bearing "no lifetime on the return type" `Copy` projection
15797        // the flat-spread axis's `Option<Copy>` shape carries), a stale-
15798        // read side effect that flipped the outer discriminant on
15799        // successive calls, or an axis-remap projection that returned a
15800        // different variant than the field storage.
15801        use crate::supervisor::RestartStrategy;
15802        for estrategia in [
15803            Some(RestartStrategy::OneForOne),
15804            Some(RestartStrategy::OneForAll),
15805            Some(RestartStrategy::RestForOne),
15806            Some(RestartStrategy::SimpleOneForOne),
15807        ] {
15808            let c = caixa_with_estrategia(estrategia);
15809            let first = c.estrategia();
15810            let second = c.estrategia();
15811            assert_eq!(
15812                first, second,
15813                "Caixa::estrategia must be idempotent — two successive \
15814                 calls on the same &self must return the same \
15815                 Option<RestartStrategy>",
15816            );
15817            assert_eq!(
15818                first, estrategia,
15819                "Caixa::estrategia must return :estrategia verbatim by \
15820                 Copy — got {first:?}, expected {estrategia:?}",
15821            );
15822        }
15823        let c = caixa_with_estrategia(None);
15824        assert!(
15825            c.estrategia().is_none(),
15826            "Caixa::estrategia must return None when :estrategia is \
15827             absent — the author-omitted arm must project through the \
15828             accessor's Option::None unchanged",
15829        );
15830    }
15831
15832    // ── Caixa::max_restarts / Caixa::restart_window —
15833    //    outer top-level M2 supervisor-tree-slot flat-spread accessors
15834    //    (Option<u32> / Option<&str>) folding on the ed04d3c
15835    //    Caixa::estrategia Option<Copy> sub-family ─────────────────────
15836
15837    fn caixa_with_max_restarts(max_restarts: Option<u32>) -> Caixa {
15838        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15839        c.max_restarts = max_restarts;
15840        c
15841    }
15842
15843    fn caixa_supervisor_with_max_restarts_and_window(
15844        max_restarts: Option<u32>,
15845        restart_window: Option<&str>,
15846    ) -> Caixa {
15847        use crate::CaixaKind;
15848        use crate::supervisor::{ChildSpec, RestartPolicy};
15849        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
15850        c.kind = CaixaKind::Supervisor;
15851        c.max_restarts = max_restarts;
15852        c.restart_window = restart_window.map(str::to_string);
15853        c.children = vec![ChildSpec {
15854            caixa: "worker".into(),
15855            versao: "^0.1".into(),
15856            restart: RestartPolicy::Permanent,
15857        }];
15858        c
15859    }
15860
15861    #[test]
15862    fn max_restarts_returns_max_restarts_option_verbatim_across_permutations() {
15863        // Value-shape pin: [`Caixa::max_restarts`] returns the
15864        // `:max-restarts` typed `Option<u32>` verbatim, `Copy`-projected
15865        // from the typed slot's own storage, byte-equal across the
15866        // author-omitted `None` arm (the "defer to the
15867        // [`Self::supervisor_view`] `unwrap_or(5)` OTP-canonical
15868        // `{intensity, 5, 60}` default" partition every
15869        // non-`Supervisor`-kind caixa carries by `#[serde(default)]`)
15870        // and each of the representative fixtures in the accept-set —
15871        // `0` (the zero-floor arm the peer
15872        // [`crate::supervisor::SupervisorSpec::validate`]
15873        // [`crate::SupervisorError::ZeroMaxRestarts`] gate refuses on
15874        // the post-composition altitude — the accessor must ship the
15875        // raw slot verbatim so struct-literal fixtures continue to
15876        // expose the zero at the accessor boundary), the OTP-canonical
15877        // `5` default (`{intensity, 5, 60}` worker-supervisor from
15878        // Learn You Some Erlang), `1000` (the
15879        // [`SUPERVISOR_MAX_RESTARTS_MAX`] cap the peer post-composition
15880        // upper-bound gate accepts on the boundary), `u32::MAX` (a
15881        // past-the-cap sentinel that the substrate-primitive accessor
15882        // must still ship verbatim). Second outer top-level
15883        // [`Caixa`] `Option<Copy>`-return supervisor-tree flat-spread
15884        // pin — folds on the sibling
15885        // `estrategia_returns_estrategia_option_verbatim_across_permutations`
15886        // (ed04d3c) pin's `Option<Copy>` shape, extending the sub-family
15887        // onto the sibling `Option<u32>` restart-budget-count arm.
15888        let fixtures: Vec<Option<u32>> = vec![None, Some(0), Some(5), Some(1000), Some(u32::MAX)];
15889        for max_restarts in fixtures {
15890            let c = caixa_with_max_restarts(max_restarts);
15891            assert_eq!(
15892                c.max_restarts(),
15893                max_restarts,
15894                "Caixa::max_restarts must return :max-restarts verbatim \
15895                 (got {:?}, expected {max_restarts:?})",
15896                c.max_restarts(),
15897            );
15898            assert_eq!(
15899                c.max_restarts(),
15900                c.max_restarts,
15901                "Caixa::max_restarts accessor and self.max_restarts \
15902                 field access must byte-equal — a presence-bit or count \
15903                 drift would silently split the paired \
15904                 Caixa::declared_supervisor_slots presence-probe arm \
15905                 from the Caixa::supervisor_view unwrap_or(5) fold's \
15906                 composition input",
15907            );
15908        }
15909    }
15910
15911    #[test]
15912    fn max_restarts_projects_option_by_copy() {
15913        // The by-`Copy` pin: [`Caixa::max_restarts`] returns
15914        // `Option<u32>` by value (`u32: Copy`) — the accessor does not
15915        // borrow `&self` past the call (no lifetime on the return type),
15916        // and calling the accessor twice on the same [`Caixa`] must
15917        // yield equal values (idempotent, no side effects). Peer of the
15918        // sibling `estrategia_projects_option_by_copy` (ed04d3c) pin on
15919        // the outer-`Caixa` `Option<Copy>`-return flat-spread axis.
15920        for max_restarts in [Some(0u32), Some(5), Some(1000), Some(u32::MAX), None] {
15921            let c = caixa_with_max_restarts(max_restarts);
15922            let first = c.max_restarts();
15923            let second = c.max_restarts();
15924            assert_eq!(
15925                first, second,
15926                "Caixa::max_restarts must be idempotent — two successive \
15927                 calls on the same &self must return the same Option<u32>",
15928            );
15929            assert_eq!(
15930                first, max_restarts,
15931                "Caixa::max_restarts must return :max-restarts verbatim \
15932                 by Copy — got {first:?}, expected {max_restarts:?}",
15933            );
15934        }
15935    }
15936
15937    #[test]
15938    fn declared_supervisor_slots_max_restarts_arm_routes_through_accessor() {
15939        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
15940        // `:max-restarts` presence-probe arm must key off
15941        // [`Caixa::max_restarts`], not the raw
15942        // `self.max_restarts.is_some()` field-probe. Structurally: every
15943        // `Caixa { max_restarts: Some(_), .. }` variant must push
15944        // `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS` onto the declared-slot
15945        // list (the presence bit is `Some` for every representative
15946        // count, so the M2 kind-coherence gate must surface the slot as
15947        // "declared"), and a `Caixa { max_restarts: None, .. }` must
15948        // NOT push the label. Peer of the sibling
15949        // `declared_supervisor_slots_estrategia_arm_routes_through_accessor`
15950        // (ed04d3c) composition pin — same routing-through-accessor
15951        // discipline extended onto the sibling flat-spread `Option<u32>`
15952        // arm.
15953        for max_restarts in [0u32, 5, 1000, u32::MAX] {
15954            let c = caixa_with_max_restarts(Some(max_restarts));
15955            let slots = c.declared_supervisor_slots();
15956            assert!(
15957                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
15958                "declared_supervisor_slots must push \
15959                 SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` \
15960                 is Some({max_restarts}) — the accessor and the \
15961                 enumerator gate must route through the same \
15962                 substrate-primitive typed dispatch on the outer \
15963                 :max-restarts presence bit (got slots={slots:?})",
15964            );
15965        }
15966        let c = caixa_with_max_restarts(None);
15967        let slots = c.declared_supervisor_slots();
15968        assert!(
15969            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
15970            "declared_supervisor_slots must NOT push \
15971             SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` is \
15972             None — the author-omitted arm must route through the \
15973             accessor's None-return unchanged (got slots={slots:?})",
15974        );
15975    }
15976
15977    #[test]
15978    fn supervisor_view_max_restarts_arm_routes_through_accessor() {
15979        // Composition pin: [`Caixa::supervisor_view`]'s per-`:max-restarts`
15980        // [`SupervisorSpec`] construction arm must key off
15981        // [`Caixa::max_restarts`]'s `unwrap_or(5)` fold, not the raw
15982        // `self.max_restarts.unwrap_or(5)` field-fold. Structurally: for
15983        // every `:kind Supervisor` `Caixa` carrying an author-declared
15984        // `Some(n)`, the composed [`SupervisorSpec`]'s `.max_restarts()`
15985        // must byte-equal `n`; and for a `:kind Supervisor` `Caixa`
15986        // carrying `None`, the composed [`SupervisorSpec`]'s
15987        // `.max_restarts()` must byte-equal the OTP-canonical `5`. Peer
15988        // of the sibling
15989        // `supervisor_view_estrategia_arm_routes_through_accessor`
15990        // (ed04d3c) composition pin.
15991        for max_restarts in [1u32, 5, 1000] {
15992            let c = caixa_supervisor_with_max_restarts_and_window(Some(max_restarts), None);
15993            let view = c.supervisor_view().expect(
15994                "supervisor_view must materialize a SupervisorSpec for a \
15995                 :kind Supervisor Caixa carrying a Some(:max-restarts)",
15996            );
15997            assert_eq!(
15998                view.max_restarts(),
15999                max_restarts,
16000                "supervisor_view must carry the outer \
16001                 Caixa::max_restarts() Some arm onto the composed \
16002                 SupervisorSpec.max_restarts field verbatim (got {}, \
16003                 expected {max_restarts})",
16004                view.max_restarts(),
16005            );
16006        }
16007        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
16008        let view = c.supervisor_view().expect(
16009            "supervisor_view must materialize a SupervisorSpec for a \
16010             :kind Supervisor Caixa carrying a None :max-restarts",
16011        );
16012        assert_eq!(
16013            view.max_restarts(),
16014            5,
16015            "supervisor_view must project the outer \
16016             Caixa::max_restarts() None arm onto the OTP-canonical \
16017             {{intensity, 5, 60}} default (5) through the flat-spread \
16018             unwrap_or(5) fold (got {})",
16019            view.max_restarts(),
16020        );
16021        assert!(
16022            c.max_restarts().is_none(),
16023            "Caixa::max_restarts() must remain None on the author-\
16024             omitted arm — the supervisor_view fold must not mutate \
16025             the outer flat-spread presence bit",
16026        );
16027    }
16028
16029    #[test]
16030    fn supervisor_view_estrategia_fallback_routes_through_lifted_default() {
16031        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
16032        // `:estrategia` arm must degrade onto the substrate-canonical
16033        // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
16034        // `pub const` — the Erlang/OTP-canonical `one_for_one` strategy
16035        // half of Learn You Some Erlang's `{one_for_one, intensity, 5, 60}`
16036        // worker-supervisor default — rather than the transitively-
16037        // derived [`crate::supervisor::RestartStrategy::default`] route
16038        // the prior `.unwrap_or_default()` fold reached for. Prior to the
16039        // lift the composition site carried `.unwrap_or_default()` with
16040        // no compile-time link back to the shared OTP-canonical strategy
16041        // default that the paired [`crate::supervisor::Default for
16042        // RestartStrategy`] impl and the [`crate::supervisor::Default for
16043        // SupervisorSpec`] impl's struct-literal `estrategia` field both
16044        // (now) route through the same lifted constant — so a future
16045        // rebrand of the OTP-canonical strategy default (an OTP
16046        // `rest_for_one` widening once the substrate discovers startup-
16047        // order-coupled child cohorts as the more common worker-
16048        // supervisor shape, a per-cluster overlay the operator pins
16049        // through the MESH-COMPOSITION §III.2 supervision-canary
16050        // `:estrategia-overrides` roadmap slot) would have had to migrate
16051        // the paired `MaxIntensity` + `Period` halves through the lifted
16052        // constants and the `one_for_one` half through a
16053        // `RestartStrategy::default()` route in lockstep or a
16054        // `:kind Supervisor` caixa carrying an author-omitted
16055        // `:estrategia` slot would silently resolve to a `SupervisorSpec`
16056        // whose `estrategia` disagreed with the paired
16057        // `SupervisorSpec::default()` view. Byte-parity against the
16058        // lifted constant closes the split. Peer of the sibling
16059        // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
16060        // composition pin on the paired `MaxIntensity` half + the
16061        // [`crate::supervisor::restart_strategy_default_routes_through_lifted_default`]
16062        // + [`crate::supervisor::supervisor_spec_default_estrategia_routes_through_lifted_default`]
16063        // pins on the sibling entry points onto the shared substrate
16064        // constant.
16065        use crate::CaixaKind;
16066        use crate::supervisor::{ChildSpec, RestartPolicy};
16067        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
16068        c.kind = CaixaKind::Supervisor;
16069        c.estrategia = None;
16070        c.children = vec![ChildSpec {
16071            caixa: "worker".into(),
16072            versao: "^0.1".into(),
16073            restart: RestartPolicy::Permanent,
16074        }];
16075        let view = c.supervisor_view().expect(
16076            "supervisor_view must materialize a SupervisorSpec for a \
16077             :kind Supervisor Caixa carrying a None :estrategia",
16078        );
16079        assert_eq!(
16080            view.estrategia(),
16081            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
16082            "supervisor_view must degrade the outer \
16083             Caixa::estrategia() None arm onto the lifted \
16084             SUPERVISOR_ESTRATEGIA_DEFAULT typed pub const (got {:?}, \
16085             expected {:?})",
16086            view.estrategia(),
16087            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
16088        );
16089    }
16090
16091    #[test]
16092    fn supervisor_view_max_restarts_fallback_routes_through_lifted_default() {
16093        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
16094        // `:max-restarts` arm must degrade onto the substrate-canonical
16095        // [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`] typed
16096        // `pub const` — the Erlang/OTP-canonical `{intensity, 5, 60}`
16097        // `MaxIntensity` default — rather than a raw `5` literal. Prior
16098        // to the lift the composition site carried an inline
16099        // `.unwrap_or(5)` with no compile-time link back to the shared
16100        // OTP-canonical default that the serde-side
16101        // `#[serde(default = "default_max_restarts")]` wire-format arm
16102        // and the [`Default for crate::supervisor::SupervisorSpec`]
16103        // struct-literal default arm both key off — so a future rebrand
16104        // of the OTP-canonical default (Elixir's `Supervisor` `3`
16105        // default, a per-cluster overlay the operator pins through the
16106        // MESH-COMPOSITION §III.2 supervision-canary
16107        // `:supervisor :max-restarts-overrides` roadmap slot) would
16108        // have had to be threaded through both the serde-side helper
16109        // and this view-construction arm in lockstep or a `:kind
16110        // Supervisor` caixa carrying `:max-restarts ()` would silently
16111        // resolve to a `SupervisorSpec` whose `max_restarts` disagreed
16112        // with the same fixture's serde-side `SupervisorSpec` view (an
16113        // author-omitted slot round-tripping through
16114        // `SupervisorSpec::default()` to the lifted constant, then
16115        // splitting to a stale literal past `supervisor_view`).
16116        // Byte-parity against the lifted constant closes the split.
16117        // Peer of the sibling
16118        // [`crate::supervisor::default_max_restarts_helper_routes_through_lifted_default`]
16119        // + [`crate::supervisor::supervisor_spec_default_max_restarts_routes_through_lifted_default`]
16120        // composition pins that close the same routing on the two
16121        // sibling entry points onto the shared substrate constant.
16122        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
16123        let view = c.supervisor_view().expect(
16124            "supervisor_view must materialize a SupervisorSpec for a \
16125             :kind Supervisor Caixa carrying a None :max-restarts",
16126        );
16127        assert_eq!(
16128            view.max_restarts(),
16129            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
16130            "supervisor_view must degrade the outer \
16131             Caixa::max_restarts() None arm onto the lifted \
16132             SUPERVISOR_MAX_RESTARTS_DEFAULT typed pub const (got {}, \
16133             expected {})",
16134            view.max_restarts(),
16135            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
16136        );
16137    }
16138
16139    #[test]
16140    fn restart_window_returns_restart_window_option_verbatim_across_permutations() {
16141        // Value-shape pin: [`Caixa::restart_window`] returns the
16142        // `:restart-window` typed `Option<String>` verbatim as an
16143        // `Option<&str>`, borrowed from the typed slot's own storage,
16144        // byte-equal across the author-omitted `None` arm and each of
16145        // the representative fixtures in the accept-set — the canonical
16146        // `"60s"` from `{intensity, 5, 60}`, the sibling
16147        // canonical-magnitude forms (`"5m"` / `"1h"` / `"500ms"` / `"30"`
16148        // / `"0s"`) the shared codec's positive-set sweep pin covers,
16149        // plus a past-the-guard sentinel (`"1.5s"` — the fractional-
16150        // seconds drift the sibling [`Self::validate_restart_window`]
16151        // gate refuses; the accessor must ship the raw slot verbatim
16152        // so struct-literal fixtures continue to expose the drift at
16153        // the accessor boundary). Third outer top-level [`Caixa`]
16154        // supervisor-tree flat-spread pin — extends the sub-family onto
16155        // the sibling `Option<&str>` raw-duration-string arm.
16156        for window in [
16157            None,
16158            Some("60s"),
16159            Some("5m"),
16160            Some("1h"),
16161            Some("500ms"),
16162            Some("1.5s"),
16163            Some(""),
16164        ] {
16165            let c = caixa_with_restart_window(window);
16166            assert_eq!(
16167                c.restart_window(),
16168                window,
16169                "Caixa::restart_window must return :restart-window \
16170                 verbatim as Option<&str> (got {:?}, expected {window:?})",
16171                c.restart_window(),
16172            );
16173            assert_eq!(
16174                c.restart_window(),
16175                c.restart_window.as_deref(),
16176                "Caixa::restart_window accessor and \
16177                 self.restart_window.as_deref() field access must \
16178                 byte-equal — a byte-level drift would silently split \
16179                 the paired Caixa::declared_supervisor_slots \
16180                 presence-probe arm from the \
16181                 Caixa::validate_restart_window shared-codec gate and \
16182                 the Caixa::supervisor_view soft-swallowing fold",
16183            );
16184        }
16185    }
16186
16187    #[test]
16188    fn restart_window_projects_slice_by_borrow() {
16189        // The by-borrow pin: [`Caixa::restart_window`] returns
16190        // `Option<&str>` by borrow — the returned string slice borrows
16191        // the underlying `Option<String>` storage of the `:restart-window`
16192        // slot and the accessor must not clone on every call. Peer of
16193        // the sibling outer top-level [`Caixa`] `Option<&str>`-return
16194        // by-borrow pins on the universal-axis scalar family
16195        // (`licenca_projects_option_ref_by_borrow` /
16196        // `descricao_projects_option_ref_by_borrow` and siblings) —
16197        // extended onto the M2 supervisor-tree flat-spread
16198        // `Option<&str>` raw-duration-string axis.
16199        for window in [None, Some("60s"), Some("5m"), Some("")] {
16200            let c = caixa_with_restart_window(window);
16201            let first = c.restart_window();
16202            let second = c.restart_window();
16203            assert_eq!(
16204                first, second,
16205                "Caixa::restart_window must be idempotent — two \
16206                 successive calls on the same &self must return the \
16207                 same Option<&str>",
16208            );
16209            if let (Some(a), Some(b)) = (first, second) {
16210                assert_eq!(
16211                    a.as_ptr(),
16212                    b.as_ptr(),
16213                    "Caixa::restart_window must borrow the underlying \
16214                     String storage — two successive Some-arm calls must \
16215                     return slices with the same backing pointer (a fresh \
16216                     String clone would change the pointer on every call)",
16217                );
16218            }
16219            assert_eq!(
16220                first, window,
16221                "Caixa::restart_window must return :restart-window \
16222                 verbatim by borrow — got {first:?}, expected {window:?}",
16223            );
16224        }
16225    }
16226
16227    #[test]
16228    fn declared_supervisor_slots_restart_window_arm_routes_through_accessor() {
16229        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
16230        // `:restart-window` presence-probe arm must key off
16231        // [`Caixa::restart_window`], not the raw
16232        // `self.restart_window.is_some()` field-probe. Structurally:
16233        // every `Caixa { restart_window: Some(_), .. }` must push
16234        // `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` onto the declared-slot
16235        // list, and a `Caixa { restart_window: None, .. }` must NOT
16236        // push the label. Peer of the sibling
16237        // `declared_supervisor_slots_max_restarts_arm_routes_through_accessor`
16238        // routing pin.
16239        for window in ["60s", "5m", "1h", "500ms", "1.5s", ""] {
16240            let c = caixa_with_restart_window(Some(window));
16241            let slots = c.declared_supervisor_slots();
16242            assert!(
16243                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
16244                "declared_supervisor_slots must push \
16245                 SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when \
16246                 `:restart-window` is Some({window:?}) — the accessor \
16247                 and the enumerator gate must route through the same \
16248                 substrate-primitive typed dispatch on the outer \
16249                 :restart-window presence bit (got slots={slots:?})",
16250            );
16251        }
16252        let c = caixa_with_restart_window(None);
16253        let slots = c.declared_supervisor_slots();
16254        assert!(
16255            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
16256            "declared_supervisor_slots must NOT push \
16257             SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when `:restart-window` \
16258             is None — the author-omitted arm must route through the \
16259             accessor's None-return unchanged (got slots={slots:?})",
16260        );
16261    }
16262
16263    #[test]
16264    fn validate_restart_window_arm_routes_through_accessor() {
16265        // Composition pin: [`Caixa::validate_restart_window`]'s
16266        // shared-codec fold arm must key off [`Caixa::restart_window`],
16267        // not the raw `self.restart_window.as_deref()` field-projection.
16268        // Structurally: (1) `None` → `Ok(())` (the "omit the slot to
16269        // express no reset" canonical shape); (2) a canonical `Some`
16270        // arm (`"60s"`) → `Ok(())`; (3) a codec-rejected `Some` arm
16271        // (`"1.5s"`) → `Err(RestartWindowMalformed { restart_window,
16272        // .. })` carrying the offending raw string verbatim. The three
16273        // arms jointly pin that the validator's raw-string binding is
16274        // the accessor's return, not a peer projection — any future
16275        // silent detour that had the accessor collapse `Some("")` to
16276        // `None` would silently absorb the empty-after-trim refusal
16277        // case at the accessor boundary.
16278        caixa_with_restart_window(None)
16279            .validate_restart_window()
16280            .expect("None :restart-window must validate through the accessor");
16281        caixa_with_restart_window(Some("60s"))
16282            .validate_restart_window()
16283            .expect("canonical :restart-window \"60s\" must validate through the accessor");
16284        let err = caixa_with_restart_window(Some("1.5s"))
16285            .validate_restart_window()
16286            .expect_err("fractional-seconds :restart-window must fail through the accessor");
16287        assert!(
16288            matches!(
16289                err,
16290                ManifestError::RestartWindowMalformed { ref restart_window, .. }
16291                    if restart_window == "1.5s"
16292            ),
16293            "validator must carry the offending raw string verbatim \
16294             from the accessor's borrowed &str (got {err:?})",
16295        );
16296    }
16297
16298    #[test]
16299    fn supervisor_view_restart_window_arm_routes_through_accessor() {
16300        // Composition pin: [`Caixa::supervisor_view`]'s
16301        // per-`:restart-window` [`SupervisorSpec`] construction arm
16302        // must key off [`Caixa::restart_window`]'s soft-swallowing
16303        // `.and_then(|s| duration_codec::parse(s).ok())` fold, not the
16304        // raw `self.restart_window.as_deref().and_then(…)` field-fold.
16305        // Structurally: (1) `None` → `SupervisorSpec.restart_window ==
16306        // None` (the "never reset" sentinel); (2) canonical `Some("60s")`
16307        // → `SupervisorSpec.restart_window == Some(Duration::from_secs(60))`
16308        // (the shared codec's canonical parse); (3) codec-rejected
16309        // `Some("1.5s")` → `SupervisorSpec.restart_window == None`
16310        // (the soft-swallow preserving the view's best-effort shape).
16311        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
16312        let view = c.supervisor_view().expect("Supervisor kind has a view");
16313        assert_eq!(
16314            view.restart_window(),
16315            None,
16316            "supervisor_view must project outer None :restart-window \
16317             onto None on the composed SupervisorSpec (never-reset \
16318             sentinel) through the accessor's None-return unchanged",
16319        );
16320
16321        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("60s"));
16322        let view = c.supervisor_view().expect("Supervisor kind has a view");
16323        assert_eq!(
16324            view.restart_window(),
16325            Some(std::time::Duration::from_secs(60)),
16326            "supervisor_view must fold outer Some(\"60s\") through the \
16327             shared duration_codec into Duration::from_secs(60) on the \
16328             composed SupervisorSpec (accessor's Some(&str) → codec \
16329             parse → Some(Duration))",
16330        );
16331
16332        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("1.5s"));
16333        let view = c.supervisor_view().expect("Supervisor kind has a view");
16334        assert_eq!(
16335            view.restart_window(),
16336            None,
16337            "supervisor_view must soft-swallow the shared-codec parse \
16338             failure to None (the view's best-effort shape the sibling \
16339             manifest-level validate_restart_window surfaces as \
16340             RestartWindowMalformed); the accessor's raw-string return \
16341             is the single input every downstream consumer keys off",
16342        );
16343    }
16344
16345    // ── Caixa::upgrade_from — outer top-level &[UpgradeFromEntry] composite-slice accessor ──
16346
16347    fn caixa_with_upgrade_from(upgrade_from: Vec<crate::upgrade::UpgradeFromEntry>) -> Caixa {
16348        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16349        c.upgrade_from = upgrade_from;
16350        c
16351    }
16352
16353    #[test]
16354    fn upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations() {
16355        // The canonical per-`Caixa` `:upgrade-from` M2 typed-slot
16356        // outer-composite `&[UpgradeFromEntry]`-return slice-shape
16357        // pin: [`Caixa::upgrade_from`] must return the `:upgrade-from`
16358        // typed `Vec<UpgradeFromEntry>` verbatim as a
16359        // `&[UpgradeFromEntry]` slice-view over the same backing
16360        // buffer the raw `self.upgrade_from.as_slice()` field access
16361        // borrows from, element-equal across every representative
16362        // fixture in the accept-set — `[]` (the "no hot-upgrade path
16363        // declared" arm every `defcaixa` without an `:upgrade-from`
16364        // block carries; `#[serde(default)]` folds an omitted slot
16365        // onto `Vec::new()`), a canonical single-entry `Restart`
16366        // fixture (the shape most Servicos carry — a single prior
16367        // version with the fallback strategy), a canonical multi-
16368        // entry list carrying every typed instruction variant
16369        // (`LoadModule` / `StateChange` / `SoftPurge` / `Purge` /
16370        // `Restart`), and a past-the-guard sentinel — a duplicate-
16371        // `:from` `[(0.1.0, Restart), (0.1.0, Restart)]` entry pair
16372        // ([`crate::upgrade::validate_upgrade_from`] rejects through
16373        // `DuplicateFrom { from: "0.1.0" }` but the accessor must
16374        // ship the raw slot verbatim so struct-literal fixtures
16375        // continue to expose the duplicate at the accessor boundary).
16376        //
16377        // Pins against a future silent detour that returned an owned
16378        // `Vec<UpgradeFromEntry>` (which would type-check but silently
16379        // clone on every accessor call, breaking the zero-cost
16380        // projection every peer sibling slice accessor carries), a
16381        // `[dup, dup] → [dup]` dedup collapse (which would silently
16382        // absorb the `DuplicateFrom` refusal case at the accessor
16383        // boundary and the [`crate::StandardLayout::verify`] cross-
16384        // entry gate would silently accept a struct-literal `Caixa`
16385        // carrying the drift), a reference to an operator-resolved
16386        // overlay (the future per-cluster `:upgrade-overrides` slot
16387        // — its resolution must land at exactly this accessor body,
16388        // not silently divert the raw slot away from a second
16389        // consumer), or an axis-shuffled projection (a future detour
16390        // that reordered entries through the accessor would silently
16391        // split the paired [`crate::StandardLayout::verify`] per-
16392        // `:upgrade-from` shape gate's traversal input from the peer
16393        // [`crate::render::servico_m2_overlay`] emitter's projection
16394        // input, since the operator's hot-upgrade dispatch matches
16395        // per-`:from` and axis reordering would silently split the
16396        // per-entry script-path existence probe's iteration order
16397        // from the M2 overlay emitter's serialized-entry order).
16398        //
16399        // First outer top-level [`Caixa`] `&[Composite]`-return
16400        // slice accessor pin on the substrate primitive for M2 / M3
16401        // typed-slot vec-carry axes — opens the outer-`Caixa`
16402        // `&[Composite]` composite-slice projection pattern the
16403        // sibling `:children` [`crate::supervisor::ChildSpec`] /
16404        // `:membros` [`crate::aplicacao::Membro`] / `:contratos`
16405        // [`crate::aplicacao::WitContract`] future outer-composite-
16406        // slice pins fold on. Peer of the closed outer-`Caixa`
16407        // scalar `Option<&Composite>` composite-reference family the
16408        // sibling `limits` / `behavior` / `politicas` / `placement`
16409        // / `entrada` `..._returns_..._option_ref_verbatim_across_
16410        // permutations` pins closed (b2bd9d7 → e4128e4) — extends
16411        // the "byte-equal, borrow-shared" outer-accessor discipline
16412        // onto the outer-`Caixa` `&[Composite]` vec-carry altitude.
16413        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
16414        let fixtures: Vec<Vec<UpgradeFromEntry>> = vec![
16415            vec![],
16416            vec![UpgradeFromEntry {
16417                from: "0.0.1".into(),
16418                instructions: vec![UpgradeInstruction::Restart],
16419            }],
16420            vec![
16421                UpgradeFromEntry {
16422                    from: "0.0.1".into(),
16423                    instructions: vec![
16424                        UpgradeInstruction::LoadModule {
16425                            module: "demo".into(),
16426                        },
16427                        UpgradeInstruction::SoftPurge {
16428                            module: "demo".into(),
16429                        },
16430                    ],
16431                },
16432                UpgradeFromEntry {
16433                    from: "0.0.2".into(),
16434                    instructions: vec![
16435                        UpgradeInstruction::StateChange {
16436                            script: "servicos/upgrade.lisp".into(),
16437                        },
16438                        UpgradeInstruction::Purge {
16439                            module: "demo".into(),
16440                        },
16441                        UpgradeInstruction::Restart,
16442                    ],
16443                },
16444            ],
16445            vec![
16446                UpgradeFromEntry {
16447                    from: "0.1.0".into(),
16448                    instructions: vec![UpgradeInstruction::Restart],
16449                },
16450                UpgradeFromEntry {
16451                    from: "0.1.0".into(),
16452                    instructions: vec![UpgradeInstruction::Restart],
16453                },
16454            ],
16455        ];
16456        for upgrade_from in fixtures {
16457            let c = caixa_with_upgrade_from(upgrade_from.clone());
16458            assert_eq!(
16459                c.upgrade_from(),
16460                upgrade_from.as_slice(),
16461                "Caixa::upgrade_from must return :upgrade-from \
16462                 verbatim (got {:?}, expected {upgrade_from:?})",
16463                c.upgrade_from(),
16464            );
16465            assert_eq!(
16466                c.upgrade_from(),
16467                c.upgrade_from.as_slice(),
16468                "Caixa::upgrade_from must element-equal the raw \
16469                 `self.upgrade_from.as_slice()` field access across \
16470                 every value in the Vec<UpgradeFromEntry> accept-set",
16471            );
16472            assert_eq!(
16473                c.upgrade_from().is_empty(),
16474                c.upgrade_from.is_empty(),
16475                "Caixa::upgrade_from().is_empty() must byte-equal \
16476                 self.upgrade_from.is_empty() — a presence-bit drift \
16477                 would silently split the paired \
16478                 Caixa::declared_servico_slots M2 declared-slot \
16479                 enumerator's presence probe from the peer \
16480                 crate::render::servico_m2_overlay M2 overlay \
16481                 emitter's presence gate",
16482            );
16483        }
16484    }
16485
16486    #[test]
16487    fn declared_servico_slots_upgrade_from_arm_routes_through_accessor() {
16488        // Composition pin: [`Caixa::declared_servico_slots`]'s
16489        // `:upgrade-from` presence-probe arm must key off
16490        // [`Caixa::upgrade_from`], not the raw
16491        // `self.upgrade_from.is_empty()` field-probe. Structurally: a
16492        // `Caixa { upgrade_from: vec![UpgradeFromEntry { from: "0.0.1",
16493        // instructions: vec![Restart] }], .. }` must push
16494        // `M2_AUTHOR_KEY_UPGRADE_FROM` onto the declared-slot list
16495        // (the presence bit is non-empty, so the M2 kind-coherence
16496        // gate must surface the slot as "declared"), and a `Caixa {
16497        // upgrade_from: vec![], .. }` must NOT push the label (the
16498        // "author omitted the slot entirely" arm — the empty-slice
16499        // partition the serde-default folds onto). The pair jointly
16500        // pins the accessor + declared-slot enumerator composition:
16501        // any future silent detour that had the accessor collapse
16502        // `[Restart]` to `[]` (a `.filter(|e| !e.instructions.
16503        // is_empty())` projection) would silently absorb the
16504        // "declared but degenerate" arm at the accessor boundary and
16505        // the [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-
16506        // coherence gate would silently accept a struct-literal
16507        // `Caixa` carrying the drift.
16508        //
16509        // Peer of the sibling
16510        // `declared_servico_slots_limits_arm_routes_through_accessor`
16511        // (b2bd9d7) and
16512        // `declared_servico_slots_behavior_arm_routes_through_accessor`
16513        // (35d8b52) composition pins on the sibling `:limits` /
16514        // `:behavior` outer-`Option<&Composite>` arms — same "the
16515        // enumerator gate must route through the substrate-primitive
16516        // typed dispatch" discipline extended onto the third M2
16517        // Servico-runtime slot axis, closing the enumerator's routing
16518        // invariant on every M2 arm.
16519        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
16520        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
16521            from: "0.0.1".into(),
16522            instructions: vec![UpgradeInstruction::Restart],
16523        }]);
16524        let slots = c.declared_servico_slots();
16525        assert!(
16526            slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
16527            "declared_servico_slots must push \
16528             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
16529             non-empty — the accessor and the enumerator gate must \
16530             route through the same substrate-primitive typed \
16531             dispatch on the outer :upgrade-from presence bit (got \
16532             slots={slots:?})",
16533        );
16534        let c = caixa_with_upgrade_from(vec![]);
16535        let slots = c.declared_servico_slots();
16536        assert!(
16537            !slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
16538            "declared_servico_slots must NOT push \
16539             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
16540             empty — the author-omitted arm must route through the \
16541             accessor's empty-slice return unchanged (got \
16542             slots={slots:?})",
16543        );
16544    }
16545
16546    #[test]
16547    fn servico_m2_overlay_upgrade_from_arm_routes_through_accessor() {
16548        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16549        // per-`:upgrade-from` M2 overlay emit arm must key off
16550        // [`Caixa::upgrade_from`], not the raw
16551        // `!caixa.upgrade_from.is_empty()` presence gate + the
16552        // `serde_yaml::to_value(&caixa.upgrade_from)` projection.
16553        // Structurally: a `Caixa { upgrade_from: vec![UpgradeFromEntry
16554        // { from: "0.0.1", instructions: vec![Restart] }], .. }` must
16555        // surface the `M2_KEY_UPGRADE_FROM` key with a per-entry
16556        // sequence in the overlay (the emitter fans onto the serde
16557        // slice-serialization), and a `Caixa { upgrade_from: vec![],
16558        // .. }` must omit the key entirely (the empty-slice
16559        // partition — the `!.is_empty()` outer gate elides the key
16560        // when the author omitted the slot). The pair jointly pins
16561        // the accessor + M2 overlay emitter composition: any future
16562        // silent detour that had the accessor return a fresh-cloned
16563        // `Vec<UpgradeFromEntry>` copy would silently break the
16564        // reference-identity pin the peer per-entry
16565        // `serde_yaml::to_value(caixa.upgrade_from())` projection
16566        // reads from — the projection would clone once per accessor
16567        // call instead of borrowing the storage buffer verbatim.
16568        //
16569        // Peer of the sibling
16570        // `servico_m2_overlay_limits_arm_routes_through_accessor`
16571        // (b2bd9d7) and
16572        // `servico_m2_overlay_behavior_arm_routes_through_accessor`
16573        // (35d8b52) composition pins on the sibling `:limits` /
16574        // `:behavior` outer-`Option<&Composite>` arms — same "the
16575        // M2 overlay emitter must route through the substrate-
16576        // primitive typed dispatch" discipline extended onto the
16577        // third M2 Servico-runtime slot axis, closing the overlay
16578        // emitter's routing invariant on every M2 arm.
16579        use crate::render::{M2_KEY_UPGRADE_FROM, servico_m2_overlay};
16580        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
16581        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
16582            from: "0.0.1".into(),
16583            instructions: vec![UpgradeInstruction::Restart],
16584        }]);
16585        let overlay = servico_m2_overlay(&c).unwrap();
16586        assert!(
16587            overlay.contains_key(M2_KEY_UPGRADE_FROM),
16588            "servico_m2_overlay must surface M2_KEY_UPGRADE_FROM when \
16589             `:upgrade-from` is non-empty — the accessor and the M2 \
16590             overlay emitter must route through the same substrate- \
16591             primitive typed dispatch on the outer :upgrade-from \
16592             slice (got overlay={overlay:?})",
16593        );
16594        let c = caixa_with_upgrade_from(vec![]);
16595        let overlay = servico_m2_overlay(&c).unwrap();
16596        assert!(
16597            !overlay.contains_key(M2_KEY_UPGRADE_FROM),
16598            "servico_m2_overlay must omit M2_KEY_UPGRADE_FROM when \
16599             `:upgrade-from` is empty — the empty-slice partition \
16600             must route through the accessor's empty-slice return \
16601             unchanged (got overlay={overlay:?})",
16602        );
16603    }
16604
16605    #[test]
16606    fn upgrade_from_projects_slice_by_borrow() {
16607        // The by-borrow pin: [`Caixa::upgrade_from`] returns
16608        // `&[UpgradeFromEntry]` by borrow — the returned slice
16609        // borrows the underlying `Vec<UpgradeFromEntry>` storage of
16610        // the `:upgrade-from` slot and the accessor must not clone
16611        // the backing `Vec` on every call. Peer of the sibling
16612        // outer top-level [`Caixa`] `&[T]`-return by-borrow pins
16613        // (`autores_projects_slice_by_borrow` b5d813f,
16614        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
16615        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
16616        // `exe_projects_slice_by_borrow` 65d9527,
16617        // `servicos_projects_slice_by_borrow` 611f78b,
16618        // `deps_projects_slice_by_borrow` ad34b4e,
16619        // `deps_dev_projects_slice_by_borrow` f7fd81e) on the
16620        // sibling outer top-level [`Caixa`] scalar-element `&[T]`
16621        // axes — extended here to the first outer-`Caixa`
16622        // composite-element `&[Composite]` axis: the accessor's
16623        // returned slice must borrow from `&self` (the returned
16624        // reference's lifetime is tied to `&self`), and calling the
16625        // accessor twice on the same [`Caixa`] must yield slices
16626        // that are pointer-equal (the underlying byte-buffer is the
16627        // storage `Vec`'s allocation, not a fresh copy) as well as
16628        // value-equal (idempotent, no side effects on `&self`).
16629        //
16630        // Pins against a future silent detour that returned an owned
16631        // `Vec<UpgradeFromEntry>` (which would type-check but
16632        // silently clone on every call), a `&Vec<UpgradeFromEntry>`
16633        // return (which would leak the backing `Vec`'s
16634        // grow/push/reserve surface no downstream consumer reaches
16635        // for), or a one-arm-only accessor that returned a
16636        // saturating value on some sentinel input.
16637        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
16638        for upgrade_from in [
16639            vec![],
16640            vec![UpgradeFromEntry {
16641                from: "0.0.1".into(),
16642                instructions: vec![UpgradeInstruction::Restart],
16643            }],
16644            vec![
16645                UpgradeFromEntry {
16646                    from: "0.0.1".into(),
16647                    instructions: vec![UpgradeInstruction::Restart],
16648                },
16649                UpgradeFromEntry {
16650                    from: "0.0.2".into(),
16651                    instructions: vec![UpgradeInstruction::SoftPurge {
16652                        module: "demo".into(),
16653                    }],
16654                },
16655            ],
16656        ] {
16657            let c = caixa_with_upgrade_from(upgrade_from.clone());
16658            let first = c.upgrade_from();
16659            let second = c.upgrade_from();
16660            assert_eq!(
16661                first, second,
16662                "Caixa::upgrade_from must be idempotent — two \
16663                 successive calls on the same &self must return the \
16664                 same &[UpgradeFromEntry]",
16665            );
16666            assert_eq!(
16667                first.as_ptr(),
16668                second.as_ptr(),
16669                "Caixa::upgrade_from must borrow the underlying \
16670                 Vec<UpgradeFromEntry> storage — two successive calls \
16671                 must return slices with the same backing pointer (a \
16672                 fresh Vec<UpgradeFromEntry> clone would change the \
16673                 pointer on every call)",
16674            );
16675            assert_eq!(
16676                first,
16677                upgrade_from.as_slice(),
16678                "Caixa::upgrade_from must return :upgrade-from \
16679                 verbatim by borrow — got {first:?}, expected \
16680                 {upgrade_from:?}",
16681            );
16682        }
16683    }
16684
16685    // ── Caixa::children — outer top-level &[ChildSpec] composite-slice accessor ──
16686
16687    fn caixa_with_children(children: Vec<crate::supervisor::ChildSpec>) -> Caixa {
16688        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16689        c.children = children;
16690        c
16691    }
16692
16693    #[test]
16694    fn children_returns_children_slice_verbatim_across_permutations() {
16695        // The canonical per-`Caixa` `:children` M2 supervisor-tree-slot
16696        // outer-composite `&[ChildSpec]`-return slice-shape pin:
16697        // [`Caixa::children`] must return the `:children` typed
16698        // `Vec<ChildSpec>` verbatim as a `&[ChildSpec]` slice-view over
16699        // the same backing buffer the raw `self.children.as_slice()`
16700        // field access borrows from, element-equal across every
16701        // representative fixture in the accept-set — `[]` (the "no
16702        // static children declared" arm every non-`Supervisor`-kind
16703        // `defcaixa` carries by `#[serde(default)]` and every
16704        // `SimpleOneForOne` supervisor carries by cross-slot refusal),
16705        // a canonical single-child `Permanent` fixture (the shape
16706        // most `OneForOne` supervisors carry — a single long-running
16707        // worker child), a canonical multi-child list carrying every
16708        // typed restart-policy variant (`Permanent` / `Transient` /
16709        // `Temporary`), and a past-the-guard sentinel — a duplicate
16710        // `:caixa` `[("w", ...), ("w", ...)]` entry pair
16711        // ([`crate::SupervisorSpec::validate`] rejects through
16712        // `DuplicateChildNome { nome: "w" }` but the accessor must
16713        // ship the raw slot verbatim so struct-literal fixtures
16714        // continue to expose the duplicate at the accessor boundary).
16715        //
16716        // Pins against a future silent detour that returned an owned
16717        // `Vec<ChildSpec>` (which would type-check but silently clone
16718        // on every accessor call, breaking the zero-cost projection
16719        // every peer sibling slice accessor carries), a `[dup, dup] →
16720        // [dup]` dedup collapse (which would silently absorb the
16721        // `DuplicateChildNome` refusal case at the accessor boundary
16722        // and the [`crate::StandardLayout::verify`] cross-child gate
16723        // would silently accept a struct-literal `Caixa` carrying the
16724        // drift), a reference to an operator-resolved overlay (the
16725        // future per-cluster `:children-overrides` slot — its
16726        // resolution must land at exactly this accessor body, not
16727        // silently divert the raw slot away from a second consumer),
16728        // or an axis-shuffled projection (a future detour that
16729        // reordered children through the accessor would silently
16730        // split the paired [`crate::StandardLayout::verify`] per-
16731        // supervisor gate's traversal input from the peer
16732        // [`Self::supervisor_view`] fold-in path's clone-order input,
16733        // since the OTP `RestForOne` restart strategy dispatches on
16734        // declared child order and axis reordering would silently
16735        // split the operator's per-cluster restart-fan-out order
16736        // from the caixa.lisp source-order).
16737        //
16738        // Second outer top-level [`Caixa`] `&[Composite]`-return slice
16739        // accessor pin on the substrate primitive for M2 / M3 typed-
16740        // slot vec-carry axes — folds on the outer-`Caixa`
16741        // `&[Composite]` composite-slice sub-family the sibling
16742        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
16743        // (2a1f907) pin opened, peer at the outer altitude of the
16744        // closed inner-`SupervisorSpec` `SupervisorSpec::children`
16745        // (bc92bce) accessor on the same OTP-supervisor static-child-
16746        // list axis.
16747        use crate::supervisor::{ChildSpec, RestartPolicy};
16748        let fixtures: Vec<Vec<ChildSpec>> = vec![
16749            vec![],
16750            vec![ChildSpec {
16751                caixa: "worker".into(),
16752                versao: "^0.1".into(),
16753                restart: RestartPolicy::Permanent,
16754            }],
16755            vec![
16756                ChildSpec {
16757                    caixa: "worker-a".into(),
16758                    versao: "^0.1".into(),
16759                    restart: RestartPolicy::Permanent,
16760                },
16761                ChildSpec {
16762                    caixa: "worker-b".into(),
16763                    versao: "^0.1".into(),
16764                    restart: RestartPolicy::Transient,
16765                },
16766                ChildSpec {
16767                    caixa: "worker-c".into(),
16768                    versao: "^0.1".into(),
16769                    restart: RestartPolicy::Temporary,
16770                },
16771            ],
16772            vec![
16773                ChildSpec {
16774                    caixa: "w".into(),
16775                    versao: "^0.1".into(),
16776                    restart: RestartPolicy::Permanent,
16777                },
16778                ChildSpec {
16779                    caixa: "w".into(),
16780                    versao: "^0.1".into(),
16781                    restart: RestartPolicy::Permanent,
16782                },
16783            ],
16784        ];
16785        for children in fixtures {
16786            let c = caixa_with_children(children.clone());
16787            assert_eq!(
16788                c.children(),
16789                children.as_slice(),
16790                "Caixa::children must return :children verbatim \
16791                 (got {:?}, expected {children:?})",
16792                c.children(),
16793            );
16794            assert_eq!(
16795                c.children(),
16796                c.children.as_slice(),
16797                "Caixa::children must element-equal the raw \
16798                 `self.children.as_slice()` field access across \
16799                 every value in the Vec<ChildSpec> accept-set",
16800            );
16801            assert_eq!(
16802                c.children().is_empty(),
16803                c.children.is_empty(),
16804                "Caixa::children().is_empty() must byte-equal \
16805                 self.children.is_empty() — a presence-bit drift \
16806                 would silently split the paired \
16807                 Caixa::declared_supervisor_slots supervisor-tree \
16808                 declared-slot enumerator's presence probe from the \
16809                 peer Caixa::supervisor_view typed-view composer's \
16810                 fold-in path",
16811            );
16812        }
16813    }
16814
16815    #[test]
16816    fn declared_supervisor_slots_children_arm_routes_through_accessor() {
16817        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
16818        // `:children` presence-probe arm must key off
16819        // [`Caixa::children`], not the raw
16820        // `!self.children.is_empty()` field-probe. Structurally: a
16821        // `Caixa { children: vec![ChildSpec { caixa: "w", versao:
16822        // "^0.1", restart: Permanent }], .. }` must push
16823        // `SUPERVISOR_AUTHOR_KEY_CHILDREN` onto the declared-slot list
16824        // (the presence bit is non-empty, so the supervisor-tree
16825        // kind-coherence gate must surface the slot as "declared"),
16826        // and a `Caixa { children: vec![], .. }` must NOT push the
16827        // label (the "author omitted the slot entirely" arm — the
16828        // empty-slice partition the serde-default folds onto). The
16829        // pair jointly pins the accessor + declared-slot enumerator
16830        // composition: any future silent detour that had the accessor
16831        // collapse `[Permanent]` to `[]` (a `.filter(|c| c.nome() !=
16832        // "__reserved__")` projection) would silently absorb the
16833        // "declared but degenerate" arm at the accessor boundary and
16834        // the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
16835        // kind-coherence gate would silently accept a struct-literal
16836        // `Caixa` carrying the drift.
16837        //
16838        // Peer of the sibling
16839        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
16840        // (2a1f907) on the M2 `:upgrade-from` composite-slice arm —
16841        // same "the enumerator gate must route through the substrate-
16842        // primitive typed dispatch" discipline extended onto the
16843        // supervisor-tree `:children` composite-slice arm.
16844        use crate::supervisor::{ChildSpec, RestartPolicy};
16845        let c = caixa_with_children(vec![ChildSpec {
16846            caixa: "w".into(),
16847            versao: "^0.1".into(),
16848            restart: RestartPolicy::Permanent,
16849        }]);
16850        let slots = c.declared_supervisor_slots();
16851        assert!(
16852            slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
16853            "declared_supervisor_slots must push \
16854             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
16855             non-empty — the accessor and the enumerator gate must \
16856             route through the same substrate-primitive typed \
16857             dispatch on the outer :children presence bit (got \
16858             slots={slots:?})",
16859        );
16860        let c = caixa_with_children(vec![]);
16861        let slots = c.declared_supervisor_slots();
16862        assert!(
16863            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
16864            "declared_supervisor_slots must NOT push \
16865             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
16866             empty — the author-omitted arm must route through the \
16867             accessor's empty-slice return unchanged (got \
16868             slots={slots:?})",
16869        );
16870    }
16871
16872    #[test]
16873    fn supervisor_view_children_arm_routes_through_accessor() {
16874        // Composition pin: [`Caixa::supervisor_view`]'s per-`:children`
16875        // fold-in arm must key off [`Caixa::children`], not the raw
16876        // `self.children.clone()` field-clone. Structurally: a `Caixa {
16877        // kind: Supervisor, estrategia: Some(OneForOne), children:
16878        // vec![ChildSpec { caixa: "w", .. }], .. }` must fold the
16879        // per-child list through the accessor into the typed
16880        // [`SupervisorSpec`] view's `children` field verbatim — every
16881        // entry the accessor surfaces must land in the view's
16882        // `children` slot in the same order. The pair jointly pins the
16883        // accessor + view-composer composition: any future silent
16884        // detour that had the accessor return a fresh-cloned
16885        // `Vec<ChildSpec>` copy would silently break the reference-
16886        // identity pin the peer `supervisor_view` fold-in path reads
16887        // from — the fold would clone once more per accessor call
16888        // instead of borrowing the storage buffer verbatim once.
16889        //
16890        // Peer of the sibling
16891        // `supervisor_view_kind_gate_routes_through_accessor` (35d8b52-
16892        // family) composition pin on the peer kind-gate arm — same
16893        // "the view composer must route through the substrate-
16894        // primitive typed dispatch" discipline extended onto the
16895        // per-`:children` fold-in arm, closing the supervisor-view
16896        // composer's routing invariant on the composite-slice input.
16897        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
16898        let mut c = caixa_with_children(vec![
16899            ChildSpec {
16900                caixa: "worker-a".into(),
16901                versao: "^0.1".into(),
16902                restart: RestartPolicy::Permanent,
16903            },
16904            ChildSpec {
16905                caixa: "worker-b".into(),
16906                versao: "^0.1".into(),
16907                restart: RestartPolicy::Transient,
16908            },
16909        ]);
16910        c.kind = crate::CaixaKind::Supervisor;
16911        c.estrategia = Some(RestartStrategy::OneForOne);
16912        let view = c
16913            .supervisor_view()
16914            .expect("Supervisor kind must produce a supervisor_view");
16915        assert_eq!(
16916            view.children(),
16917            c.children(),
16918            "supervisor_view must fold Caixa::children verbatim into \
16919             SupervisorSpec::children — the accessor and the view \
16920             composer must route through the same substrate-primitive \
16921             typed dispatch on the outer :children slice (got view \
16922             children={:?}, expected {:?})",
16923            view.children(),
16924            c.children(),
16925        );
16926    }
16927
16928    #[test]
16929    fn children_projects_slice_by_borrow() {
16930        // The by-borrow pin: [`Caixa::children`] returns
16931        // `&[ChildSpec]` by borrow — the returned slice borrows the
16932        // underlying `Vec<ChildSpec>` storage of the `:children` slot
16933        // and the accessor must not clone the backing `Vec` on every
16934        // call. Peer of the sibling outer top-level [`Caixa`]
16935        // `&[T]`-return by-borrow pins (`autores_projects_slice_by_borrow`
16936        // b5d813f, `etiquetas_projects_slice_by_borrow` 78c7d3c,
16937        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
16938        // `exe_projects_slice_by_borrow` 65d9527,
16939        // `servicos_projects_slice_by_borrow` 611f78b,
16940        // `deps_projects_slice_by_borrow` ad34b4e,
16941        // `deps_dev_projects_slice_by_borrow` f7fd81e,
16942        // `upgrade_from_projects_slice_by_borrow` 2a1f907) on the
16943        // sibling outer top-level [`Caixa`] scalar-element and
16944        // composite-element `&[T]` axes — folds on the outer-`Caixa`
16945        // composite-element `&[Composite]` axis: the accessor's
16946        // returned slice must borrow from `&self` (the returned
16947        // reference's lifetime is tied to `&self`), and calling the
16948        // accessor twice on the same [`Caixa`] must yield slices
16949        // that are pointer-equal (the underlying byte-buffer is the
16950        // storage `Vec`'s allocation, not a fresh copy) as well as
16951        // value-equal (idempotent, no side effects on `&self`).
16952        //
16953        // Pins against a future silent detour that returned an owned
16954        // `Vec<ChildSpec>` (which would type-check but silently clone
16955        // on every call), a `&Vec<ChildSpec>` return (which would leak
16956        // the backing `Vec`'s grow/push/reserve surface no downstream
16957        // consumer reaches for), or a one-arm-only accessor that
16958        // returned a saturating value on some sentinel input.
16959        use crate::supervisor::{ChildSpec, RestartPolicy};
16960        for children in [
16961            vec![],
16962            vec![ChildSpec {
16963                caixa: "w".into(),
16964                versao: "^0.1".into(),
16965                restart: RestartPolicy::Permanent,
16966            }],
16967            vec![
16968                ChildSpec {
16969                    caixa: "worker-a".into(),
16970                    versao: "^0.1".into(),
16971                    restart: RestartPolicy::Permanent,
16972                },
16973                ChildSpec {
16974                    caixa: "worker-b".into(),
16975                    versao: "^0.1".into(),
16976                    restart: RestartPolicy::Transient,
16977                },
16978            ],
16979        ] {
16980            let c = caixa_with_children(children.clone());
16981            let first = c.children();
16982            let second = c.children();
16983            assert_eq!(
16984                first, second,
16985                "Caixa::children must be idempotent — two successive \
16986                 calls on the same &self must return the same \
16987                 &[ChildSpec]",
16988            );
16989            assert_eq!(
16990                first.as_ptr(),
16991                second.as_ptr(),
16992                "Caixa::children must borrow the underlying \
16993                 Vec<ChildSpec> storage — two successive calls must \
16994                 return slices with the same backing pointer (a fresh \
16995                 Vec<ChildSpec> clone would change the pointer on \
16996                 every call)",
16997            );
16998            assert_eq!(
16999                first,
17000                children.as_slice(),
17001                "Caixa::children must return :children verbatim by \
17002                 borrow — got {first:?}, expected {children:?}",
17003            );
17004        }
17005    }
17006
17007    // ── Caixa::membros — outer top-level &[Membro] composite-slice accessor ──
17008
17009    fn caixa_aplicacao_with_membros(membros: Vec<crate::aplicacao::Membro>) -> Caixa {
17010        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17011        c.kind = CaixaKind::Aplicacao;
17012        c.membros = membros;
17013        c
17014    }
17015
17016    #[test]
17017    fn membros_returns_membros_slice_verbatim_across_permutations() {
17018        // The canonical per-`Caixa` `:membros` M3 mesh-slot outer-
17019        // composite `&[Membro]`-return slice-shape pin:
17020        // [`Caixa::membros`] must return the `:membros` typed
17021        // `Vec<Membro>` verbatim as a `&[Membro]` slice-view over the
17022        // same backing buffer the raw `self.membros.as_slice()` field
17023        // access borrows from, element-equal across every
17024        // representative fixture in the accept-set — `[]` (the "no
17025        // members declared" arm every non-`Aplicacao`-kind `defcaixa`
17026        // carries by `#[serde(default)]` and every partially-authored
17027        // Aplicacao carries before the
17028        // [`crate::AplicacaoError::MembrosEmpty`] gate fires), a
17029        // canonical single-member fixture (the shape a minimal
17030        // Aplicacao carries — one Servico wrapping one contained
17031        // computation), a canonical multi-member list carrying three
17032        // distinct entries (the canonical checkout-shape Aplicacao —
17033        // cart / pricing / auth — every canonical example carries), and
17034        // a past-the-guard sentinel — a duplicate `:caixa`
17035        // `[("cart", ...), ("cart", ...)]` entry pair
17036        // ([`crate::AplicacaoSpec::validate`] rejects through
17037        // `DuplicateMembro { nome: "cart" }` but the accessor must ship
17038        // the raw slot verbatim so struct-literal fixtures continue to
17039        // expose the duplicate at the accessor boundary).
17040        //
17041        // Pins against a future silent detour that returned an owned
17042        // `Vec<Membro>` (which would type-check but silently clone on
17043        // every accessor call, breaking the zero-cost projection every
17044        // peer sibling slice accessor carries), a `[dup, dup] → [dup]`
17045        // dedup collapse (which would silently absorb the
17046        // `DuplicateMembro` refusal case at the accessor boundary and
17047        // the [`crate::StandardLayout::verify`] cross-member gate would
17048        // silently accept a struct-literal `Caixa` carrying the drift),
17049        // a reference to an operator-resolved overlay (the future per-
17050        // cluster `:membros-overrides` slot — its resolution must land
17051        // at exactly this accessor body, not silently divert the raw
17052        // slot away from a second consumer), or an axis-shuffled
17053        // projection (a future detour that reordered members through
17054        // the accessor would silently split the paired
17055        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
17056        // traversal input from the peer [`Self::aplicacao_view`] fold-
17057        // in path's clone-order input, since the canonical `:contratos`
17058        // `:de`/`:para` and `:entrada :para` cross-slot refusal probes
17059        // read the member set through the same slice).
17060        //
17061        // Third outer top-level [`Caixa`] `&[Composite]`-return slice
17062        // accessor pin on the substrate primitive for M2 / M3 typed-
17063        // slot vec-carry axes — opens the outer-`Caixa` M3 mesh-slot
17064        // arm of the `&[Composite]` composite-slice sub-family the
17065        // sibling M2 `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
17066        // (2a1f907) and
17067        // `children_returns_children_slice_verbatim_across_permutations`
17068        // (c17b51e) pins opened, peer at the outer altitude of the
17069        // closed inner-[`crate::AplicacaoSpec::membros`] (6c77e36)
17070        // accessor on the same MESH-COMPOSITION per-Aplicacao member-
17071        // list axis.
17072        use crate::aplicacao::Membro;
17073        let fixtures: Vec<Vec<Membro>> = vec![
17074            vec![],
17075            vec![Membro {
17076                caixa: "cart".into(),
17077                versao: "^0.1".into(),
17078            }],
17079            vec![
17080                Membro {
17081                    caixa: "cart".into(),
17082                    versao: "^0.1".into(),
17083                },
17084                Membro {
17085                    caixa: "pricing".into(),
17086                    versao: "^0.2".into(),
17087                },
17088                Membro {
17089                    caixa: "auth".into(),
17090                    versao: "^1.0".into(),
17091                },
17092            ],
17093            vec![
17094                Membro {
17095                    caixa: "cart".into(),
17096                    versao: "^0.1".into(),
17097                },
17098                Membro {
17099                    caixa: "cart".into(),
17100                    versao: "^0.1".into(),
17101                },
17102            ],
17103        ];
17104        for membros in fixtures {
17105            let c = caixa_aplicacao_with_membros(membros.clone());
17106            assert_eq!(
17107                c.membros(),
17108                membros.as_slice(),
17109                "Caixa::membros must return :membros verbatim \
17110                 (got {:?}, expected {membros:?})",
17111                c.membros(),
17112            );
17113            assert_eq!(
17114                c.membros(),
17115                c.membros.as_slice(),
17116                "Caixa::membros must element-equal the raw \
17117                 `self.membros.as_slice()` field access across every \
17118                 value in the Vec<Membro> accept-set",
17119            );
17120            assert_eq!(
17121                c.membros().is_empty(),
17122                c.membros.is_empty(),
17123                "Caixa::membros().is_empty() must byte-equal \
17124                 self.membros.is_empty() — a presence-bit drift would \
17125                 silently split the paired Caixa::declared_mesh_slots \
17126                 mesh declared-slot enumerator's presence probe from \
17127                 the peer Caixa::aplicacao_view typed-view composer's \
17128                 fold-in path",
17129            );
17130        }
17131    }
17132
17133    #[test]
17134    fn declared_mesh_slots_membros_arm_routes_through_accessor() {
17135        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:membros`
17136        // presence-probe arm must key off [`Caixa::membros`], not the
17137        // raw `!self.membros.is_empty()` field-probe. Structurally: a
17138        // `Caixa { membros: vec![Membro { caixa: "cart", versao:
17139        // "^0.1" }], .. }` must push `M3_AUTHOR_KEY_MEMBROS` onto the
17140        // declared-slot list (the presence bit is non-empty, so the
17141        // mesh kind-coherence gate must surface the slot as
17142        // "declared"), and a `Caixa { membros: vec![], .. }` must NOT
17143        // push the label (the "author omitted the slot entirely" arm
17144        // — the empty-slice partition the serde-default folds onto).
17145        // The pair jointly pins the accessor + declared-slot
17146        // enumerator composition: any future silent detour that had
17147        // the accessor collapse `[Membro { .. }]` to `[]` (a
17148        // `.filter(|m| m.nome() != "__reserved__")` projection) would
17149        // silently absorb the "declared but degenerate" arm at the
17150        // accessor boundary and the
17151        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
17152        // coherence gate would silently accept a struct-literal
17153        // `Caixa` carrying the drift.
17154        //
17155        // Peer of the sibling
17156        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
17157        // (2a1f907) and
17158        // `declared_supervisor_slots_children_arm_routes_through_accessor`
17159        // (c17b51e) composition pins on the M2 `:upgrade-from` /
17160        // `:children` composite-slice arms — same "the enumerator gate
17161        // must route through the substrate-primitive typed dispatch"
17162        // discipline extended onto the M3 `:membros` composite-slice
17163        // arm, opening the M3 arm of the declared-slot enumerator's
17164        // routing invariant.
17165        use crate::aplicacao::Membro;
17166        let c = caixa_aplicacao_with_membros(vec![Membro {
17167            caixa: "cart".into(),
17168            versao: "^0.1".into(),
17169        }]);
17170        let slots = c.declared_mesh_slots();
17171        assert!(
17172            slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
17173            "declared_mesh_slots must push M3_AUTHOR_KEY_MEMBROS when \
17174             `:membros` is non-empty — the accessor and the enumerator \
17175             gate must route through the same substrate-primitive \
17176             typed dispatch on the outer :membros presence bit (got \
17177             slots={slots:?})",
17178        );
17179        let c = caixa_aplicacao_with_membros(vec![]);
17180        let slots = c.declared_mesh_slots();
17181        assert!(
17182            !slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
17183            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_MEMBROS \
17184             when `:membros` is empty — the author-omitted arm must \
17185             route through the accessor's empty-slice return unchanged \
17186             (got slots={slots:?})",
17187        );
17188    }
17189
17190    #[test]
17191    fn aplicacao_view_membros_arm_routes_through_accessor() {
17192        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:membros`
17193        // fold-in arm must key off [`Caixa::membros`], not the raw
17194        // `self.membros.clone()` field-clone. Structurally: a `Caixa {
17195        // kind: Aplicacao, membros: vec![Membro { caixa: "cart", .. },
17196        // Membro { caixa: "pricing", .. }], .. }` must fold the per-
17197        // member list through the accessor into the typed
17198        // [`crate::AplicacaoSpec`] view's `membros` slot verbatim —
17199        // every entry the accessor surfaces must land in the view's
17200        // `membros` slot in the same order. The pair jointly pins the
17201        // accessor + view-composer composition: any future silent
17202        // detour that had the accessor return a fresh-cloned
17203        // `Vec<Membro>` copy would silently break the reference-
17204        // identity pin the peer `aplicacao_view` fold-in path reads
17205        // from — the fold would clone once more per accessor call
17206        // instead of borrowing the storage buffer verbatim once.
17207        //
17208        // Peer of the sibling
17209        // `aplicacao_view_politicas_arm_folds_through_accessor`
17210        // (5d23d29) /
17211        // `aplicacao_view_placement_arm_folds_through_accessor`
17212        // (4fb8074) /
17213        // `aplicacao_view_entrada_arm_folds_through_accessor` (e4128e4)
17214        // composition pins on the M3 `:politicas` / `:placement` /
17215        // `:entrada` outer-`Option<&Composite>` arms — extended here to
17216        // the M3 `:membros` outer-`&[Composite]` composite-slice arm,
17217        // closing the aplicacao-view composer's routing invariant on
17218        // the composite-slice input.
17219        use crate::aplicacao::Membro;
17220        let c = caixa_aplicacao_with_membros(vec![
17221            Membro {
17222                caixa: "cart".into(),
17223                versao: "^0.1".into(),
17224            },
17225            Membro {
17226                caixa: "pricing".into(),
17227                versao: "^0.2".into(),
17228            },
17229        ]);
17230        let view = c
17231            .aplicacao_view()
17232            .expect("Aplicacao kind must produce an aplicacao_view");
17233        assert_eq!(
17234            view.membros(),
17235            c.membros(),
17236            "aplicacao_view must fold Caixa::membros verbatim into \
17237             AplicacaoSpec::membros — the accessor and the view \
17238             composer must route through the same substrate-primitive \
17239             typed dispatch on the outer :membros slice (got view \
17240             membros={:?}, expected {:?})",
17241            view.membros(),
17242            c.membros(),
17243        );
17244    }
17245
17246    #[test]
17247    fn membros_projects_slice_by_borrow() {
17248        // The by-borrow pin: [`Caixa::membros`] returns `&[Membro]` by
17249        // borrow — the returned slice borrows the underlying
17250        // `Vec<Membro>` storage of the `:membros` slot and the
17251        // accessor must not clone the backing `Vec` on every call.
17252        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
17253        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
17254        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
17255        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
17256        // `exe_projects_slice_by_borrow` 65d9527,
17257        // `servicos_projects_slice_by_borrow` 611f78b,
17258        // `deps_projects_slice_by_borrow` ad34b4e,
17259        // `deps_dev_projects_slice_by_borrow` f7fd81e,
17260        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
17261        // `children_projects_slice_by_borrow` c17b51e) on the sibling
17262        // outer top-level [`Caixa`] scalar-element and composite-
17263        // element `&[T]` axes — folds on the outer-`Caixa` M3 mesh-
17264        // slot composite-element `&[Composite]` axis: the accessor's
17265        // returned slice must borrow from `&self` (the returned
17266        // reference's lifetime is tied to `&self`), and calling the
17267        // accessor twice on the same [`Caixa`] must yield slices that
17268        // are pointer-equal (the underlying byte-buffer is the storage
17269        // `Vec`'s allocation, not a fresh copy) as well as value-equal
17270        // (idempotent, no side effects on `&self`).
17271        //
17272        // Pins against a future silent detour that returned an owned
17273        // `Vec<Membro>` (which would type-check but silently clone on
17274        // every call), a `&Vec<Membro>` return (which would leak the
17275        // backing `Vec`'s grow/push/reserve surface no downstream
17276        // consumer reaches for), or a one-arm-only accessor that
17277        // returned a saturating value on some sentinel input.
17278        use crate::aplicacao::Membro;
17279        for membros in [
17280            vec![],
17281            vec![Membro {
17282                caixa: "cart".into(),
17283                versao: "^0.1".into(),
17284            }],
17285            vec![
17286                Membro {
17287                    caixa: "cart".into(),
17288                    versao: "^0.1".into(),
17289                },
17290                Membro {
17291                    caixa: "pricing".into(),
17292                    versao: "^0.2".into(),
17293                },
17294            ],
17295        ] {
17296            let c = caixa_aplicacao_with_membros(membros.clone());
17297            let first = c.membros();
17298            let second = c.membros();
17299            assert_eq!(
17300                first, second,
17301                "Caixa::membros must be idempotent — two successive \
17302                 calls on the same &self must return the same &[Membro]",
17303            );
17304            assert_eq!(
17305                first.as_ptr(),
17306                second.as_ptr(),
17307                "Caixa::membros must borrow the underlying Vec<Membro> \
17308                 storage — two successive calls must return slices with \
17309                 the same backing pointer (a fresh Vec<Membro> clone \
17310                 would change the pointer on every call)",
17311            );
17312            assert_eq!(
17313                first,
17314                membros.as_slice(),
17315                "Caixa::membros must return :membros verbatim by borrow \
17316                 — got {first:?}, expected {membros:?}",
17317            );
17318        }
17319    }
17320
17321    // ── Caixa::contratos — outer top-level &[WitContract] composite-slice accessor ──
17322
17323    fn caixa_aplicacao_with_contratos(contratos: Vec<crate::aplicacao::WitContract>) -> Caixa {
17324        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17325        c.kind = CaixaKind::Aplicacao;
17326        c.contratos = contratos;
17327        c
17328    }
17329
17330    fn contrato_http_for_test(
17331        de: &str,
17332        para: &str,
17333        endpoint: &str,
17334    ) -> crate::aplicacao::WitContract {
17335        crate::aplicacao::WitContract {
17336            de: de.into(),
17337            para: para.into(),
17338            wit: "wasi:http/proxy".into(),
17339            endpoint: Some(endpoint.into()),
17340            subject: None,
17341            slot: None,
17342        }
17343    }
17344
17345    #[test]
17346    fn contratos_returns_contratos_slice_verbatim_across_permutations() {
17347        // The canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
17348        // composite `&[WitContract]`-return slice-shape pin:
17349        // [`Caixa::contratos`] must return the `:contratos` typed
17350        // `Vec<WitContract>` verbatim as a `&[WitContract]` slice-view
17351        // over the same backing buffer the raw
17352        // `self.contratos.as_slice()` field access borrows from,
17353        // element-equal across every representative fixture in the
17354        // accept-set — `[]` (the "no contracts declared" arm every
17355        // non-`Aplicacao`-kind `defcaixa` carries by
17356        // `#[serde(default)]` and every leaf-Aplicacao with a single
17357        // member carries), a canonical single-edge fixture (the
17358        // minimal directed-graph shape: one HTTP-shape `(cart → catalog)`
17359        // edge), and a canonical multi-edge fixture with three distinct
17360        // edges (the checkout-shape Aplicacao's HTTP-fan pattern:
17361        // `(cart → catalog)`, `(cart → pricing)`, `(cart → auth)`).
17362        //
17363        // Pins against a future silent detour that returned an owned
17364        // `Vec<WitContract>` (which would type-check but silently clone
17365        // on every accessor call, breaking the zero-cost projection
17366        // every peer sibling slice accessor carries), an axis-shuffled
17367        // projection (a future detour that reordered edges through the
17368        // accessor would silently split the paired
17369        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
17370        // traversal input from the peer [`Self::aplicacao_view`] fold-
17371        // in path's clone-order input, since every canonical
17372        // `caixa-mesh` renderer's per-`(:de, :para)` adjacency-list
17373        // seed dispatch reads the edge set through the same slice),
17374        // or a reference to an operator-resolved overlay (the future
17375        // per-cluster `:contratos-overrides` slot — its resolution
17376        // must land at exactly this accessor body, not silently divert
17377        // the raw slot away from a second consumer).
17378        //
17379        // Fourth outer top-level [`Caixa`] `&[Composite]`-return slice
17380        // accessor pin on the substrate primitive for M2 / M3 typed-
17381        // slot vec-carry axes — closes the outer-`Caixa`
17382        // `&[Composite]` composite-slice sub-family the sibling M2
17383        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
17384        // (2a1f907) and
17385        // `children_returns_children_slice_verbatim_across_permutations`
17386        // (c17b51e) pins opened and the M3
17387        // `membros_returns_membros_slice_verbatim_across_permutations`
17388        // (0f26987) pin folded on, closing the outer-`Caixa` M3 mesh-
17389        // slot arm of the composite-slice sub-family. Peer at the outer
17390        // altitude of the closed inner-
17391        // [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
17392        // same MESH-COMPOSITION per-Aplicacao contract-list axis.
17393        let fixtures: Vec<Vec<crate::aplicacao::WitContract>> = vec![
17394            vec![],
17395            vec![contrato_http_for_test("cart", "catalog", "/items")],
17396            vec![
17397                contrato_http_for_test("cart", "catalog", "/items"),
17398                contrato_http_for_test("cart", "pricing", "/price"),
17399                contrato_http_for_test("cart", "auth", "/whoami"),
17400            ],
17401        ];
17402        for contratos in fixtures {
17403            let c = caixa_aplicacao_with_contratos(contratos.clone());
17404            assert_eq!(
17405                c.contratos(),
17406                contratos.as_slice(),
17407                "Caixa::contratos must return :contratos verbatim \
17408                 (got {:?}, expected {contratos:?})",
17409                c.contratos(),
17410            );
17411            assert_eq!(
17412                c.contratos(),
17413                c.contratos.as_slice(),
17414                "Caixa::contratos must element-equal the raw \
17415                 `self.contratos.as_slice()` field access across every \
17416                 value in the Vec<WitContract> accept-set",
17417            );
17418            assert_eq!(
17419                c.contratos().is_empty(),
17420                c.contratos.is_empty(),
17421                "Caixa::contratos().is_empty() must byte-equal \
17422                 self.contratos.is_empty() — a presence-bit drift would \
17423                 silently split the paired Caixa::declared_mesh_slots \
17424                 mesh declared-slot enumerator's presence probe from \
17425                 the peer Caixa::aplicacao_view typed-view composer's \
17426                 fold-in path",
17427            );
17428        }
17429    }
17430
17431    #[test]
17432    fn declared_mesh_slots_contratos_arm_routes_through_accessor() {
17433        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:contratos`
17434        // presence-probe arm must key off [`Caixa::contratos`], not the
17435        // raw `!self.contratos.is_empty()` field-probe. Structurally: a
17436        // `Caixa { contratos: vec![WitContract { .. }], .. }` must push
17437        // `M3_AUTHOR_KEY_CONTRATOS` onto the declared-slot list (the
17438        // presence bit is non-empty, so the mesh kind-coherence gate
17439        // must surface the slot as "declared"), and a `Caixa {
17440        // contratos: vec![], .. }` must NOT push the label (the "author
17441        // omitted the slot entirely" arm — the empty-slice partition
17442        // the serde-default folds onto). The pair jointly pins the
17443        // accessor + declared-slot enumerator composition: any future
17444        // silent detour that had the accessor collapse
17445        // `[WitContract { .. }]` to `[]` (a `.filter(|c| c.de() !=
17446        // "__reserved__")` projection) would silently absorb the
17447        // "declared but degenerate" arm at the accessor boundary and
17448        // the [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
17449        // coherence gate would silently accept a struct-literal
17450        // `Caixa` carrying the drift.
17451        //
17452        // Peer of the sibling
17453        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
17454        // (2a1f907),
17455        // `declared_supervisor_slots_children_arm_routes_through_accessor`
17456        // (c17b51e), and
17457        // `declared_mesh_slots_membros_arm_routes_through_accessor`
17458        // (0f26987) composition pins on the M2 `:upgrade-from` /
17459        // `:children` / M3 `:membros` composite-slice arms — same "the
17460        // enumerator gate must route through the substrate-primitive
17461        // typed dispatch" discipline extended onto the M3 `:contratos`
17462        // composite-slice arm, closing the M3 mesh-slot arm of the
17463        // declared-slot enumerator's routing invariant on the
17464        // composite-slice inputs.
17465        let c = caixa_aplicacao_with_contratos(vec![contrato_http_for_test(
17466            "cart", "catalog", "/items",
17467        )]);
17468        let slots = c.declared_mesh_slots();
17469        assert!(
17470            slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
17471            "declared_mesh_slots must push M3_AUTHOR_KEY_CONTRATOS when \
17472             `:contratos` is non-empty — the accessor and the enumerator \
17473             gate must route through the same substrate-primitive \
17474             typed dispatch on the outer :contratos presence bit (got \
17475             slots={slots:?})",
17476        );
17477        let c = caixa_aplicacao_with_contratos(vec![]);
17478        let slots = c.declared_mesh_slots();
17479        assert!(
17480            !slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
17481            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_CONTRATOS \
17482             when `:contratos` is empty — the author-omitted arm must \
17483             route through the accessor's empty-slice return unchanged \
17484             (got slots={slots:?})",
17485        );
17486    }
17487
17488    #[test]
17489    fn aplicacao_view_contratos_arm_routes_through_accessor() {
17490        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:contratos`
17491        // fold-in arm must key off [`Caixa::contratos`], not the raw
17492        // `self.contratos.clone()` field-clone. Structurally: a `Caixa
17493        // { kind: Aplicacao, contratos: vec![WitContract { de: "cart",
17494        // .. }, WitContract { de: "pricing", .. }], .. }` must fold the
17495        // per-edge list through the accessor into the typed
17496        // [`crate::AplicacaoSpec`] view's `contratos` slot verbatim —
17497        // every entry the accessor surfaces must land in the view's
17498        // `contratos` slot in the same order. The pair jointly pins
17499        // the accessor + view-composer composition: a future silent
17500        // detour that had the accessor shuffle or drop an edge would
17501        // silently split the paired declared-slot enumerator's
17502        // presence bit from the typed-view composer's edge-list, a
17503        // two-consumer split at the enumerator and the view composer
17504        // far from the source `caixa.lisp`.
17505        //
17506        // Peer of the sibling
17507        // `aplicacao_view_membros_arm_routes_through_accessor`
17508        // (0f26987) composition pin on the M3 `:membros` outer-
17509        // `&[Composite]` composite-slice arm, closing the aplicacao-
17510        // view composer's routing invariant on the composite-slice
17511        // inputs at the outer altitude.
17512        let c = caixa_aplicacao_with_contratos(vec![
17513            contrato_http_for_test("cart", "catalog", "/items"),
17514            contrato_http_for_test("cart", "pricing", "/price"),
17515        ]);
17516        let view = c
17517            .aplicacao_view()
17518            .expect("Aplicacao kind must produce an aplicacao_view");
17519        assert_eq!(
17520            view.contratos(),
17521            c.contratos(),
17522            "aplicacao_view must fold Caixa::contratos verbatim into \
17523             AplicacaoSpec::contratos — the accessor and the view \
17524             composer must route through the same substrate-primitive \
17525             typed dispatch on the outer :contratos slice (got view \
17526             contratos={:?}, expected {:?})",
17527            view.contratos(),
17528            c.contratos(),
17529        );
17530    }
17531
17532    #[test]
17533    fn contratos_projects_slice_by_borrow() {
17534        // The by-borrow pin: [`Caixa::contratos`] returns `&[WitContract]`
17535        // by borrow — the returned slice borrows the underlying
17536        // `Vec<WitContract>` storage of the `:contratos` slot and the
17537        // accessor must not clone the backing `Vec` on every call.
17538        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
17539        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
17540        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
17541        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
17542        // `exe_projects_slice_by_borrow` 65d9527,
17543        // `servicos_projects_slice_by_borrow` 611f78b,
17544        // `deps_projects_slice_by_borrow` ad34b4e,
17545        // `deps_dev_projects_slice_by_borrow` f7fd81e,
17546        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
17547        // `children_projects_slice_by_borrow` c17b51e,
17548        // `membros_projects_slice_by_borrow` 0f26987) on the sibling
17549        // outer top-level [`Caixa`] scalar-element and composite-
17550        // element `&[T]` axes — closes the outer-`Caixa` M3 mesh-slot
17551        // composite-element `&[Composite]` axis on the by-borrow pin:
17552        // the accessor's returned slice must borrow from `&self` (the
17553        // returned reference's lifetime is tied to `&self`), and
17554        // calling the accessor twice on the same [`Caixa`] must yield
17555        // slices that are pointer-equal (the underlying byte-buffer is
17556        // the storage `Vec`'s allocation, not a fresh copy) as well as
17557        // value-equal (idempotent, no side effects on `&self`).
17558        //
17559        // Pins against a future silent detour that returned an owned
17560        // `Vec<WitContract>` (which would type-check but silently clone
17561        // on every call), a `&Vec<WitContract>` return (which would
17562        // leak the backing `Vec`'s grow/push/reserve surface no
17563        // downstream consumer reaches for), or a one-arm-only accessor
17564        // that returned a saturating value on some sentinel input.
17565        for contratos in [
17566            vec![],
17567            vec![contrato_http_for_test("cart", "catalog", "/items")],
17568            vec![
17569                contrato_http_for_test("cart", "catalog", "/items"),
17570                contrato_http_for_test("cart", "pricing", "/price"),
17571            ],
17572        ] {
17573            let c = caixa_aplicacao_with_contratos(contratos.clone());
17574            let first = c.contratos();
17575            let second = c.contratos();
17576            assert_eq!(
17577                first, second,
17578                "Caixa::contratos must be idempotent — two successive \
17579                 calls on the same &self must return the same \
17580                 &[WitContract]",
17581            );
17582            assert_eq!(
17583                first.as_ptr(),
17584                second.as_ptr(),
17585                "Caixa::contratos must borrow the underlying \
17586                 Vec<WitContract> storage — two successive calls must \
17587                 return slices with the same backing pointer (a fresh \
17588                 Vec<WitContract> clone would change the pointer on \
17589                 every call)",
17590            );
17591            assert_eq!(
17592                first,
17593                contratos.as_slice(),
17594                "Caixa::contratos must return :contratos verbatim by \
17595                 borrow — got {first:?}, expected {contratos:?}",
17596            );
17597        }
17598    }
17599
17600    // ── drift-detection: Caixa top-level multi-word serde-derive-to-const identity ──
17601
17602    #[test]
17603    fn caixa_multi_word_serde_keys_match_lifted_top_level_key_consts() {
17604        // Load-bearing invariant: every multi-word top-level [`Caixa`]
17605        // serde-derived JSON key routes through a lifted `&'static str`
17606        // const. The Rust field names are `snake_case`
17607        // (`deps_dev` / `upgrade_from` / `max_restarts` /
17608        // `restart_window`); [`Caixa`]'s `#[serde(rename_all =
17609        // "camelCase")]` derive attribute maps each to the camelCase
17610        // byte-string the [`Caixa::to_lisp`] round-trip's
17611        // `serde_json::to_value(self)` step lands under before
17612        // `tatara_lisp::domain::json_to_sexp` re-projects the JSON keys
17613        // to the kebab-case `:deps-dev` / `:upgrade-from` /
17614        // `:max-restarts` / `:restart-window` author surface. Serialize
17615        // a fully-populated [`Caixa`] and pin that each canonical
17616        // byte-sequence appears verbatim in the JSON — a future
17617        // accidental `rename_all = "snake_case"` / `"kebab-case"` /
17618        // verbatim-field-name flip at the derive attribute (any of
17619        // which would silently break every [`Caixa::to_lisp`]
17620        // round-trip and the future M4 operator-side manifest ingest's
17621        // `Value::get(<key>)` navigation) surfaces here as a build-time
17622        // test failure at `manifest.rs`, not as an apply-time
17623        // `.get(<stale-canonical-const>)` returning `None` far from the
17624        // derive-attr drift's commit. Same discipline the sibling
17625        // `supervisor_spec_serde_keys_match_lifted_supervisor_key_consts`
17626        // (40cc4e5), `membro_serde_keys_match_lifted_membro_key_consts`
17627        // (ce80ca0), and `upgrade_from_entry_serde_keys_match_lifted_
17628        // m2_upgrade_from_key_consts` (36ffe65) pins established on the
17629        // sibling M2 supervision-tree, M3 [`Membro`] per-entry, and M2
17630        // [`UpgradeFromEntry`] per-entry axes — extended here to the
17631        // enclosing M0 [`Caixa`] top-level axis so the last of the four
17632        // multi-word top-level [`Caixa`] serde-derived JSON keys
17633        // (`depsDev`) joins the substrate's "one canonical byte-string
17634        // per typed serialized-key axis" discipline.
17635        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
17636        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
17637        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17638        c.deps_dev = vec![Dep::simple("tatara-check", "^0.1")];
17639        c.upgrade_from = vec![UpgradeFromEntry {
17640            from: "0.0.1".into(),
17641            instructions: vec![UpgradeInstruction::Restart],
17642        }];
17643        c.estrategia = Some(RestartStrategy::OneForOne);
17644        c.max_restarts = Some(3);
17645        c.restart_window = Some("60s".into());
17646        c.children = vec![ChildSpec {
17647            caixa: "child".into(),
17648            versao: "^0.1".into(),
17649            restart: RestartPolicy::Permanent,
17650        }];
17651        let json = serde_json::to_string(&c).unwrap();
17652        for key in [
17653            crate::render::CAIXA_KEY_DEPS_DEV,
17654            crate::render::M2_KEY_UPGRADE_FROM,
17655            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
17656            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
17657        ] {
17658            let quoted = format!("\"{key}\"");
17659            assert!(
17660                json.contains(&quoted),
17661                "serialized Caixa must carry the lifted top-level \
17662                 multi-word byte-sequence {quoted} verbatim in the JSON \
17663                 emission (got: {json})",
17664            );
17665        }
17666    }
17667
17668    #[test]
17669    fn caixa_top_level_multi_word_key_consts_are_pairwise_distinct() {
17670        // Cross-axis drift-detection pin: a future collapse of the four
17671        // canonical [`Caixa`] top-level multi-word byte-strings onto the
17672        // same value (e.g. an accidental copy-paste flip of
17673        // [`crate::render::CAIXA_KEY_DEPS_DEV`] to also read
17674        // `"upgradeFrom"`) would silently reroute every downstream
17675        // `Value::get(<key>)` probe on one axis onto the sibling axis's
17676        // top-level entry and pass every propagation-probe test that
17677        // expected only the stale axis's value. Peer of the sibling
17678        // four-way distinct pin on the `SUPERVISOR_KEY_*` tetrad
17679        // (40cc4e5) and the two-way pin on `MEMBRO_KEY_*` (ce80ca0).
17680        let all = [
17681            crate::render::CAIXA_KEY_DEPS_DEV,
17682            crate::render::M2_KEY_UPGRADE_FROM,
17683            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
17684            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
17685        ];
17686        for (i, a) in all.iter().enumerate() {
17687            for b in all.iter().skip(i + 1) {
17688                assert_ne!(
17689                    a, b,
17690                    "Caixa top-level multi-word key consts must be \
17691                     pairwise-distinct canonical byte-sequences — got \
17692                     `{a}` == `{b}`",
17693                );
17694            }
17695        }
17696    }
17697
17698    #[test]
17699    fn caixa_top_level_multi_word_key_consts_are_lower_camel_case_shape() {
17700        // Shape-pin: every [`Caixa`] top-level multi-word key const must
17701        // be a lowerCamelCase byte-sequence (no `snake_case`
17702        // underscores, no `kebab-case` hyphens, no leading colon, no
17703        // `PascalCase` leading capital, no whitespace / dots) — the
17704        // canonical shape the `#[serde(rename_all = "camelCase")]`
17705        // derive produces on [`Caixa`]. A future flip to a
17706        // non-camelCase attribute at the derive surfaces both here
17707        // (this test fails on the stale-constant shape) and at
17708        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
17709        // (that test fails on the mismatch between const and derive).
17710        // Peer with `membro_key_consts_are_lower_camel_case_shape`
17711        // (ce80ca0) and `supervisor_key_consts_are_lower_camel_case_shape`
17712        // (40cc4e5) on the sibling per-entry / supervisor-tree axes.
17713        for key in [
17714            crate::render::CAIXA_KEY_DEPS_DEV,
17715            crate::render::M2_KEY_UPGRADE_FROM,
17716            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
17717            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
17718        ] {
17719            assert!(
17720                !key.is_empty(),
17721                "Caixa top-level multi-word key const must be non-empty \
17722                 (got {key:?})"
17723            );
17724            let first = key.chars().next().unwrap();
17725            assert!(
17726                first.is_ascii_lowercase(),
17727                "Caixa top-level multi-word key const must lead with an \
17728                 ASCII-lowercase byte (got {key:?}, leads with {first:?})",
17729            );
17730            assert!(
17731                key.chars().all(|c| c.is_ascii_alphanumeric()),
17732                "Caixa top-level multi-word key const must be \
17733                 ASCII-alphanumeric only — no `_` / `-` / `:` / `.` / \
17734                 whitespace (got {key:?})",
17735            );
17736        }
17737    }
17738
17739    #[test]
17740    fn caixa_key_deps_dev_pins_canonical_camel_case_byte_string() {
17741        // Scalar-value pin: the byte-string the
17742        // [`crate::render::CAIXA_KEY_DEPS_DEV`] const resolves to,
17743        // asserted verbatim. A future rebrand (`depsDev` → `devDeps`
17744        // matching Cargo's verbatim `dev-dependencies` axis, `depsDev`
17745        // → `depsTest` matching a hypothetical per-test-target
17746        // vocabulary flip) lands as an edit to exactly one const AND
17747        // one derive attribute — the sibling
17748        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
17749        // pin already ties the const to the derive attribute, so a
17750        // rebrand that touches only one side of the pair fails at
17751        // caixa-core build time. Same "scalar-value pin per const"
17752        // discipline the sibling
17753        // `m2_top_level_author_key_consts_pin_canonical_kebab_case_labels`
17754        // (f49c8b0) and `contrato_key_consts_pin_canonical_camel_case_labels`
17755        // (ca463a4) pins carry on the peer M2 / M3 top-level slot axes.
17756        assert_eq!(crate::render::CAIXA_KEY_DEPS_DEV, "depsDev");
17757    }
17758
17759    #[test]
17760    fn caixa_key_deps_pins_canonical_byte_string() {
17761        // Scalar-value pin: the byte-string the
17762        // [`crate::render::CAIXA_KEY_DEPS`] const resolves to, asserted
17763        // verbatim. Peer of `caixa_key_deps_dev_pins_canonical_camel_case_byte_string`
17764        // on the two-list dep-graph serialized-key axis — the sibling
17765        // pin covers the multi-word `deps_dev → depsDev` camelCase
17766        // arm, this pin covers the single-word `deps → deps` no-op arm
17767        // (the [`crate::Caixa::deps`] field name carries no `_`, so the
17768        // `#[serde(rename_all = "camelCase")]` derive is a no-op on this
17769        // axis and the emitted JSON key equals the source-side field
17770        // name byte-for-byte). A future [`crate::Caixa::deps`] field
17771        // rename (`deps` → `dependencies` matching Cargo's verbatim
17772        // `[dependencies]` axis, `deps` → `runtime_deps` matching a
17773        // hypothetical per-runtime-target vocabulary flip) OR an added
17774        // `#[serde(rename = "…")]` explicit override lands as an edit
17775        // to exactly one const AND one derive-attr / field name — the
17776        // sibling `caixa_deps_serde_key_matches_lifted_caixa_key_deps`
17777        // pin ties the const to the emitted JSON key, so a rebrand
17778        // that touches only one side of the pair fails at caixa-core
17779        // build time.
17780        assert_eq!(crate::render::CAIXA_KEY_DEPS, "deps");
17781    }
17782
17783    #[test]
17784    fn caixa_deps_serde_key_matches_lifted_caixa_key_deps() {
17785        // Load-bearing invariant on the single-word `deps` top-level
17786        // axis: the byte-string [`crate::render::CAIXA_KEY_DEPS`] pins
17787        // must appear verbatim in the JSON [`Caixa::to_lisp`]'s
17788        // `serde_json::to_value(self)` step emits. Serialize a
17789        // populated [`Caixa`] whose `:deps` slot carries at least one
17790        // entry (the `#[serde(default)]` attribute on the field emits
17791        // an empty `[]` even without members, but a non-empty vec
17792        // additionally covers the codec's per-`Dep`-entry emission
17793        // path) and pin that `"deps"` appears verbatim in the JSON
17794        // emission — a future accidental `rename_all = "snake_case"` /
17795        // `"kebab-case"` flip at the derive attribute (or an added
17796        // `#[serde(rename = "…")]` explicit override on the field, or
17797        // a Rust field rename) would break every [`Caixa::to_lisp`]
17798        // round-trip and the future M4 operator-side manifest ingest's
17799        // `Value::get(CAIXA_KEY_DEPS)` navigation — surfaces here as a
17800        // build-time test failure at `manifest.rs`, not as an
17801        // apply-time `.get(<stale-canonical-const>)` returning `None`
17802        // far from the drift's commit. Peer of the sibling
17803        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
17804        // multi-word pin on the same M0 [`Caixa`] top-level
17805        // serialized-key axis, extended here to the single-word arm
17806        // the multi-word test's `rename_all = "camelCase"` sweep can't
17807        // reach (single-word `deps → deps` is a no-op the multi-word
17808        // pin's `\"depsDev\"` / `\"upgradeFrom\"` / `\"maxRestarts\"` /
17809        // `\"restartWindow\"` byte-scan can never observe).
17810        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17811        c.deps = vec![Dep::simple("caixa-core", "^0.1")];
17812        let json = serde_json::to_string(&c).unwrap();
17813        let quoted = format!("\"{}\"", crate::render::CAIXA_KEY_DEPS);
17814        assert!(
17815            json.contains(&quoted),
17816            "serialized Caixa must carry the lifted top-level `deps` \
17817             byte-sequence {quoted} verbatim in the JSON emission (got: \
17818             {json})",
17819        );
17820    }
17821
17822    #[test]
17823    fn caixa_dep_graph_two_list_key_consts_are_pairwise_distinct() {
17824        // Cross-axis drift-detection pin on the two-list dep-graph
17825        // renderer-side wire-key axis: a future collapse of the
17826        // canonical [`crate::render::CAIXA_KEY_DEPS`] /
17827        // [`crate::render::CAIXA_KEY_DEPS_DEV`] byte-strings onto the
17828        // same value (e.g. an accidental copy-paste flip of
17829        // `CAIXA_KEY_DEPS_DEV` to also read `"deps"`) would silently
17830        // reroute every downstream `Value::get(<key>)` probe on one
17831        // axis onto the sibling axis's dep-list and pass every
17832        // propagation-probe test that expected only the stale axis's
17833        // value — a dev-only dep would land in the runtime closure at
17834        // publish time, or a runtime dep would be excluded from the
17835        // published lacre. Peer of the sibling four-way distinct pin
17836        // on the top-level multi-word tetrad
17837        // (`caixa_top_level_multi_word_key_consts_are_pairwise_distinct`)
17838        // and the two-way pin on the sibling
17839        // [`DEP_AUTHOR_KEY_DEPS`] / [`DEP_AUTHOR_KEY_DEPS_DEV`]
17840        // author-facing arm (4da6fba's test), extended here to the
17841        // renderer-side wire-key arm of the same two-list dep-graph
17842        // axis so both halves of the "one canonical byte-string per
17843        // typed axis per (author, wire)" grid carry the same
17844        // distinct-ness discipline.
17845        assert_ne!(
17846            crate::render::CAIXA_KEY_DEPS,
17847            crate::render::CAIXA_KEY_DEPS_DEV,
17848            "CAIXA_KEY_DEPS and CAIXA_KEY_DEPS_DEV must be distinct \
17849             canonical byte-sequences on the two-list dep-graph \
17850             renderer-side wire-key axis"
17851        );
17852    }
17853
17854    // ── DepList / Caixa::push_dep pin ────────────────────────────────
17855    //
17856    // The compounding pin: the two-arm closed-set typed enum
17857    // [`crate::dep::DepList`] carries the runtime-closure `:deps`
17858    // (`Prod`) vs dev-only-closure `:deps-dev` (`Dev`) dispatch every
17859    // consumer of the top-level manifest's dep-mutation surface reads
17860    // through, and the typed dispatch [`Caixa::push_dep`] on the
17861    // substrate primitive folds the "select list → check within-list
17862    // dup → push" cascade onto one method call. Prior to this landing
17863    // the two axes lived across two `&'static str` constants
17864    // (`DEP_AUTHOR_KEY_DEPS`, `DEP_AUTHOR_KEY_DEPS_DEV`) with no closed-
17865    // set type carrying the pair; the `feira add` mutation site's
17866    // inline `if self.dev { &mut caixa.deps_dev } else { &mut
17867    // caixa.deps }` dispatch expressed no compile-time link back to
17868    // the substrate primitive, and a future third dep-list axis would
17869    // have silently split at every open-coded mutation site.
17870
17871    #[test]
17872    fn dep_list_as_str_routes_through_lifted_author_key_constants() {
17873        // Every arm returns the same `&'static str` the substrate's
17874        // canonical `DEP_AUTHOR_KEY_DEPS` / `DEP_AUTHOR_KEY_DEPS_DEV`
17875        // constants carry. A future rebrand on either constant reaches
17876        // the enum through one edit; a regression to inline literals
17877        // (e.g. `Prod => ":deps"`) would silently split the diagnostic
17878        // quotes from the wire-format constants every consumer routes
17879        // through and this pin flags it at build time.
17880        assert_eq!(
17881            crate::dep::DepList::Prod.as_str(),
17882            crate::render::DEP_AUTHOR_KEY_DEPS
17883        );
17884        assert_eq!(
17885            crate::dep::DepList::Dev.as_str(),
17886            crate::render::DEP_AUTHOR_KEY_DEPS_DEV
17887        );
17888    }
17889
17890    #[test]
17891    fn dep_list_display_routes_through_as_str() {
17892        // Same as-str-through-Display convergence discipline the
17893        // sibling closed-set typed enums carry — a `format!("{list}")`
17894        // call must land byte-for-byte on the accessor's return so a
17895        // future consumer that formats the enum for a diagnostic line
17896        // reaches the same wire-format constant the wire-format
17897        // producers do.
17898        assert_eq!(
17899            format!("{}", crate::dep::DepList::Prod),
17900            crate::dep::DepList::Prod.as_str()
17901        );
17902        assert_eq!(
17903            format!("{}", crate::dep::DepList::Dev),
17904            crate::dep::DepList::Dev.as_str()
17905        );
17906    }
17907
17908    #[test]
17909    fn dep_list_all_enumerates_every_variant_once() {
17910        // Exhaustive-iteration pin — every arm appears exactly once in
17911        // `ALL`, matching the closed set the compiler enforces on the
17912        // sibling `match self` arms. A future variant addition that
17913        // extends only one method's match without extending `ALL`
17914        // would silently drop the new arm from every consumer that
17915        // iterates the slice.
17916        let variants: &[crate::dep::DepList] = crate::dep::DepList::ALL;
17917        assert!(variants.contains(&crate::dep::DepList::Prod));
17918        assert!(variants.contains(&crate::dep::DepList::Dev));
17919        assert_eq!(variants.len(), 2);
17920    }
17921
17922    #[test]
17923    fn dep_list_from_wire_returns_prod_on_deps_wire_scalar() {
17924        // Reverse projection on the two-list dep-graph axis: the
17925        // author-surface wire tag the sibling `as_str` emitter walks
17926        // for `Prod` (`:deps` via `DEP_AUTHOR_KEY_DEPS`) parses back to
17927        // `Some(DepList::Prod)`. A regression that hand-rolled the
17928        // per-arm match without routing through the lifted
17929        // `DEP_AUTHOR_KEY_DEPS` const would silently disagree on any
17930        // future wire-tag rebrand and this pin flags it at build time.
17931        assert_eq!(
17932            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS),
17933            Some(crate::dep::DepList::Prod)
17934        );
17935    }
17936
17937    #[test]
17938    fn dep_list_from_wire_returns_dev_on_deps_dev_wire_scalar() {
17939        // Peer of the `Prod`-arm pin on the dev-only axis: the
17940        // author-surface wire tag the sibling `as_str` emitter walks
17941        // for `Dev` (`:deps-dev` via `DEP_AUTHOR_KEY_DEPS_DEV`) parses
17942        // back to `Some(DepList::Dev)`. Same drift-detection posture
17943        // as the peer arm — the sibling method `match` arms are
17944        // compiler-checked exhaustive so a future variant addition
17945        // trips at build time.
17946        assert_eq!(
17947            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS_DEV),
17948            Some(crate::dep::DepList::Dev)
17949        );
17950    }
17951
17952    #[test]
17953    fn dep_list_from_wire_returns_none_on_unknown_wire_scalar() {
17954        // Every input outside the closed-set arm-string set the
17955        // sibling `as_str` emitter walks lands on the terminal `None`
17956        // fallback — no silent-accept surface. Sweeps a set of
17957        // plausibly-adjacent scalars (unprefixed wire form, PascalCase
17958        // rebrand candidates, foreign wire tags, empty string) so a
17959        // future variant addition that widened one wire form without
17960        // extending the emitter's arm-set would trip the sibling
17961        // round-trip pin below rather than silently accepting the new
17962        // form here.
17963        for candidate in [
17964            "",
17965            "deps",
17966            "deps-dev",
17967            ":deps ",
17968            ":Deps",
17969            ":DEPS",
17970            ":build-dep",
17971            ":tool-dep",
17972            "prod",
17973            "dev",
17974        ] {
17975            assert_eq!(
17976                crate::dep::DepList::from_wire(candidate),
17977                None,
17978                "from_wire({candidate:?}) must return None; every input outside \
17979                 the {{DEP_AUTHOR_KEY_DEPS, DEP_AUTHOR_KEY_DEPS_DEV}} accept-set \
17980                 the sibling as_str emitter walks lands on the terminal fallback",
17981            );
17982        }
17983    }
17984
17985    #[test]
17986    fn dep_list_round_trips_through_as_str_and_from_wire() {
17987        // Load-bearing round-trip pin: every arm the `ALL` iteration
17988        // exposes survives the `as_str` → `from_wire` composition
17989        // byte-for-byte. Same discipline the sibling closed-set enums
17990        // carry — `CaixaKind` /
17991        // `RestartStrategy` / `RestartPolicy` /
17992        // `PlacementStrategy` — extended onto the two-list dep-graph
17993        // axis. A future variant addition that extends `ALL` +
17994        // `as_str` without extending `from_wire` (or vice versa)
17995        // trips at build time on this iteration because the compiler
17996        // enforces exhaustiveness on the sibling `match self` arms.
17997        for &list in crate::dep::DepList::ALL {
17998            assert_eq!(
17999                crate::dep::DepList::from_wire(list.as_str()),
18000                Some(list),
18001                "DepList::from_wire(as_str({list:?})) must round-trip to Some({list:?}) — \
18002                 a silent split between the forward emitter and the reverse parser \
18003                 would drift the two halves of the two-list dep-graph axis's typed dispatch",
18004            );
18005        }
18006    }
18007
18008    #[test]
18009    fn push_dep_routes_to_deps_slot_on_prod_arm() {
18010        // The `Prod` arm dispatches to the runtime-closure `:deps`
18011        // slot every downstream lacre-pipeline consumer resolves at
18012        // build time. A future arm that regressed to inline `&mut
18013        // self.deps_dev` on the `Prod` path would silently reroute
18014        // every runtime dep into the dev-only closure at publish time
18015        // — this pin refuses that regression.
18016        let src = Caixa::template("host");
18017        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18018        let before_deps = caixa.deps().len();
18019        let before_deps_dev = caixa.deps_dev().len();
18020        let dep = Dep {
18021            nome: "caixa-teia".to_string(),
18022            versao: "^0.1".to_string(),
18023            fonte: None,
18024            opcional: false,
18025            caracteristicas: Vec::new(),
18026        };
18027        caixa
18028            .push_dep(crate::dep::DepList::Prod, dep)
18029            .expect("first push into :deps succeeds");
18030        assert_eq!(caixa.deps().len(), before_deps + 1);
18031        assert_eq!(caixa.deps_dev().len(), before_deps_dev);
18032        assert_eq!(caixa.deps().last().unwrap().nome(), "caixa-teia");
18033    }
18034
18035    #[test]
18036    fn push_dep_routes_to_deps_dev_slot_on_dev_arm() {
18037        // Peer of the sibling `Prod`-arm dispatch pin — the `Dev` arm
18038        // must dispatch to the dev-only-closure `:deps-dev` slot every
18039        // downstream test-facing artifact resolver reads. A future
18040        // regression that inverted the two arms would silently route
18041        // every dev-only dep into the runtime closure at publish time
18042        // and this pin catches it before the drift ships.
18043        let src = Caixa::template("host");
18044        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18045        let dep = Dep {
18046            nome: "tatara-check".to_string(),
18047            versao: "*".to_string(),
18048            fonte: None,
18049            opcional: false,
18050            caracteristicas: Vec::new(),
18051        };
18052        caixa
18053            .push_dep(crate::dep::DepList::Dev, dep)
18054            .expect("first push into :deps-dev succeeds");
18055        assert!(caixa.deps().is_empty());
18056        assert_eq!(caixa.deps_dev().len(), 1);
18057        assert_eq!(caixa.deps_dev().last().unwrap().nome(), "tatara-check");
18058    }
18059
18060    #[test]
18061    fn push_dep_refuses_within_list_duplicate_nome_with_typed_error() {
18062        // Within-list dup check routes through the canonical
18063        // [`DepError::DuplicateNome`] carrier — the substrate's typed
18064        // diagnostic for the same axis [`Caixa::validate_deps`]'s
18065        // parse-time [`crate::render::insert_first_seen`] walk raises
18066        // on. Prior to the lift the mutation site's inline
18067        // `bail!("dep '{}' already declared", …)` string-diagnostic
18068        // path expressed no through-line back to the typed error;
18069        // routing every dep-list refusal through one carrier means an
18070        // author reading a `feira add` refusal and a `feira build`
18071        // refusal reaches for the same corrective surface without
18072        // switching diagnostic idioms.
18073        let src = Caixa::template("host");
18074        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18075        let dep = Dep {
18076            nome: "caixa-teia".to_string(),
18077            versao: "^0.1".to_string(),
18078            fonte: None,
18079            opcional: false,
18080            caracteristicas: Vec::new(),
18081        };
18082        caixa
18083            .push_dep(crate::dep::DepList::Prod, dep.clone())
18084            .expect("first push succeeds");
18085        let dup = Dep {
18086            nome: "caixa-teia".to_string(),
18087            versao: "^0.2".to_string(),
18088            fonte: None,
18089            opcional: false,
18090            caracteristicas: Vec::new(),
18091        };
18092        let err = caixa
18093            .push_dep(crate::dep::DepList::Prod, dup)
18094            .expect_err("second push with same :nome refuses");
18095        assert_eq!(
18096            err,
18097            DepError::DuplicateNome {
18098                nome: "caixa-teia".to_string(),
18099                list: crate::render::DEP_AUTHOR_KEY_DEPS,
18100            }
18101        );
18102        // The refused mutation must not corrupt the target list —
18103        // exactly one entry lives past the refusal, matching the
18104        // canonical single-source-of-truth invariant `Caixa::deps()`
18105        // carries.
18106        assert_eq!(caixa.deps().len(), 1);
18107    }
18108
18109    #[test]
18110    fn push_dep_refuses_dup_on_dev_list_arm_names_deps_dev_key() {
18111        // Peer of the sibling `Prod`-arm dup-refusal pin — the `Dev`
18112        // arm's refusal must carry `DEP_AUTHOR_KEY_DEPS_DEV` in the
18113        // `list` payload so a future author reading the refusal grep's
18114        // for the correct `:deps-dev` block in their `caixa.lisp`,
18115        // not the sibling `:deps` block the runtime closure resolves.
18116        let src = Caixa::template("host");
18117        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18118        let dep = Dep {
18119            nome: "tatara-check".to_string(),
18120            versao: "*".to_string(),
18121            fonte: None,
18122            opcional: false,
18123            caracteristicas: Vec::new(),
18124        };
18125        caixa
18126            .push_dep(crate::dep::DepList::Dev, dep.clone())
18127            .expect("first push succeeds");
18128        let err = caixa
18129            .push_dep(crate::dep::DepList::Dev, dep)
18130            .expect_err("second push with same :nome refuses");
18131        assert!(matches!(
18132            err,
18133            DepError::DuplicateNome {
18134                ref nome,
18135                list,
18136            } if nome == "tatara-check"
18137                && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
18138        ));
18139    }
18140
18141    #[test]
18142    fn push_dep_allows_same_nome_across_prod_and_dev_lists() {
18143        // The within-list dup check is scoped to the target arm — a
18144        // caixa may legitimately carry the same `:nome` under both
18145        // `:deps` and `:deps-dev` (though the substrate's peer
18146        // [`crate::Caixa::validate_deps`] walk still refuses the
18147        // shape at parse time; the mutation-site refusal is scoped to
18148        // the mutation-site's list to match the peer parse-time
18149        // per-list [`crate::render::insert_first_seen`] discipline).
18150        // The two arms hold independent seen-sets.
18151        let src = Caixa::template("host");
18152        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18153        let dep_prod = Dep {
18154            nome: "shared".to_string(),
18155            versao: "^0.1".to_string(),
18156            fonte: None,
18157            opcional: false,
18158            caracteristicas: Vec::new(),
18159        };
18160        let dep_dev = Dep {
18161            nome: "shared".to_string(),
18162            versao: "*".to_string(),
18163            fonte: None,
18164            opcional: false,
18165            caracteristicas: Vec::new(),
18166        };
18167        caixa
18168            .push_dep(crate::dep::DepList::Prod, dep_prod)
18169            .expect("push into :deps succeeds");
18170        caixa
18171            .push_dep(crate::dep::DepList::Dev, dep_dev)
18172            .expect("push same :nome into :deps-dev succeeds");
18173        assert_eq!(caixa.deps().len(), 1);
18174        assert_eq!(caixa.deps_dev().len(), 1);
18175    }
18176
18177    #[test]
18178    fn deps_of_prod_returns_the_deps_slot_verbatim() {
18179        // The `Prod` arm of the typed-dispatch [`Caixa::deps_of`] read
18180        // accessor must project onto the runtime-closure `:deps` slot —
18181        // element-equal and length-equal to the sibling per-slot
18182        // [`Caixa::deps`] accessor's return over every per-caixa fixture.
18183        // A future arm that regressed to `self.deps_dev()` on the `Prod`
18184        // path would silently reroute every downstream typed-dispatch
18185        // walker (the [`Caixa::validate_deps`] per-list
18186        // [`crate::render::insert_first_seen`] dedup walk, any future
18187        // per-axis-parametrised consumer) into the sibling dev-only
18188        // closure and this pin refuses that regression.
18189        let src = Caixa::template("host");
18190        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18191        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
18192        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 0);
18193        let dep = Dep {
18194            nome: "caixa-teia".to_string(),
18195            versao: "^0.1".to_string(),
18196            fonte: None,
18197            opcional: false,
18198            caracteristicas: Vec::new(),
18199        };
18200        caixa
18201            .push_dep(crate::dep::DepList::Prod, dep.clone())
18202            .expect("push into :deps succeeds");
18203        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
18204        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 1);
18205        assert_eq!(
18206            caixa.deps_of(crate::dep::DepList::Prod)[0].nome(),
18207            "caixa-teia"
18208        );
18209    }
18210
18211    #[test]
18212    fn deps_of_dev_returns_the_deps_dev_slot_verbatim() {
18213        // Peer of the sibling `Prod`-arm pin — the `Dev` arm of
18214        // [`Caixa::deps_of`] must project onto the dev-only-closure
18215        // `:deps-dev` slot, element-equal and length-equal to the
18216        // sibling per-slot [`Caixa::deps_dev`] accessor's return. A
18217        // future regression that inverted the two arms would silently
18218        // route every dev-list walker onto the runtime closure and this
18219        // pin catches it before the drift ships.
18220        let src = Caixa::template("host");
18221        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18222        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
18223        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 0);
18224        let dep = Dep {
18225            nome: "tatara-check".to_string(),
18226            versao: "*".to_string(),
18227            fonte: None,
18228            opcional: false,
18229            caracteristicas: Vec::new(),
18230        };
18231        caixa
18232            .push_dep(crate::dep::DepList::Dev, dep)
18233            .expect("push into :deps-dev succeeds");
18234        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
18235        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 1);
18236        assert_eq!(
18237            caixa.deps_of(crate::dep::DepList::Dev)[0].nome(),
18238            "tatara-check"
18239        );
18240    }
18241
18242    #[test]
18243    fn deps_of_exhaustive_over_dep_list_all_covers_the_two_slots() {
18244        // Composition pin: iterating [`crate::dep::DepList::ALL`] through
18245        // [`Caixa::deps_of`] must land on the same two-slot partition the
18246        // per-slot [`Caixa::deps`] / [`Caixa::deps_dev`] accessors
18247        // expose — the canonical dispatch a future per-axis-parametrised
18248        // walker (a future `feira app graph` per-list dep summary, a
18249        // future M4 per-cluster dev-closure-audit overlay the CR
18250        // materializer resolves per-CR) reads through. Prior to the
18251        // lift the two-block iteration lived open-coded at every walker,
18252        // so a future third dep-list axis (`:deps-build`, per CAIXA-SDLC
18253        // §I) would have had to grow a third block at every consumer.
18254        // A regression that dropped the `Dev` arm from `ALL` would flip
18255        // the collected pairs to `[(":deps", &[])]` alone and this pin
18256        // refuses that shape.
18257        let src = Caixa::template("host");
18258        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18259        let prod_dep = Dep {
18260            nome: "caixa-teia".to_string(),
18261            versao: "^0.1".to_string(),
18262            fonte: None,
18263            opcional: false,
18264            caracteristicas: Vec::new(),
18265        };
18266        let dev_dep = Dep {
18267            nome: "tatara-check".to_string(),
18268            versao: "*".to_string(),
18269            fonte: None,
18270            opcional: false,
18271            caracteristicas: Vec::new(),
18272        };
18273        caixa
18274            .push_dep(crate::dep::DepList::Prod, prod_dep)
18275            .expect("push into :deps succeeds");
18276        caixa
18277            .push_dep(crate::dep::DepList::Dev, dev_dep)
18278            .expect("push into :deps-dev succeeds");
18279        let collected: Vec<(&'static str, usize, &str)> = crate::dep::DepList::ALL
18280            .iter()
18281            .map(|&list| {
18282                let slice = caixa.deps_of(list);
18283                (list.as_str(), slice.len(), slice[0].nome())
18284            })
18285            .collect();
18286        assert_eq!(
18287            collected,
18288            vec![
18289                (crate::render::DEP_AUTHOR_KEY_DEPS, 1, "caixa-teia"),
18290                (crate::render::DEP_AUTHOR_KEY_DEPS_DEV, 1, "tatara-check"),
18291            ]
18292        );
18293    }
18294
18295    #[test]
18296    fn validate_deps_iterates_through_dep_list_all_via_deps_of() {
18297        // Composition pin: the [`Caixa::validate_deps`] parse-time gate
18298        // must route its per-list [`crate::render::insert_first_seen`]
18299        // dedup walk through [`Caixa::deps_of`] + [`crate::dep::DepList::ALL`]
18300        // rather than the pre-lift open-coded two-block iteration over
18301        // `self.deps()` + `self.deps_dev()`. A regression that dropped
18302        // one arm (e.g. hand-inlining `self.deps()` alone) would silently
18303        // stop refusing within-list dups on the sibling arm; a
18304        // regression that flipped the arm-to-list-key mapping
18305        // (`Dev => DEP_AUTHOR_KEY_DEPS`) would silently mislabel the
18306        // diagnostic surface. Both drifts surface here through a paired
18307        // duplicate-name refusal per arm plus an offending-list-key
18308        // check on the emitted [`DepError::DuplicateNome`] carrier.
18309        for &list in crate::dep::DepList::ALL {
18310            let src = Caixa::template("host");
18311            let mut caixa = Caixa::from_lisp(&src).expect("template parses");
18312            let dup = Dep {
18313                nome: "twin".to_string(),
18314                versao: "^0.1".to_string(),
18315                fonte: None,
18316                opcional: false,
18317                caracteristicas: Vec::new(),
18318            };
18319            match list {
18320                crate::dep::DepList::Prod => {
18321                    caixa.deps.push(dup.clone());
18322                    caixa.deps.push(dup);
18323                }
18324                crate::dep::DepList::Dev => {
18325                    caixa.deps_dev.push(dup.clone());
18326                    caixa.deps_dev.push(dup);
18327                }
18328            }
18329            let err = caixa
18330                .validate_deps()
18331                .expect_err("within-list duplicate :nome must refuse");
18332            assert_eq!(
18333                err,
18334                DepError::DuplicateNome {
18335                    nome: "twin".to_string(),
18336                    list: list.as_str(),
18337                },
18338                "validate_deps on {list} arm must emit \
18339                 DepError::DuplicateNome carrying the arm's own \
18340                 as_str() diagnostic — the arm-to-list-key mapping \
18341                 flowed through DepList::ALL + Caixa::deps_of"
18342            );
18343        }
18344    }
18345
18346    #[test]
18347    fn caixa_licenca_default_pins_canonical_mit_byte() {
18348        // Bridge-arm pin: [`CAIXA_LICENCA_DEFAULT`] resolves to the
18349        // canonical SPDX-`"MIT"` byte today, the same license expression
18350        // every peer substrate-side consumer of the author-omitted
18351        // `:licenca` slot ([`caixa-helm`]'s `build_readme` fallback arm at
18352        // `caixa-helm/src/lib.rs`, the future M4
18353        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-CR
18354        // `Chart.yaml annotations["artifacthub.io/license"]` emitter this
18355        // crate's [`Caixa::validate_licenca`] docstring roadmap already
18356        // names as the second consumer) fills into its per-consumer
18357        // README/annotation emit site. Pin the literal here (peer with the
18358        // [`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`] /
18359        // [`crate::version::DEFAULT_GIT_REMOTE`] /
18360        // [`crate::version::DEFAULT_PLEME_GIT_ORG`] canonical-literal pins
18361        // on the sibling lifted-constant surfaces) so a future
18362        // substrate-side license-fallback rebrand surfaces here as a
18363        // coordinated edit-point: the sibling caixa-helm
18364        // `build_readme_license_line_routes_through_lifted_caixa_licenca_default`
18365        // pinning test already pins the equality at the renderer-emit
18366        // axis; this pin closes the second coordinate of the pair by
18367        // anchoring the lifted constant's current byte to the canonical
18368        // CAIXA-SDLC §I license scaffold's documented shape.
18369        assert_eq!(CAIXA_LICENCA_DEFAULT, "MIT");
18370    }
18371}